2 * Copyright 2009 Solarflare Communications Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
31 #include "efx_types.h"
37 #define TAG_TYPE_LBN 7
38 #define TAG_TYPE_WIDTH 1
39 #define TAG_TYPE_LARGE_ITEM_DECODE 1
40 #define TAG_TYPE_SMALL_ITEM_DECODE 0
42 #define TAG_SMALL_ITEM_NAME_LBN 3
43 #define TAG_SMALL_ITEM_NAME_WIDTH 4
44 #define TAG_SMALL_ITEM_SIZE_LBN 0
45 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
47 #define TAG_LARGE_ITEM_NAME_LBN 0
48 #define TAG_LARGE_ITEM_NAME_WIDTH 7
50 #define TAG_NAME_END_DECODE 0x0f
51 #define TAG_NAME_ID_STRING_DECODE 0x02
52 #define TAG_NAME_VPD_R_DECODE 0x10
53 #define TAG_NAME_VPD_W_DECODE 0x11
57 static efx_vpd_ops_t __cs __efx_vpd_falcon_ops = {
58 NULL, /* evpdo_init */
59 falcon_vpd_size, /* evpdo_size */
60 falcon_vpd_read, /* evpdo_read */
61 falcon_vpd_verify, /* evpdo_verify */
62 NULL, /* evpdo_reinit */
63 falcon_vpd_get, /* evpdo_get */
64 falcon_vpd_set, /* evpdo_set */
65 falcon_vpd_next, /* evpdo_next */
66 falcon_vpd_write, /* evpdo_write */
67 NULL, /* evpdo_fini */
70 #endif /* EFSYS_OPT_FALCON */
74 static efx_vpd_ops_t __cs __efx_vpd_siena_ops = {
75 siena_vpd_init, /* evpdo_init */
76 siena_vpd_size, /* evpdo_size */
77 siena_vpd_read, /* evpdo_read */
78 siena_vpd_verify, /* evpdo_verify */
79 siena_vpd_reinit, /* evpdo_reinit */
80 siena_vpd_get, /* evpdo_get */
81 siena_vpd_set, /* evpdo_set */
82 siena_vpd_next, /* evpdo_next */
83 siena_vpd_write, /* evpdo_write */
84 siena_vpd_fini, /* evpdo_fini */
87 #endif /* EFSYS_OPT_SIENA */
93 efx_vpd_ops_t *evpdop;
96 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
97 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
98 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
100 switch (enp->en_family) {
102 case EFX_FAMILY_FALCON:
103 evpdop = (efx_vpd_ops_t *)&__efx_vpd_falcon_ops;
105 #endif /* EFSYS_OPT_FALCON */
108 case EFX_FAMILY_SIENA:
109 evpdop = (efx_vpd_ops_t *)&__efx_vpd_siena_ops;
111 #endif /* EFSYS_OPT_SIENA */
119 if (evpdop->evpdo_init != NULL) {
120 if ((rc = evpdop->evpdo_init(enp)) != 0)
124 enp->en_evpdop = evpdop;
125 enp->en_mod_flags |= EFX_MOD_VPD;
132 EFSYS_PROBE1(fail1, int, rc);
142 efx_vpd_ops_t *evpdop = enp->en_evpdop;
145 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
146 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
148 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
154 EFSYS_PROBE1(fail1, int, rc);
162 __out_bcount(size) caddr_t data,
165 efx_vpd_ops_t *evpdop = enp->en_evpdop;
168 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
169 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
171 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
177 EFSYS_PROBE1(fail1, int, rc);
185 __in_bcount(size) caddr_t data,
188 efx_vpd_ops_t *evpdop = enp->en_evpdop;
191 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
192 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
194 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
200 EFSYS_PROBE1(fail1, int, rc);
208 __in_bcount(size) caddr_t data,
211 efx_vpd_ops_t *evpdop = enp->en_evpdop;
214 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
215 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
217 if (evpdop->evpdo_reinit == NULL) {
222 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
230 EFSYS_PROBE1(fail1, int, rc);
238 __in_bcount(size) caddr_t data,
240 __inout efx_vpd_value_t *evvp)
242 efx_vpd_ops_t *evpdop = enp->en_evpdop;
245 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
248 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0)
254 EFSYS_PROBE1(fail1, int, rc);
262 __inout_bcount(size) caddr_t data,
264 __in efx_vpd_value_t *evvp)
266 efx_vpd_ops_t *evpdop = enp->en_evpdop;
269 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
270 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
272 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
278 EFSYS_PROBE1(fail1, int, rc);
286 __inout_bcount(size) caddr_t data,
288 __out efx_vpd_value_t *evvp,
289 __inout unsigned int *contp)
291 efx_vpd_ops_t *evpdop = enp->en_evpdop;
294 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
295 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
297 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
303 EFSYS_PROBE1(fail1, int, rc);
311 __in_bcount(size) caddr_t data,
314 efx_vpd_ops_t *evpdop = enp->en_evpdop;
317 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
318 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
320 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
326 EFSYS_PROBE1(fail1, int, rc);
331 static __checkReturn int
335 __inout unsigned int *offsetp,
336 __out efx_vpd_tag_t *tagp,
337 __out uint16_t *lengthp)
346 if (*offsetp >= size) {
351 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
353 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
354 case TAG_TYPE_SMALL_ITEM_DECODE:
357 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
358 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
362 case TAG_TYPE_LARGE_ITEM_DECODE:
365 if (*offsetp + headlen > size) {
370 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
371 EFX_POPULATE_WORD_2(word,
372 EFX_BYTE_0, data[*offsetp + 1],
373 EFX_BYTE_1, data[*offsetp + 2]);
374 length = EFX_WORD_FIELD(word, EFX_WORD_0);
383 if (*offsetp + headlen + length > size) {
388 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
389 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
390 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
391 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
392 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
393 name != EFX_VPD_RO) {
411 EFSYS_PROBE1(fail1, int, rc);
416 static __checkReturn int
417 efx_vpd_next_keyword(
418 __in_bcount(size) caddr_t tag,
420 __in unsigned int pos,
421 __out efx_vpd_keyword_t *keywordp,
422 __out uint8_t *lengthp)
424 efx_vpd_keyword_t keyword;
428 if (pos + 3U > size) {
433 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
434 length = tag[pos + 2];
436 if (length == 0 || pos + 3U + length > size) {
449 EFSYS_PROBE1(fail1, int, rc);
456 __in_bcount(size) caddr_t data,
458 __out size_t *lengthp)
466 _NOTE(CONSTANTCONDITION)
468 if ((rc = efx_vpd_next_tag(data, size, &offset,
469 &tag, &taglen)) != 0)
472 if (tag == EFX_VPD_END)
481 EFSYS_PROBE1(fail1, int, rc);
488 __in_bcount(size) caddr_t data,
490 __out_opt boolean_t *cksummedp)
493 efx_vpd_keyword_t keyword;
500 boolean_t cksummed = B_FALSE;
504 * Parse every tag,keyword in the existing VPD. If the csum is present,
505 * the assert it is correct, and is the final keyword in the RO block.
508 _NOTE(CONSTANTCONDITION)
510 if ((rc = efx_vpd_next_tag(data, size, &offset,
511 &tag, &taglen)) != 0)
513 if (tag == EFX_VPD_END)
515 else if (tag == EFX_VPD_ID)
518 for (pos = 0; pos != taglen; pos += 3 + keylen) {
519 /* RV keyword must be the last in the block */
523 if ((rc = efx_vpd_next_keyword(data + offset,
524 taglen, pos, &keyword, &keylen)) != 0)
527 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
529 for (i = 0; i < offset + pos + 4; i++)
550 if (cksummedp != NULL)
551 *cksummedp = cksummed;
564 EFSYS_PROBE1(fail1, int, rc);
569 static uint8_t __cs __efx_vpd_blank_pid[] = {
570 /* Large resource type ID length 1 */
572 /* Product name ' ' */
576 static uint8_t __cs __efx_vpd_blank_r[] = {
577 /* Large resource type VPD-R length 4 */
579 /* RV keyword length 1 */
581 /* RV payload checksum */
589 __in boolean_t wantpid)
591 unsigned int offset = 0;
603 memcpy(data + offset, __efx_vpd_blank_pid,
604 sizeof (__efx_vpd_blank_pid));
605 offset += sizeof (__efx_vpd_blank_pid);
608 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
609 offset += sizeof (__efx_vpd_blank_r);
611 /* Update checksum */
613 for (pos = 0; pos < offset; pos++)
615 data[offset - 1] -= cksum;
617 /* Append trailing tag */
618 EFX_POPULATE_BYTE_3(byte,
619 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
620 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
621 TAG_SMALL_ITEM_SIZE, 0);
622 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
628 EFSYS_PROBE1(fail1, int, rc);
635 __in_bcount(size) caddr_t data,
637 __out efx_vpd_tag_t *tagp,
638 __out efx_vpd_keyword_t *keywordp,
639 __out_bcount_opt(*paylenp) unsigned int *payloadp,
640 __out_opt uint8_t *paylenp,
641 __inout unsigned int *contp)
644 efx_vpd_keyword_t keyword = 0;
654 _NOTE(CONSTANTCONDITION)
656 if ((rc = efx_vpd_next_tag(data, size, &offset,
657 &tag, &taglen)) != 0)
659 if (tag == EFX_VPD_END)
662 if (tag == EFX_VPD_ID) {
663 if (index == *contp) {
664 EFSYS_ASSERT3U(taglen, <, 0x100);
665 paylen = (uint8_t)MIN(taglen, 0xff);
670 for (pos = 0; pos != taglen; pos += 3 + keylen) {
671 if ((rc = efx_vpd_next_keyword(data + offset,
672 taglen, pos, &keyword, &keylen)) != 0)
675 if (index == *contp) {
693 if (payloadp != NULL)
704 EFSYS_PROBE1(fail1, int, rc);
711 __in_bcount(size) caddr_t data,
713 __in efx_vpd_tag_t tag,
714 __in efx_vpd_keyword_t keyword,
715 __out unsigned int *payloadp,
716 __out uint8_t *paylenp)
719 efx_vpd_keyword_t ikeyword;
727 _NOTE(CONSTANTCONDITION)
729 if ((rc = efx_vpd_next_tag(data, size, &offset,
730 &itag, &taglen)) != 0)
732 if (itag == EFX_VPD_END)
736 if (itag == EFX_VPD_ID) {
737 EFSYS_ASSERT3U(taglen, <, 0x100);
739 *paylenp = (uint8_t)MIN(taglen, 0xff);
744 for (pos = 0; pos != taglen; pos += 3 + keylen) {
745 if ((rc = efx_vpd_next_keyword(data + offset,
746 taglen, pos, &ikeyword, &keylen)) != 0)
749 if (ikeyword == keyword) {
751 *payloadp = offset + pos + 3;
766 EFSYS_PROBE1(fail1, int, rc);
773 __in_bcount(size) caddr_t data,
775 __in efx_vpd_value_t *evvp)
779 efx_vpd_keyword_t keyword;
782 unsigned int taghead;
792 switch (evvp->evv_tag) {
794 if (evvp->evv_keyword != 0) {
799 /* Can't delete the ID keyword */
800 if (evvp->evv_length == 0) {
807 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
818 /* Determine total size of all current tags */
819 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
823 _NOTE(CONSTANTCONDITION)
826 if ((rc = efx_vpd_next_tag(data, size, &offset,
827 &tag, &taglen)) != 0)
829 if (tag == EFX_VPD_END)
831 else if (tag != evvp->evv_tag) {
836 /* We only support modifying large resource tags */
837 if (offset - taghead != 3) {
843 * Work out the offset of the byte immediately after the
844 * old (=source) and new (=dest) new keyword/tag
847 if (tag == EFX_VPD_ID) {
848 source = offset + taglen;
849 dest = offset + evvp->evv_length;
853 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
855 for (pos = 0; pos != taglen; pos += 3 + keylen) {
856 if ((rc = efx_vpd_next_keyword(data + offset,
857 taglen, pos, &keyword, &keylen)) != 0)
860 if (keyword == evvp->evv_keyword &&
861 evvp->evv_length == 0) {
862 /* Deleting this keyword */
863 source = offset + pos + 3 + keylen;
867 } else if (keyword == evvp->evv_keyword) {
868 /* Adjusting this keyword */
869 source = offset + pos + 3 + keylen;
870 dest = offset + pos + 3 + evvp->evv_length;
873 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
874 /* The RV keyword must be at the end */
875 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
878 * The keyword doesn't already exist. If the
879 * user deleting a non-existant keyword then
882 if (evvp->evv_length == 0)
885 /* Insert this keyword before the RV keyword */
886 source = offset + pos;
887 dest = offset + pos + 3 + evvp->evv_length;
893 if (used + dest > size + source) {
898 /* Move trailing data */
899 (void) memmove(data + dest, data + source, used - source);
902 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
905 /* Insert new keyword header if required */
906 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
907 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
909 data[offset + pos + 0] =
910 EFX_WORD_FIELD(word, EFX_BYTE_0);
911 data[offset + pos + 1] =
912 EFX_WORD_FIELD(word, EFX_BYTE_1);
913 data[offset + pos + 2] = evvp->evv_length;
916 /* Modify tag length (large resource type) */
917 taglen += (dest - source);
918 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
919 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
920 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
925 /* Unable to find the matching tag */
930 /* Find the RV tag, and update the checksum */
932 _NOTE(CONSTANTCONDITION)
934 if ((rc = efx_vpd_next_tag(data, size, &offset,
935 &tag, &taglen)) != 0)
937 if (tag == EFX_VPD_END)
939 if (tag == EFX_VPD_RO) {
940 for (pos = 0; pos != taglen; pos += 3 + keylen) {
941 if ((rc = efx_vpd_next_keyword(data + offset,
942 taglen, pos, &keyword, &keylen)) != 0)
945 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
947 for (i = 0; i < offset + pos + 3; i++)
958 /* Zero out the unused portion */
959 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
980 EFSYS_PROBE1(fail1, int, rc);
989 efx_vpd_ops_t *evpdop = enp->en_evpdop;
991 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
992 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
993 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
995 if (evpdop->evpdo_fini != NULL)
996 evpdop->evpdo_fini(enp);
998 enp->en_evpdop = NULL;
999 enp->en_mod_flags &= ~EFX_MOD_VPD;
1002 #endif /* EFSYS_OPT_VPD */