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.
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) {
266 EFSYS_PROBE1(fail1, efx_rc_t, rc);
271 __checkReturn efx_rc_t
274 __inout_bcount(size) caddr_t data,
276 __in efx_vpd_value_t *evvp)
278 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
281 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
282 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
284 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
290 EFSYS_PROBE1(fail1, efx_rc_t, rc);
295 __checkReturn efx_rc_t
298 __inout_bcount(size) caddr_t data,
300 __out efx_vpd_value_t *evvp,
301 __inout unsigned int *contp)
303 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
306 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
307 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
309 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
315 EFSYS_PROBE1(fail1, efx_rc_t, rc);
320 __checkReturn efx_rc_t
323 __in_bcount(size) caddr_t data,
326 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
329 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
330 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
332 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
338 EFSYS_PROBE1(fail1, efx_rc_t, rc);
343 static __checkReturn efx_rc_t
347 __inout unsigned int *offsetp,
348 __out efx_vpd_tag_t *tagp,
349 __out uint16_t *lengthp)
358 if (*offsetp >= size) {
363 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
365 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
366 case TAG_TYPE_SMALL_ITEM_DECODE:
369 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
370 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
374 case TAG_TYPE_LARGE_ITEM_DECODE:
377 if (*offsetp + headlen > size) {
382 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
383 EFX_POPULATE_WORD_2(word,
384 EFX_BYTE_0, data[*offsetp + 1],
385 EFX_BYTE_1, data[*offsetp + 2]);
386 length = EFX_WORD_FIELD(word, EFX_WORD_0);
395 if (*offsetp + headlen + length > size) {
400 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
401 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
402 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
403 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
404 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
405 name != EFX_VPD_RO) {
423 EFSYS_PROBE1(fail1, efx_rc_t, rc);
428 static __checkReturn efx_rc_t
429 efx_vpd_next_keyword(
430 __in_bcount(size) caddr_t tag,
432 __in unsigned int pos,
433 __out efx_vpd_keyword_t *keywordp,
434 __out uint8_t *lengthp)
436 efx_vpd_keyword_t keyword;
440 if (pos + 3U > size) {
445 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
446 length = tag[pos + 2];
448 if (length == 0 || pos + 3U + length > size) {
461 EFSYS_PROBE1(fail1, efx_rc_t, rc);
466 __checkReturn efx_rc_t
468 __in_bcount(size) caddr_t data,
470 __out size_t *lengthp)
478 _NOTE(CONSTANTCONDITION)
480 if ((rc = efx_vpd_next_tag(data, size, &offset,
481 &tag, &taglen)) != 0)
484 if (tag == EFX_VPD_END)
493 EFSYS_PROBE1(fail1, efx_rc_t, rc);
498 __checkReturn efx_rc_t
500 __in_bcount(size) caddr_t data,
502 __out_opt boolean_t *cksummedp)
505 efx_vpd_keyword_t keyword;
512 boolean_t cksummed = B_FALSE;
516 * Parse every tag,keyword in the existing VPD. If the csum is present,
517 * the assert it is correct, and is the final keyword in the RO block.
520 _NOTE(CONSTANTCONDITION)
522 if ((rc = efx_vpd_next_tag(data, size, &offset,
523 &tag, &taglen)) != 0)
525 if (tag == EFX_VPD_END)
527 else if (tag == EFX_VPD_ID)
530 for (pos = 0; pos != taglen; pos += 3 + keylen) {
531 /* RV keyword must be the last in the block */
537 if ((rc = efx_vpd_next_keyword(data + offset,
538 taglen, pos, &keyword, &keylen)) != 0)
541 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
543 for (i = 0; i < offset + pos + 4; i++)
564 if (cksummedp != NULL)
565 *cksummedp = cksummed;
578 EFSYS_PROBE1(fail1, efx_rc_t, rc);
583 static uint8_t __efx_vpd_blank_pid[] = {
584 /* Large resource type ID length 1 */
586 /* Product name ' ' */
590 static uint8_t __efx_vpd_blank_r[] = {
591 /* Large resource type VPD-R length 4 */
593 /* RV keyword length 1 */
595 /* RV payload checksum */
599 __checkReturn efx_rc_t
601 __in_bcount(size) caddr_t data,
603 __in boolean_t wantpid)
605 unsigned int offset = 0;
617 memcpy(data + offset, __efx_vpd_blank_pid,
618 sizeof (__efx_vpd_blank_pid));
619 offset += sizeof (__efx_vpd_blank_pid);
622 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
623 offset += sizeof (__efx_vpd_blank_r);
625 /* Update checksum */
627 for (pos = 0; pos < offset; pos++)
629 data[offset - 1] -= cksum;
631 /* Append trailing tag */
632 EFX_POPULATE_BYTE_3(byte,
633 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
634 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
635 TAG_SMALL_ITEM_SIZE, 0);
636 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
642 EFSYS_PROBE1(fail1, efx_rc_t, rc);
647 __checkReturn efx_rc_t
649 __in_bcount(size) caddr_t data,
651 __out efx_vpd_tag_t *tagp,
652 __out efx_vpd_keyword_t *keywordp,
653 __out_opt unsigned int *payloadp,
654 __out_opt uint8_t *paylenp,
655 __inout unsigned int *contp)
658 efx_vpd_keyword_t keyword = 0;
668 _NOTE(CONSTANTCONDITION)
670 if ((rc = efx_vpd_next_tag(data, size, &offset,
671 &tag, &taglen)) != 0)
674 if (tag == EFX_VPD_END) {
681 if (tag == EFX_VPD_ID) {
682 if (index++ == *contp) {
683 EFSYS_ASSERT3U(taglen, <, 0x100);
685 paylen = (uint8_t)MIN(taglen, 0xff);
690 for (pos = 0; pos != taglen; pos += 3 + keylen) {
691 if ((rc = efx_vpd_next_keyword(data + offset,
692 taglen, pos, &keyword, &keylen)) != 0)
695 if (index++ == *contp) {
710 if (payloadp != NULL)
721 EFSYS_PROBE1(fail1, efx_rc_t, rc);
726 __checkReturn efx_rc_t
728 __in_bcount(size) caddr_t data,
730 __in efx_vpd_tag_t tag,
731 __in efx_vpd_keyword_t keyword,
732 __out unsigned int *payloadp,
733 __out uint8_t *paylenp)
736 efx_vpd_keyword_t ikeyword;
744 _NOTE(CONSTANTCONDITION)
746 if ((rc = efx_vpd_next_tag(data, size, &offset,
747 &itag, &taglen)) != 0)
749 if (itag == EFX_VPD_END)
753 if (itag == EFX_VPD_ID) {
754 EFSYS_ASSERT3U(taglen, <, 0x100);
756 *paylenp = (uint8_t)MIN(taglen, 0xff);
761 for (pos = 0; pos != taglen; pos += 3 + keylen) {
762 if ((rc = efx_vpd_next_keyword(data + offset,
763 taglen, pos, &ikeyword, &keylen)) != 0)
766 if (ikeyword == keyword) {
768 *payloadp = offset + pos + 3;
783 EFSYS_PROBE1(fail1, efx_rc_t, rc);
788 __checkReturn efx_rc_t
790 __in_bcount(size) caddr_t data,
792 __in efx_vpd_value_t *evvp)
796 efx_vpd_keyword_t keyword;
799 unsigned int taghead;
809 switch (evvp->evv_tag) {
811 if (evvp->evv_keyword != 0) {
816 /* Can't delete the ID keyword */
817 if (evvp->evv_length == 0) {
824 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
835 /* Determine total size of all current tags */
836 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
840 _NOTE(CONSTANTCONDITION)
843 if ((rc = efx_vpd_next_tag(data, size, &offset,
844 &tag, &taglen)) != 0)
846 if (tag == EFX_VPD_END)
848 else if (tag != evvp->evv_tag) {
853 /* We only support modifying large resource tags */
854 if (offset - taghead != 3) {
860 * Work out the offset of the byte immediately after the
861 * old (=source) and new (=dest) new keyword/tag
864 if (tag == EFX_VPD_ID) {
865 source = offset + taglen;
866 dest = offset + evvp->evv_length;
870 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
872 for (pos = 0; pos != taglen; pos += 3 + keylen) {
873 if ((rc = efx_vpd_next_keyword(data + offset,
874 taglen, pos, &keyword, &keylen)) != 0)
877 if (keyword == evvp->evv_keyword &&
878 evvp->evv_length == 0) {
879 /* Deleting this keyword */
880 source = offset + pos + 3 + keylen;
884 } else if (keyword == evvp->evv_keyword) {
885 /* Adjusting this keyword */
886 source = offset + pos + 3 + keylen;
887 dest = offset + pos + 3 + evvp->evv_length;
890 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
891 /* The RV keyword must be at the end */
892 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
895 * The keyword doesn't already exist. If the
896 * user deleting a non-existant keyword then
899 if (evvp->evv_length == 0)
902 /* Insert this keyword before the RV keyword */
903 source = offset + pos;
904 dest = offset + pos + 3 + evvp->evv_length;
910 if (used + dest > size + source) {
915 /* Move trailing data */
916 (void) memmove(data + dest, data + source, used - source);
919 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
922 /* Insert new keyword header if required */
923 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
924 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
926 data[offset + pos + 0] =
927 EFX_WORD_FIELD(word, EFX_BYTE_0);
928 data[offset + pos + 1] =
929 EFX_WORD_FIELD(word, EFX_BYTE_1);
930 data[offset + pos + 2] = evvp->evv_length;
933 /* Modify tag length (large resource type) */
934 taglen += (dest - source);
935 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
936 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
937 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
942 /* Unable to find the matching tag */
947 /* Find the RV tag, and update the checksum */
949 _NOTE(CONSTANTCONDITION)
951 if ((rc = efx_vpd_next_tag(data, size, &offset,
952 &tag, &taglen)) != 0)
954 if (tag == EFX_VPD_END)
956 if (tag == EFX_VPD_RO) {
957 for (pos = 0; pos != taglen; pos += 3 + keylen) {
958 if ((rc = efx_vpd_next_keyword(data + offset,
959 taglen, pos, &keyword, &keylen)) != 0)
962 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
964 for (i = 0; i < offset + pos + 3; i++)
975 /* Zero out the unused portion */
976 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
997 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1004 __in efx_nic_t *enp)
1006 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1008 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1009 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1010 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1012 if (evpdop->evpdo_fini != NULL)
1013 evpdop->evpdo_fini(enp);
1015 enp->en_evpdop = NULL;
1016 enp->en_mod_flags &= ~EFX_MOD_VPD;
1019 #endif /* EFSYS_OPT_VPD */