2 * Copyright (c) 2009-2016 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
36 #define TAG_TYPE_LBN 7
37 #define TAG_TYPE_WIDTH 1
38 #define TAG_TYPE_LARGE_ITEM_DECODE 1
39 #define TAG_TYPE_SMALL_ITEM_DECODE 0
41 #define TAG_SMALL_ITEM_NAME_LBN 3
42 #define TAG_SMALL_ITEM_NAME_WIDTH 4
43 #define TAG_SMALL_ITEM_SIZE_LBN 0
44 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
46 #define TAG_LARGE_ITEM_NAME_LBN 0
47 #define TAG_LARGE_ITEM_NAME_WIDTH 7
49 #define TAG_NAME_END_DECODE 0x0f
50 #define TAG_NAME_ID_STRING_DECODE 0x02
51 #define TAG_NAME_VPD_R_DECODE 0x10
52 #define TAG_NAME_VPD_W_DECODE 0x11
56 static const efx_vpd_ops_t __efx_vpd_siena_ops = {
57 siena_vpd_init, /* evpdo_init */
58 siena_vpd_size, /* evpdo_size */
59 siena_vpd_read, /* evpdo_read */
60 siena_vpd_verify, /* evpdo_verify */
61 siena_vpd_reinit, /* evpdo_reinit */
62 siena_vpd_get, /* evpdo_get */
63 siena_vpd_set, /* evpdo_set */
64 siena_vpd_next, /* evpdo_next */
65 siena_vpd_write, /* evpdo_write */
66 siena_vpd_fini, /* evpdo_fini */
69 #endif /* EFSYS_OPT_SIENA */
71 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
73 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
74 ef10_vpd_init, /* evpdo_init */
75 ef10_vpd_size, /* evpdo_size */
76 ef10_vpd_read, /* evpdo_read */
77 ef10_vpd_verify, /* evpdo_verify */
78 ef10_vpd_reinit, /* evpdo_reinit */
79 ef10_vpd_get, /* evpdo_get */
80 ef10_vpd_set, /* evpdo_set */
81 ef10_vpd_next, /* evpdo_next */
82 ef10_vpd_write, /* evpdo_write */
83 ef10_vpd_fini, /* evpdo_fini */
86 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
88 __checkReturn efx_rc_t
92 const efx_vpd_ops_t *evpdop;
95 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
96 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
97 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
99 switch (enp->en_family) {
101 case EFX_FAMILY_SIENA:
102 evpdop = &__efx_vpd_siena_ops;
104 #endif /* EFSYS_OPT_SIENA */
106 #if EFSYS_OPT_HUNTINGTON
107 case EFX_FAMILY_HUNTINGTON:
108 evpdop = &__efx_vpd_ef10_ops;
110 #endif /* EFSYS_OPT_HUNTINGTON */
112 #if EFSYS_OPT_MEDFORD
113 case EFX_FAMILY_MEDFORD:
114 evpdop = &__efx_vpd_ef10_ops;
116 #endif /* EFSYS_OPT_MEDFORD */
124 if (evpdop->evpdo_init != NULL) {
125 if ((rc = evpdop->evpdo_init(enp)) != 0)
129 enp->en_evpdop = evpdop;
130 enp->en_mod_flags |= EFX_MOD_VPD;
137 EFSYS_PROBE1(fail1, efx_rc_t, rc);
142 __checkReturn efx_rc_t
147 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
150 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
151 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
153 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
159 EFSYS_PROBE1(fail1, efx_rc_t, rc);
164 __checkReturn efx_rc_t
167 __out_bcount(size) caddr_t data,
170 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
173 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
174 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
176 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
182 EFSYS_PROBE1(fail1, efx_rc_t, rc);
187 __checkReturn efx_rc_t
190 __in_bcount(size) caddr_t data,
193 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
196 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
197 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
199 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
205 EFSYS_PROBE1(fail1, efx_rc_t, rc);
210 __checkReturn efx_rc_t
213 __in_bcount(size) caddr_t data,
216 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
219 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
220 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
222 if (evpdop->evpdo_reinit == NULL) {
227 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
235 EFSYS_PROBE1(fail1, efx_rc_t, rc);
240 __checkReturn efx_rc_t
243 __in_bcount(size) caddr_t data,
245 __inout efx_vpd_value_t *evvp)
247 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
250 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
251 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
253 if ((rc = evpdop->evpdo_get(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 __in efx_vpd_value_t *evvp)
275 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
278 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
279 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
281 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
287 EFSYS_PROBE1(fail1, efx_rc_t, rc);
292 __checkReturn efx_rc_t
295 __inout_bcount(size) caddr_t data,
297 __out efx_vpd_value_t *evvp,
298 __inout unsigned int *contp)
300 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
303 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
304 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
306 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
312 EFSYS_PROBE1(fail1, efx_rc_t, rc);
317 __checkReturn efx_rc_t
320 __in_bcount(size) caddr_t data,
323 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
326 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
327 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
329 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
335 EFSYS_PROBE1(fail1, efx_rc_t, rc);
340 static __checkReturn efx_rc_t
344 __inout unsigned int *offsetp,
345 __out efx_vpd_tag_t *tagp,
346 __out uint16_t *lengthp)
355 if (*offsetp >= size) {
360 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
362 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
363 case TAG_TYPE_SMALL_ITEM_DECODE:
366 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
367 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
371 case TAG_TYPE_LARGE_ITEM_DECODE:
374 if (*offsetp + headlen > size) {
379 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
380 EFX_POPULATE_WORD_2(word,
381 EFX_BYTE_0, data[*offsetp + 1],
382 EFX_BYTE_1, data[*offsetp + 2]);
383 length = EFX_WORD_FIELD(word, EFX_WORD_0);
392 if (*offsetp + headlen + length > size) {
397 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
398 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
399 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
400 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
401 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
402 name != EFX_VPD_RO) {
420 EFSYS_PROBE1(fail1, efx_rc_t, rc);
425 static __checkReturn efx_rc_t
426 efx_vpd_next_keyword(
427 __in_bcount(size) caddr_t tag,
429 __in unsigned int pos,
430 __out efx_vpd_keyword_t *keywordp,
431 __out uint8_t *lengthp)
433 efx_vpd_keyword_t keyword;
437 if (pos + 3U > size) {
442 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
443 length = tag[pos + 2];
445 if (length == 0 || pos + 3U + length > size) {
458 EFSYS_PROBE1(fail1, efx_rc_t, rc);
463 __checkReturn efx_rc_t
465 __in_bcount(size) caddr_t data,
467 __out size_t *lengthp)
475 _NOTE(CONSTANTCONDITION)
477 if ((rc = efx_vpd_next_tag(data, size, &offset,
478 &tag, &taglen)) != 0)
481 if (tag == EFX_VPD_END)
490 EFSYS_PROBE1(fail1, efx_rc_t, rc);
495 __checkReturn efx_rc_t
497 __in_bcount(size) caddr_t data,
499 __out_opt boolean_t *cksummedp)
502 efx_vpd_keyword_t keyword;
509 boolean_t cksummed = B_FALSE;
513 * Parse every tag,keyword in the existing VPD. If the csum is present,
514 * the assert it is correct, and is the final keyword in the RO block.
517 _NOTE(CONSTANTCONDITION)
519 if ((rc = efx_vpd_next_tag(data, size, &offset,
520 &tag, &taglen)) != 0)
522 if (tag == EFX_VPD_END)
524 else if (tag == EFX_VPD_ID)
527 for (pos = 0; pos != taglen; pos += 3 + keylen) {
528 /* RV keyword must be the last in the block */
534 if ((rc = efx_vpd_next_keyword(data + offset,
535 taglen, pos, &keyword, &keylen)) != 0)
538 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
540 for (i = 0; i < offset + pos + 4; i++)
561 if (cksummedp != NULL)
562 *cksummedp = cksummed;
575 EFSYS_PROBE1(fail1, efx_rc_t, rc);
580 static uint8_t __efx_vpd_blank_pid[] = {
581 /* Large resource type ID length 1 */
583 /* Product name ' ' */
587 static uint8_t __efx_vpd_blank_r[] = {
588 /* Large resource type VPD-R length 4 */
590 /* RV keyword length 1 */
592 /* RV payload checksum */
596 __checkReturn efx_rc_t
598 __in_bcount(size) caddr_t data,
600 __in boolean_t wantpid)
602 unsigned int offset = 0;
614 memcpy(data + offset, __efx_vpd_blank_pid,
615 sizeof (__efx_vpd_blank_pid));
616 offset += sizeof (__efx_vpd_blank_pid);
619 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
620 offset += sizeof (__efx_vpd_blank_r);
622 /* Update checksum */
624 for (pos = 0; pos < offset; pos++)
626 data[offset - 1] -= cksum;
628 /* Append trailing tag */
629 EFX_POPULATE_BYTE_3(byte,
630 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
631 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
632 TAG_SMALL_ITEM_SIZE, 0);
633 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
639 EFSYS_PROBE1(fail1, efx_rc_t, rc);
644 __checkReturn efx_rc_t
646 __in_bcount(size) caddr_t data,
648 __out efx_vpd_tag_t *tagp,
649 __out efx_vpd_keyword_t *keywordp,
650 __out_opt unsigned int *payloadp,
651 __out_opt uint8_t *paylenp,
652 __inout unsigned int *contp)
655 efx_vpd_keyword_t keyword = 0;
665 _NOTE(CONSTANTCONDITION)
667 if ((rc = efx_vpd_next_tag(data, size, &offset,
668 &tag, &taglen)) != 0)
671 if (tag == EFX_VPD_END) {
678 if (tag == EFX_VPD_ID) {
679 if (index++ == *contp) {
680 EFSYS_ASSERT3U(taglen, <, 0x100);
682 paylen = (uint8_t)MIN(taglen, 0xff);
687 for (pos = 0; pos != taglen; pos += 3 + keylen) {
688 if ((rc = efx_vpd_next_keyword(data + offset,
689 taglen, pos, &keyword, &keylen)) != 0)
692 if (index++ == *contp) {
707 if (payloadp != NULL)
718 EFSYS_PROBE1(fail1, efx_rc_t, rc);
723 __checkReturn efx_rc_t
725 __in_bcount(size) caddr_t data,
727 __in efx_vpd_tag_t tag,
728 __in efx_vpd_keyword_t keyword,
729 __out unsigned int *payloadp,
730 __out uint8_t *paylenp)
733 efx_vpd_keyword_t ikeyword;
741 _NOTE(CONSTANTCONDITION)
743 if ((rc = efx_vpd_next_tag(data, size, &offset,
744 &itag, &taglen)) != 0)
746 if (itag == EFX_VPD_END)
750 if (itag == EFX_VPD_ID) {
751 EFSYS_ASSERT3U(taglen, <, 0x100);
753 *paylenp = (uint8_t)MIN(taglen, 0xff);
758 for (pos = 0; pos != taglen; pos += 3 + keylen) {
759 if ((rc = efx_vpd_next_keyword(data + offset,
760 taglen, pos, &ikeyword, &keylen)) != 0)
763 if (ikeyword == keyword) {
765 *payloadp = offset + pos + 3;
780 EFSYS_PROBE1(fail1, efx_rc_t, rc);
785 __checkReturn efx_rc_t
787 __in_bcount(size) caddr_t data,
789 __in efx_vpd_value_t *evvp)
793 efx_vpd_keyword_t keyword;
796 unsigned int taghead;
806 switch (evvp->evv_tag) {
808 if (evvp->evv_keyword != 0) {
813 /* Can't delete the ID keyword */
814 if (evvp->evv_length == 0) {
821 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
832 /* Determine total size of all current tags */
833 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
837 _NOTE(CONSTANTCONDITION)
840 if ((rc = efx_vpd_next_tag(data, size, &offset,
841 &tag, &taglen)) != 0)
843 if (tag == EFX_VPD_END)
845 else if (tag != evvp->evv_tag) {
850 /* We only support modifying large resource tags */
851 if (offset - taghead != 3) {
857 * Work out the offset of the byte immediately after the
858 * old (=source) and new (=dest) new keyword/tag
861 if (tag == EFX_VPD_ID) {
862 source = offset + taglen;
863 dest = offset + evvp->evv_length;
867 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
869 for (pos = 0; pos != taglen; pos += 3 + keylen) {
870 if ((rc = efx_vpd_next_keyword(data + offset,
871 taglen, pos, &keyword, &keylen)) != 0)
874 if (keyword == evvp->evv_keyword &&
875 evvp->evv_length == 0) {
876 /* Deleting this keyword */
877 source = offset + pos + 3 + keylen;
881 } else if (keyword == evvp->evv_keyword) {
882 /* Adjusting this keyword */
883 source = offset + pos + 3 + keylen;
884 dest = offset + pos + 3 + evvp->evv_length;
887 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
888 /* The RV keyword must be at the end */
889 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
892 * The keyword doesn't already exist. If the
893 * user deleting a non-existant keyword then
896 if (evvp->evv_length == 0)
899 /* Insert this keyword before the RV keyword */
900 source = offset + pos;
901 dest = offset + pos + 3 + evvp->evv_length;
907 if (used + dest > size + source) {
912 /* Move trailing data */
913 (void) memmove(data + dest, data + source, used - source);
916 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
919 /* Insert new keyword header if required */
920 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
921 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
923 data[offset + pos + 0] =
924 EFX_WORD_FIELD(word, EFX_BYTE_0);
925 data[offset + pos + 1] =
926 EFX_WORD_FIELD(word, EFX_BYTE_1);
927 data[offset + pos + 2] = evvp->evv_length;
930 /* Modify tag length (large resource type) */
931 taglen += (dest - source);
932 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
933 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
934 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
939 /* Unable to find the matching tag */
944 /* Find the RV tag, and update the checksum */
946 _NOTE(CONSTANTCONDITION)
948 if ((rc = efx_vpd_next_tag(data, size, &offset,
949 &tag, &taglen)) != 0)
951 if (tag == EFX_VPD_END)
953 if (tag == EFX_VPD_RO) {
954 for (pos = 0; pos != taglen; pos += 3 + keylen) {
955 if ((rc = efx_vpd_next_keyword(data + offset,
956 taglen, pos, &keyword, &keylen)) != 0)
959 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
961 for (i = 0; i < offset + pos + 3; i++)
972 /* Zero out the unused portion */
973 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
994 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1001 __in efx_nic_t *enp)
1003 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1005 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1006 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1007 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1009 if (evpdop->evpdo_fini != NULL)
1010 evpdop->evpdo_fini(enp);
1012 enp->en_evpdop = NULL;
1013 enp->en_mod_flags &= ~EFX_MOD_VPD;
1016 #endif /* EFSYS_OPT_VPD */