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