1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2009-2018 Solarflare Communications Inc.
12 #define TAG_TYPE_LBN 7
13 #define TAG_TYPE_WIDTH 1
14 #define TAG_TYPE_LARGE_ITEM_DECODE 1
15 #define TAG_TYPE_SMALL_ITEM_DECODE 0
17 #define TAG_SMALL_ITEM_NAME_LBN 3
18 #define TAG_SMALL_ITEM_NAME_WIDTH 4
19 #define TAG_SMALL_ITEM_SIZE_LBN 0
20 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
22 #define TAG_LARGE_ITEM_NAME_LBN 0
23 #define TAG_LARGE_ITEM_NAME_WIDTH 7
25 #define TAG_NAME_END_DECODE 0x0f
26 #define TAG_NAME_ID_STRING_DECODE 0x02
27 #define TAG_NAME_VPD_R_DECODE 0x10
28 #define TAG_NAME_VPD_W_DECODE 0x11
32 static const efx_vpd_ops_t __efx_vpd_siena_ops = {
33 siena_vpd_init, /* evpdo_init */
34 siena_vpd_size, /* evpdo_size */
35 siena_vpd_read, /* evpdo_read */
36 siena_vpd_verify, /* evpdo_verify */
37 siena_vpd_reinit, /* evpdo_reinit */
38 siena_vpd_get, /* evpdo_get */
39 siena_vpd_set, /* evpdo_set */
40 siena_vpd_next, /* evpdo_next */
41 siena_vpd_write, /* evpdo_write */
42 siena_vpd_fini, /* evpdo_fini */
45 #endif /* EFSYS_OPT_SIENA */
47 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
49 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
50 ef10_vpd_init, /* evpdo_init */
51 ef10_vpd_size, /* evpdo_size */
52 ef10_vpd_read, /* evpdo_read */
53 ef10_vpd_verify, /* evpdo_verify */
54 ef10_vpd_reinit, /* evpdo_reinit */
55 ef10_vpd_get, /* evpdo_get */
56 ef10_vpd_set, /* evpdo_set */
57 ef10_vpd_next, /* evpdo_next */
58 ef10_vpd_write, /* evpdo_write */
59 ef10_vpd_fini, /* evpdo_fini */
62 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
64 __checkReturn efx_rc_t
68 const efx_vpd_ops_t *evpdop;
71 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
72 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
73 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
75 switch (enp->en_family) {
77 case EFX_FAMILY_SIENA:
78 evpdop = &__efx_vpd_siena_ops;
80 #endif /* EFSYS_OPT_SIENA */
82 #if EFSYS_OPT_HUNTINGTON
83 case EFX_FAMILY_HUNTINGTON:
84 evpdop = &__efx_vpd_ef10_ops;
86 #endif /* EFSYS_OPT_HUNTINGTON */
89 case EFX_FAMILY_MEDFORD:
90 evpdop = &__efx_vpd_ef10_ops;
92 #endif /* EFSYS_OPT_MEDFORD */
100 if (evpdop->evpdo_init != NULL) {
101 if ((rc = evpdop->evpdo_init(enp)) != 0)
105 enp->en_evpdop = evpdop;
106 enp->en_mod_flags |= EFX_MOD_VPD;
113 EFSYS_PROBE1(fail1, efx_rc_t, rc);
118 __checkReturn efx_rc_t
123 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
126 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
127 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
129 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
135 EFSYS_PROBE1(fail1, efx_rc_t, rc);
140 __checkReturn efx_rc_t
143 __out_bcount(size) caddr_t data,
146 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
149 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
150 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
152 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
158 EFSYS_PROBE1(fail1, efx_rc_t, rc);
163 __checkReturn efx_rc_t
166 __in_bcount(size) caddr_t data,
169 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
172 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
173 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
175 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
181 EFSYS_PROBE1(fail1, efx_rc_t, rc);
186 __checkReturn efx_rc_t
189 __in_bcount(size) caddr_t data,
192 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
195 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
196 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
198 if (evpdop->evpdo_reinit == NULL) {
203 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
211 EFSYS_PROBE1(fail1, efx_rc_t, rc);
216 __checkReturn efx_rc_t
219 __in_bcount(size) caddr_t data,
221 __inout efx_vpd_value_t *evvp)
223 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
226 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
227 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
229 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
239 EFSYS_PROBE1(fail1, efx_rc_t, rc);
244 __checkReturn efx_rc_t
247 __inout_bcount(size) caddr_t data,
249 __in efx_vpd_value_t *evvp)
251 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
254 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
255 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
257 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
263 EFSYS_PROBE1(fail1, efx_rc_t, rc);
268 __checkReturn efx_rc_t
271 __inout_bcount(size) caddr_t data,
273 __out efx_vpd_value_t *evvp,
274 __inout unsigned int *contp)
276 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
279 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
280 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
282 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
288 EFSYS_PROBE1(fail1, efx_rc_t, rc);
293 __checkReturn efx_rc_t
296 __in_bcount(size) caddr_t data,
299 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
302 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
303 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
305 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
311 EFSYS_PROBE1(fail1, efx_rc_t, rc);
316 static __checkReturn efx_rc_t
320 __inout unsigned int *offsetp,
321 __out efx_vpd_tag_t *tagp,
322 __out uint16_t *lengthp)
331 if (*offsetp >= size) {
336 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
338 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
339 case TAG_TYPE_SMALL_ITEM_DECODE:
342 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
343 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
347 case TAG_TYPE_LARGE_ITEM_DECODE:
350 if (*offsetp + headlen > size) {
355 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
356 EFX_POPULATE_WORD_2(word,
357 EFX_BYTE_0, data[*offsetp + 1],
358 EFX_BYTE_1, data[*offsetp + 2]);
359 length = EFX_WORD_FIELD(word, EFX_WORD_0);
368 if (*offsetp + headlen + length > size) {
373 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
374 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
375 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
376 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
377 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
378 name != EFX_VPD_RO) {
396 EFSYS_PROBE1(fail1, efx_rc_t, rc);
401 static __checkReturn efx_rc_t
402 efx_vpd_next_keyword(
403 __in_bcount(size) caddr_t tag,
405 __in unsigned int pos,
406 __out efx_vpd_keyword_t *keywordp,
407 __out uint8_t *lengthp)
409 efx_vpd_keyword_t keyword;
413 if (pos + 3U > size) {
418 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
419 length = tag[pos + 2];
421 if (length == 0 || pos + 3U + length > size) {
434 EFSYS_PROBE1(fail1, efx_rc_t, rc);
439 __checkReturn efx_rc_t
441 __in_bcount(size) caddr_t data,
443 __out size_t *lengthp)
451 _NOTE(CONSTANTCONDITION)
453 if ((rc = efx_vpd_next_tag(data, size, &offset,
454 &tag, &taglen)) != 0)
457 if (tag == EFX_VPD_END)
466 EFSYS_PROBE1(fail1, efx_rc_t, rc);
471 __checkReturn efx_rc_t
473 __in_bcount(size) caddr_t data,
475 __out_opt boolean_t *cksummedp)
478 efx_vpd_keyword_t keyword;
485 boolean_t cksummed = B_FALSE;
489 * Parse every tag,keyword in the existing VPD. If the csum is present,
490 * the assert it is correct, and is the final keyword in the RO block.
493 _NOTE(CONSTANTCONDITION)
495 if ((rc = efx_vpd_next_tag(data, size, &offset,
496 &tag, &taglen)) != 0)
498 if (tag == EFX_VPD_END)
500 else if (tag == EFX_VPD_ID)
503 for (pos = 0; pos != taglen; pos += 3 + keylen) {
504 /* RV keyword must be the last in the block */
510 if ((rc = efx_vpd_next_keyword(data + offset,
511 taglen, pos, &keyword, &keylen)) != 0)
514 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
516 for (i = 0; i < offset + pos + 4; i++)
537 if (cksummedp != NULL)
538 *cksummedp = cksummed;
551 EFSYS_PROBE1(fail1, efx_rc_t, rc);
556 static uint8_t __efx_vpd_blank_pid[] = {
557 /* Large resource type ID length 1 */
559 /* Product name ' ' */
563 static uint8_t __efx_vpd_blank_r[] = {
564 /* Large resource type VPD-R length 4 */
566 /* RV keyword length 1 */
568 /* RV payload checksum */
572 __checkReturn efx_rc_t
574 __in_bcount(size) caddr_t data,
576 __in boolean_t wantpid)
578 unsigned int offset = 0;
590 memcpy(data + offset, __efx_vpd_blank_pid,
591 sizeof (__efx_vpd_blank_pid));
592 offset += sizeof (__efx_vpd_blank_pid);
595 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
596 offset += sizeof (__efx_vpd_blank_r);
598 /* Update checksum */
600 for (pos = 0; pos < offset; pos++)
602 data[offset - 1] -= cksum;
604 /* Append trailing tag */
605 EFX_POPULATE_BYTE_3(byte,
606 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
607 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
608 TAG_SMALL_ITEM_SIZE, 0);
609 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
615 EFSYS_PROBE1(fail1, efx_rc_t, rc);
620 __checkReturn efx_rc_t
622 __in_bcount(size) caddr_t data,
624 __out efx_vpd_tag_t *tagp,
625 __out efx_vpd_keyword_t *keywordp,
626 __out_opt unsigned int *payloadp,
627 __out_opt uint8_t *paylenp,
628 __inout unsigned int *contp)
631 efx_vpd_keyword_t keyword = 0;
641 _NOTE(CONSTANTCONDITION)
643 if ((rc = efx_vpd_next_tag(data, size, &offset,
644 &tag, &taglen)) != 0)
647 if (tag == EFX_VPD_END) {
654 if (tag == EFX_VPD_ID) {
655 if (index++ == *contp) {
656 EFSYS_ASSERT3U(taglen, <, 0x100);
658 paylen = (uint8_t)MIN(taglen, 0xff);
663 for (pos = 0; pos != taglen; pos += 3 + keylen) {
664 if ((rc = efx_vpd_next_keyword(data + offset,
665 taglen, pos, &keyword, &keylen)) != 0)
668 if (index++ == *contp) {
683 if (payloadp != NULL)
694 EFSYS_PROBE1(fail1, efx_rc_t, rc);
699 __checkReturn efx_rc_t
701 __in_bcount(size) caddr_t data,
703 __in efx_vpd_tag_t tag,
704 __in efx_vpd_keyword_t keyword,
705 __out unsigned int *payloadp,
706 __out uint8_t *paylenp)
709 efx_vpd_keyword_t ikeyword;
717 _NOTE(CONSTANTCONDITION)
719 if ((rc = efx_vpd_next_tag(data, size, &offset,
720 &itag, &taglen)) != 0)
722 if (itag == EFX_VPD_END)
726 if (itag == EFX_VPD_ID) {
727 EFSYS_ASSERT3U(taglen, <, 0x100);
729 *paylenp = (uint8_t)MIN(taglen, 0xff);
734 for (pos = 0; pos != taglen; pos += 3 + keylen) {
735 if ((rc = efx_vpd_next_keyword(data + offset,
736 taglen, pos, &ikeyword, &keylen)) != 0)
739 if (ikeyword == keyword) {
741 *payloadp = offset + pos + 3;
756 EFSYS_PROBE1(fail1, efx_rc_t, rc);
761 __checkReturn efx_rc_t
763 __in_bcount(size) caddr_t data,
765 __in efx_vpd_value_t *evvp)
769 efx_vpd_keyword_t keyword;
772 unsigned int taghead;
782 switch (evvp->evv_tag) {
784 if (evvp->evv_keyword != 0) {
789 /* Can't delete the ID keyword */
790 if (evvp->evv_length == 0) {
797 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
808 /* Determine total size of all current tags */
809 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
813 _NOTE(CONSTANTCONDITION)
816 if ((rc = efx_vpd_next_tag(data, size, &offset,
817 &tag, &taglen)) != 0)
819 if (tag == EFX_VPD_END)
821 else if (tag != evvp->evv_tag) {
826 /* We only support modifying large resource tags */
827 if (offset - taghead != 3) {
833 * Work out the offset of the byte immediately after the
834 * old (=source) and new (=dest) new keyword/tag
837 if (tag == EFX_VPD_ID) {
838 source = offset + taglen;
839 dest = offset + evvp->evv_length;
843 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
845 for (pos = 0; pos != taglen; pos += 3 + keylen) {
846 if ((rc = efx_vpd_next_keyword(data + offset,
847 taglen, pos, &keyword, &keylen)) != 0)
850 if (keyword == evvp->evv_keyword &&
851 evvp->evv_length == 0) {
852 /* Deleting this keyword */
853 source = offset + pos + 3 + keylen;
857 } else if (keyword == evvp->evv_keyword) {
858 /* Adjusting this keyword */
859 source = offset + pos + 3 + keylen;
860 dest = offset + pos + 3 + evvp->evv_length;
863 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
864 /* The RV keyword must be at the end */
865 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
868 * The keyword doesn't already exist. If the
869 * user deleting a non-existant keyword then
872 if (evvp->evv_length == 0)
875 /* Insert this keyword before the RV keyword */
876 source = offset + pos;
877 dest = offset + pos + 3 + evvp->evv_length;
883 if (used + dest > size + source) {
888 /* Move trailing data */
889 (void) memmove(data + dest, data + source, used - source);
892 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
895 /* Insert new keyword header if required */
896 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
897 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
899 data[offset + pos + 0] =
900 EFX_WORD_FIELD(word, EFX_BYTE_0);
901 data[offset + pos + 1] =
902 EFX_WORD_FIELD(word, EFX_BYTE_1);
903 data[offset + pos + 2] = evvp->evv_length;
906 /* Modify tag length (large resource type) */
907 taglen += (uint16_t)(dest - source);
908 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
909 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
910 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
915 /* Unable to find the matching tag */
920 /* Find the RV tag, and update the checksum */
922 _NOTE(CONSTANTCONDITION)
924 if ((rc = efx_vpd_next_tag(data, size, &offset,
925 &tag, &taglen)) != 0)
927 if (tag == EFX_VPD_END)
929 if (tag == EFX_VPD_RO) {
930 for (pos = 0; pos != taglen; pos += 3 + keylen) {
931 if ((rc = efx_vpd_next_keyword(data + offset,
932 taglen, pos, &keyword, &keylen)) != 0)
935 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
937 for (i = 0; i < offset + pos + 3; i++)
948 /* Zero out the unused portion */
949 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
970 EFSYS_PROBE1(fail1, efx_rc_t, rc);
979 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
981 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
982 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
983 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
985 if (evpdop->evpdo_fini != NULL)
986 evpdop->evpdo_fini(enp);
988 enp->en_evpdop = NULL;
989 enp->en_mod_flags &= ~EFX_MOD_VPD;
992 #endif /* EFSYS_OPT_VPD */