xref: /freebsd/sys/dev/sfxge/common/siena_vpd.c (revision 10b59a9b4add0320d52c15ce057dd697261e7dfc)
1 /*-
2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_regs.h"
30 #include "efx_impl.h"
31 
32 #if EFSYS_OPT_VPD
33 
34 #if EFSYS_OPT_SIENA
35 
36 static	__checkReturn			int
37 siena_vpd_get_static(
38 	__in				efx_nic_t *enp,
39 	__in				unsigned int partn,
40 	__deref_out_bcount_opt(*sizep)	caddr_t *svpdp,
41 	__out				size_t *sizep)
42 {
43 	siena_mc_static_config_hdr_t *scfg;
44 	caddr_t svpd;
45 	size_t size;
46 	uint8_t cksum;
47 	unsigned int vpd_offset;
48 	unsigned int vpd_length;
49 	unsigned int hdr_length;
50 	unsigned int pos;
51 	unsigned int region;
52 	int rc;
53 
54 	EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
55 		    partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
56 
57 	/* Allocate sufficient memory for the entire static cfg area */
58 	if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
59 		goto fail1;
60 
61 	EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
62 	if (scfg == NULL) {
63 		rc = ENOMEM;
64 		goto fail2;
65 	}
66 
67 	if ((rc = siena_nvram_partn_read(enp, partn, 0,
68 	    (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
69 		goto fail3;
70 
71 	/* Verify the magic number */
72 	if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
73 	    SIENA_MC_STATIC_CONFIG_MAGIC) {
74 		rc = EINVAL;
75 		goto fail4;
76 	}
77 
78 	/* All future versions of the structure must be backwards compatable */
79 	EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
80 
81 	hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
82 	vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
83 	vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
84 
85 	/* Verify the hdr doesn't overflow the sector size */
86 	if (hdr_length > size || vpd_offset > size || vpd_length > size ||
87 	    vpd_length + vpd_offset > size) {
88 		rc = EINVAL;
89 		goto fail5;
90 	}
91 
92 	/* Read the remainder of scfg + static vpd */
93 	region = vpd_offset + vpd_length;
94 	if (region > SIENA_NVRAM_CHUNK) {
95 		if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
96 		    (caddr_t)scfg + SIENA_NVRAM_CHUNK,
97 		    region - SIENA_NVRAM_CHUNK)) != 0)
98 			goto fail6;
99 	}
100 
101 	/* Verify checksum */
102 	cksum = 0;
103 	for (pos = 0; pos < hdr_length; pos++)
104 		cksum += ((uint8_t *)scfg)[pos];
105 	if (cksum != 0) {
106 		rc = EINVAL;
107 		goto fail7;
108 	}
109 
110 	if (vpd_length == 0)
111 		svpd = NULL;
112 	else {
113 		/* Copy the vpd data out */
114 		EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
115 		if (svpd == NULL) {
116 			rc = ENOMEM;
117 			goto fail8;
118 		}
119 		memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
120 	}
121 
122 	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
123 
124 	*svpdp = svpd;
125 	*sizep = vpd_length;
126 
127 	return (0);
128 
129 fail8:
130 	EFSYS_PROBE(fail8);
131 fail7:
132 	EFSYS_PROBE(fail7);
133 fail6:
134 	EFSYS_PROBE(fail6);
135 fail5:
136 	EFSYS_PROBE(fail5);
137 fail4:
138 	EFSYS_PROBE(fail4);
139 fail3:
140 	EFSYS_PROBE(fail3);
141 fail2:
142 	EFSYS_PROBE(fail2);
143 
144 	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
145 
146 fail1:
147 	EFSYS_PROBE1(fail1, int, rc);
148 
149 	return (rc);
150 }
151 
152 	__checkReturn		int
153 siena_vpd_init(
154 	__in			efx_nic_t *enp)
155 {
156 	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
157 	caddr_t svpd = NULL;
158 	unsigned partn;
159 	size_t size = 0;
160 	int rc;
161 
162 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
163 
164 	partn = (emip->emi_port == 1)
165 		? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
166 		: MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
167 
168 	/*
169 	 * We need the static VPD sector to present a unified static+dynamic
170 	 * VPD, that is, basically on every read, write, verify cycle. Since
171 	 * it should *never* change we can just cache it here.
172 	 */
173 	if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
174 		goto fail1;
175 
176 	if (svpd != NULL && size > 0) {
177 		if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
178 			goto fail2;
179 	}
180 
181 	enp->en_u.siena.enu_svpd = svpd;
182 	enp->en_u.siena.enu_svpd_length = size;
183 
184 	return (0);
185 
186 fail2:
187 	EFSYS_PROBE(fail2);
188 
189 	EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
190 fail1:
191 	EFSYS_PROBE1(fail1, int, rc);
192 
193 	return (rc);
194 }
195 
196 	__checkReturn		int
197 siena_vpd_size(
198 	__in			efx_nic_t *enp,
199 	__out			size_t *sizep)
200 {
201 	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
202 	unsigned int partn;
203 	int rc;
204 
205 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
206 
207 	/*
208 	 * This function returns the total size the user should allocate
209 	 * for all VPD operations. We've already cached the static vpd,
210 	 * so we just need to return an upper bound on the dynamic vpd.
211 	 * Since the dynamic_config structure can change under our feet,
212 	 * (as version numbers are inserted), just be safe and return the
213 	 * total size of the dynamic_config *sector*
214 	 */
215 	partn = (emip->emi_port == 1)
216 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
217 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
218 
219 	if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
220 		goto fail1;
221 
222 	return (0);
223 
224 fail1:
225 	EFSYS_PROBE1(fail1, int, rc);
226 
227 	return (rc);
228 }
229 
230 	__checkReturn		int
231 siena_vpd_read(
232 	__in			efx_nic_t *enp,
233 	__out_bcount(size)	caddr_t data,
234 	__in			size_t size)
235 {
236 	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
237 	siena_mc_dynamic_config_hdr_t *dcfg;
238 	unsigned int vpd_length;
239 	unsigned int vpd_offset;
240 	unsigned int dcfg_partn;
241 	size_t dcfg_size;
242 	int rc;
243 
244 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
245 
246 	dcfg_partn = (emip->emi_port == 1)
247 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
248 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
249 
250 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
251 	    B_TRUE, &dcfg, &dcfg_size)) != 0)
252 		goto fail1;
253 
254 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
255 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
256 
257 	if (vpd_length > size) {
258 		rc = EFAULT;	/* Invalid dcfg: header bigger than sector */
259 		goto fail2;
260 	}
261 
262 	EFSYS_ASSERT3U(vpd_length, <=, size);
263 	memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
264 
265 	/* Pad data with all-1s, consistent with update operations */
266 	memset(data + vpd_length, 0xff, size - vpd_length);
267 
268 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
269 
270 	return (0);
271 
272 fail2:
273 	EFSYS_PROBE(fail2);
274 
275 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
276 fail1:
277 	EFSYS_PROBE1(fail1, int, rc);
278 
279 	return (rc);
280 }
281 
282 	__checkReturn		int
283 siena_vpd_verify(
284 	__in			efx_nic_t *enp,
285 	__in_bcount(size)	caddr_t data,
286 	__in			size_t size)
287 {
288 	efx_vpd_tag_t stag;
289 	efx_vpd_tag_t dtag;
290 	efx_vpd_keyword_t skey;
291 	efx_vpd_keyword_t dkey;
292 	unsigned int scont;
293 	unsigned int dcont;
294 
295 	int rc;
296 
297 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
298 
299 	/*
300 	 * Strictly you could take the view that dynamic vpd is optional.
301 	 * Instead, to conform more closely to the read/verify/reinit()
302 	 * paradigm, we require dynamic vpd. siena_vpd_reinit() will
303 	 * reinitialize it as required.
304 	 */
305 	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
306 		goto fail1;
307 
308 	/*
309 	 * Verify that there is no duplication between the static and
310 	 * dynamic cfg sectors.
311 	 */
312 	if (enp->en_u.siena.enu_svpd_length == 0)
313 		goto done;
314 
315 	dcont = 0;
316 	_NOTE(CONSTANTCONDITION)
317 	while (1) {
318 		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
319 		    &dkey, NULL, NULL, &dcont)) != 0)
320 			goto fail2;
321 		if (dcont == 0)
322 			break;
323 
324 		scont = 0;
325 		_NOTE(CONSTANTCONDITION)
326 		while (1) {
327 			if ((rc = efx_vpd_hunk_next(
328 			    enp->en_u.siena.enu_svpd,
329 			    enp->en_u.siena.enu_svpd_length, &stag, &skey,
330 			    NULL, NULL, &scont)) != 0)
331 				goto fail3;
332 			if (scont == 0)
333 				break;
334 
335 			if (stag == dtag && skey == dkey) {
336 				rc = EEXIST;
337 				goto fail4;
338 			}
339 		}
340 	}
341 
342 done:
343 	return (0);
344 
345 fail4:
346 	EFSYS_PROBE(fail4);
347 fail3:
348 	EFSYS_PROBE(fail3);
349 fail2:
350 	EFSYS_PROBE(fail2);
351 fail1:
352 	EFSYS_PROBE1(fail1, int, rc);
353 
354 	return (rc);
355 }
356 
357 	__checkReturn		int
358 siena_vpd_reinit(
359 	__in			efx_nic_t *enp,
360 	__in_bcount(size)	caddr_t data,
361 	__in			size_t size)
362 {
363 	boolean_t wantpid;
364 	int rc;
365 
366 	/*
367 	 * Only create a PID if the dynamic cfg doesn't have one
368 	 */
369 	if (enp->en_u.siena.enu_svpd_length == 0)
370 		wantpid = B_TRUE;
371 	else {
372 		unsigned int offset;
373 		uint8_t length;
374 
375 		rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
376 				    enp->en_u.siena.enu_svpd_length,
377 				    EFX_VPD_ID, 0, &offset, &length);
378 		if (rc == 0)
379 			wantpid = B_FALSE;
380 		else if (rc == ENOENT)
381 			wantpid = B_TRUE;
382 		else
383 			goto fail1;
384 	}
385 
386 	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
387 		goto fail2;
388 
389 	return (0);
390 
391 fail2:
392 	EFSYS_PROBE(fail2);
393 fail1:
394 	EFSYS_PROBE1(fail1, int, rc);
395 
396 	return (rc);
397 }
398 
399 	__checkReturn		int
400 siena_vpd_get(
401 	__in			efx_nic_t *enp,
402 	__in_bcount(size)	caddr_t data,
403 	__in			size_t size,
404 	__inout			efx_vpd_value_t *evvp)
405 {
406 	unsigned int offset;
407 	uint8_t length;
408 	int rc;
409 
410 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
411 
412 	/* Attempt to satisfy the request from svpd first */
413 	if (enp->en_u.siena.enu_svpd_length > 0) {
414 		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
415 		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
416 		    evvp->evv_keyword, &offset, &length)) == 0) {
417 			evvp->evv_length = length;
418 			memcpy(evvp->evv_value,
419 			    enp->en_u.siena.enu_svpd + offset, length);
420 			return (0);
421 		} else if (rc != ENOENT)
422 			goto fail1;
423 	}
424 
425 	/* And then from the provided data buffer */
426 	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
427 	    evvp->evv_keyword, &offset, &length)) != 0)
428 		goto fail2;
429 
430 	evvp->evv_length = length;
431 	memcpy(evvp->evv_value, data + offset, length);
432 
433 	return (0);
434 
435 fail2:
436 	EFSYS_PROBE(fail2);
437 fail1:
438 	EFSYS_PROBE1(fail1, int, rc);
439 
440 	return (rc);
441 }
442 
443 	__checkReturn		int
444 siena_vpd_set(
445 	__in			efx_nic_t *enp,
446 	__in_bcount(size)	caddr_t data,
447 	__in			size_t size,
448 	__in			efx_vpd_value_t *evvp)
449 {
450 	int rc;
451 
452 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
453 
454 	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
455 	if (enp->en_u.siena.enu_svpd_length > 0) {
456 		unsigned int offset;
457 		uint8_t length;
458 
459 		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
460 		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
461 		    evvp->evv_keyword, &offset, &length)) == 0) {
462 			rc = EACCES;
463 			goto fail1;
464 		}
465 	}
466 
467 	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
468 		goto fail2;
469 
470 	return (0);
471 
472 fail2:
473 	EFSYS_PROBE(fail2);
474 fail1:
475 	EFSYS_PROBE1(fail1, int, rc);
476 
477 	return (rc);
478 }
479 
480 	__checkReturn		int
481 siena_vpd_next(
482 	__in			efx_nic_t *enp,
483 	__in_bcount(size)	caddr_t data,
484 	__in			size_t size,
485 	__out			efx_vpd_value_t *evvp,
486 	__inout			unsigned int *contp)
487 {
488 	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
489 
490 	return (ENOTSUP);
491 }
492 
493 	__checkReturn		int
494 siena_vpd_write(
495 	__in			efx_nic_t *enp,
496 	__in_bcount(size)	caddr_t data,
497 	__in			size_t size)
498 {
499 	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
500 	siena_mc_dynamic_config_hdr_t *dcfg;
501 	unsigned int vpd_offset;
502 	unsigned int dcfg_partn;
503 	unsigned int hdr_length;
504 	unsigned int pos;
505 	uint8_t cksum;
506 	size_t partn_size, dcfg_size;
507 	size_t vpd_length;
508 	int rc;
509 
510 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
511 
512 	/* Determine total length of all tags */
513 	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
514 		goto fail1;
515 
516 	/* Lock dynamic config sector for write, and read structure only */
517 	dcfg_partn = (emip->emi_port == 1)
518 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
519 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
520 
521 	if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
522 		goto fail2;
523 
524 	if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
525 		goto fail2;
526 
527 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
528 	    B_FALSE, &dcfg, &dcfg_size)) != 0)
529 		goto fail3;
530 
531 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
532 
533 	/* Allocated memory should have room for the new VPD */
534 	if (hdr_length + vpd_length > dcfg_size) {
535 		rc = ENOSPC;
536 		goto fail3;
537 	}
538 
539 	/* Copy in new vpd and update header */
540 	vpd_offset = dcfg_size - vpd_length;
541 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
542 			     EFX_DWORD_0, vpd_offset);
543 	memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
544 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length,
545 			    EFX_DWORD_0, vpd_length);
546 
547 	/* Update the checksum */
548 	cksum = 0;
549 	for (pos = 0; pos < hdr_length; pos++)
550 		cksum += ((uint8_t *)dcfg)[pos];
551 	dcfg->csum.eb_u8[0] -= cksum;
552 
553 	/* Erase and write the new sector */
554 	if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
555 		goto fail4;
556 
557 	/* Write out the new structure to nvram */
558 	if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
559 	    vpd_offset + vpd_length)) != 0)
560 		goto fail5;
561 
562 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
563 
564 	siena_nvram_partn_unlock(enp, dcfg_partn);
565 
566 	return (0);
567 
568 fail5:
569 	EFSYS_PROBE(fail5);
570 fail4:
571 	EFSYS_PROBE(fail4);
572 fail3:
573 	EFSYS_PROBE(fail3);
574 
575 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
576 fail2:
577 	EFSYS_PROBE(fail2);
578 
579 	siena_nvram_partn_unlock(enp, dcfg_partn);
580 fail1:
581 	EFSYS_PROBE1(fail1, int, rc);
582 
583 	return (rc);
584 }
585 
586 				void
587 siena_vpd_fini(
588 	__in			efx_nic_t *enp)
589 {
590 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
591 
592 	if (enp->en_u.siena.enu_svpd_length > 0) {
593 		EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
594 				enp->en_u.siena.enu_svpd);
595 
596 		enp->en_u.siena.enu_svpd = NULL;
597 		enp->en_u.siena.enu_svpd_length = 0;
598 	}
599 }
600 
601 #endif	/* EFSYS_OPT_SIENA */
602 
603 #endif	/* EFSYS_OPT_VPD */
604