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 || EFSYS_OPT_MEDFORD2
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 || EFSYS_OPT_MEDFORD2 */
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 */
123 #if EFSYS_OPT_MEDFORD2
124 case EFX_FAMILY_MEDFORD2:
125 evpdop = &__efx_vpd_ef10_ops;
127 #endif /* EFSYS_OPT_MEDFORD2 */
135 if (evpdop->evpdo_init != NULL) {
136 if ((rc = evpdop->evpdo_init(enp)) != 0)
140 enp->en_evpdop = evpdop;
141 enp->en_mod_flags |= EFX_MOD_VPD;
148 EFSYS_PROBE1(fail1, efx_rc_t, rc);
153 __checkReturn efx_rc_t
158 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
161 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
162 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
164 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
170 EFSYS_PROBE1(fail1, efx_rc_t, rc);
175 __checkReturn efx_rc_t
178 __out_bcount(size) caddr_t data,
181 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
184 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
185 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
187 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
193 EFSYS_PROBE1(fail1, efx_rc_t, rc);
198 __checkReturn efx_rc_t
201 __in_bcount(size) caddr_t data,
204 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
207 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
208 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
210 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
216 EFSYS_PROBE1(fail1, efx_rc_t, rc);
221 __checkReturn efx_rc_t
224 __in_bcount(size) caddr_t data,
227 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
230 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
231 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
233 if (evpdop->evpdo_reinit == NULL) {
238 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
246 EFSYS_PROBE1(fail1, efx_rc_t, rc);
251 __checkReturn efx_rc_t
254 __in_bcount(size) caddr_t data,
256 __inout efx_vpd_value_t *evvp)
258 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
261 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
264 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
274 EFSYS_PROBE1(fail1, efx_rc_t, rc);
279 __checkReturn efx_rc_t
282 __inout_bcount(size) caddr_t data,
284 __in efx_vpd_value_t *evvp)
286 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
289 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
290 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
292 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
298 EFSYS_PROBE1(fail1, efx_rc_t, rc);
303 __checkReturn efx_rc_t
306 __inout_bcount(size) caddr_t data,
308 __out efx_vpd_value_t *evvp,
309 __inout unsigned int *contp)
311 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
314 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
315 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
317 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
323 EFSYS_PROBE1(fail1, efx_rc_t, rc);
328 __checkReturn efx_rc_t
331 __in_bcount(size) caddr_t data,
334 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
337 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
338 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
340 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
346 EFSYS_PROBE1(fail1, efx_rc_t, rc);
351 static __checkReturn efx_rc_t
355 __inout unsigned int *offsetp,
356 __out efx_vpd_tag_t *tagp,
357 __out uint16_t *lengthp)
366 if (*offsetp >= size) {
371 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
373 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
374 case TAG_TYPE_SMALL_ITEM_DECODE:
377 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
378 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
382 case TAG_TYPE_LARGE_ITEM_DECODE:
385 if (*offsetp + headlen > size) {
390 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
391 EFX_POPULATE_WORD_2(word,
392 EFX_BYTE_0, data[*offsetp + 1],
393 EFX_BYTE_1, data[*offsetp + 2]);
394 length = EFX_WORD_FIELD(word, EFX_WORD_0);
403 if (*offsetp + headlen + length > size) {
408 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
409 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
410 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
411 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
412 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
413 name != EFX_VPD_RO) {
431 EFSYS_PROBE1(fail1, efx_rc_t, rc);
436 static __checkReturn efx_rc_t
437 efx_vpd_next_keyword(
438 __in_bcount(size) caddr_t tag,
440 __in unsigned int pos,
441 __out efx_vpd_keyword_t *keywordp,
442 __out uint8_t *lengthp)
444 efx_vpd_keyword_t keyword;
448 if (pos + 3U > size) {
453 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
454 length = tag[pos + 2];
456 if (length == 0 || pos + 3U + length > size) {
469 EFSYS_PROBE1(fail1, efx_rc_t, rc);
474 __checkReturn efx_rc_t
476 __in_bcount(size) caddr_t data,
478 __out size_t *lengthp)
486 _NOTE(CONSTANTCONDITION)
488 if ((rc = efx_vpd_next_tag(data, size, &offset,
489 &tag, &taglen)) != 0)
492 if (tag == EFX_VPD_END)
501 EFSYS_PROBE1(fail1, efx_rc_t, rc);
506 __checkReturn efx_rc_t
508 __in_bcount(size) caddr_t data,
510 __out_opt boolean_t *cksummedp)
513 efx_vpd_keyword_t keyword;
520 boolean_t cksummed = B_FALSE;
524 * Parse every tag,keyword in the existing VPD. If the csum is present,
525 * the assert it is correct, and is the final keyword in the RO block.
528 _NOTE(CONSTANTCONDITION)
530 if ((rc = efx_vpd_next_tag(data, size, &offset,
531 &tag, &taglen)) != 0)
533 if (tag == EFX_VPD_END)
535 else if (tag == EFX_VPD_ID)
538 for (pos = 0; pos != taglen; pos += 3 + keylen) {
539 /* RV keyword must be the last in the block */
545 if ((rc = efx_vpd_next_keyword(data + offset,
546 taglen, pos, &keyword, &keylen)) != 0)
549 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
551 for (i = 0; i < offset + pos + 4; i++)
572 if (cksummedp != NULL)
573 *cksummedp = cksummed;
586 EFSYS_PROBE1(fail1, efx_rc_t, rc);
591 static uint8_t __efx_vpd_blank_pid[] = {
592 /* Large resource type ID length 1 */
594 /* Product name ' ' */
598 static uint8_t __efx_vpd_blank_r[] = {
599 /* Large resource type VPD-R length 4 */
601 /* RV keyword length 1 */
603 /* RV payload checksum */
607 __checkReturn efx_rc_t
609 __in_bcount(size) caddr_t data,
611 __in boolean_t wantpid)
613 unsigned int offset = 0;
625 memcpy(data + offset, __efx_vpd_blank_pid,
626 sizeof (__efx_vpd_blank_pid));
627 offset += sizeof (__efx_vpd_blank_pid);
630 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
631 offset += sizeof (__efx_vpd_blank_r);
633 /* Update checksum */
635 for (pos = 0; pos < offset; pos++)
637 data[offset - 1] -= cksum;
639 /* Append trailing tag */
640 EFX_POPULATE_BYTE_3(byte,
641 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
642 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
643 TAG_SMALL_ITEM_SIZE, 0);
644 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
650 EFSYS_PROBE1(fail1, efx_rc_t, rc);
655 __checkReturn efx_rc_t
657 __in_bcount(size) caddr_t data,
659 __out efx_vpd_tag_t *tagp,
660 __out efx_vpd_keyword_t *keywordp,
661 __out_opt unsigned int *payloadp,
662 __out_opt uint8_t *paylenp,
663 __inout unsigned int *contp)
666 efx_vpd_keyword_t keyword = 0;
676 _NOTE(CONSTANTCONDITION)
678 if ((rc = efx_vpd_next_tag(data, size, &offset,
679 &tag, &taglen)) != 0)
682 if (tag == EFX_VPD_END) {
689 if (tag == EFX_VPD_ID) {
690 if (index++ == *contp) {
691 EFSYS_ASSERT3U(taglen, <, 0x100);
693 paylen = (uint8_t)MIN(taglen, 0xff);
698 for (pos = 0; pos != taglen; pos += 3 + keylen) {
699 if ((rc = efx_vpd_next_keyword(data + offset,
700 taglen, pos, &keyword, &keylen)) != 0)
703 if (index++ == *contp) {
718 if (payloadp != NULL)
729 EFSYS_PROBE1(fail1, efx_rc_t, rc);
734 __checkReturn efx_rc_t
736 __in_bcount(size) caddr_t data,
738 __in efx_vpd_tag_t tag,
739 __in efx_vpd_keyword_t keyword,
740 __out unsigned int *payloadp,
741 __out uint8_t *paylenp)
744 efx_vpd_keyword_t ikeyword;
752 _NOTE(CONSTANTCONDITION)
754 if ((rc = efx_vpd_next_tag(data, size, &offset,
755 &itag, &taglen)) != 0)
757 if (itag == EFX_VPD_END)
761 if (itag == EFX_VPD_ID) {
762 EFSYS_ASSERT3U(taglen, <, 0x100);
764 *paylenp = (uint8_t)MIN(taglen, 0xff);
769 for (pos = 0; pos != taglen; pos += 3 + keylen) {
770 if ((rc = efx_vpd_next_keyword(data + offset,
771 taglen, pos, &ikeyword, &keylen)) != 0)
774 if (ikeyword == keyword) {
776 *payloadp = offset + pos + 3;
791 EFSYS_PROBE1(fail1, efx_rc_t, rc);
796 __checkReturn efx_rc_t
798 __in_bcount(size) caddr_t data,
800 __in efx_vpd_value_t *evvp)
804 efx_vpd_keyword_t keyword;
807 unsigned int taghead;
817 switch (evvp->evv_tag) {
819 if (evvp->evv_keyword != 0) {
824 /* Can't delete the ID keyword */
825 if (evvp->evv_length == 0) {
832 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
843 /* Determine total size of all current tags */
844 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
848 _NOTE(CONSTANTCONDITION)
851 if ((rc = efx_vpd_next_tag(data, size, &offset,
852 &tag, &taglen)) != 0)
854 if (tag == EFX_VPD_END)
856 else if (tag != evvp->evv_tag) {
861 /* We only support modifying large resource tags */
862 if (offset - taghead != 3) {
868 * Work out the offset of the byte immediately after the
869 * old (=source) and new (=dest) new keyword/tag
872 if (tag == EFX_VPD_ID) {
873 source = offset + taglen;
874 dest = offset + evvp->evv_length;
878 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
880 for (pos = 0; pos != taglen; pos += 3 + keylen) {
881 if ((rc = efx_vpd_next_keyword(data + offset,
882 taglen, pos, &keyword, &keylen)) != 0)
885 if (keyword == evvp->evv_keyword &&
886 evvp->evv_length == 0) {
887 /* Deleting this keyword */
888 source = offset + pos + 3 + keylen;
892 } else if (keyword == evvp->evv_keyword) {
893 /* Adjusting this keyword */
894 source = offset + pos + 3 + keylen;
895 dest = offset + pos + 3 + evvp->evv_length;
898 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
899 /* The RV keyword must be at the end */
900 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
903 * The keyword doesn't already exist. If the
904 * user deleting a non-existant keyword then
907 if (evvp->evv_length == 0)
910 /* Insert this keyword before the RV keyword */
911 source = offset + pos;
912 dest = offset + pos + 3 + evvp->evv_length;
918 if (used + dest > size + source) {
923 /* Move trailing data */
924 (void) memmove(data + dest, data + source, used - source);
927 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
930 /* Insert new keyword header if required */
931 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
932 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
934 data[offset + pos + 0] =
935 EFX_WORD_FIELD(word, EFX_BYTE_0);
936 data[offset + pos + 1] =
937 EFX_WORD_FIELD(word, EFX_BYTE_1);
938 data[offset + pos + 2] = evvp->evv_length;
941 /* Modify tag length (large resource type) */
942 taglen += (uint16_t)(dest - source);
943 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
944 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
945 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
950 /* Unable to find the matching tag */
955 /* Find the RV tag, and update the checksum */
957 _NOTE(CONSTANTCONDITION)
959 if ((rc = efx_vpd_next_tag(data, size, &offset,
960 &tag, &taglen)) != 0)
962 if (tag == EFX_VPD_END)
964 if (tag == EFX_VPD_RO) {
965 for (pos = 0; pos != taglen; pos += 3 + keylen) {
966 if ((rc = efx_vpd_next_keyword(data + offset,
967 taglen, pos, &keyword, &keylen)) != 0)
970 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
972 for (i = 0; i < offset + pos + 3; i++)
983 /* Zero out the unused portion */
984 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
1005 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1012 __in efx_nic_t *enp)
1014 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1016 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1017 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1018 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1020 if (evpdop->evpdo_fini != NULL)
1021 evpdop->evpdo_fini(enp);
1023 enp->en_evpdop = NULL;
1024 enp->en_mod_flags &= ~EFX_MOD_VPD;
1027 #endif /* EFSYS_OPT_VPD */