2 * Copyright (c) 2009-2015 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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
39 #define TAG_TYPE_LBN 7
40 #define TAG_TYPE_WIDTH 1
41 #define TAG_TYPE_LARGE_ITEM_DECODE 1
42 #define TAG_TYPE_SMALL_ITEM_DECODE 0
44 #define TAG_SMALL_ITEM_NAME_LBN 3
45 #define TAG_SMALL_ITEM_NAME_WIDTH 4
46 #define TAG_SMALL_ITEM_SIZE_LBN 0
47 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
49 #define TAG_LARGE_ITEM_NAME_LBN 0
50 #define TAG_LARGE_ITEM_NAME_WIDTH 7
52 #define TAG_NAME_END_DECODE 0x0f
53 #define TAG_NAME_ID_STRING_DECODE 0x02
54 #define TAG_NAME_VPD_R_DECODE 0x10
55 #define TAG_NAME_VPD_W_DECODE 0x11
59 static efx_vpd_ops_t __efx_vpd_falcon_ops = {
60 NULL, /* evpdo_init */
61 falcon_vpd_size, /* evpdo_size */
62 falcon_vpd_read, /* evpdo_read */
63 falcon_vpd_verify, /* evpdo_verify */
64 NULL, /* evpdo_reinit */
65 falcon_vpd_get, /* evpdo_get */
66 falcon_vpd_set, /* evpdo_set */
67 falcon_vpd_next, /* evpdo_next */
68 falcon_vpd_write, /* evpdo_write */
69 NULL, /* evpdo_fini */
72 #endif /* EFSYS_OPT_FALCON */
76 static efx_vpd_ops_t __efx_vpd_siena_ops = {
77 siena_vpd_init, /* evpdo_init */
78 siena_vpd_size, /* evpdo_size */
79 siena_vpd_read, /* evpdo_read */
80 siena_vpd_verify, /* evpdo_verify */
81 siena_vpd_reinit, /* evpdo_reinit */
82 siena_vpd_get, /* evpdo_get */
83 siena_vpd_set, /* evpdo_set */
84 siena_vpd_next, /* evpdo_next */
85 siena_vpd_write, /* evpdo_write */
86 siena_vpd_fini, /* evpdo_fini */
89 #endif /* EFSYS_OPT_SIENA */
91 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
93 static efx_vpd_ops_t __efx_vpd_ef10_ops = {
94 ef10_vpd_init, /* evpdo_init */
95 ef10_vpd_size, /* evpdo_size */
96 ef10_vpd_read, /* evpdo_read */
97 ef10_vpd_verify, /* evpdo_verify */
98 ef10_vpd_reinit, /* evpdo_reinit */
99 ef10_vpd_get, /* evpdo_get */
100 ef10_vpd_set, /* evpdo_set */
101 ef10_vpd_next, /* evpdo_next */
102 ef10_vpd_write, /* evpdo_write */
103 ef10_vpd_fini, /* evpdo_fini */
106 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
108 __checkReturn efx_rc_t
112 efx_vpd_ops_t *evpdop;
115 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
116 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
117 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
119 switch (enp->en_family) {
121 case EFX_FAMILY_FALCON:
122 evpdop = (efx_vpd_ops_t *)&__efx_vpd_falcon_ops;
124 #endif /* EFSYS_OPT_FALCON */
127 case EFX_FAMILY_SIENA:
128 evpdop = (efx_vpd_ops_t *)&__efx_vpd_siena_ops;
130 #endif /* EFSYS_OPT_SIENA */
132 #if EFSYS_OPT_HUNTINGTON
133 case EFX_FAMILY_HUNTINGTON:
134 evpdop = (efx_vpd_ops_t *)&__efx_vpd_ef10_ops;
136 #endif /* EFSYS_OPT_HUNTINGTON */
138 #if EFSYS_OPT_MEDFORD
139 case EFX_FAMILY_MEDFORD:
140 evpdop = (efx_vpd_ops_t *)&__efx_vpd_ef10_ops;
142 #endif /* EFSYS_OPT_MEDFORD */
150 if (evpdop->evpdo_init != NULL) {
151 if ((rc = evpdop->evpdo_init(enp)) != 0)
155 enp->en_evpdop = evpdop;
156 enp->en_mod_flags |= EFX_MOD_VPD;
163 EFSYS_PROBE1(fail1, efx_rc_t, rc);
168 __checkReturn efx_rc_t
173 efx_vpd_ops_t *evpdop = enp->en_evpdop;
176 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
177 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
179 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
185 EFSYS_PROBE1(fail1, efx_rc_t, rc);
190 __checkReturn efx_rc_t
193 __out_bcount(size) caddr_t data,
196 efx_vpd_ops_t *evpdop = enp->en_evpdop;
199 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
200 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
202 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
208 EFSYS_PROBE1(fail1, efx_rc_t, rc);
213 __checkReturn efx_rc_t
216 __in_bcount(size) caddr_t data,
219 efx_vpd_ops_t *evpdop = enp->en_evpdop;
222 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
223 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
225 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
231 EFSYS_PROBE1(fail1, efx_rc_t, rc);
236 __checkReturn efx_rc_t
239 __in_bcount(size) caddr_t data,
242 efx_vpd_ops_t *evpdop = enp->en_evpdop;
245 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
248 if (evpdop->evpdo_reinit == NULL) {
253 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
261 EFSYS_PROBE1(fail1, efx_rc_t, rc);
266 __checkReturn efx_rc_t
269 __in_bcount(size) caddr_t data,
271 __inout efx_vpd_value_t *evvp)
273 efx_vpd_ops_t *evpdop = enp->en_evpdop;
276 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
277 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
279 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0)
285 EFSYS_PROBE1(fail1, efx_rc_t, rc);
290 __checkReturn efx_rc_t
293 __inout_bcount(size) caddr_t data,
295 __in efx_vpd_value_t *evvp)
297 efx_vpd_ops_t *evpdop = enp->en_evpdop;
300 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
301 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
303 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
309 EFSYS_PROBE1(fail1, efx_rc_t, rc);
314 __checkReturn efx_rc_t
317 __inout_bcount(size) caddr_t data,
319 __out efx_vpd_value_t *evvp,
320 __inout unsigned int *contp)
322 efx_vpd_ops_t *evpdop = enp->en_evpdop;
325 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
326 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
328 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
334 EFSYS_PROBE1(fail1, efx_rc_t, rc);
339 __checkReturn efx_rc_t
342 __in_bcount(size) caddr_t data,
345 efx_vpd_ops_t *evpdop = enp->en_evpdop;
348 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
349 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
351 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
357 EFSYS_PROBE1(fail1, efx_rc_t, rc);
362 static __checkReturn efx_rc_t
366 __inout unsigned int *offsetp,
367 __out efx_vpd_tag_t *tagp,
368 __out uint16_t *lengthp)
377 if (*offsetp >= size) {
382 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
384 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
385 case TAG_TYPE_SMALL_ITEM_DECODE:
388 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
389 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
393 case TAG_TYPE_LARGE_ITEM_DECODE:
396 if (*offsetp + headlen > size) {
401 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
402 EFX_POPULATE_WORD_2(word,
403 EFX_BYTE_0, data[*offsetp + 1],
404 EFX_BYTE_1, data[*offsetp + 2]);
405 length = EFX_WORD_FIELD(word, EFX_WORD_0);
414 if (*offsetp + headlen + length > size) {
419 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
420 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
421 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
422 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
423 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
424 name != EFX_VPD_RO) {
442 EFSYS_PROBE1(fail1, efx_rc_t, rc);
447 static __checkReturn efx_rc_t
448 efx_vpd_next_keyword(
449 __in_bcount(size) caddr_t tag,
451 __in unsigned int pos,
452 __out efx_vpd_keyword_t *keywordp,
453 __out uint8_t *lengthp)
455 efx_vpd_keyword_t keyword;
459 if (pos + 3U > size) {
464 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
465 length = tag[pos + 2];
467 if (length == 0 || pos + 3U + length > size) {
480 EFSYS_PROBE1(fail1, efx_rc_t, rc);
485 __checkReturn efx_rc_t
487 __in_bcount(size) caddr_t data,
489 __out size_t *lengthp)
497 _NOTE(CONSTANTCONDITION)
499 if ((rc = efx_vpd_next_tag(data, size, &offset,
500 &tag, &taglen)) != 0)
503 if (tag == EFX_VPD_END)
512 EFSYS_PROBE1(fail1, efx_rc_t, rc);
517 __checkReturn efx_rc_t
519 __in_bcount(size) caddr_t data,
521 __out_opt boolean_t *cksummedp)
524 efx_vpd_keyword_t keyword;
531 boolean_t cksummed = B_FALSE;
535 * Parse every tag,keyword in the existing VPD. If the csum is present,
536 * the assert it is correct, and is the final keyword in the RO block.
539 _NOTE(CONSTANTCONDITION)
541 if ((rc = efx_vpd_next_tag(data, size, &offset,
542 &tag, &taglen)) != 0)
544 if (tag == EFX_VPD_END)
546 else if (tag == EFX_VPD_ID)
549 for (pos = 0; pos != taglen; pos += 3 + keylen) {
550 /* RV keyword must be the last in the block */
556 if ((rc = efx_vpd_next_keyword(data + offset,
557 taglen, pos, &keyword, &keylen)) != 0)
560 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
562 for (i = 0; i < offset + pos + 4; i++)
583 if (cksummedp != NULL)
584 *cksummedp = cksummed;
597 EFSYS_PROBE1(fail1, efx_rc_t, rc);
602 static uint8_t __efx_vpd_blank_pid[] = {
603 /* Large resource type ID length 1 */
605 /* Product name ' ' */
609 static uint8_t __efx_vpd_blank_r[] = {
610 /* Large resource type VPD-R length 4 */
612 /* RV keyword length 1 */
614 /* RV payload checksum */
618 __checkReturn efx_rc_t
620 __in_bcount(size) caddr_t data,
622 __in boolean_t wantpid)
624 unsigned int offset = 0;
636 memcpy(data + offset, __efx_vpd_blank_pid,
637 sizeof (__efx_vpd_blank_pid));
638 offset += sizeof (__efx_vpd_blank_pid);
641 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
642 offset += sizeof (__efx_vpd_blank_r);
644 /* Update checksum */
646 for (pos = 0; pos < offset; pos++)
648 data[offset - 1] -= cksum;
650 /* Append trailing tag */
651 EFX_POPULATE_BYTE_3(byte,
652 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
653 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
654 TAG_SMALL_ITEM_SIZE, 0);
655 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
661 EFSYS_PROBE1(fail1, efx_rc_t, rc);
666 __checkReturn efx_rc_t
668 __in_bcount(size) caddr_t data,
670 __out efx_vpd_tag_t *tagp,
671 __out efx_vpd_keyword_t *keywordp,
672 __out_opt unsigned int *payloadp,
673 __out_opt uint8_t *paylenp,
674 __inout unsigned int *contp)
677 efx_vpd_keyword_t keyword = 0;
687 _NOTE(CONSTANTCONDITION)
689 if ((rc = efx_vpd_next_tag(data, size, &offset,
690 &tag, &taglen)) != 0)
693 if (tag == EFX_VPD_END) {
700 if (tag == EFX_VPD_ID) {
701 if (index++ == *contp) {
702 EFSYS_ASSERT3U(taglen, <, 0x100);
704 paylen = (uint8_t)MIN(taglen, 0xff);
709 for (pos = 0; pos != taglen; pos += 3 + keylen) {
710 if ((rc = efx_vpd_next_keyword(data + offset,
711 taglen, pos, &keyword, &keylen)) != 0)
714 if (index++ == *contp) {
729 if (payloadp != NULL)
740 EFSYS_PROBE1(fail1, efx_rc_t, rc);
745 __checkReturn efx_rc_t
747 __in_bcount(size) caddr_t data,
749 __in efx_vpd_tag_t tag,
750 __in efx_vpd_keyword_t keyword,
751 __out unsigned int *payloadp,
752 __out uint8_t *paylenp)
755 efx_vpd_keyword_t ikeyword;
763 _NOTE(CONSTANTCONDITION)
765 if ((rc = efx_vpd_next_tag(data, size, &offset,
766 &itag, &taglen)) != 0)
768 if (itag == EFX_VPD_END)
772 if (itag == EFX_VPD_ID) {
773 EFSYS_ASSERT3U(taglen, <, 0x100);
775 *paylenp = (uint8_t)MIN(taglen, 0xff);
780 for (pos = 0; pos != taglen; pos += 3 + keylen) {
781 if ((rc = efx_vpd_next_keyword(data + offset,
782 taglen, pos, &ikeyword, &keylen)) != 0)
785 if (ikeyword == keyword) {
787 *payloadp = offset + pos + 3;
802 EFSYS_PROBE1(fail1, efx_rc_t, rc);
807 __checkReturn efx_rc_t
809 __in_bcount(size) caddr_t data,
811 __in efx_vpd_value_t *evvp)
815 efx_vpd_keyword_t keyword;
818 unsigned int taghead;
828 switch (evvp->evv_tag) {
830 if (evvp->evv_keyword != 0) {
835 /* Can't delete the ID keyword */
836 if (evvp->evv_length == 0) {
843 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
854 /* Determine total size of all current tags */
855 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
859 _NOTE(CONSTANTCONDITION)
862 if ((rc = efx_vpd_next_tag(data, size, &offset,
863 &tag, &taglen)) != 0)
865 if (tag == EFX_VPD_END)
867 else if (tag != evvp->evv_tag) {
872 /* We only support modifying large resource tags */
873 if (offset - taghead != 3) {
879 * Work out the offset of the byte immediately after the
880 * old (=source) and new (=dest) new keyword/tag
883 if (tag == EFX_VPD_ID) {
884 source = offset + taglen;
885 dest = offset + evvp->evv_length;
889 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
891 for (pos = 0; pos != taglen; pos += 3 + keylen) {
892 if ((rc = efx_vpd_next_keyword(data + offset,
893 taglen, pos, &keyword, &keylen)) != 0)
896 if (keyword == evvp->evv_keyword &&
897 evvp->evv_length == 0) {
898 /* Deleting this keyword */
899 source = offset + pos + 3 + keylen;
903 } else if (keyword == evvp->evv_keyword) {
904 /* Adjusting this keyword */
905 source = offset + pos + 3 + keylen;
906 dest = offset + pos + 3 + evvp->evv_length;
909 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
910 /* The RV keyword must be at the end */
911 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
914 * The keyword doesn't already exist. If the
915 * user deleting a non-existant keyword then
918 if (evvp->evv_length == 0)
921 /* Insert this keyword before the RV keyword */
922 source = offset + pos;
923 dest = offset + pos + 3 + evvp->evv_length;
929 if (used + dest > size + source) {
934 /* Move trailing data */
935 (void) memmove(data + dest, data + source, used - source);
938 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
941 /* Insert new keyword header if required */
942 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
943 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
945 data[offset + pos + 0] =
946 EFX_WORD_FIELD(word, EFX_BYTE_0);
947 data[offset + pos + 1] =
948 EFX_WORD_FIELD(word, EFX_BYTE_1);
949 data[offset + pos + 2] = evvp->evv_length;
952 /* Modify tag length (large resource type) */
953 taglen += (dest - source);
954 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
955 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
956 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
961 /* Unable to find the matching tag */
966 /* Find the RV tag, and update the checksum */
968 _NOTE(CONSTANTCONDITION)
970 if ((rc = efx_vpd_next_tag(data, size, &offset,
971 &tag, &taglen)) != 0)
973 if (tag == EFX_VPD_END)
975 if (tag == EFX_VPD_RO) {
976 for (pos = 0; pos != taglen; pos += 3 + keylen) {
977 if ((rc = efx_vpd_next_keyword(data + offset,
978 taglen, pos, &keyword, &keylen)) != 0)
981 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
983 for (i = 0; i < offset + pos + 3; i++)
994 /* Zero out the unused portion */
995 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
1016 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1023 __in efx_nic_t *enp)
1025 efx_vpd_ops_t *evpdop = enp->en_evpdop;
1027 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1028 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1029 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1031 if (evpdop->evpdo_fini != NULL)
1032 evpdop->evpdo_fini(enp);
1034 enp->en_evpdop = NULL;
1035 enp->en_mod_flags &= ~EFX_MOD_VPD;
1038 #endif /* EFSYS_OPT_VPD */