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