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$");
36 #include "efx_types.h"
42 #define TAG_TYPE_LBN 7
43 #define TAG_TYPE_WIDTH 1
44 #define TAG_TYPE_LARGE_ITEM_DECODE 1
45 #define TAG_TYPE_SMALL_ITEM_DECODE 0
47 #define TAG_SMALL_ITEM_NAME_LBN 3
48 #define TAG_SMALL_ITEM_NAME_WIDTH 4
49 #define TAG_SMALL_ITEM_SIZE_LBN 0
50 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
52 #define TAG_LARGE_ITEM_NAME_LBN 0
53 #define TAG_LARGE_ITEM_NAME_WIDTH 7
55 #define TAG_NAME_END_DECODE 0x0f
56 #define TAG_NAME_ID_STRING_DECODE 0x02
57 #define TAG_NAME_VPD_R_DECODE 0x10
58 #define TAG_NAME_VPD_W_DECODE 0x11
62 static efx_vpd_ops_t __efx_vpd_falcon_ops = {
63 NULL, /* evpdo_init */
64 falcon_vpd_size, /* evpdo_size */
65 falcon_vpd_read, /* evpdo_read */
66 falcon_vpd_verify, /* evpdo_verify */
67 NULL, /* evpdo_reinit */
68 falcon_vpd_get, /* evpdo_get */
69 falcon_vpd_set, /* evpdo_set */
70 falcon_vpd_next, /* evpdo_next */
71 falcon_vpd_write, /* evpdo_write */
72 NULL, /* evpdo_fini */
75 #endif /* EFSYS_OPT_FALCON */
79 static efx_vpd_ops_t __efx_vpd_siena_ops = {
80 siena_vpd_init, /* evpdo_init */
81 siena_vpd_size, /* evpdo_size */
82 siena_vpd_read, /* evpdo_read */
83 siena_vpd_verify, /* evpdo_verify */
84 siena_vpd_reinit, /* evpdo_reinit */
85 siena_vpd_get, /* evpdo_get */
86 siena_vpd_set, /* evpdo_set */
87 siena_vpd_next, /* evpdo_next */
88 siena_vpd_write, /* evpdo_write */
89 siena_vpd_fini, /* evpdo_fini */
92 #endif /* EFSYS_OPT_SIENA */
94 #if EFSYS_OPT_HUNTINGTON
96 static efx_vpd_ops_t __efx_vpd_hunt_ops = {
97 hunt_vpd_init, /* evpdo_init */
98 hunt_vpd_size, /* evpdo_size */
99 hunt_vpd_read, /* evpdo_read */
100 hunt_vpd_verify, /* evpdo_verify */
101 hunt_vpd_reinit, /* evpdo_reinit */
102 hunt_vpd_get, /* evpdo_get */
103 hunt_vpd_set, /* evpdo_set */
104 hunt_vpd_next, /* evpdo_next */
105 hunt_vpd_write, /* evpdo_write */
106 hunt_vpd_fini, /* evpdo_fini */
109 #endif /* EFSYS_OPT_HUNTINGTON */
115 efx_vpd_ops_t *evpdop;
118 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
119 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
120 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
122 switch (enp->en_family) {
124 case EFX_FAMILY_FALCON:
125 evpdop = (efx_vpd_ops_t *)&__efx_vpd_falcon_ops;
127 #endif /* EFSYS_OPT_FALCON */
130 case EFX_FAMILY_SIENA:
131 evpdop = (efx_vpd_ops_t *)&__efx_vpd_siena_ops;
133 #endif /* EFSYS_OPT_SIENA */
135 #if EFSYS_OPT_HUNTINGTON
136 case EFX_FAMILY_HUNTINGTON:
137 evpdop = (efx_vpd_ops_t *)&__efx_vpd_hunt_ops;
139 #endif /* EFSYS_OPT_HUNTINGTON */
147 if (evpdop->evpdo_init != NULL) {
148 if ((rc = evpdop->evpdo_init(enp)) != 0)
152 enp->en_evpdop = evpdop;
153 enp->en_mod_flags |= EFX_MOD_VPD;
160 EFSYS_PROBE1(fail1, int, rc);
170 efx_vpd_ops_t *evpdop = enp->en_evpdop;
173 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
174 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
176 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
182 EFSYS_PROBE1(fail1, int, rc);
190 __out_bcount(size) caddr_t data,
193 efx_vpd_ops_t *evpdop = enp->en_evpdop;
196 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
197 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
199 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
205 EFSYS_PROBE1(fail1, int, rc);
213 __in_bcount(size) caddr_t data,
216 efx_vpd_ops_t *evpdop = enp->en_evpdop;
219 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
220 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
222 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
228 EFSYS_PROBE1(fail1, int, rc);
236 __in_bcount(size) caddr_t data,
239 efx_vpd_ops_t *evpdop = enp->en_evpdop;
242 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
243 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
245 if (evpdop->evpdo_reinit == NULL) {
250 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
258 EFSYS_PROBE1(fail1, int, rc);
266 __in_bcount(size) caddr_t data,
268 __inout efx_vpd_value_t *evvp)
270 efx_vpd_ops_t *evpdop = enp->en_evpdop;
273 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
274 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
276 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0)
282 EFSYS_PROBE1(fail1, int, rc);
290 __inout_bcount(size) caddr_t data,
292 __in efx_vpd_value_t *evvp)
294 efx_vpd_ops_t *evpdop = enp->en_evpdop;
297 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
298 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
300 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
306 EFSYS_PROBE1(fail1, int, rc);
314 __inout_bcount(size) caddr_t data,
316 __out efx_vpd_value_t *evvp,
317 __inout unsigned int *contp)
319 efx_vpd_ops_t *evpdop = enp->en_evpdop;
322 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
323 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
325 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
331 EFSYS_PROBE1(fail1, int, rc);
339 __in_bcount(size) caddr_t data,
342 efx_vpd_ops_t *evpdop = enp->en_evpdop;
345 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
346 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
348 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
354 EFSYS_PROBE1(fail1, int, rc);
359 static __checkReturn int
363 __inout unsigned int *offsetp,
364 __out efx_vpd_tag_t *tagp,
365 __out uint16_t *lengthp)
374 if (*offsetp >= size) {
379 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
381 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
382 case TAG_TYPE_SMALL_ITEM_DECODE:
385 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
386 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
390 case TAG_TYPE_LARGE_ITEM_DECODE:
393 if (*offsetp + headlen > size) {
398 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
399 EFX_POPULATE_WORD_2(word,
400 EFX_BYTE_0, data[*offsetp + 1],
401 EFX_BYTE_1, data[*offsetp + 2]);
402 length = EFX_WORD_FIELD(word, EFX_WORD_0);
411 if (*offsetp + headlen + length > size) {
416 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
417 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
418 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
419 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
420 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
421 name != EFX_VPD_RO) {
439 EFSYS_PROBE1(fail1, int, rc);
444 static __checkReturn int
445 efx_vpd_next_keyword(
446 __in_bcount(size) caddr_t tag,
448 __in unsigned int pos,
449 __out efx_vpd_keyword_t *keywordp,
450 __out uint8_t *lengthp)
452 efx_vpd_keyword_t keyword;
456 if (pos + 3U > size) {
461 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
462 length = tag[pos + 2];
464 if (length == 0 || pos + 3U + length > size) {
477 EFSYS_PROBE1(fail1, int, rc);
484 __in_bcount(size) caddr_t data,
486 __out size_t *lengthp)
494 _NOTE(CONSTANTCONDITION)
496 if ((rc = efx_vpd_next_tag(data, size, &offset,
497 &tag, &taglen)) != 0)
500 if (tag == EFX_VPD_END)
509 EFSYS_PROBE1(fail1, int, rc);
516 __in_bcount(size) caddr_t data,
518 __out_opt boolean_t *cksummedp)
521 efx_vpd_keyword_t keyword;
528 boolean_t cksummed = B_FALSE;
532 * Parse every tag,keyword in the existing VPD. If the csum is present,
533 * the assert it is correct, and is the final keyword in the RO block.
536 _NOTE(CONSTANTCONDITION)
538 if ((rc = efx_vpd_next_tag(data, size, &offset,
539 &tag, &taglen)) != 0)
541 if (tag == EFX_VPD_END)
543 else if (tag == EFX_VPD_ID)
546 for (pos = 0; pos != taglen; pos += 3 + keylen) {
547 /* RV keyword must be the last in the block */
551 if ((rc = efx_vpd_next_keyword(data + offset,
552 taglen, pos, &keyword, &keylen)) != 0)
555 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
557 for (i = 0; i < offset + pos + 4; i++)
578 if (cksummedp != NULL)
579 *cksummedp = cksummed;
592 EFSYS_PROBE1(fail1, int, rc);
597 static uint8_t __efx_vpd_blank_pid[] = {
598 /* Large resource type ID length 1 */
600 /* Product name ' ' */
604 static uint8_t __efx_vpd_blank_r[] = {
605 /* Large resource type VPD-R length 4 */
607 /* RV keyword length 1 */
609 /* RV payload checksum */
615 __in_bcount(size) caddr_t data,
617 __in boolean_t wantpid)
619 unsigned int offset = 0;
631 memcpy(data + offset, __efx_vpd_blank_pid,
632 sizeof (__efx_vpd_blank_pid));
633 offset += sizeof (__efx_vpd_blank_pid);
636 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
637 offset += sizeof (__efx_vpd_blank_r);
639 /* Update checksum */
641 for (pos = 0; pos < offset; pos++)
643 data[offset - 1] -= cksum;
645 /* Append trailing tag */
646 EFX_POPULATE_BYTE_3(byte,
647 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
648 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
649 TAG_SMALL_ITEM_SIZE, 0);
650 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
656 EFSYS_PROBE1(fail1, int, rc);
663 __in_bcount(size) caddr_t data,
665 __out efx_vpd_tag_t *tagp,
666 __out efx_vpd_keyword_t *keywordp,
667 __out_bcount_opt(*paylenp) unsigned int *payloadp,
668 __out_opt uint8_t *paylenp,
669 __inout unsigned int *contp)
672 efx_vpd_keyword_t keyword = 0;
682 _NOTE(CONSTANTCONDITION)
684 if ((rc = efx_vpd_next_tag(data, size, &offset,
685 &tag, &taglen)) != 0)
687 if (tag == EFX_VPD_END)
690 if (tag == EFX_VPD_ID) {
691 if (index == *contp) {
692 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) {
721 if (payloadp != NULL)
732 EFSYS_PROBE1(fail1, int, rc);
739 __in_bcount(size) caddr_t data,
741 __in efx_vpd_tag_t tag,
742 __in efx_vpd_keyword_t keyword,
743 __out unsigned int *payloadp,
744 __out uint8_t *paylenp)
747 efx_vpd_keyword_t ikeyword;
755 _NOTE(CONSTANTCONDITION)
757 if ((rc = efx_vpd_next_tag(data, size, &offset,
758 &itag, &taglen)) != 0)
760 if (itag == EFX_VPD_END)
764 if (itag == EFX_VPD_ID) {
765 EFSYS_ASSERT3U(taglen, <, 0x100);
767 *paylenp = (uint8_t)MIN(taglen, 0xff);
772 for (pos = 0; pos != taglen; pos += 3 + keylen) {
773 if ((rc = efx_vpd_next_keyword(data + offset,
774 taglen, pos, &ikeyword, &keylen)) != 0)
777 if (ikeyword == keyword) {
779 *payloadp = offset + pos + 3;
794 EFSYS_PROBE1(fail1, int, rc);
801 __in_bcount(size) caddr_t data,
803 __in efx_vpd_value_t *evvp)
807 efx_vpd_keyword_t keyword;
810 unsigned int taghead;
820 switch (evvp->evv_tag) {
822 if (evvp->evv_keyword != 0) {
827 /* Can't delete the ID keyword */
828 if (evvp->evv_length == 0) {
835 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
846 /* Determine total size of all current tags */
847 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
851 _NOTE(CONSTANTCONDITION)
854 if ((rc = efx_vpd_next_tag(data, size, &offset,
855 &tag, &taglen)) != 0)
857 if (tag == EFX_VPD_END)
859 else if (tag != evvp->evv_tag) {
864 /* We only support modifying large resource tags */
865 if (offset - taghead != 3) {
871 * Work out the offset of the byte immediately after the
872 * old (=source) and new (=dest) new keyword/tag
875 if (tag == EFX_VPD_ID) {
876 source = offset + taglen;
877 dest = offset + evvp->evv_length;
881 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
883 for (pos = 0; pos != taglen; pos += 3 + keylen) {
884 if ((rc = efx_vpd_next_keyword(data + offset,
885 taglen, pos, &keyword, &keylen)) != 0)
888 if (keyword == evvp->evv_keyword &&
889 evvp->evv_length == 0) {
890 /* Deleting this keyword */
891 source = offset + pos + 3 + keylen;
895 } else if (keyword == evvp->evv_keyword) {
896 /* Adjusting this keyword */
897 source = offset + pos + 3 + keylen;
898 dest = offset + pos + 3 + evvp->evv_length;
901 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
902 /* The RV keyword must be at the end */
903 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
906 * The keyword doesn't already exist. If the
907 * user deleting a non-existant keyword then
910 if (evvp->evv_length == 0)
913 /* Insert this keyword before the RV keyword */
914 source = offset + pos;
915 dest = offset + pos + 3 + evvp->evv_length;
921 if (used + dest > size + source) {
926 /* Move trailing data */
927 (void) memmove(data + dest, data + source, used - source);
930 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
933 /* Insert new keyword header if required */
934 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
935 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
937 data[offset + pos + 0] =
938 EFX_WORD_FIELD(word, EFX_BYTE_0);
939 data[offset + pos + 1] =
940 EFX_WORD_FIELD(word, EFX_BYTE_1);
941 data[offset + pos + 2] = evvp->evv_length;
944 /* Modify tag length (large resource type) */
945 taglen += (dest - source);
946 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
947 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
948 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
953 /* Unable to find the matching tag */
958 /* Find the RV tag, and update the checksum */
960 _NOTE(CONSTANTCONDITION)
962 if ((rc = efx_vpd_next_tag(data, size, &offset,
963 &tag, &taglen)) != 0)
965 if (tag == EFX_VPD_END)
967 if (tag == EFX_VPD_RO) {
968 for (pos = 0; pos != taglen; pos += 3 + keylen) {
969 if ((rc = efx_vpd_next_keyword(data + offset,
970 taglen, pos, &keyword, &keylen)) != 0)
973 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
975 for (i = 0; i < offset + pos + 3; i++)
986 /* Zero out the unused portion */
987 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
1008 EFSYS_PROBE1(fail1, int, rc);
1015 __in efx_nic_t *enp)
1017 efx_vpd_ops_t *evpdop = enp->en_evpdop;
1019 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1020 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1021 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1023 if (evpdop->evpdo_fini != NULL)
1024 evpdop->evpdo_fini(enp);
1026 enp->en_evpdop = NULL;
1027 enp->en_mod_flags &= ~EFX_MOD_VPD;
1030 #endif /* EFSYS_OPT_VPD */