2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2016 Solarflare Communications Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
41 #define TAG_TYPE_LBN 7
42 #define TAG_TYPE_WIDTH 1
43 #define TAG_TYPE_LARGE_ITEM_DECODE 1
44 #define TAG_TYPE_SMALL_ITEM_DECODE 0
46 #define TAG_SMALL_ITEM_NAME_LBN 3
47 #define TAG_SMALL_ITEM_NAME_WIDTH 4
48 #define TAG_SMALL_ITEM_SIZE_LBN 0
49 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
51 #define TAG_LARGE_ITEM_NAME_LBN 0
52 #define TAG_LARGE_ITEM_NAME_WIDTH 7
54 #define TAG_NAME_END_DECODE 0x0f
55 #define TAG_NAME_ID_STRING_DECODE 0x02
56 #define TAG_NAME_VPD_R_DECODE 0x10
57 #define TAG_NAME_VPD_W_DECODE 0x11
61 static const efx_vpd_ops_t __efx_vpd_siena_ops = {
62 siena_vpd_init, /* evpdo_init */
63 siena_vpd_size, /* evpdo_size */
64 siena_vpd_read, /* evpdo_read */
65 siena_vpd_verify, /* evpdo_verify */
66 siena_vpd_reinit, /* evpdo_reinit */
67 siena_vpd_get, /* evpdo_get */
68 siena_vpd_set, /* evpdo_set */
69 siena_vpd_next, /* evpdo_next */
70 siena_vpd_write, /* evpdo_write */
71 siena_vpd_fini, /* evpdo_fini */
74 #endif /* EFSYS_OPT_SIENA */
76 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
78 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
79 ef10_vpd_init, /* evpdo_init */
80 ef10_vpd_size, /* evpdo_size */
81 ef10_vpd_read, /* evpdo_read */
82 ef10_vpd_verify, /* evpdo_verify */
83 ef10_vpd_reinit, /* evpdo_reinit */
84 ef10_vpd_get, /* evpdo_get */
85 ef10_vpd_set, /* evpdo_set */
86 ef10_vpd_next, /* evpdo_next */
87 ef10_vpd_write, /* evpdo_write */
88 ef10_vpd_fini, /* evpdo_fini */
91 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
93 __checkReturn efx_rc_t
97 const efx_vpd_ops_t *evpdop;
100 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
101 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
102 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
104 switch (enp->en_family) {
106 case EFX_FAMILY_SIENA:
107 evpdop = &__efx_vpd_siena_ops;
109 #endif /* EFSYS_OPT_SIENA */
111 #if EFSYS_OPT_HUNTINGTON
112 case EFX_FAMILY_HUNTINGTON:
113 evpdop = &__efx_vpd_ef10_ops;
115 #endif /* EFSYS_OPT_HUNTINGTON */
117 #if EFSYS_OPT_MEDFORD
118 case EFX_FAMILY_MEDFORD:
119 evpdop = &__efx_vpd_ef10_ops;
121 #endif /* EFSYS_OPT_MEDFORD */
129 if (evpdop->evpdo_init != NULL) {
130 if ((rc = evpdop->evpdo_init(enp)) != 0)
134 enp->en_evpdop = evpdop;
135 enp->en_mod_flags |= EFX_MOD_VPD;
142 EFSYS_PROBE1(fail1, efx_rc_t, rc);
147 __checkReturn efx_rc_t
152 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
155 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
158 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
164 EFSYS_PROBE1(fail1, efx_rc_t, rc);
169 __checkReturn efx_rc_t
172 __out_bcount(size) caddr_t data,
175 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
178 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
179 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
181 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
187 EFSYS_PROBE1(fail1, efx_rc_t, rc);
192 __checkReturn efx_rc_t
195 __in_bcount(size) caddr_t data,
198 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
201 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
202 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
204 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
210 EFSYS_PROBE1(fail1, efx_rc_t, rc);
215 __checkReturn efx_rc_t
218 __in_bcount(size) caddr_t data,
221 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
224 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
225 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
227 if (evpdop->evpdo_reinit == NULL) {
232 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
240 EFSYS_PROBE1(fail1, efx_rc_t, rc);
245 __checkReturn efx_rc_t
248 __in_bcount(size) caddr_t data,
250 __inout efx_vpd_value_t *evvp)
252 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
255 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
256 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
258 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
268 EFSYS_PROBE1(fail1, efx_rc_t, rc);
273 __checkReturn efx_rc_t
276 __inout_bcount(size) caddr_t data,
278 __in efx_vpd_value_t *evvp)
280 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
283 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
284 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
286 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
292 EFSYS_PROBE1(fail1, efx_rc_t, rc);
297 __checkReturn efx_rc_t
300 __inout_bcount(size) caddr_t data,
302 __out efx_vpd_value_t *evvp,
303 __inout unsigned int *contp)
305 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
308 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
309 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
311 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
317 EFSYS_PROBE1(fail1, efx_rc_t, rc);
322 __checkReturn efx_rc_t
325 __in_bcount(size) caddr_t data,
328 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
331 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
332 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
334 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
340 EFSYS_PROBE1(fail1, efx_rc_t, rc);
345 static __checkReturn efx_rc_t
349 __inout unsigned int *offsetp,
350 __out efx_vpd_tag_t *tagp,
351 __out uint16_t *lengthp)
360 if (*offsetp >= size) {
365 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
367 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
368 case TAG_TYPE_SMALL_ITEM_DECODE:
371 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
372 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
376 case TAG_TYPE_LARGE_ITEM_DECODE:
379 if (*offsetp + headlen > size) {
384 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
385 EFX_POPULATE_WORD_2(word,
386 EFX_BYTE_0, data[*offsetp + 1],
387 EFX_BYTE_1, data[*offsetp + 2]);
388 length = EFX_WORD_FIELD(word, EFX_WORD_0);
397 if (*offsetp + headlen + length > size) {
402 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
403 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
404 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
405 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
406 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
407 name != EFX_VPD_RO) {
425 EFSYS_PROBE1(fail1, efx_rc_t, rc);
430 static __checkReturn efx_rc_t
431 efx_vpd_next_keyword(
432 __in_bcount(size) caddr_t tag,
434 __in unsigned int pos,
435 __out efx_vpd_keyword_t *keywordp,
436 __out uint8_t *lengthp)
438 efx_vpd_keyword_t keyword;
442 if (pos + 3U > size) {
447 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
448 length = tag[pos + 2];
450 if (length == 0 || pos + 3U + length > size) {
463 EFSYS_PROBE1(fail1, efx_rc_t, rc);
468 __checkReturn efx_rc_t
470 __in_bcount(size) caddr_t data,
472 __out size_t *lengthp)
480 _NOTE(CONSTANTCONDITION)
482 if ((rc = efx_vpd_next_tag(data, size, &offset,
483 &tag, &taglen)) != 0)
486 if (tag == EFX_VPD_END)
495 EFSYS_PROBE1(fail1, efx_rc_t, rc);
500 __checkReturn efx_rc_t
502 __in_bcount(size) caddr_t data,
504 __out_opt boolean_t *cksummedp)
507 efx_vpd_keyword_t keyword;
514 boolean_t cksummed = B_FALSE;
518 * Parse every tag,keyword in the existing VPD. If the csum is present,
519 * the assert it is correct, and is the final keyword in the RO block.
522 _NOTE(CONSTANTCONDITION)
524 if ((rc = efx_vpd_next_tag(data, size, &offset,
525 &tag, &taglen)) != 0)
527 if (tag == EFX_VPD_END)
529 else if (tag == EFX_VPD_ID)
532 for (pos = 0; pos != taglen; pos += 3 + keylen) {
533 /* RV keyword must be the last in the block */
539 if ((rc = efx_vpd_next_keyword(data + offset,
540 taglen, pos, &keyword, &keylen)) != 0)
543 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
545 for (i = 0; i < offset + pos + 4; i++)
566 if (cksummedp != NULL)
567 *cksummedp = cksummed;
580 EFSYS_PROBE1(fail1, efx_rc_t, rc);
585 static uint8_t __efx_vpd_blank_pid[] = {
586 /* Large resource type ID length 1 */
588 /* Product name ' ' */
592 static uint8_t __efx_vpd_blank_r[] = {
593 /* Large resource type VPD-R length 4 */
595 /* RV keyword length 1 */
597 /* RV payload checksum */
601 __checkReturn efx_rc_t
603 __in_bcount(size) caddr_t data,
605 __in boolean_t wantpid)
607 unsigned int offset = 0;
619 memcpy(data + offset, __efx_vpd_blank_pid,
620 sizeof (__efx_vpd_blank_pid));
621 offset += sizeof (__efx_vpd_blank_pid);
624 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
625 offset += sizeof (__efx_vpd_blank_r);
627 /* Update checksum */
629 for (pos = 0; pos < offset; pos++)
631 data[offset - 1] -= cksum;
633 /* Append trailing tag */
634 EFX_POPULATE_BYTE_3(byte,
635 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
636 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
637 TAG_SMALL_ITEM_SIZE, 0);
638 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
644 EFSYS_PROBE1(fail1, efx_rc_t, rc);
649 __checkReturn efx_rc_t
651 __in_bcount(size) caddr_t data,
653 __out efx_vpd_tag_t *tagp,
654 __out efx_vpd_keyword_t *keywordp,
655 __out_opt unsigned int *payloadp,
656 __out_opt uint8_t *paylenp,
657 __inout unsigned int *contp)
660 efx_vpd_keyword_t keyword = 0;
670 _NOTE(CONSTANTCONDITION)
672 if ((rc = efx_vpd_next_tag(data, size, &offset,
673 &tag, &taglen)) != 0)
676 if (tag == EFX_VPD_END) {
683 if (tag == EFX_VPD_ID) {
684 if (index++ == *contp) {
685 EFSYS_ASSERT3U(taglen, <, 0x100);
687 paylen = (uint8_t)MIN(taglen, 0xff);
692 for (pos = 0; pos != taglen; pos += 3 + keylen) {
693 if ((rc = efx_vpd_next_keyword(data + offset,
694 taglen, pos, &keyword, &keylen)) != 0)
697 if (index++ == *contp) {
712 if (payloadp != NULL)
723 EFSYS_PROBE1(fail1, efx_rc_t, rc);
728 __checkReturn efx_rc_t
730 __in_bcount(size) caddr_t data,
732 __in efx_vpd_tag_t tag,
733 __in efx_vpd_keyword_t keyword,
734 __out unsigned int *payloadp,
735 __out uint8_t *paylenp)
738 efx_vpd_keyword_t ikeyword;
746 _NOTE(CONSTANTCONDITION)
748 if ((rc = efx_vpd_next_tag(data, size, &offset,
749 &itag, &taglen)) != 0)
751 if (itag == EFX_VPD_END)
755 if (itag == EFX_VPD_ID) {
756 EFSYS_ASSERT3U(taglen, <, 0x100);
758 *paylenp = (uint8_t)MIN(taglen, 0xff);
763 for (pos = 0; pos != taglen; pos += 3 + keylen) {
764 if ((rc = efx_vpd_next_keyword(data + offset,
765 taglen, pos, &ikeyword, &keylen)) != 0)
768 if (ikeyword == keyword) {
770 *payloadp = offset + pos + 3;
785 EFSYS_PROBE1(fail1, efx_rc_t, rc);
790 __checkReturn efx_rc_t
792 __in_bcount(size) caddr_t data,
794 __in efx_vpd_value_t *evvp)
798 efx_vpd_keyword_t keyword;
801 unsigned int taghead;
811 switch (evvp->evv_tag) {
813 if (evvp->evv_keyword != 0) {
818 /* Can't delete the ID keyword */
819 if (evvp->evv_length == 0) {
826 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
837 /* Determine total size of all current tags */
838 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
842 _NOTE(CONSTANTCONDITION)
845 if ((rc = efx_vpd_next_tag(data, size, &offset,
846 &tag, &taglen)) != 0)
848 if (tag == EFX_VPD_END)
850 else if (tag != evvp->evv_tag) {
855 /* We only support modifying large resource tags */
856 if (offset - taghead != 3) {
862 * Work out the offset of the byte immediately after the
863 * old (=source) and new (=dest) new keyword/tag
866 if (tag == EFX_VPD_ID) {
867 source = offset + taglen;
868 dest = offset + evvp->evv_length;
872 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
874 for (pos = 0; pos != taglen; pos += 3 + keylen) {
875 if ((rc = efx_vpd_next_keyword(data + offset,
876 taglen, pos, &keyword, &keylen)) != 0)
879 if (keyword == evvp->evv_keyword &&
880 evvp->evv_length == 0) {
881 /* Deleting this keyword */
882 source = offset + pos + 3 + keylen;
886 } else if (keyword == evvp->evv_keyword) {
887 /* Adjusting this keyword */
888 source = offset + pos + 3 + keylen;
889 dest = offset + pos + 3 + evvp->evv_length;
892 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
893 /* The RV keyword must be at the end */
894 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
897 * The keyword doesn't already exist. If the
898 * user deleting a non-existant keyword then
901 if (evvp->evv_length == 0)
904 /* Insert this keyword before the RV keyword */
905 source = offset + pos;
906 dest = offset + pos + 3 + evvp->evv_length;
912 if (used + dest > size + source) {
917 /* Move trailing data */
918 (void) memmove(data + dest, data + source, used - source);
921 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
924 /* Insert new keyword header if required */
925 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
926 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
928 data[offset + pos + 0] =
929 EFX_WORD_FIELD(word, EFX_BYTE_0);
930 data[offset + pos + 1] =
931 EFX_WORD_FIELD(word, EFX_BYTE_1);
932 data[offset + pos + 2] = evvp->evv_length;
935 /* Modify tag length (large resource type) */
936 taglen += (dest - source);
937 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
938 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
939 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
944 /* Unable to find the matching tag */
949 /* Find the RV tag, and update the checksum */
951 _NOTE(CONSTANTCONDITION)
953 if ((rc = efx_vpd_next_tag(data, size, &offset,
954 &tag, &taglen)) != 0)
956 if (tag == EFX_VPD_END)
958 if (tag == EFX_VPD_RO) {
959 for (pos = 0; pos != taglen; pos += 3 + keylen) {
960 if ((rc = efx_vpd_next_keyword(data + offset,
961 taglen, pos, &keyword, &keylen)) != 0)
964 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
966 for (i = 0; i < offset + pos + 3; i++)
977 /* Zero out the unused portion */
978 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
999 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1006 __in efx_nic_t *enp)
1008 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1010 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1011 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1012 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1014 if (evpdop->evpdo_fini != NULL)
1015 evpdop->evpdo_fini(enp);
1017 enp->en_evpdop = NULL;
1018 enp->en_mod_flags &= ~EFX_MOD_VPD;
1021 #endif /* EFSYS_OPT_VPD */