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_bcount_opt(*paylenp) 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)
692 if (tag == EFX_VPD_END)
695 if (tag == EFX_VPD_ID) {
696 if (index == *contp) {
697 EFSYS_ASSERT3U(taglen, <, 0x100);
698 paylen = (uint8_t)MIN(taglen, 0xff);
703 for (pos = 0; pos != taglen; pos += 3 + keylen) {
704 if ((rc = efx_vpd_next_keyword(data + offset,
705 taglen, pos, &keyword, &keylen)) != 0)
708 if (index == *contp) {
726 if (payloadp != NULL)
737 EFSYS_PROBE1(fail1, efx_rc_t, rc);
742 __checkReturn efx_rc_t
744 __in_bcount(size) caddr_t data,
746 __in efx_vpd_tag_t tag,
747 __in efx_vpd_keyword_t keyword,
748 __out unsigned int *payloadp,
749 __out uint8_t *paylenp)
752 efx_vpd_keyword_t ikeyword;
760 _NOTE(CONSTANTCONDITION)
762 if ((rc = efx_vpd_next_tag(data, size, &offset,
763 &itag, &taglen)) != 0)
765 if (itag == EFX_VPD_END)
769 if (itag == EFX_VPD_ID) {
770 EFSYS_ASSERT3U(taglen, <, 0x100);
772 *paylenp = (uint8_t)MIN(taglen, 0xff);
777 for (pos = 0; pos != taglen; pos += 3 + keylen) {
778 if ((rc = efx_vpd_next_keyword(data + offset,
779 taglen, pos, &ikeyword, &keylen)) != 0)
782 if (ikeyword == keyword) {
784 *payloadp = offset + pos + 3;
799 EFSYS_PROBE1(fail1, efx_rc_t, rc);
804 __checkReturn efx_rc_t
806 __in_bcount(size) caddr_t data,
808 __in efx_vpd_value_t *evvp)
812 efx_vpd_keyword_t keyword;
815 unsigned int taghead;
825 switch (evvp->evv_tag) {
827 if (evvp->evv_keyword != 0) {
832 /* Can't delete the ID keyword */
833 if (evvp->evv_length == 0) {
840 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
851 /* Determine total size of all current tags */
852 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
856 _NOTE(CONSTANTCONDITION)
859 if ((rc = efx_vpd_next_tag(data, size, &offset,
860 &tag, &taglen)) != 0)
862 if (tag == EFX_VPD_END)
864 else if (tag != evvp->evv_tag) {
869 /* We only support modifying large resource tags */
870 if (offset - taghead != 3) {
876 * Work out the offset of the byte immediately after the
877 * old (=source) and new (=dest) new keyword/tag
880 if (tag == EFX_VPD_ID) {
881 source = offset + taglen;
882 dest = offset + evvp->evv_length;
886 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
888 for (pos = 0; pos != taglen; pos += 3 + keylen) {
889 if ((rc = efx_vpd_next_keyword(data + offset,
890 taglen, pos, &keyword, &keylen)) != 0)
893 if (keyword == evvp->evv_keyword &&
894 evvp->evv_length == 0) {
895 /* Deleting this keyword */
896 source = offset + pos + 3 + keylen;
900 } else if (keyword == evvp->evv_keyword) {
901 /* Adjusting this keyword */
902 source = offset + pos + 3 + keylen;
903 dest = offset + pos + 3 + evvp->evv_length;
906 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
907 /* The RV keyword must be at the end */
908 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
911 * The keyword doesn't already exist. If the
912 * user deleting a non-existant keyword then
915 if (evvp->evv_length == 0)
918 /* Insert this keyword before the RV keyword */
919 source = offset + pos;
920 dest = offset + pos + 3 + evvp->evv_length;
926 if (used + dest > size + source) {
931 /* Move trailing data */
932 (void) memmove(data + dest, data + source, used - source);
935 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
938 /* Insert new keyword header if required */
939 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
940 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
942 data[offset + pos + 0] =
943 EFX_WORD_FIELD(word, EFX_BYTE_0);
944 data[offset + pos + 1] =
945 EFX_WORD_FIELD(word, EFX_BYTE_1);
946 data[offset + pos + 2] = evvp->evv_length;
949 /* Modify tag length (large resource type) */
950 taglen += (dest - source);
951 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
952 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
953 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
958 /* Unable to find the matching tag */
963 /* Find the RV tag, and update the checksum */
965 _NOTE(CONSTANTCONDITION)
967 if ((rc = efx_vpd_next_tag(data, size, &offset,
968 &tag, &taglen)) != 0)
970 if (tag == EFX_VPD_END)
972 if (tag == EFX_VPD_RO) {
973 for (pos = 0; pos != taglen; pos += 3 + keylen) {
974 if ((rc = efx_vpd_next_keyword(data + offset,
975 taglen, pos, &keyword, &keylen)) != 0)
978 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
980 for (i = 0; i < offset + pos + 3; i++)
991 /* Zero out the unused portion */
992 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
1013 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1020 __in efx_nic_t *enp)
1022 efx_vpd_ops_t *evpdop = enp->en_evpdop;
1024 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1025 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1026 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1028 if (evpdop->evpdo_fini != NULL)
1029 evpdop->evpdo_fini(enp);
1031 enp->en_evpdop = NULL;
1032 enp->en_mod_flags &= ~EFX_MOD_VPD;
1035 #endif /* EFSYS_OPT_VPD */