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