1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2009-2015 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include "efx.h"
32*49ef7e06SGarrett D'Amore #include "efx_impl.h"
33*49ef7e06SGarrett D'Amore 
34*49ef7e06SGarrett D'Amore #if EFSYS_OPT_VPD
35*49ef7e06SGarrett D'Amore 
36*49ef7e06SGarrett D'Amore #define	TAG_TYPE_LBN 7
37*49ef7e06SGarrett D'Amore #define	TAG_TYPE_WIDTH 1
38*49ef7e06SGarrett D'Amore #define	TAG_TYPE_LARGE_ITEM_DECODE 1
39*49ef7e06SGarrett D'Amore #define	TAG_TYPE_SMALL_ITEM_DECODE 0
40*49ef7e06SGarrett D'Amore 
41*49ef7e06SGarrett D'Amore #define	TAG_SMALL_ITEM_NAME_LBN 3
42*49ef7e06SGarrett D'Amore #define	TAG_SMALL_ITEM_NAME_WIDTH 4
43*49ef7e06SGarrett D'Amore #define	TAG_SMALL_ITEM_SIZE_LBN 0
44*49ef7e06SGarrett D'Amore #define	TAG_SMALL_ITEM_SIZE_WIDTH 3
45*49ef7e06SGarrett D'Amore 
46*49ef7e06SGarrett D'Amore #define	TAG_LARGE_ITEM_NAME_LBN 0
47*49ef7e06SGarrett D'Amore #define	TAG_LARGE_ITEM_NAME_WIDTH 7
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore #define	TAG_NAME_END_DECODE 0x0f
50*49ef7e06SGarrett D'Amore #define	TAG_NAME_ID_STRING_DECODE 0x02
51*49ef7e06SGarrett D'Amore #define	TAG_NAME_VPD_R_DECODE 0x10
52*49ef7e06SGarrett D'Amore #define	TAG_NAME_VPD_W_DECODE 0x11
53*49ef7e06SGarrett D'Amore 
54*49ef7e06SGarrett D'Amore #if EFSYS_OPT_SIENA
55*49ef7e06SGarrett D'Amore 
56*49ef7e06SGarrett D'Amore static const efx_vpd_ops_t	__efx_vpd_siena_ops = {
57*49ef7e06SGarrett D'Amore 	siena_vpd_init,		/* evpdo_init */
58*49ef7e06SGarrett D'Amore 	siena_vpd_size,		/* evpdo_size */
59*49ef7e06SGarrett D'Amore 	siena_vpd_read,		/* evpdo_read */
60*49ef7e06SGarrett D'Amore 	siena_vpd_verify,	/* evpdo_verify */
61*49ef7e06SGarrett D'Amore 	siena_vpd_reinit,	/* evpdo_reinit */
62*49ef7e06SGarrett D'Amore 	siena_vpd_get,		/* evpdo_get */
63*49ef7e06SGarrett D'Amore 	siena_vpd_set,		/* evpdo_set */
64*49ef7e06SGarrett D'Amore 	siena_vpd_next,		/* evpdo_next */
65*49ef7e06SGarrett D'Amore 	siena_vpd_write,	/* evpdo_write */
66*49ef7e06SGarrett D'Amore 	siena_vpd_fini,		/* evpdo_fini */
67*49ef7e06SGarrett D'Amore };
68*49ef7e06SGarrett D'Amore 
69*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_SIENA */
70*49ef7e06SGarrett D'Amore 
71*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
72*49ef7e06SGarrett D'Amore 
73*49ef7e06SGarrett D'Amore static const efx_vpd_ops_t	__efx_vpd_ef10_ops = {
74*49ef7e06SGarrett D'Amore 	ef10_vpd_init,		/* evpdo_init */
75*49ef7e06SGarrett D'Amore 	ef10_vpd_size,		/* evpdo_size */
76*49ef7e06SGarrett D'Amore 	ef10_vpd_read,		/* evpdo_read */
77*49ef7e06SGarrett D'Amore 	ef10_vpd_verify,	/* evpdo_verify */
78*49ef7e06SGarrett D'Amore 	ef10_vpd_reinit,	/* evpdo_reinit */
79*49ef7e06SGarrett D'Amore 	ef10_vpd_get,		/* evpdo_get */
80*49ef7e06SGarrett D'Amore 	ef10_vpd_set,		/* evpdo_set */
81*49ef7e06SGarrett D'Amore 	ef10_vpd_next,		/* evpdo_next */
82*49ef7e06SGarrett D'Amore 	ef10_vpd_write,		/* evpdo_write */
83*49ef7e06SGarrett D'Amore 	ef10_vpd_fini,		/* evpdo_fini */
84*49ef7e06SGarrett D'Amore };
85*49ef7e06SGarrett D'Amore 
86*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
87*49ef7e06SGarrett D'Amore 
88*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_init(__in efx_nic_t * enp)89*49ef7e06SGarrett D'Amore efx_vpd_init(
90*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp)
91*49ef7e06SGarrett D'Amore {
92*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop;
93*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
94*49ef7e06SGarrett D'Amore 
95*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
96*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
97*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
98*49ef7e06SGarrett D'Amore 
99*49ef7e06SGarrett D'Amore 	switch (enp->en_family) {
100*49ef7e06SGarrett D'Amore #if EFSYS_OPT_SIENA
101*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_SIENA:
102*49ef7e06SGarrett D'Amore 		evpdop = &__efx_vpd_siena_ops;
103*49ef7e06SGarrett D'Amore 		break;
104*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_SIENA */
105*49ef7e06SGarrett D'Amore 
106*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON
107*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_HUNTINGTON:
108*49ef7e06SGarrett D'Amore 		evpdop = &__efx_vpd_ef10_ops;
109*49ef7e06SGarrett D'Amore 		break;
110*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_HUNTINGTON */
111*49ef7e06SGarrett D'Amore 
112*49ef7e06SGarrett D'Amore #if EFSYS_OPT_MEDFORD
113*49ef7e06SGarrett D'Amore 	case EFX_FAMILY_MEDFORD:
114*49ef7e06SGarrett D'Amore 		evpdop = &__efx_vpd_ef10_ops;
115*49ef7e06SGarrett D'Amore 		break;
116*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_MEDFORD */
117*49ef7e06SGarrett D'Amore 
118*49ef7e06SGarrett D'Amore 	default:
119*49ef7e06SGarrett D'Amore 		EFSYS_ASSERT(0);
120*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
121*49ef7e06SGarrett D'Amore 		goto fail1;
122*49ef7e06SGarrett D'Amore 	}
123*49ef7e06SGarrett D'Amore 
124*49ef7e06SGarrett D'Amore 	if (evpdop->evpdo_init != NULL) {
125*49ef7e06SGarrett D'Amore 		if ((rc = evpdop->evpdo_init(enp)) != 0)
126*49ef7e06SGarrett D'Amore 			goto fail2;
127*49ef7e06SGarrett D'Amore 	}
128*49ef7e06SGarrett D'Amore 
129*49ef7e06SGarrett D'Amore 	enp->en_evpdop = evpdop;
130*49ef7e06SGarrett D'Amore 	enp->en_mod_flags |= EFX_MOD_VPD;
131*49ef7e06SGarrett D'Amore 
132*49ef7e06SGarrett D'Amore 	return (0);
133*49ef7e06SGarrett D'Amore 
134*49ef7e06SGarrett D'Amore fail2:
135*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
136*49ef7e06SGarrett D'Amore fail1:
137*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
138*49ef7e06SGarrett D'Amore 
139*49ef7e06SGarrett D'Amore 	return (rc);
140*49ef7e06SGarrett D'Amore }
141*49ef7e06SGarrett D'Amore 
142*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_size(__in efx_nic_t * enp,__out size_t * sizep)143*49ef7e06SGarrett D'Amore efx_vpd_size(
144*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
145*49ef7e06SGarrett D'Amore 	__out			size_t *sizep)
146*49ef7e06SGarrett D'Amore {
147*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
148*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
149*49ef7e06SGarrett D'Amore 
150*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
151*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
152*49ef7e06SGarrett D'Amore 
153*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
154*49ef7e06SGarrett D'Amore 		goto fail1;
155*49ef7e06SGarrett D'Amore 
156*49ef7e06SGarrett D'Amore 	return (0);
157*49ef7e06SGarrett D'Amore 
158*49ef7e06SGarrett D'Amore fail1:
159*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
160*49ef7e06SGarrett D'Amore 
161*49ef7e06SGarrett D'Amore 	return (rc);
162*49ef7e06SGarrett D'Amore }
163*49ef7e06SGarrett D'Amore 
164*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_read(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size)165*49ef7e06SGarrett D'Amore efx_vpd_read(
166*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
167*49ef7e06SGarrett D'Amore 	__out_bcount(size)	caddr_t data,
168*49ef7e06SGarrett D'Amore 	__in			size_t size)
169*49ef7e06SGarrett D'Amore {
170*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
171*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
172*49ef7e06SGarrett D'Amore 
173*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
174*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
175*49ef7e06SGarrett D'Amore 
176*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
177*49ef7e06SGarrett D'Amore 		goto fail1;
178*49ef7e06SGarrett D'Amore 
179*49ef7e06SGarrett D'Amore 	return (0);
180*49ef7e06SGarrett D'Amore 
181*49ef7e06SGarrett D'Amore fail1:
182*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
183*49ef7e06SGarrett D'Amore 
184*49ef7e06SGarrett D'Amore 	return (rc);
185*49ef7e06SGarrett D'Amore }
186*49ef7e06SGarrett D'Amore 
187*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_verify(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)188*49ef7e06SGarrett D'Amore efx_vpd_verify(
189*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
190*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
191*49ef7e06SGarrett D'Amore 	__in			size_t size)
192*49ef7e06SGarrett D'Amore {
193*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
194*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
195*49ef7e06SGarrett D'Amore 
196*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
197*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
198*49ef7e06SGarrett D'Amore 
199*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
200*49ef7e06SGarrett D'Amore 		goto fail1;
201*49ef7e06SGarrett D'Amore 
202*49ef7e06SGarrett D'Amore 	return (0);
203*49ef7e06SGarrett D'Amore 
204*49ef7e06SGarrett D'Amore fail1:
205*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
206*49ef7e06SGarrett D'Amore 
207*49ef7e06SGarrett D'Amore 	return (rc);
208*49ef7e06SGarrett D'Amore }
209*49ef7e06SGarrett D'Amore 
210*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_reinit(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)211*49ef7e06SGarrett D'Amore efx_vpd_reinit(
212*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
213*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
214*49ef7e06SGarrett D'Amore 	__in			size_t size)
215*49ef7e06SGarrett D'Amore {
216*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
217*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
218*49ef7e06SGarrett D'Amore 
219*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
220*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
221*49ef7e06SGarrett D'Amore 
222*49ef7e06SGarrett D'Amore 	if (evpdop->evpdo_reinit == NULL) {
223*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
224*49ef7e06SGarrett D'Amore 		goto fail1;
225*49ef7e06SGarrett D'Amore 	}
226*49ef7e06SGarrett D'Amore 
227*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
228*49ef7e06SGarrett D'Amore 		goto fail2;
229*49ef7e06SGarrett D'Amore 
230*49ef7e06SGarrett D'Amore 	return (0);
231*49ef7e06SGarrett D'Amore 
232*49ef7e06SGarrett D'Amore fail2:
233*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
234*49ef7e06SGarrett D'Amore fail1:
235*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
236*49ef7e06SGarrett D'Amore 
237*49ef7e06SGarrett D'Amore 	return (rc);
238*49ef7e06SGarrett D'Amore }
239*49ef7e06SGarrett D'Amore 
240*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_get(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__inout efx_vpd_value_t * evvp)241*49ef7e06SGarrett D'Amore efx_vpd_get(
242*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
243*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
244*49ef7e06SGarrett D'Amore 	__in			size_t size,
245*49ef7e06SGarrett D'Amore 	__inout			efx_vpd_value_t *evvp)
246*49ef7e06SGarrett D'Amore {
247*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
248*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
249*49ef7e06SGarrett D'Amore 
250*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
251*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
252*49ef7e06SGarrett D'Amore 
253*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0)
254*49ef7e06SGarrett D'Amore 		goto fail1;
255*49ef7e06SGarrett D'Amore 
256*49ef7e06SGarrett D'Amore 	return (0);
257*49ef7e06SGarrett D'Amore 
258*49ef7e06SGarrett D'Amore fail1:
259*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
260*49ef7e06SGarrett D'Amore 
261*49ef7e06SGarrett D'Amore 	return (rc);
262*49ef7e06SGarrett D'Amore }
263*49ef7e06SGarrett D'Amore 
264*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_set(__in efx_nic_t * enp,__inout_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)265*49ef7e06SGarrett D'Amore efx_vpd_set(
266*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
267*49ef7e06SGarrett D'Amore 	__inout_bcount(size)	caddr_t data,
268*49ef7e06SGarrett D'Amore 	__in			size_t size,
269*49ef7e06SGarrett D'Amore 	__in			efx_vpd_value_t *evvp)
270*49ef7e06SGarrett D'Amore {
271*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
272*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
273*49ef7e06SGarrett D'Amore 
274*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
275*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
276*49ef7e06SGarrett D'Amore 
277*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
278*49ef7e06SGarrett D'Amore 		goto fail1;
279*49ef7e06SGarrett D'Amore 
280*49ef7e06SGarrett D'Amore 	return (0);
281*49ef7e06SGarrett D'Amore 
282*49ef7e06SGarrett D'Amore fail1:
283*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
284*49ef7e06SGarrett D'Amore 
285*49ef7e06SGarrett D'Amore 	return (rc);
286*49ef7e06SGarrett D'Amore }
287*49ef7e06SGarrett D'Amore 
288*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_next(__in efx_nic_t * enp,__inout_bcount (size)caddr_t data,__in size_t size,__out efx_vpd_value_t * evvp,__inout unsigned int * contp)289*49ef7e06SGarrett D'Amore efx_vpd_next(
290*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
291*49ef7e06SGarrett D'Amore 	__inout_bcount(size)	caddr_t data,
292*49ef7e06SGarrett D'Amore 	__in			size_t size,
293*49ef7e06SGarrett D'Amore 	__out			efx_vpd_value_t *evvp,
294*49ef7e06SGarrett D'Amore 	__inout			unsigned int *contp)
295*49ef7e06SGarrett D'Amore {
296*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
297*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
298*49ef7e06SGarrett D'Amore 
299*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
300*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
301*49ef7e06SGarrett D'Amore 
302*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
303*49ef7e06SGarrett D'Amore 		goto fail1;
304*49ef7e06SGarrett D'Amore 
305*49ef7e06SGarrett D'Amore 	return (0);
306*49ef7e06SGarrett D'Amore 
307*49ef7e06SGarrett D'Amore fail1:
308*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
309*49ef7e06SGarrett D'Amore 
310*49ef7e06SGarrett D'Amore 	return (rc);
311*49ef7e06SGarrett D'Amore }
312*49ef7e06SGarrett D'Amore 
313*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_write(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)314*49ef7e06SGarrett D'Amore efx_vpd_write(
315*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
316*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
317*49ef7e06SGarrett D'Amore 	__in			size_t size)
318*49ef7e06SGarrett D'Amore {
319*49ef7e06SGarrett D'Amore 	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
320*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
321*49ef7e06SGarrett D'Amore 
322*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
323*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
324*49ef7e06SGarrett D'Amore 
325*49ef7e06SGarrett D'Amore 	if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
326*49ef7e06SGarrett D'Amore 		goto fail1;
327*49ef7e06SGarrett D'Amore 
328*49ef7e06SGarrett D'Amore 	return (0);
329*49ef7e06SGarrett D'Amore 
330*49ef7e06SGarrett D'Amore fail1:
331*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
332*49ef7e06SGarrett D'Amore 
333*49ef7e06SGarrett D'Amore 	return (rc);
334*49ef7e06SGarrett D'Amore }
335*49ef7e06SGarrett D'Amore 
336*49ef7e06SGarrett D'Amore static	__checkReturn		efx_rc_t
efx_vpd_next_tag(__in caddr_t data,__in size_t size,__inout unsigned int * offsetp,__out efx_vpd_tag_t * tagp,__out uint16_t * lengthp)337*49ef7e06SGarrett D'Amore efx_vpd_next_tag(
338*49ef7e06SGarrett D'Amore 	__in			caddr_t data,
339*49ef7e06SGarrett D'Amore 	__in			size_t size,
340*49ef7e06SGarrett D'Amore 	__inout			unsigned int *offsetp,
341*49ef7e06SGarrett D'Amore 	__out			efx_vpd_tag_t *tagp,
342*49ef7e06SGarrett D'Amore 	__out			uint16_t *lengthp)
343*49ef7e06SGarrett D'Amore {
344*49ef7e06SGarrett D'Amore 	efx_byte_t byte;
345*49ef7e06SGarrett D'Amore 	efx_word_t word;
346*49ef7e06SGarrett D'Amore 	uint8_t name;
347*49ef7e06SGarrett D'Amore 	uint16_t length;
348*49ef7e06SGarrett D'Amore 	size_t headlen;
349*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
350*49ef7e06SGarrett D'Amore 
351*49ef7e06SGarrett D'Amore 	if (*offsetp >= size) {
352*49ef7e06SGarrett D'Amore 		rc = EFAULT;
353*49ef7e06SGarrett D'Amore 		goto fail1;
354*49ef7e06SGarrett D'Amore 	}
355*49ef7e06SGarrett D'Amore 
356*49ef7e06SGarrett D'Amore 	EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
357*49ef7e06SGarrett D'Amore 
358*49ef7e06SGarrett D'Amore 	switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
359*49ef7e06SGarrett D'Amore 	case TAG_TYPE_SMALL_ITEM_DECODE:
360*49ef7e06SGarrett D'Amore 		headlen = 1;
361*49ef7e06SGarrett D'Amore 
362*49ef7e06SGarrett D'Amore 		name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
363*49ef7e06SGarrett D'Amore 		length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
364*49ef7e06SGarrett D'Amore 
365*49ef7e06SGarrett D'Amore 		break;
366*49ef7e06SGarrett D'Amore 
367*49ef7e06SGarrett D'Amore 	case TAG_TYPE_LARGE_ITEM_DECODE:
368*49ef7e06SGarrett D'Amore 		headlen = 3;
369*49ef7e06SGarrett D'Amore 
370*49ef7e06SGarrett D'Amore 		if (*offsetp + headlen > size) {
371*49ef7e06SGarrett D'Amore 			rc = EFAULT;
372*49ef7e06SGarrett D'Amore 			goto fail2;
373*49ef7e06SGarrett D'Amore 		}
374*49ef7e06SGarrett D'Amore 
375*49ef7e06SGarrett D'Amore 		name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
376*49ef7e06SGarrett D'Amore 		EFX_POPULATE_WORD_2(word,
377*49ef7e06SGarrett D'Amore 				    EFX_BYTE_0, data[*offsetp + 1],
378*49ef7e06SGarrett D'Amore 				    EFX_BYTE_1, data[*offsetp + 2]);
379*49ef7e06SGarrett D'Amore 		length = EFX_WORD_FIELD(word, EFX_WORD_0);
380*49ef7e06SGarrett D'Amore 
381*49ef7e06SGarrett D'Amore 		break;
382*49ef7e06SGarrett D'Amore 
383*49ef7e06SGarrett D'Amore 	default:
384*49ef7e06SGarrett D'Amore 		rc = EFAULT;
385*49ef7e06SGarrett D'Amore 		goto fail2;
386*49ef7e06SGarrett D'Amore 	}
387*49ef7e06SGarrett D'Amore 
388*49ef7e06SGarrett D'Amore 	if (*offsetp + headlen + length > size) {
389*49ef7e06SGarrett D'Amore 		rc = EFAULT;
390*49ef7e06SGarrett D'Amore 		goto fail3;
391*49ef7e06SGarrett D'Amore 	}
392*49ef7e06SGarrett D'Amore 
393*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
394*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
395*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
396*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
397*49ef7e06SGarrett D'Amore 	if (name != EFX_VPD_END && name != EFX_VPD_ID &&
398*49ef7e06SGarrett D'Amore 	    name != EFX_VPD_RO) {
399*49ef7e06SGarrett D'Amore 		rc = EFAULT;
400*49ef7e06SGarrett D'Amore 		goto fail4;
401*49ef7e06SGarrett D'Amore 	}
402*49ef7e06SGarrett D'Amore 
403*49ef7e06SGarrett D'Amore 	*tagp = name;
404*49ef7e06SGarrett D'Amore 	*lengthp = length;
405*49ef7e06SGarrett D'Amore 	*offsetp += headlen;
406*49ef7e06SGarrett D'Amore 
407*49ef7e06SGarrett D'Amore 	return (0);
408*49ef7e06SGarrett D'Amore 
409*49ef7e06SGarrett D'Amore fail4:
410*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail4);
411*49ef7e06SGarrett D'Amore fail3:
412*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail3);
413*49ef7e06SGarrett D'Amore fail2:
414*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
415*49ef7e06SGarrett D'Amore fail1:
416*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
417*49ef7e06SGarrett D'Amore 
418*49ef7e06SGarrett D'Amore 	return (rc);
419*49ef7e06SGarrett D'Amore }
420*49ef7e06SGarrett D'Amore 
421*49ef7e06SGarrett D'Amore static	__checkReturn		efx_rc_t
efx_vpd_next_keyword(__in_bcount (size)caddr_t tag,__in size_t size,__in unsigned int pos,__out efx_vpd_keyword_t * keywordp,__out uint8_t * lengthp)422*49ef7e06SGarrett D'Amore efx_vpd_next_keyword(
423*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t tag,
424*49ef7e06SGarrett D'Amore 	__in			size_t size,
425*49ef7e06SGarrett D'Amore 	__in			unsigned int pos,
426*49ef7e06SGarrett D'Amore 	__out			efx_vpd_keyword_t *keywordp,
427*49ef7e06SGarrett D'Amore 	__out			uint8_t *lengthp)
428*49ef7e06SGarrett D'Amore {
429*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t keyword;
430*49ef7e06SGarrett D'Amore 	uint8_t length;
431*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
432*49ef7e06SGarrett D'Amore 
433*49ef7e06SGarrett D'Amore 	if (pos + 3U > size) {
434*49ef7e06SGarrett D'Amore 		rc = EFAULT;
435*49ef7e06SGarrett D'Amore 		goto fail1;
436*49ef7e06SGarrett D'Amore 	}
437*49ef7e06SGarrett D'Amore 
438*49ef7e06SGarrett D'Amore 	keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
439*49ef7e06SGarrett D'Amore 	length = tag[pos + 2];
440*49ef7e06SGarrett D'Amore 
441*49ef7e06SGarrett D'Amore 	if (length == 0 || pos + 3U + length > size) {
442*49ef7e06SGarrett D'Amore 		rc = EFAULT;
443*49ef7e06SGarrett D'Amore 		goto fail2;
444*49ef7e06SGarrett D'Amore 	}
445*49ef7e06SGarrett D'Amore 
446*49ef7e06SGarrett D'Amore 	*keywordp = keyword;
447*49ef7e06SGarrett D'Amore 	*lengthp = length;
448*49ef7e06SGarrett D'Amore 
449*49ef7e06SGarrett D'Amore 	return (0);
450*49ef7e06SGarrett D'Amore 
451*49ef7e06SGarrett D'Amore fail2:
452*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
453*49ef7e06SGarrett D'Amore fail1:
454*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
455*49ef7e06SGarrett D'Amore 
456*49ef7e06SGarrett D'Amore 	return (rc);
457*49ef7e06SGarrett D'Amore }
458*49ef7e06SGarrett D'Amore 
459*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_hunk_length(__in_bcount (size)caddr_t data,__in size_t size,__out size_t * lengthp)460*49ef7e06SGarrett D'Amore efx_vpd_hunk_length(
461*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
462*49ef7e06SGarrett D'Amore 	__in			size_t size,
463*49ef7e06SGarrett D'Amore 	__out			size_t *lengthp)
464*49ef7e06SGarrett D'Amore {
465*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t tag;
466*49ef7e06SGarrett D'Amore 	unsigned int offset;
467*49ef7e06SGarrett D'Amore 	uint16_t taglen;
468*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
469*49ef7e06SGarrett D'Amore 
470*49ef7e06SGarrett D'Amore 	offset = 0;
471*49ef7e06SGarrett D'Amore 	_NOTE(CONSTANTCONDITION)
472*49ef7e06SGarrett D'Amore 	while (1) {
473*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_next_tag(data, size, &offset,
474*49ef7e06SGarrett D'Amore 		    &tag, &taglen)) != 0)
475*49ef7e06SGarrett D'Amore 			goto fail1;
476*49ef7e06SGarrett D'Amore 		offset += taglen;
477*49ef7e06SGarrett D'Amore 		if (tag == EFX_VPD_END)
478*49ef7e06SGarrett D'Amore 			break;
479*49ef7e06SGarrett D'Amore 	}
480*49ef7e06SGarrett D'Amore 
481*49ef7e06SGarrett D'Amore 	*lengthp = offset;
482*49ef7e06SGarrett D'Amore 
483*49ef7e06SGarrett D'Amore 	return (0);
484*49ef7e06SGarrett D'Amore 
485*49ef7e06SGarrett D'Amore fail1:
486*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
487*49ef7e06SGarrett D'Amore 
488*49ef7e06SGarrett D'Amore 	return (rc);
489*49ef7e06SGarrett D'Amore }
490*49ef7e06SGarrett D'Amore 
491*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_hunk_verify(__in_bcount (size)caddr_t data,__in size_t size,__out_opt boolean_t * cksummedp)492*49ef7e06SGarrett D'Amore efx_vpd_hunk_verify(
493*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
494*49ef7e06SGarrett D'Amore 	__in			size_t size,
495*49ef7e06SGarrett D'Amore 	__out_opt		boolean_t *cksummedp)
496*49ef7e06SGarrett D'Amore {
497*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t tag;
498*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t keyword;
499*49ef7e06SGarrett D'Amore 	unsigned int offset;
500*49ef7e06SGarrett D'Amore 	unsigned int pos;
501*49ef7e06SGarrett D'Amore 	unsigned int i;
502*49ef7e06SGarrett D'Amore 	uint16_t taglen;
503*49ef7e06SGarrett D'Amore 	uint8_t keylen;
504*49ef7e06SGarrett D'Amore 	uint8_t cksum;
505*49ef7e06SGarrett D'Amore 	boolean_t cksummed = B_FALSE;
506*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
507*49ef7e06SGarrett D'Amore 
508*49ef7e06SGarrett D'Amore 	/*
509*49ef7e06SGarrett D'Amore 	 * Parse every tag,keyword in the existing VPD. If the csum is present,
510*49ef7e06SGarrett D'Amore 	 * the assert it is correct, and is the final keyword in the RO block.
511*49ef7e06SGarrett D'Amore 	 */
512*49ef7e06SGarrett D'Amore 	offset = 0;
513*49ef7e06SGarrett D'Amore 	_NOTE(CONSTANTCONDITION)
514*49ef7e06SGarrett D'Amore 	while (1) {
515*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_next_tag(data, size, &offset,
516*49ef7e06SGarrett D'Amore 		    &tag, &taglen)) != 0)
517*49ef7e06SGarrett D'Amore 			goto fail1;
518*49ef7e06SGarrett D'Amore 		if (tag == EFX_VPD_END)
519*49ef7e06SGarrett D'Amore 			break;
520*49ef7e06SGarrett D'Amore 		else if (tag == EFX_VPD_ID)
521*49ef7e06SGarrett D'Amore 			goto done;
522*49ef7e06SGarrett D'Amore 
523*49ef7e06SGarrett D'Amore 		for (pos = 0; pos != taglen; pos += 3 + keylen) {
524*49ef7e06SGarrett D'Amore 			/* RV keyword must be the last in the block */
525*49ef7e06SGarrett D'Amore 			if (cksummed) {
526*49ef7e06SGarrett D'Amore 				rc = EFAULT;
527*49ef7e06SGarrett D'Amore 				goto fail2;
528*49ef7e06SGarrett D'Amore 			}
529*49ef7e06SGarrett D'Amore 
530*49ef7e06SGarrett D'Amore 			if ((rc = efx_vpd_next_keyword(data + offset,
531*49ef7e06SGarrett D'Amore 			    taglen, pos, &keyword, &keylen)) != 0)
532*49ef7e06SGarrett D'Amore 				goto fail3;
533*49ef7e06SGarrett D'Amore 
534*49ef7e06SGarrett D'Amore 			if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
535*49ef7e06SGarrett D'Amore 				cksum = 0;
536*49ef7e06SGarrett D'Amore 				for (i = 0; i < offset + pos + 4; i++)
537*49ef7e06SGarrett D'Amore 					cksum += data[i];
538*49ef7e06SGarrett D'Amore 
539*49ef7e06SGarrett D'Amore 				if (cksum != 0) {
540*49ef7e06SGarrett D'Amore 					rc = EFAULT;
541*49ef7e06SGarrett D'Amore 					goto fail4;
542*49ef7e06SGarrett D'Amore 				}
543*49ef7e06SGarrett D'Amore 
544*49ef7e06SGarrett D'Amore 				cksummed = B_TRUE;
545*49ef7e06SGarrett D'Amore 			}
546*49ef7e06SGarrett D'Amore 		}
547*49ef7e06SGarrett D'Amore 
548*49ef7e06SGarrett D'Amore 	done:
549*49ef7e06SGarrett D'Amore 		offset += taglen;
550*49ef7e06SGarrett D'Amore 	}
551*49ef7e06SGarrett D'Amore 
552*49ef7e06SGarrett D'Amore 	if (!cksummed) {
553*49ef7e06SGarrett D'Amore 		rc = EFAULT;
554*49ef7e06SGarrett D'Amore 		goto fail5;
555*49ef7e06SGarrett D'Amore 	}
556*49ef7e06SGarrett D'Amore 
557*49ef7e06SGarrett D'Amore 	if (cksummedp != NULL)
558*49ef7e06SGarrett D'Amore 		*cksummedp = cksummed;
559*49ef7e06SGarrett D'Amore 
560*49ef7e06SGarrett D'Amore 	return (0);
561*49ef7e06SGarrett D'Amore 
562*49ef7e06SGarrett D'Amore fail5:
563*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail5);
564*49ef7e06SGarrett D'Amore fail4:
565*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail4);
566*49ef7e06SGarrett D'Amore fail3:
567*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail3);
568*49ef7e06SGarrett D'Amore fail2:
569*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
570*49ef7e06SGarrett D'Amore fail1:
571*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
572*49ef7e06SGarrett D'Amore 
573*49ef7e06SGarrett D'Amore 	return (rc);
574*49ef7e06SGarrett D'Amore }
575*49ef7e06SGarrett D'Amore 
576*49ef7e06SGarrett D'Amore static	uint8_t	__efx_vpd_blank_pid[] = {
577*49ef7e06SGarrett D'Amore 	/* Large resource type ID length 1 */
578*49ef7e06SGarrett D'Amore 	0x82, 0x01, 0x00,
579*49ef7e06SGarrett D'Amore 	/* Product name ' ' */
580*49ef7e06SGarrett D'Amore 	0x32,
581*49ef7e06SGarrett D'Amore };
582*49ef7e06SGarrett D'Amore 
583*49ef7e06SGarrett D'Amore static uint8_t __efx_vpd_blank_r[] = {
584*49ef7e06SGarrett D'Amore 	/* Large resource type VPD-R length 4 */
585*49ef7e06SGarrett D'Amore 	0x90, 0x04, 0x00,
586*49ef7e06SGarrett D'Amore 	/* RV keyword length 1 */
587*49ef7e06SGarrett D'Amore 	'R', 'V', 0x01,
588*49ef7e06SGarrett D'Amore 	/* RV payload checksum */
589*49ef7e06SGarrett D'Amore 	0x00,
590*49ef7e06SGarrett D'Amore };
591*49ef7e06SGarrett D'Amore 
592*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_hunk_reinit(__in_bcount (size)caddr_t data,__in size_t size,__in boolean_t wantpid)593*49ef7e06SGarrett D'Amore efx_vpd_hunk_reinit(
594*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
595*49ef7e06SGarrett D'Amore 	__in			size_t size,
596*49ef7e06SGarrett D'Amore 	__in			boolean_t wantpid)
597*49ef7e06SGarrett D'Amore {
598*49ef7e06SGarrett D'Amore 	unsigned int offset = 0;
599*49ef7e06SGarrett D'Amore 	unsigned int pos;
600*49ef7e06SGarrett D'Amore 	efx_byte_t byte;
601*49ef7e06SGarrett D'Amore 	uint8_t cksum;
602*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
603*49ef7e06SGarrett D'Amore 
604*49ef7e06SGarrett D'Amore 	if (size < 0x100) {
605*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
606*49ef7e06SGarrett D'Amore 		goto fail1;
607*49ef7e06SGarrett D'Amore 	}
608*49ef7e06SGarrett D'Amore 
609*49ef7e06SGarrett D'Amore 	if (wantpid) {
610*49ef7e06SGarrett D'Amore 		(void) memcpy(data + offset, __efx_vpd_blank_pid,
611*49ef7e06SGarrett D'Amore 		    sizeof (__efx_vpd_blank_pid));
612*49ef7e06SGarrett D'Amore 		offset += sizeof (__efx_vpd_blank_pid);
613*49ef7e06SGarrett D'Amore 	}
614*49ef7e06SGarrett D'Amore 
615*49ef7e06SGarrett D'Amore 	(void) memcpy(data + offset, __efx_vpd_blank_r,
616*49ef7e06SGarrett D'Amore 	    sizeof (__efx_vpd_blank_r));
617*49ef7e06SGarrett D'Amore 	offset += sizeof (__efx_vpd_blank_r);
618*49ef7e06SGarrett D'Amore 
619*49ef7e06SGarrett D'Amore 	/* Update checksum */
620*49ef7e06SGarrett D'Amore 	cksum = 0;
621*49ef7e06SGarrett D'Amore 	for (pos = 0; pos < offset; pos++)
622*49ef7e06SGarrett D'Amore 		cksum += data[pos];
623*49ef7e06SGarrett D'Amore 	data[offset - 1] -= cksum;
624*49ef7e06SGarrett D'Amore 
625*49ef7e06SGarrett D'Amore 	/* Append trailing tag */
626*49ef7e06SGarrett D'Amore 	EFX_POPULATE_BYTE_3(byte,
627*49ef7e06SGarrett D'Amore 			    TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
628*49ef7e06SGarrett D'Amore 			    TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
629*49ef7e06SGarrett D'Amore 			    TAG_SMALL_ITEM_SIZE, 0);
630*49ef7e06SGarrett D'Amore 	data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
631*49ef7e06SGarrett D'Amore 	offset++;
632*49ef7e06SGarrett D'Amore 
633*49ef7e06SGarrett D'Amore 	return (0);
634*49ef7e06SGarrett D'Amore 
635*49ef7e06SGarrett D'Amore fail1:
636*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
637*49ef7e06SGarrett D'Amore 
638*49ef7e06SGarrett D'Amore 	return (rc);
639*49ef7e06SGarrett D'Amore }
640*49ef7e06SGarrett D'Amore 
641*49ef7e06SGarrett D'Amore 	__checkReturn			efx_rc_t
efx_vpd_hunk_next(__in_bcount (size)caddr_t data,__in size_t size,__out efx_vpd_tag_t * tagp,__out efx_vpd_keyword_t * keywordp,__out_opt unsigned int * payloadp,__out_opt uint8_t * paylenp,__inout unsigned int * contp)642*49ef7e06SGarrett D'Amore efx_vpd_hunk_next(
643*49ef7e06SGarrett D'Amore 	__in_bcount(size)		caddr_t data,
644*49ef7e06SGarrett D'Amore 	__in				size_t size,
645*49ef7e06SGarrett D'Amore 	__out				efx_vpd_tag_t *tagp,
646*49ef7e06SGarrett D'Amore 	__out				efx_vpd_keyword_t *keywordp,
647*49ef7e06SGarrett D'Amore 	__out_opt			unsigned int *payloadp,
648*49ef7e06SGarrett D'Amore 	__out_opt			uint8_t *paylenp,
649*49ef7e06SGarrett D'Amore 	__inout				unsigned int *contp)
650*49ef7e06SGarrett D'Amore {
651*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t tag;
652*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t keyword = 0;
653*49ef7e06SGarrett D'Amore 	unsigned int offset;
654*49ef7e06SGarrett D'Amore 	unsigned int pos;
655*49ef7e06SGarrett D'Amore 	unsigned int index;
656*49ef7e06SGarrett D'Amore 	uint16_t taglen;
657*49ef7e06SGarrett D'Amore 	uint8_t keylen;
658*49ef7e06SGarrett D'Amore 	uint8_t paylen;
659*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
660*49ef7e06SGarrett D'Amore 
661*49ef7e06SGarrett D'Amore 	offset = index = 0;
662*49ef7e06SGarrett D'Amore 	_NOTE(CONSTANTCONDITION)
663*49ef7e06SGarrett D'Amore 	while (1) {
664*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_next_tag(data, size, &offset,
665*49ef7e06SGarrett D'Amore 		    &tag, &taglen)) != 0)
666*49ef7e06SGarrett D'Amore 			goto fail1;
667*49ef7e06SGarrett D'Amore 
668*49ef7e06SGarrett D'Amore 		if (tag == EFX_VPD_END) {
669*49ef7e06SGarrett D'Amore 			keyword = 0;
670*49ef7e06SGarrett D'Amore 			paylen = 0;
671*49ef7e06SGarrett D'Amore 			index = 0;
672*49ef7e06SGarrett D'Amore 			break;
673*49ef7e06SGarrett D'Amore 		}
674*49ef7e06SGarrett D'Amore 
675*49ef7e06SGarrett D'Amore 		if (tag == EFX_VPD_ID) {
676*49ef7e06SGarrett D'Amore 			if (index++ == *contp) {
677*49ef7e06SGarrett D'Amore 				EFSYS_ASSERT3U(taglen, <, 0x100);
678*49ef7e06SGarrett D'Amore 				keyword = 0;
679*49ef7e06SGarrett D'Amore 				paylen = (uint8_t)MIN(taglen, 0xff);
680*49ef7e06SGarrett D'Amore 
681*49ef7e06SGarrett D'Amore 				goto done;
682*49ef7e06SGarrett D'Amore 			}
683*49ef7e06SGarrett D'Amore 		} else {
684*49ef7e06SGarrett D'Amore 			for (pos = 0; pos != taglen; pos += 3 + keylen) {
685*49ef7e06SGarrett D'Amore 				if ((rc = efx_vpd_next_keyword(data + offset,
686*49ef7e06SGarrett D'Amore 				    taglen, pos, &keyword, &keylen)) != 0)
687*49ef7e06SGarrett D'Amore 					goto fail2;
688*49ef7e06SGarrett D'Amore 
689*49ef7e06SGarrett D'Amore 				if (index++ == *contp) {
690*49ef7e06SGarrett D'Amore 					offset += pos + 3;
691*49ef7e06SGarrett D'Amore 					paylen = keylen;
692*49ef7e06SGarrett D'Amore 
693*49ef7e06SGarrett D'Amore 					goto done;
694*49ef7e06SGarrett D'Amore 				}
695*49ef7e06SGarrett D'Amore 			}
696*49ef7e06SGarrett D'Amore 		}
697*49ef7e06SGarrett D'Amore 
698*49ef7e06SGarrett D'Amore 		offset += taglen;
699*49ef7e06SGarrett D'Amore 	}
700*49ef7e06SGarrett D'Amore 
701*49ef7e06SGarrett D'Amore done:
702*49ef7e06SGarrett D'Amore 	*tagp = tag;
703*49ef7e06SGarrett D'Amore 	*keywordp = keyword;
704*49ef7e06SGarrett D'Amore 	if (payloadp != NULL)
705*49ef7e06SGarrett D'Amore 		*payloadp = offset;
706*49ef7e06SGarrett D'Amore 	if (paylenp != NULL)
707*49ef7e06SGarrett D'Amore 		*paylenp = paylen;
708*49ef7e06SGarrett D'Amore 
709*49ef7e06SGarrett D'Amore 	*contp = index;
710*49ef7e06SGarrett D'Amore 	return (0);
711*49ef7e06SGarrett D'Amore 
712*49ef7e06SGarrett D'Amore fail2:
713*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
714*49ef7e06SGarrett D'Amore fail1:
715*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
716*49ef7e06SGarrett D'Amore 
717*49ef7e06SGarrett D'Amore 	return (rc);
718*49ef7e06SGarrett D'Amore }
719*49ef7e06SGarrett D'Amore 
720*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
efx_vpd_hunk_get(__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_tag_t tag,__in efx_vpd_keyword_t keyword,__out unsigned int * payloadp,__out uint8_t * paylenp)721*49ef7e06SGarrett D'Amore efx_vpd_hunk_get(
722*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
723*49ef7e06SGarrett D'Amore 	__in			size_t size,
724*49ef7e06SGarrett D'Amore 	__in			efx_vpd_tag_t tag,
725*49ef7e06SGarrett D'Amore 	__in			efx_vpd_keyword_t keyword,
726*49ef7e06SGarrett D'Amore 	__out			unsigned int *payloadp,
727*49ef7e06SGarrett D'Amore 	__out			uint8_t *paylenp)
728*49ef7e06SGarrett D'Amore {
729*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t itag;
730*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t ikeyword;
731*49ef7e06SGarrett D'Amore 	unsigned int offset;
732*49ef7e06SGarrett D'Amore 	unsigned int pos;
733*49ef7e06SGarrett D'Amore 	uint16_t taglen;
734*49ef7e06SGarrett D'Amore 	uint8_t keylen;
735*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
736*49ef7e06SGarrett D'Amore 
737*49ef7e06SGarrett D'Amore 	offset = 0;
738*49ef7e06SGarrett D'Amore 	_NOTE(CONSTANTCONDITION)
739*49ef7e06SGarrett D'Amore 	while (1) {
740*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_next_tag(data, size, &offset,
741*49ef7e06SGarrett D'Amore 		    &itag, &taglen)) != 0)
742*49ef7e06SGarrett D'Amore 			goto fail1;
743