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 #define TAG_TYPE_LBN 7
42 #define TAG_TYPE_WIDTH 1
43 #define TAG_TYPE_LARGE_ITEM_DECODE 1
44 #define TAG_TYPE_SMALL_ITEM_DECODE 0
45
46 #define TAG_SMALL_ITEM_NAME_LBN 3
47 #define TAG_SMALL_ITEM_NAME_WIDTH 4
48 #define TAG_SMALL_ITEM_SIZE_LBN 0
49 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
50
51 #define TAG_LARGE_ITEM_NAME_LBN 0
52 #define TAG_LARGE_ITEM_NAME_WIDTH 7
53
54 #define TAG_NAME_END_DECODE 0x0f
55 #define TAG_NAME_ID_STRING_DECODE 0x02
56 #define TAG_NAME_VPD_R_DECODE 0x10
57 #define TAG_NAME_VPD_W_DECODE 0x11
58
59 #if EFSYS_OPT_SIENA
60
61 static const efx_vpd_ops_t __efx_vpd_siena_ops = {
62 siena_vpd_init, /* evpdo_init */
63 siena_vpd_size, /* evpdo_size */
64 siena_vpd_read, /* evpdo_read */
65 siena_vpd_verify, /* evpdo_verify */
66 siena_vpd_reinit, /* evpdo_reinit */
67 siena_vpd_get, /* evpdo_get */
68 siena_vpd_set, /* evpdo_set */
69 siena_vpd_next, /* evpdo_next */
70 siena_vpd_write, /* evpdo_write */
71 siena_vpd_fini, /* evpdo_fini */
72 };
73
74 #endif /* EFSYS_OPT_SIENA */
75
76 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
77
78 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
79 ef10_vpd_init, /* evpdo_init */
80 ef10_vpd_size, /* evpdo_size */
81 ef10_vpd_read, /* evpdo_read */
82 ef10_vpd_verify, /* evpdo_verify */
83 ef10_vpd_reinit, /* evpdo_reinit */
84 ef10_vpd_get, /* evpdo_get */
85 ef10_vpd_set, /* evpdo_set */
86 ef10_vpd_next, /* evpdo_next */
87 ef10_vpd_write, /* evpdo_write */
88 ef10_vpd_fini, /* evpdo_fini */
89 };
90
91 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
92
93 __checkReturn efx_rc_t
94 efx_vpd_init(
95 __in efx_nic_t *enp)
96 {
97 const efx_vpd_ops_t *evpdop;
98 efx_rc_t rc;
99
100 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
101 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
102 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
103
104 switch (enp->en_family) {
105 #if EFSYS_OPT_SIENA
106 case EFX_FAMILY_SIENA:
107 evpdop = &__efx_vpd_siena_ops;
108 break;
109 #endif /* EFSYS_OPT_SIENA */
110
111 #if EFSYS_OPT_HUNTINGTON
112 case EFX_FAMILY_HUNTINGTON:
113 evpdop = &__efx_vpd_ef10_ops;
114 break;
115 #endif /* EFSYS_OPT_HUNTINGTON */
116
117 #if EFSYS_OPT_MEDFORD
118 case EFX_FAMILY_MEDFORD:
119 evpdop = &__efx_vpd_ef10_ops;
120 break;
121 #endif /* EFSYS_OPT_MEDFORD */
122
123 #if EFSYS_OPT_MEDFORD2
124 case EFX_FAMILY_MEDFORD2:
125 evpdop = &__efx_vpd_ef10_ops;
126 break;
127 #endif /* EFSYS_OPT_MEDFORD2 */
128
129 default:
130 EFSYS_ASSERT(0);
131 rc = ENOTSUP;
132 goto fail1;
133 }
134
135 if (evpdop->evpdo_init != NULL) {
136 if ((rc = evpdop->evpdo_init(enp)) != 0)
137 goto fail2;
138 }
139
140 enp->en_evpdop = evpdop;
141 enp->en_mod_flags |= EFX_MOD_VPD;
142
143 return (0);
144
145 fail2:
146 EFSYS_PROBE(fail2);
147 fail1:
148 EFSYS_PROBE1(fail1, efx_rc_t, rc);
149
150 return (rc);
151 }
152
153 __checkReturn efx_rc_t
154 efx_vpd_size(
155 __in efx_nic_t *enp,
156 __out size_t *sizep)
157 {
158 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
159 efx_rc_t rc;
160
161 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
162 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
163
164 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
165 goto fail1;
166
167 return (0);
168
169 fail1:
170 EFSYS_PROBE1(fail1, efx_rc_t, rc);
171
172 return (rc);
173 }
174
175 __checkReturn efx_rc_t
176 efx_vpd_read(
177 __in efx_nic_t *enp,
178 __out_bcount(size) caddr_t data,
179 __in size_t size)
180 {
181 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
182 efx_rc_t rc;
183
184 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
185 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
186
187 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
188 goto fail1;
189
190 return (0);
191
192 fail1:
193 EFSYS_PROBE1(fail1, efx_rc_t, rc);
194
195 return (rc);
196 }
197
198 __checkReturn efx_rc_t
199 efx_vpd_verify(
200 __in efx_nic_t *enp,
201 __in_bcount(size) caddr_t data,
202 __in size_t size)
203 {
204 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
205 efx_rc_t rc;
206
207 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
208 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
209
210 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
211 goto fail1;
212
213 return (0);
214
215 fail1:
216 EFSYS_PROBE1(fail1, efx_rc_t, rc);
217
218 return (rc);
219 }
220
221 __checkReturn efx_rc_t
222 efx_vpd_reinit(
223 __in efx_nic_t *enp,
224 __in_bcount(size) caddr_t data,
225 __in size_t size)
226 {
227 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
228 efx_rc_t rc;
229
230 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
231 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
232
233 if (evpdop->evpdo_reinit == NULL) {
234 rc = ENOTSUP;
235 goto fail1;
236 }
237
238 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
239 goto fail2;
240
241 return (0);
242
243 fail2:
244 EFSYS_PROBE(fail2);
245 fail1:
246 EFSYS_PROBE1(fail1, efx_rc_t, rc);
247
248 return (rc);
249 }
250
251 __checkReturn efx_rc_t
252 efx_vpd_get(
253 __in efx_nic_t *enp,
254 __in_bcount(size) caddr_t data,
255 __in size_t size,
256 __inout efx_vpd_value_t *evvp)
257 {
258 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
259 efx_rc_t rc;
260
261 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
263
264 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
265 if (rc == ENOENT)
266 return (rc);
267
268 goto fail1;
269 }
270
271 return (0);
272
273 fail1:
274 EFSYS_PROBE1(fail1, efx_rc_t, rc);
275
276 return (rc);
277 }
278
279 __checkReturn efx_rc_t
280 efx_vpd_set(
281 __in efx_nic_t *enp,
282 __inout_bcount(size) caddr_t data,
283 __in size_t size,
284 __in efx_vpd_value_t *evvp)
285 {
286 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
287 efx_rc_t rc;
288
289 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
290 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
291
292 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
293 goto fail1;
294
295 return (0);
296
297 fail1:
298 EFSYS_PROBE1(fail1, efx_rc_t, rc);
299
300 return (rc);
301 }
302
303 __checkReturn efx_rc_t
304 efx_vpd_next(
305 __in efx_nic_t *enp,
306 __inout_bcount(size) caddr_t data,
307 __in size_t size,
308 __out efx_vpd_value_t *evvp,
309 __inout unsigned int *contp)
310 {
311 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
312 efx_rc_t rc;
313
314 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
315 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
316
317 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
318 goto fail1;
319
320 return (0);
321
322 fail1:
323 EFSYS_PROBE1(fail1, efx_rc_t, rc);
324
325 return (rc);
326 }
327
328 __checkReturn efx_rc_t
329 efx_vpd_write(
330 __in efx_nic_t *enp,
331 __in_bcount(size) caddr_t data,
332 __in size_t size)
333 {
334 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
335 efx_rc_t rc;
336
337 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
338 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
339
340 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
341 goto fail1;
342
343 return (0);
344
345 fail1:
346 EFSYS_PROBE1(fail1, efx_rc_t, rc);
347
348 return (rc);
349 }
350
351 static __checkReturn efx_rc_t
352 efx_vpd_next_tag(
353 __in caddr_t data,
354 __in size_t size,
355 __inout unsigned int *offsetp,
356 __out efx_vpd_tag_t *tagp,
357 __out uint16_t *lengthp)
358 {
359 efx_byte_t byte;
360 efx_word_t word;
361 uint8_t name;
362 uint16_t length;
363 size_t headlen;
364 efx_rc_t rc;
365
366 if (*offsetp >= size) {
367 rc = EFAULT;
368 goto fail1;
369 }
370
371 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
372
373 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
374 case TAG_TYPE_SMALL_ITEM_DECODE:
375 headlen = 1;
376
377 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
378 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
379
380 break;
381
382 case TAG_TYPE_LARGE_ITEM_DECODE:
383 headlen = 3;
384
385 if (*offsetp + headlen > size) {
386 rc = EFAULT;
387 goto fail2;
388 }
389
390 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
391 EFX_POPULATE_WORD_2(word,
392 EFX_BYTE_0, data[*offsetp + 1],
393 EFX_BYTE_1, data[*offsetp + 2]);
394 length = EFX_WORD_FIELD(word, EFX_WORD_0);
395
396 break;
397
398 default:
399 rc = EFAULT;
400 goto fail2;
401 }
402
403 if (*offsetp + headlen + length > size) {
404 rc = EFAULT;
405 goto fail3;
406 }
407
408 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
409 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
410 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
411 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
412 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
413 name != EFX_VPD_RO) {
414 rc = EFAULT;
415 goto fail4;
416 }
417
418 *tagp = name;
419 *lengthp = length;
420 *offsetp += headlen;
421
422 return (0);
423
424 fail4:
425 EFSYS_PROBE(fail4);
426 fail3:
427 EFSYS_PROBE(fail3);
428 fail2:
429 EFSYS_PROBE(fail2);
430 fail1:
431 EFSYS_PROBE1(fail1, efx_rc_t, rc);
432
433 return (rc);
434 }
435
436 static __checkReturn efx_rc_t
437 efx_vpd_next_keyword(
438 __in_bcount(size) caddr_t tag,
439 __in size_t size,
440 __in unsigned int pos,
441 __out efx_vpd_keyword_t *keywordp,
442 __out uint8_t *lengthp)
443 {
444 efx_vpd_keyword_t keyword;
445 uint8_t length;
446 efx_rc_t rc;
447
448 if (pos + 3U > size) {
449 rc = EFAULT;
450 goto fail1;
451 }
452
453 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
454 length = tag[pos + 2];
455
456 if (length == 0 || pos + 3U + length > size) {
457 rc = EFAULT;
458 goto fail2;
459 }
460
461 *keywordp = keyword;
462 *lengthp = length;
463
464 return (0);
465
466 fail2:
467 EFSYS_PROBE(fail2);
468 fail1:
469 EFSYS_PROBE1(fail1, efx_rc_t, rc);
470
471 return (rc);
472 }
473
474 __checkReturn efx_rc_t
475 efx_vpd_hunk_length(
476 __in_bcount(size) caddr_t data,
477 __in size_t size,
478 __out size_t *lengthp)
479 {
480 efx_vpd_tag_t tag;
481 unsigned int offset;
482 uint16_t taglen;
483 efx_rc_t rc;
484
485 offset = 0;
486 _NOTE(CONSTANTCONDITION)
487 while (1) {
488 if ((rc = efx_vpd_next_tag(data, size, &offset,
489 &tag, &taglen)) != 0)
490 goto fail1;
491 offset += taglen;
492 if (tag == EFX_VPD_END)
493 break;
494 }
495
496 *lengthp = offset;
497
498 return (0);
499
500 fail1:
501 EFSYS_PROBE1(fail1, efx_rc_t, rc);
502
503 return (rc);
504 }
505
506 __checkReturn efx_rc_t
507 efx_vpd_hunk_verify(
508 __in_bcount(size) caddr_t data,
509 __in size_t size,
510 __out_opt boolean_t *cksummedp)
511 {
512 efx_vpd_tag_t tag;
513 efx_vpd_keyword_t keyword;
514 unsigned int offset;
515 unsigned int pos;
516 unsigned int i;
517 uint16_t taglen;
518 uint8_t keylen;
519 uint8_t cksum;
520 boolean_t cksummed = B_FALSE;
521 efx_rc_t rc;
522
523 /*
524 * Parse every tag,keyword in the existing VPD. If the csum is present,
525 * the assert it is correct, and is the final keyword in the RO block.
526 */
527 offset = 0;
528 _NOTE(CONSTANTCONDITION)
529 while (1) {
530 if ((rc = efx_vpd_next_tag(data, size, &offset,
531 &tag, &taglen)) != 0)
532 goto fail1;
533 if (tag == EFX_VPD_END)
534 break;
535 else if (tag == EFX_VPD_ID)
536 goto done;
537
538 for (pos = 0; pos != taglen; pos += 3 + keylen) {
539 /* RV keyword must be the last in the block */
540 if (cksummed) {
541 rc = EFAULT;
542 goto fail2;
543 }
544
545 if ((rc = efx_vpd_next_keyword(data + offset,
546 taglen, pos, &keyword, &keylen)) != 0)
547 goto fail3;
548
549 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
550 cksum = 0;
551 for (i = 0; i < offset + pos + 4; i++)
552 cksum += data[i];
553
554 if (cksum != 0) {
555 rc = EFAULT;
556 goto fail4;
557 }
558
559 cksummed = B_TRUE;
560 }
561 }
562
563 done:
564 offset += taglen;
565 }
566
567 if (!cksummed) {
568 rc = EFAULT;
569 goto fail5;
570 }
571
572 if (cksummedp != NULL)
573 *cksummedp = cksummed;
574
575 return (0);
576
577 fail5:
578 EFSYS_PROBE(fail5);
579 fail4:
580 EFSYS_PROBE(fail4);
581 fail3:
582 EFSYS_PROBE(fail3);
583 fail2:
584 EFSYS_PROBE(fail2);
585 fail1:
586 EFSYS_PROBE1(fail1, efx_rc_t, rc);
587
588 return (rc);
589 }
590
591 static uint8_t __efx_vpd_blank_pid[] = {
592 /* Large resource type ID length 1 */
593 0x82, 0x01, 0x00,
594 /* Product name ' ' */
595 0x32,
596 };
597
598 static uint8_t __efx_vpd_blank_r[] = {
599 /* Large resource type VPD-R length 4 */
600 0x90, 0x04, 0x00,
601 /* RV keyword length 1 */
602 'R', 'V', 0x01,
603 /* RV payload checksum */
604 0x00,
605 };
606
607 __checkReturn efx_rc_t
608 efx_vpd_hunk_reinit(
609 __in_bcount(size) caddr_t data,
610 __in size_t size,
611 __in boolean_t wantpid)
612 {
613 unsigned int offset = 0;
614 unsigned int pos;
615 efx_byte_t byte;
616 uint8_t cksum;
617 efx_rc_t rc;
618
619 if (size < 0x100) {
620 rc = ENOSPC;
621 goto fail1;
622 }
623
624 if (wantpid) {
625 memcpy(data + offset, __efx_vpd_blank_pid,
626 sizeof (__efx_vpd_blank_pid));
627 offset += sizeof (__efx_vpd_blank_pid);
628 }
629
630 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
631 offset += sizeof (__efx_vpd_blank_r);
632
633 /* Update checksum */
634 cksum = 0;
635 for (pos = 0; pos < offset; pos++)
636 cksum += data[pos];
637 data[offset - 1] -= cksum;
638
639 /* Append trailing tag */
640 EFX_POPULATE_BYTE_3(byte,
641 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
642 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
643 TAG_SMALL_ITEM_SIZE, 0);
644 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
645 offset++;
646
647 return (0);
648
649 fail1:
650 EFSYS_PROBE1(fail1, efx_rc_t, rc);
651
652 return (rc);
653 }
654
655 __checkReturn efx_rc_t
656 efx_vpd_hunk_next(
657 __in_bcount(size) caddr_t data,
658 __in size_t size,
659 __out efx_vpd_tag_t *tagp,
660 __out efx_vpd_keyword_t *keywordp,
661 __out_opt unsigned int *payloadp,
662 __out_opt uint8_t *paylenp,
663 __inout unsigned int *contp)
664 {
665 efx_vpd_tag_t tag;
666 efx_vpd_keyword_t keyword = 0;
667 unsigned int offset;
668 unsigned int pos;
669 unsigned int index;
670 uint16_t taglen;
671 uint8_t keylen;
672 uint8_t paylen;
673 efx_rc_t rc;
674
675 offset = index = 0;
676 _NOTE(CONSTANTCONDITION)
677 while (1) {
678 if ((rc = efx_vpd_next_tag(data, size, &offset,
679 &tag, &taglen)) != 0)
680 goto fail1;
681
682 if (tag == EFX_VPD_END) {
683 keyword = 0;
684 paylen = 0;
685 index = 0;
686 break;
687 }
688
689 if (tag == EFX_VPD_ID) {
690 if (index++ == *contp) {
691 EFSYS_ASSERT3U(taglen, <, 0x100);
692 keyword = 0;
693 paylen = (uint8_t)MIN(taglen, 0xff);
694
695 goto done;
696 }
697 } else {
698 for (pos = 0; pos != taglen; pos += 3 + keylen) {
699 if ((rc = efx_vpd_next_keyword(data + offset,
700 taglen, pos, &keyword, &keylen)) != 0)
701 goto fail2;
702
703 if (index++ == *contp) {
704 offset += pos + 3;
705 paylen = keylen;
706
707 goto done;
708 }
709 }
710 }
711
712 offset += taglen;
713 }
714
715 done:
716 *tagp = tag;
717 *keywordp = keyword;
718 if (payloadp != NULL)
719 *payloadp = offset;
720 if (paylenp != NULL)
721 *paylenp = paylen;
722
723 *contp = index;
724 return (0);
725
726 fail2:
727 EFSYS_PROBE(fail2);
728 fail1:
729 EFSYS_PROBE1(fail1, efx_rc_t, rc);
730
731 return (rc);
732 }
733
734 __checkReturn efx_rc_t
735 efx_vpd_hunk_get(
736 __in_bcount(size) caddr_t data,
737 __in size_t size,
738 __in efx_vpd_tag_t tag,
739 __in efx_vpd_keyword_t keyword,
740 __out unsigned int *payloadp,
741 __out uint8_t *paylenp)
742 {
743 efx_vpd_tag_t itag;
744 efx_vpd_keyword_t ikeyword;
745 unsigned int offset;
746 unsigned int pos;
747 uint16_t taglen;
748 uint8_t keylen;
749 efx_rc_t rc;
750
751 offset = 0;
752 _NOTE(CONSTANTCONDITION)
753 while (1) {
754 if ((rc = efx_vpd_next_tag(data, size, &offset,
755 &itag, &taglen)) != 0)
756 goto fail1;
757 if (itag == EFX_VPD_END)
758 break;
759
760 if (itag == tag) {
761 if (itag == EFX_VPD_ID) {
762 EFSYS_ASSERT3U(taglen, <, 0x100);
763
764 *paylenp = (uint8_t)MIN(taglen, 0xff);
765 *payloadp = offset;
766 return (0);
767 }
768
769 for (pos = 0; pos != taglen; pos += 3 + keylen) {
770 if ((rc = efx_vpd_next_keyword(data + offset,
771 taglen, pos, &ikeyword, &keylen)) != 0)
772 goto fail2;
773
774 if (ikeyword == keyword) {
775 *paylenp = keylen;
776 *payloadp = offset + pos + 3;
777 return (0);
778 }
779 }
780 }
781
782 offset += taglen;
783 }
784
785 /* Not an error */
786 return (ENOENT);
787
788 fail2:
789 EFSYS_PROBE(fail2);
790 fail1:
791 EFSYS_PROBE1(fail1, efx_rc_t, rc);
792
793 return (rc);
794 }
795
796 __checkReturn efx_rc_t
797 efx_vpd_hunk_set(
798 __in_bcount(size) caddr_t data,
799 __in size_t size,
800 __in efx_vpd_value_t *evvp)
801 {
802 efx_word_t word;
803 efx_vpd_tag_t tag;
804 efx_vpd_keyword_t keyword;
805 unsigned int offset;
806 unsigned int pos;
807 unsigned int taghead;
808 unsigned int source;
809 unsigned int dest;
810 unsigned int i;
811 uint16_t taglen;
812 uint8_t keylen;
813 uint8_t cksum;
814 size_t used;
815 efx_rc_t rc;
816
817 switch (evvp->evv_tag) {
818 case EFX_VPD_ID:
819 if (evvp->evv_keyword != 0) {
820 rc = EINVAL;
821 goto fail1;
822 }
823
824 /* Can't delete the ID keyword */
825 if (evvp->evv_length == 0) {
826 rc = EINVAL;
827 goto fail1;
828 }
829 break;
830
831 case EFX_VPD_RO:
832 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
833 rc = EINVAL;
834 goto fail1;
835 }
836 break;
837
838 default:
839 rc = EINVAL;
840 goto fail1;
841 }
842
843 /* Determine total size of all current tags */
844 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
845 goto fail2;
846
847 offset = 0;
848 _NOTE(CONSTANTCONDITION)
849 while (1) {
850 taghead = offset;
851 if ((rc = efx_vpd_next_tag(data, size, &offset,
852 &tag, &taglen)) != 0)
853 goto fail3;
854 if (tag == EFX_VPD_END)
855 break;
856 else if (tag != evvp->evv_tag) {
857 offset += taglen;
858 continue;
859 }
860
861 /* We only support modifying large resource tags */
862 if (offset - taghead != 3) {
863 rc = EINVAL;
864 goto fail4;
865 }
866
867 /*
868 * Work out the offset of the byte immediately after the
869 * old (=source) and new (=dest) new keyword/tag
870 */
871 pos = 0;
872 if (tag == EFX_VPD_ID) {
873 source = offset + taglen;
874 dest = offset + evvp->evv_length;
875 goto check_space;
876 }
877
878 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
879 source = dest = 0;
880 for (pos = 0; pos != taglen; pos += 3 + keylen) {
881 if ((rc = efx_vpd_next_keyword(data + offset,
882 taglen, pos, &keyword, &keylen)) != 0)
883 goto fail5;
884
885 if (keyword == evvp->evv_keyword &&
886 evvp->evv_length == 0) {
887 /* Deleting this keyword */
888 source = offset + pos + 3 + keylen;
889 dest = offset + pos;
890 break;
891
892 } else if (keyword == evvp->evv_keyword) {
893 /* Adjusting this keyword */
894 source = offset + pos + 3 + keylen;
895 dest = offset + pos + 3 + evvp->evv_length;
896 break;
897
898 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
899 /* The RV keyword must be at the end */
900 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
901
902 /*
903 * The keyword doesn't already exist. If the
904 * user deleting a non-existent keyword then
905 * this is a no-op.
906 */
907 if (evvp->evv_length == 0)
908 return (0);
909
910 /* Insert this keyword before the RV keyword */
911 source = offset + pos;
912 dest = offset + pos + 3 + evvp->evv_length;
913 break;
914 }
915 }
916
917 check_space:
918 if (used + dest > size + source) {
919 rc = ENOSPC;
920 goto fail6;
921 }
922
923 /* Move trailing data */
924 (void) memmove(data + dest, data + source, used - source);
925
926 /* Copy contents */
927 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
928 evvp->evv_length);
929
930 /* Insert new keyword header if required */
931 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
932 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
933 evvp->evv_keyword);
934 data[offset + pos + 0] =
935 EFX_WORD_FIELD(word, EFX_BYTE_0);
936 data[offset + pos + 1] =
937 EFX_WORD_FIELD(word, EFX_BYTE_1);
938 data[offset + pos + 2] = evvp->evv_length;
939 }
940
941 /* Modify tag length (large resource type) */
942 taglen += (uint16_t)(dest - source);
943 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
944 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
945 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
946
947 goto checksum;
948 }
949
950 /* Unable to find the matching tag */
951 rc = ENOENT;
952 goto fail7;
953
954 checksum:
955 /* Find the RV tag, and update the checksum */
956 offset = 0;
957 _NOTE(CONSTANTCONDITION)
958 while (1) {
959 if ((rc = efx_vpd_next_tag(data, size, &offset,
960 &tag, &taglen)) != 0)
961 goto fail8;
962 if (tag == EFX_VPD_END)
963 break;
964 if (tag == EFX_VPD_RO) {
965 for (pos = 0; pos != taglen; pos += 3 + keylen) {
966 if ((rc = efx_vpd_next_keyword(data + offset,
967 taglen, pos, &keyword, &keylen)) != 0)
968 goto fail9;
969
970 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
971 cksum = 0;
972 for (i = 0; i < offset + pos + 3; i++)
973 cksum += data[i];
974 data[i] = -cksum;
975 break;
976 }
977 }
978 }
979
980 offset += taglen;
981 }
982
983 /* Zero out the unused portion */
984 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
985
986 return (0);
987
988 fail9:
989 EFSYS_PROBE(fail9);
990 fail8:
991 EFSYS_PROBE(fail8);
992 fail7:
993 EFSYS_PROBE(fail7);
994 fail6:
995 EFSYS_PROBE(fail6);
996 fail5:
997 EFSYS_PROBE(fail5);
998 fail4:
999 EFSYS_PROBE(fail4);
1000 fail3:
1001 EFSYS_PROBE(fail3);
1002 fail2:
1003 EFSYS_PROBE(fail2);
1004 fail1:
1005 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1006
1007 return (rc);
1008 }
1009
1010 void
1011 efx_vpd_fini(
1012 __in efx_nic_t *enp)
1013 {
1014 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1015
1016 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1017 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1018 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1019
1020 if (evpdop->evpdo_fini != NULL)
1021 evpdop->evpdo_fini(enp);
1022
1023 enp->en_evpdop = NULL;
1024 enp->en_mod_flags &= ~EFX_MOD_VPD;
1025 }
1026
1027 #endif /* EFSYS_OPT_VPD */
Cache object: 1ca5cfcf721ef4d30e0f200a635ffb26
|