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 const efx_vpd_ops_t __efx_vpd_siena_ops = {
60 siena_vpd_init, /* evpdo_init */
61 siena_vpd_size, /* evpdo_size */
62 siena_vpd_read, /* evpdo_read */
63 siena_vpd_verify, /* evpdo_verify */
64 siena_vpd_reinit, /* evpdo_reinit */
65 siena_vpd_get, /* evpdo_get */
66 siena_vpd_set, /* evpdo_set */
67 siena_vpd_next, /* evpdo_next */
68 siena_vpd_write, /* evpdo_write */
69 siena_vpd_fini, /* evpdo_fini */
72 #endif /* EFSYS_OPT_SIENA */
74 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
76 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
77 ef10_vpd_init, /* evpdo_init */
78 ef10_vpd_size, /* evpdo_size */
79 ef10_vpd_read, /* evpdo_read */
80 ef10_vpd_verify, /* evpdo_verify */
81 ef10_vpd_reinit, /* evpdo_reinit */
82 ef10_vpd_get, /* evpdo_get */
83 ef10_vpd_set, /* evpdo_set */
84 ef10_vpd_next, /* evpdo_next */
85 ef10_vpd_write, /* evpdo_write */
86 ef10_vpd_fini, /* evpdo_fini */
89 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
91 __checkReturn efx_rc_t
95 const efx_vpd_ops_t *evpdop;
98 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
99 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
100 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
102 switch (enp->en_family) {
104 case EFX_FAMILY_SIENA:
105 evpdop = &__efx_vpd_siena_ops;
107 #endif /* EFSYS_OPT_SIENA */
109 #if EFSYS_OPT_HUNTINGTON
110 case EFX_FAMILY_HUNTINGTON:
111 evpdop = &__efx_vpd_ef10_ops;
113 #endif /* EFSYS_OPT_HUNTINGTON */
115 #if EFSYS_OPT_MEDFORD
116 case EFX_FAMILY_MEDFORD:
117 evpdop = &__efx_vpd_ef10_ops;
119 #endif /* EFSYS_OPT_MEDFORD */
127 if (evpdop->evpdo_init != NULL) {
128 if ((rc = evpdop->evpdo_init(enp)) != 0)
132 enp->en_evpdop = evpdop;
133 enp->en_mod_flags |= EFX_MOD_VPD;
140 EFSYS_PROBE1(fail1, efx_rc_t, rc);
145 __checkReturn efx_rc_t
150 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
153 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
154 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
156 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
162 EFSYS_PROBE1(fail1, efx_rc_t, rc);
167 __checkReturn efx_rc_t
170 __out_bcount(size) caddr_t data,
173 const 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_read(enp, data, size)) != 0)
185 EFSYS_PROBE1(fail1, efx_rc_t, rc);
190 __checkReturn efx_rc_t
193 __in_bcount(size) caddr_t data,
196 const 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_verify(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 const 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 (evpdop->evpdo_reinit == NULL) {
230 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
238 EFSYS_PROBE1(fail1, efx_rc_t, rc);
243 __checkReturn efx_rc_t
246 __in_bcount(size) caddr_t data,
248 __inout efx_vpd_value_t *evvp)
250 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
253 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
254 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
256 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0)
262 EFSYS_PROBE1(fail1, efx_rc_t, rc);
267 __checkReturn efx_rc_t
270 __inout_bcount(size) caddr_t data,
272 __in efx_vpd_value_t *evvp)
274 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
277 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
278 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
280 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
286 EFSYS_PROBE1(fail1, efx_rc_t, rc);
291 __checkReturn efx_rc_t
294 __inout_bcount(size) caddr_t data,
296 __out efx_vpd_value_t *evvp,
297 __inout unsigned int *contp)
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_next(enp, data, size, evvp, contp)) != 0)
311 EFSYS_PROBE1(fail1, efx_rc_t, rc);
316 __checkReturn efx_rc_t
319 __in_bcount(size) caddr_t data,
322 const 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_write(enp, data, size)) != 0)
334 EFSYS_PROBE1(fail1, efx_rc_t, rc);
339 static __checkReturn efx_rc_t
343 __inout unsigned int *offsetp,
344 __out efx_vpd_tag_t *tagp,
345 __out uint16_t *lengthp)
354 if (*offsetp >= size) {
359 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
361 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
362 case TAG_TYPE_SMALL_ITEM_DECODE:
365 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
366 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
370 case TAG_TYPE_LARGE_ITEM_DECODE:
373 if (*offsetp + headlen > size) {
378 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
379 EFX_POPULATE_WORD_2(word,
380 EFX_BYTE_0, data[*offsetp + 1],
381 EFX_BYTE_1, data[*offsetp + 2]);
382 length = EFX_WORD_FIELD(word, EFX_WORD_0);
391 if (*offsetp + headlen + length > size) {
396 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
397 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
398 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
399 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
400 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
401 name != EFX_VPD_RO) {
419 EFSYS_PROBE1(fail1, efx_rc_t, rc);
424 static __checkReturn efx_rc_t
425 efx_vpd_next_keyword(
426 __in_bcount(size) caddr_t tag,
428 __in unsigned int pos,
429 __out efx_vpd_keyword_t *keywordp,
430 __out uint8_t *lengthp)
432 efx_vpd_keyword_t keyword;
436 if (pos + 3U > size) {
441 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
442 length = tag[pos + 2];
444 if (length == 0 || pos + 3U + length > size) {
457 EFSYS_PROBE1(fail1, efx_rc_t, rc);
462 __checkReturn efx_rc_t
464 __in_bcount(size) caddr_t data,
466 __out size_t *lengthp)
474 _NOTE(CONSTANTCONDITION)
476 if ((rc = efx_vpd_next_tag(data, size, &offset,
477 &tag, &taglen)) != 0)
480 if (tag == EFX_VPD_END)
489 EFSYS_PROBE1(fail1, efx_rc_t, rc);
494 __checkReturn efx_rc_t
496 __in_bcount(size) caddr_t data,
498 __out_opt boolean_t *cksummedp)
501 efx_vpd_keyword_t keyword;
508 boolean_t cksummed = B_FALSE;
512 * Parse every tag,keyword in the existing VPD. If the csum is present,
513 * the assert it is correct, and is the final keyword in the RO block.
516 _NOTE(CONSTANTCONDITION)
518 if ((rc = efx_vpd_next_tag(data, size, &offset,
519 &tag, &taglen)) != 0)
521 if (tag == EFX_VPD_END)
523 else if (tag == EFX_VPD_ID)
526 for (pos = 0; pos != taglen; pos += 3 + keylen) {
527 /* RV keyword must be the last in the block */
533 if ((rc = efx_vpd_next_keyword(data + offset,
534 taglen, pos, &keyword, &keylen)) != 0)
537 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
539 for (i = 0; i < offset + pos + 4; i++)
560 if (cksummedp != NULL)
561 *cksummedp = cksummed;
574 EFSYS_PROBE1(fail1, efx_rc_t, rc);
579 static uint8_t __efx_vpd_blank_pid[] = {
580 /* Large resource type ID length 1 */
582 /* Product name ' ' */
586 static uint8_t __efx_vpd_blank_r[] = {
587 /* Large resource type VPD-R length 4 */
589 /* RV keyword length 1 */
591 /* RV payload checksum */
595 __checkReturn efx_rc_t
597 __in_bcount(size) caddr_t data,
599 __in boolean_t wantpid)
601 unsigned int offset = 0;
613 memcpy(data + offset, __efx_vpd_blank_pid,
614 sizeof (__efx_vpd_blank_pid));
615 offset += sizeof (__efx_vpd_blank_pid);
618 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
619 offset += sizeof (__efx_vpd_blank_r);
621 /* Update checksum */
623 for (pos = 0; pos < offset; pos++)
625 data[offset - 1] -= cksum;
627 /* Append trailing tag */
628 EFX_POPULATE_BYTE_3(byte,
629 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
630 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
631 TAG_SMALL_ITEM_SIZE, 0);
632 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
638 EFSYS_PROBE1(fail1, efx_rc_t, rc);
643 __checkReturn efx_rc_t
645 __in_bcount(size) caddr_t data,
647 __out efx_vpd_tag_t *tagp,
648 __out efx_vpd_keyword_t *keywordp,
649 __out_opt unsigned int *payloadp,
650 __out_opt uint8_t *paylenp,
651 __inout unsigned int *contp)
654 efx_vpd_keyword_t keyword = 0;
664 _NOTE(CONSTANTCONDITION)
666 if ((rc = efx_vpd_next_tag(data, size, &offset,
667 &tag, &taglen)) != 0)
670 if (tag == EFX_VPD_END) {
677 if (tag == EFX_VPD_ID) {
678 if (index++ == *contp) {
679 EFSYS_ASSERT3U(taglen, <, 0x100);
681 paylen = (uint8_t)MIN(taglen, 0xff);
686 for (pos = 0; pos != taglen; pos += 3 + keylen) {
687 if ((rc = efx_vpd_next_keyword(data + offset,
688 taglen, pos, &keyword, &keylen)) != 0)
691 if (index++ == *contp) {
706 if (payloadp != NULL)
717 EFSYS_PROBE1(fail1, efx_rc_t, rc);
722 __checkReturn efx_rc_t
724 __in_bcount(size) caddr_t data,
726 __in efx_vpd_tag_t tag,
727 __in efx_vpd_keyword_t keyword,
728 __out unsigned int *payloadp,
729 __out uint8_t *paylenp)
732 efx_vpd_keyword_t ikeyword;
740 _NOTE(CONSTANTCONDITION)
742 if ((rc = efx_vpd_next_tag(data, size, &offset,
743 &itag, &taglen)) != 0)
745 if (itag == EFX_VPD_END)
749 if (itag == EFX_VPD_ID) {
750 EFSYS_ASSERT3U(taglen, <, 0x100);
752 *paylenp = (uint8_t)MIN(taglen, 0xff);
757 for (pos = 0; pos != taglen; pos += 3 + keylen) {
758 if ((rc = efx_vpd_next_keyword(data + offset,
759 taglen, pos, &ikeyword, &keylen)) != 0)
762 if (ikeyword == keyword) {
764 *payloadp = offset + pos + 3;
779 EFSYS_PROBE1(fail1, efx_rc_t, rc);
784 __checkReturn efx_rc_t
786 __in_bcount(size) caddr_t data,
788 __in efx_vpd_value_t *evvp)
792 efx_vpd_keyword_t keyword;
795 unsigned int taghead;
805 switch (evvp->evv_tag) {
807 if (evvp->evv_keyword != 0) {
812 /* Can't delete the ID keyword */
813 if (evvp->evv_length == 0) {
820 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
831 /* Determine total size of all current tags */
832 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
836 _NOTE(CONSTANTCONDITION)
839 if ((rc = efx_vpd_next_tag(data, size, &offset,
840 &tag, &taglen)) != 0)
842 if (tag == EFX_VPD_END)
844 else if (tag != evvp->evv_tag) {
849 /* We only support modifying large resource tags */
850 if (offset - taghead != 3) {
856 * Work out the offset of the byte immediately after the
857 * old (=source) and new (=dest) new keyword/tag
860 if (tag == EFX_VPD_ID) {
861 source = offset + taglen;
862 dest = offset + evvp->evv_length;
866 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
868 for (pos = 0; pos != taglen; pos += 3 + keylen) {
869 if ((rc = efx_vpd_next_keyword(data + offset,
870 taglen, pos, &keyword, &keylen)) != 0)
873 if (keyword == evvp->evv_keyword &&
874 evvp->evv_length == 0) {
875 /* Deleting this keyword */
876 source = offset + pos + 3 + keylen;
880 } else if (keyword == evvp->evv_keyword) {
881 /* Adjusting this keyword */
882 source = offset + pos + 3 + keylen;
883 dest = offset + pos + 3 + evvp->evv_length;
886 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
887 /* The RV keyword must be at the end */
888 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
891 * The keyword doesn't already exist. If the
892 * user deleting a non-existant keyword then
895 if (evvp->evv_length == 0)
898 /* Insert this keyword before the RV keyword */
899 source = offset + pos;
900 dest = offset + pos + 3 + evvp->evv_length;
906 if (used + dest > size + source) {
911 /* Move trailing data */
912 (void) memmove(data + dest, data + source, used - source);
915 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
918 /* Insert new keyword header if required */
919 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
920 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
922 data[offset + pos + 0] =
923 EFX_WORD_FIELD(word, EFX_BYTE_0);
924 data[offset + pos + 1] =
925 EFX_WORD_FIELD(word, EFX_BYTE_1);
926 data[offset + pos + 2] = evvp->evv_length;
929 /* Modify tag length (large resource type) */
930 taglen += (dest - source);
931 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
932 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
933 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
938 /* Unable to find the matching tag */
943 /* Find the RV tag, and update the checksum */
945 _NOTE(CONSTANTCONDITION)
947 if ((rc = efx_vpd_next_tag(data, size, &offset,
948 &tag, &taglen)) != 0)
950 if (tag == EFX_VPD_END)
952 if (tag == EFX_VPD_RO) {
953 for (pos = 0; pos != taglen; pos += 3 + keylen) {
954 if ((rc = efx_vpd_next_keyword(data + offset,
955 taglen, pos, &keyword, &keylen)) != 0)
958 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
960 for (i = 0; i < offset + pos + 3; i++)
971 /* Zero out the unused portion */
972 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
993 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1000 __in efx_nic_t *enp)
1002 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1004 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1005 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1006 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1008 if (evpdop->evpdo_fini != NULL)
1009 evpdop->evpdo_fini(enp);
1011 enp->en_evpdop = NULL;
1012 enp->en_mod_flags &= ~EFX_MOD_VPD;
1015 #endif /* EFSYS_OPT_VPD */