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 
35*49ef7e06SGarrett D'Amore #if EFSYS_OPT_VPD
36*49ef7e06SGarrett D'Amore 
37*49ef7e06SGarrett D'Amore #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
38*49ef7e06SGarrett D'Amore 
39*49ef7e06SGarrett D'Amore #include "ef10_tlv_layout.h"
40*49ef7e06SGarrett D'Amore 
41*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_init(__in efx_nic_t * enp)42*49ef7e06SGarrett D'Amore ef10_vpd_init(
43*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp)
44*49ef7e06SGarrett D'Amore {
45*49ef7e06SGarrett D'Amore 	caddr_t svpd;
46*49ef7e06SGarrett D'Amore 	size_t svpd_size;
47*49ef7e06SGarrett D'Amore 	uint32_t pci_pf;
48*49ef7e06SGarrett D'Amore 	uint32_t tag;
49*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
50*49ef7e06SGarrett D'Amore 
51*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
52*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
53*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
54*49ef7e06SGarrett D'Amore 
55*49ef7e06SGarrett D'Amore 	if (enp->en_nic_cfg.enc_vpd_is_global) {
56*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_GLOBAL_STATIC_VPD;
57*49ef7e06SGarrett D'Amore 	} else {
58*49ef7e06SGarrett D'Amore 		pci_pf = enp->en_nic_cfg.enc_pf;
59*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_PF_STATIC_VPD(pci_pf);
60*49ef7e06SGarrett D'Amore 	}
61*49ef7e06SGarrett D'Amore 
62*49ef7e06SGarrett D'Amore 	/*
63*49ef7e06SGarrett D'Amore 	 * The VPD interface exposes VPD resources from the combined static and
64*49ef7e06SGarrett D'Amore 	 * dynamic VPD storage. As the static VPD configuration should *never*
65*49ef7e06SGarrett D'Amore 	 * change, we can cache it.
66*49ef7e06SGarrett D'Amore 	 */
67*49ef7e06SGarrett D'Amore 	svpd = NULL;
68*49ef7e06SGarrett D'Amore 	svpd_size = 0;
69*49ef7e06SGarrett D'Amore 	rc = ef10_nvram_partn_read_tlv(enp,
70*49ef7e06SGarrett D'Amore 	    NVRAM_PARTITION_TYPE_STATIC_CONFIG,
71*49ef7e06SGarrett D'Amore 	    tag, &svpd, &svpd_size);
72*49ef7e06SGarrett D'Amore 	if (rc != 0) {
73*49ef7e06SGarrett D'Amore 		if (rc == EACCES) {
74*49ef7e06SGarrett D'Amore 			/* Unprivileged functions cannot access VPD */
75*49ef7e06SGarrett D'Amore 			goto out;
76*49ef7e06SGarrett D'Amore 		}
77*49ef7e06SGarrett D'Amore 		goto fail1;
78*49ef7e06SGarrett D'Amore 	}
79*49ef7e06SGarrett D'Amore 
80*49ef7e06SGarrett D'Amore 	if (svpd != NULL && svpd_size > 0) {
81*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
82*49ef7e06SGarrett D'Amore 			goto fail2;
83*49ef7e06SGarrett D'Amore 	}
84*49ef7e06SGarrett D'Amore 
85*49ef7e06SGarrett D'Amore 	enp->en_arch.ef10.ena_svpd = svpd;
86*49ef7e06SGarrett D'Amore 	enp->en_arch.ef10.ena_svpd_length = svpd_size;
87*49ef7e06SGarrett D'Amore 
88*49ef7e06SGarrett D'Amore out:
89*49ef7e06SGarrett D'Amore 	return (0);
90*49ef7e06SGarrett D'Amore 
91*49ef7e06SGarrett D'Amore fail2:
92*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
93*49ef7e06SGarrett D'Amore 
94*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
95*49ef7e06SGarrett D'Amore fail1:
96*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
97*49ef7e06SGarrett D'Amore 
98*49ef7e06SGarrett D'Amore 	return (rc);
99*49ef7e06SGarrett D'Amore }
100*49ef7e06SGarrett D'Amore 
101*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_size(__in efx_nic_t * enp,__out size_t * sizep)102*49ef7e06SGarrett D'Amore ef10_vpd_size(
103*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
104*49ef7e06SGarrett D'Amore 	__out			size_t *sizep)
105*49ef7e06SGarrett D'Amore {
106*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
107*49ef7e06SGarrett D'Amore 
108*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
109*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
110*49ef7e06SGarrett D'Amore 
111*49ef7e06SGarrett D'Amore 	/*
112*49ef7e06SGarrett D'Amore 	 * This function returns the total size the user should allocate
113*49ef7e06SGarrett D'Amore 	 * for all VPD operations. We've already cached the static vpd,
114*49ef7e06SGarrett D'Amore 	 * so we just need to return an upper bound on the dynamic vpd,
115*49ef7e06SGarrett D'Amore 	 * which is the size of the DYNAMIC_CONFIG partition.
116*49ef7e06SGarrett D'Amore 	 */
117*49ef7e06SGarrett D'Amore 	if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
118*49ef7e06SGarrett D'Amore 		    sizep, NULL, NULL, NULL)) != 0)
119*49ef7e06SGarrett D'Amore 		goto fail1;
120*49ef7e06SGarrett D'Amore 
121*49ef7e06SGarrett D'Amore 	return (0);
122*49ef7e06SGarrett D'Amore 
123*49ef7e06SGarrett D'Amore fail1:
124*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
125*49ef7e06SGarrett D'Amore 
126*49ef7e06SGarrett D'Amore 	return (rc);
127*49ef7e06SGarrett D'Amore }
128*49ef7e06SGarrett D'Amore 
129*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_read(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size)130*49ef7e06SGarrett D'Amore ef10_vpd_read(
131*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
132*49ef7e06SGarrett D'Amore 	__out_bcount(size)	caddr_t data,
133*49ef7e06SGarrett D'Amore 	__in			size_t size)
134*49ef7e06SGarrett D'Amore {
135*49ef7e06SGarrett D'Amore 	caddr_t dvpd;
136*49ef7e06SGarrett D'Amore 	size_t dvpd_size;
137*49ef7e06SGarrett D'Amore 	uint32_t pci_pf;
138*49ef7e06SGarrett D'Amore 	uint32_t tag;
139*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
140*49ef7e06SGarrett D'Amore 
141*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
142*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
143*49ef7e06SGarrett D'Amore 
144*49ef7e06SGarrett D'Amore 	if (enp->en_nic_cfg.enc_vpd_is_global) {
145*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
146*49ef7e06SGarrett D'Amore 	} else {
147*49ef7e06SGarrett D'Amore 		pci_pf = enp->en_nic_cfg.enc_pf;
148*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
149*49ef7e06SGarrett D'Amore 	}
150*49ef7e06SGarrett D'Amore 
151*49ef7e06SGarrett D'Amore 	if ((rc = ef10_nvram_partn_read_tlv(enp,
152*49ef7e06SGarrett D'Amore 		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
153*49ef7e06SGarrett D'Amore 		    tag, &dvpd, &dvpd_size)) != 0)
154*49ef7e06SGarrett D'Amore 		goto fail1;
155*49ef7e06SGarrett D'Amore 
156*49ef7e06SGarrett D'Amore 	if (dvpd_size > size) {
157*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
158*49ef7e06SGarrett D'Amore 		goto fail2;
159*49ef7e06SGarrett D'Amore 	}
160*49ef7e06SGarrett D'Amore 	(void) memcpy(data, dvpd, dvpd_size);
161*49ef7e06SGarrett D'Amore 
162*49ef7e06SGarrett D'Amore 	/* Pad data with all-1s, consistent with update operations */
163*49ef7e06SGarrett D'Amore 	(void) memset(data + dvpd_size, 0xff, size - dvpd_size);
164*49ef7e06SGarrett D'Amore 
165*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
166*49ef7e06SGarrett D'Amore 
167*49ef7e06SGarrett D'Amore 	return (0);
168*49ef7e06SGarrett D'Amore 
169*49ef7e06SGarrett D'Amore fail2:
170*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
171*49ef7e06SGarrett D'Amore 
172*49ef7e06SGarrett D'Amore 	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
173*49ef7e06SGarrett D'Amore fail1:
174*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
175*49ef7e06SGarrett D'Amore 
176*49ef7e06SGarrett D'Amore 	return (rc);
177*49ef7e06SGarrett D'Amore }
178*49ef7e06SGarrett D'Amore 
179*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_verify(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)180*49ef7e06SGarrett D'Amore ef10_vpd_verify(
181*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
182*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
183*49ef7e06SGarrett D'Amore 	__in			size_t size)
184*49ef7e06SGarrett D'Amore {
185*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t stag;
186*49ef7e06SGarrett D'Amore 	efx_vpd_tag_t dtag;
187*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t skey;
188*49ef7e06SGarrett D'Amore 	efx_vpd_keyword_t dkey;
189*49ef7e06SGarrett D'Amore 	unsigned int scont;
190*49ef7e06SGarrett D'Amore 	unsigned int dcont;
191*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
192*49ef7e06SGarrett D'Amore 
193*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
194*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
195*49ef7e06SGarrett D'Amore 
196*49ef7e06SGarrett D'Amore 	/*
197*49ef7e06SGarrett D'Amore 	 * Strictly you could take the view that dynamic vpd is optional.
198*49ef7e06SGarrett D'Amore 	 * Instead, to conform more closely to the read/verify/reinit()
199*49ef7e06SGarrett D'Amore 	 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
200*49ef7e06SGarrett D'Amore 	 * reinitialize it as required.
201*49ef7e06SGarrett D'Amore 	 */
202*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
203*49ef7e06SGarrett D'Amore 		goto fail1;
204*49ef7e06SGarrett D'Amore 
205*49ef7e06SGarrett D'Amore 	/*
206*49ef7e06SGarrett D'Amore 	 * Verify that there is no duplication between the static and
207*49ef7e06SGarrett D'Amore 	 * dynamic cfg sectors.
208*49ef7e06SGarrett D'Amore 	 */
209*49ef7e06SGarrett D'Amore 	if (enp->en_arch.ef10.ena_svpd_length == 0)
210*49ef7e06SGarrett D'Amore 		goto done;
211*49ef7e06SGarrett D'Amore 
212*49ef7e06SGarrett D'Amore 	dcont = 0;
213*49ef7e06SGarrett D'Amore 	_NOTE(CONSTANTCONDITION)
214*49ef7e06SGarrett D'Amore 	while (1) {
215*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
216*49ef7e06SGarrett D'Amore 		    &dkey, NULL, NULL, &dcont)) != 0)
217*49ef7e06SGarrett D'Amore 			goto fail2;
218*49ef7e06SGarrett D'Amore 		if (dcont == 0)
219*49ef7e06SGarrett D'Amore 			break;
220*49ef7e06SGarrett D'Amore 
221*49ef7e06SGarrett D'Amore 		/*
222*49ef7e06SGarrett D'Amore 		 * Skip the RV keyword. It should be present in both the static
223*49ef7e06SGarrett D'Amore 		 * and dynamic cfg sectors.
224*49ef7e06SGarrett D'Amore 		 */
225*49ef7e06SGarrett D'Amore 		if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
226*49ef7e06SGarrett D'Amore 			continue;
227*49ef7e06SGarrett D'Amore 
228*49ef7e06SGarrett D'Amore 		scont = 0;
229*49ef7e06SGarrett D'Amore 		_NOTE(CONSTANTCONDITION)
230*49ef7e06SGarrett D'Amore 		while (1) {
231*49ef7e06SGarrett D'Amore 			if ((rc = efx_vpd_hunk_next(
232*49ef7e06SGarrett D'Amore 			    enp->en_arch.ef10.ena_svpd,
233*49ef7e06SGarrett D'Amore 			    enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
234*49ef7e06SGarrett D'Amore 			    NULL, NULL, &scont)) != 0)
235*49ef7e06SGarrett D'Amore 				goto fail3;
236*49ef7e06SGarrett D'Amore 			if (scont == 0)
237*49ef7e06SGarrett D'Amore 				break;
238*49ef7e06SGarrett D'Amore 
239*49ef7e06SGarrett D'Amore 			if (stag == dtag && skey == dkey) {
240*49ef7e06SGarrett D'Amore 				rc = EEXIST;
241*49ef7e06SGarrett D'Amore 				goto fail4;
242*49ef7e06SGarrett D'Amore 			}
243*49ef7e06SGarrett D'Amore 		}
244*49ef7e06SGarrett D'Amore 	}
245*49ef7e06SGarrett D'Amore 
246*49ef7e06SGarrett D'Amore done:
247*49ef7e06SGarrett D'Amore 	return (0);
248*49ef7e06SGarrett D'Amore 
249*49ef7e06SGarrett D'Amore fail4:
250*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail4);
251*49ef7e06SGarrett D'Amore fail3:
252*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail3);
253*49ef7e06SGarrett D'Amore fail2:
254*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
255*49ef7e06SGarrett D'Amore fail1:
256*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
257*49ef7e06SGarrett D'Amore 
258*49ef7e06SGarrett D'Amore 	return (rc);
259*49ef7e06SGarrett D'Amore }
260*49ef7e06SGarrett D'Amore 
261*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_reinit(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)262*49ef7e06SGarrett D'Amore ef10_vpd_reinit(
263*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
264*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
265*49ef7e06SGarrett D'Amore 	__in			size_t size)
266*49ef7e06SGarrett D'Amore {
267*49ef7e06SGarrett D'Amore 	boolean_t wantpid;
268*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
269*49ef7e06SGarrett D'Amore 
270*49ef7e06SGarrett D'Amore 	/*
271*49ef7e06SGarrett D'Amore 	 * Only create an ID string if the dynamic cfg doesn't have one
272*49ef7e06SGarrett D'Amore 	 */
273*49ef7e06SGarrett D'Amore 	if (enp->en_arch.ef10.ena_svpd_length == 0)
274*49ef7e06SGarrett D'Amore 		wantpid = B_TRUE;
275*49ef7e06SGarrett D'Amore 	else {
276*49ef7e06SGarrett D'Amore 		unsigned int offset;
277*49ef7e06SGarrett D'Amore 		uint8_t length;
278*49ef7e06SGarrett D'Amore 
279*49ef7e06SGarrett D'Amore 		rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
280*49ef7e06SGarrett D'Amore 				    enp->en_arch.ef10.ena_svpd_length,
281*49ef7e06SGarrett D'Amore 				    EFX_VPD_ID, 0, &offset, &length);
282*49ef7e06SGarrett D'Amore 		if (rc == 0)
283*49ef7e06SGarrett D'Amore 			wantpid = B_FALSE;
284*49ef7e06SGarrett D'Amore 		else if (rc == ENOENT)
285*49ef7e06SGarrett D'Amore 			wantpid = B_TRUE;
286*49ef7e06SGarrett D'Amore 		else
287*49ef7e06SGarrett D'Amore 			goto fail1;
288*49ef7e06SGarrett D'Amore 	}
289*49ef7e06SGarrett D'Amore 
290*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
291*49ef7e06SGarrett D'Amore 		goto fail2;
292*49ef7e06SGarrett D'Amore 
293*49ef7e06SGarrett D'Amore 	return (0);
294*49ef7e06SGarrett D'Amore 
295*49ef7e06SGarrett D'Amore fail2:
296*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
297*49ef7e06SGarrett D'Amore fail1:
298*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
299*49ef7e06SGarrett D'Amore 
300*49ef7e06SGarrett D'Amore 	return (rc);
301*49ef7e06SGarrett D'Amore }
302*49ef7e06SGarrett D'Amore 
303*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_get(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__inout efx_vpd_value_t * evvp)304*49ef7e06SGarrett D'Amore ef10_vpd_get(
305*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
306*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
307*49ef7e06SGarrett D'Amore 	__in			size_t size,
308*49ef7e06SGarrett D'Amore 	__inout			efx_vpd_value_t *evvp)
309*49ef7e06SGarrett D'Amore {
310*49ef7e06SGarrett D'Amore 	unsigned int offset;
311*49ef7e06SGarrett D'Amore 	uint8_t length;
312*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
313*49ef7e06SGarrett D'Amore 
314*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
315*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
316*49ef7e06SGarrett D'Amore 
317*49ef7e06SGarrett D'Amore 	/* Attempt to satisfy the request from svpd first */
318*49ef7e06SGarrett D'Amore 	if (enp->en_arch.ef10.ena_svpd_length > 0) {
319*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
320*49ef7e06SGarrett D'Amore 		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
321*49ef7e06SGarrett D'Amore 		    evvp->evv_keyword, &offset, &length)) == 0) {
322*49ef7e06SGarrett D'Amore 			evvp->evv_length = length;
323*49ef7e06SGarrett D'Amore 			(void) memcpy(evvp->evv_value,
324*49ef7e06SGarrett D'Amore 			    enp->en_arch.ef10.ena_svpd + offset, length);
325*49ef7e06SGarrett D'Amore 			return (0);
326*49ef7e06SGarrett D'Amore 		} else if (rc != ENOENT)
327*49ef7e06SGarrett D'Amore 			goto fail1;
328*49ef7e06SGarrett D'Amore 	}
329*49ef7e06SGarrett D'Amore 
330*49ef7e06SGarrett D'Amore 	/* And then from the provided data buffer */
331*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
332*49ef7e06SGarrett D'Amore 	    evvp->evv_keyword, &offset, &length)) != 0)
333*49ef7e06SGarrett D'Amore 		goto fail2;
334*49ef7e06SGarrett D'Amore 
335*49ef7e06SGarrett D'Amore 	evvp->evv_length = length;
336*49ef7e06SGarrett D'Amore 	(void) memcpy(evvp->evv_value, data + offset, length);
337*49ef7e06SGarrett D'Amore 
338*49ef7e06SGarrett D'Amore 	return (0);
339*49ef7e06SGarrett D'Amore 
340*49ef7e06SGarrett D'Amore fail2:
341*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
342*49ef7e06SGarrett D'Amore fail1:
343*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
344*49ef7e06SGarrett D'Amore 
345*49ef7e06SGarrett D'Amore 	return (rc);
346*49ef7e06SGarrett D'Amore }
347*49ef7e06SGarrett D'Amore 
348*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_set(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)349*49ef7e06SGarrett D'Amore ef10_vpd_set(
350*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
351*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
352*49ef7e06SGarrett D'Amore 	__in			size_t size,
353*49ef7e06SGarrett D'Amore 	__in			efx_vpd_value_t *evvp)
354*49ef7e06SGarrett D'Amore {
355*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
356*49ef7e06SGarrett D'Amore 
357*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
358*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
359*49ef7e06SGarrett D'Amore 
360*49ef7e06SGarrett D'Amore 	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
361*49ef7e06SGarrett D'Amore 	if (enp->en_arch.ef10.ena_svpd_length > 0) {
362*49ef7e06SGarrett D'Amore 		unsigned int offset;
363*49ef7e06SGarrett D'Amore 		uint8_t length;
364*49ef7e06SGarrett D'Amore 
365*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
366*49ef7e06SGarrett D'Amore 		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
367*49ef7e06SGarrett D'Amore 		    evvp->evv_keyword, &offset, &length)) == 0) {
368*49ef7e06SGarrett D'Amore 			rc = EACCES;
369*49ef7e06SGarrett D'Amore 			goto fail1;
370*49ef7e06SGarrett D'Amore 		}
371*49ef7e06SGarrett D'Amore 	}
372*49ef7e06SGarrett D'Amore 
373*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
374*49ef7e06SGarrett D'Amore 		goto fail2;
375*49ef7e06SGarrett D'Amore 
376*49ef7e06SGarrett D'Amore 	return (0);
377*49ef7e06SGarrett D'Amore 
378*49ef7e06SGarrett D'Amore fail2:
379*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
380*49ef7e06SGarrett D'Amore fail1:
381*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
382*49ef7e06SGarrett D'Amore 
383*49ef7e06SGarrett D'Amore 	return (rc);
384*49ef7e06SGarrett D'Amore }
385*49ef7e06SGarrett D'Amore 
386*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_next(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__out efx_vpd_value_t * evvp,__inout unsigned int * contp)387*49ef7e06SGarrett D'Amore ef10_vpd_next(
388*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
389*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
390*49ef7e06SGarrett D'Amore 	__in			size_t size,
391*49ef7e06SGarrett D'Amore 	__out			efx_vpd_value_t *evvp,
392*49ef7e06SGarrett D'Amore 	__inout			unsigned int *contp)
393*49ef7e06SGarrett D'Amore {
394*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
395*49ef7e06SGarrett D'Amore 
396*49ef7e06SGarrett D'Amore 	return (ENOTSUP);
397*49ef7e06SGarrett D'Amore }
398*49ef7e06SGarrett D'Amore 
399*49ef7e06SGarrett D'Amore 	__checkReturn		efx_rc_t
ef10_vpd_write(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)400*49ef7e06SGarrett D'Amore ef10_vpd_write(
401*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp,
402*49ef7e06SGarrett D'Amore 	__in_bcount(size)	caddr_t data,
403*49ef7e06SGarrett D'Amore 	__in			size_t size)
404*49ef7e06SGarrett D'Amore {
405*49ef7e06SGarrett D'Amore 	size_t vpd_length;
406*49ef7e06SGarrett D'Amore 	uint32_t pci_pf;
407*49ef7e06SGarrett D'Amore 	uint32_t tag;
408*49ef7e06SGarrett D'Amore 	efx_rc_t rc;
409*49ef7e06SGarrett D'Amore 
410*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
411*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
412*49ef7e06SGarrett D'Amore 
413*49ef7e06SGarrett D'Amore 	if (enp->en_nic_cfg.enc_vpd_is_global) {
414*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
415*49ef7e06SGarrett D'Amore 	} else {
416*49ef7e06SGarrett D'Amore 		pci_pf = enp->en_nic_cfg.enc_pf;
417*49ef7e06SGarrett D'Amore 		tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
418*49ef7e06SGarrett D'Amore 	}
419*49ef7e06SGarrett D'Amore 
420*49ef7e06SGarrett D'Amore 	/* Determine total length of new dynamic VPD */
421*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
422*49ef7e06SGarrett D'Amore 		goto fail1;
423*49ef7e06SGarrett D'Amore 
424*49ef7e06SGarrett D'Amore 	/* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
425*49ef7e06SGarrett D'Amore 	if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
426*49ef7e06SGarrett D'Amore 		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
427*49ef7e06SGarrett D'Amore 		    tag, data, vpd_length, B_TRUE)) != 0) {
428*49ef7e06SGarrett D'Amore 		goto fail2;
429*49ef7e06SGarrett D'Amore 	}
430*49ef7e06SGarrett D'Amore 
431*49ef7e06SGarrett D'Amore 	return (0);
432*49ef7e06SGarrett D'Amore 
433*49ef7e06SGarrett D'Amore fail2:
434*49ef7e06SGarrett D'Amore 	EFSYS_PROBE(fail2);
435*49ef7e06SGarrett D'Amore 
436*49ef7e06SGarrett D'Amore fail1:
437*49ef7e06SGarrett D'Amore 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
438*49ef7e06SGarrett D'Amore 
439*49ef7e06SGarrett D'Amore 	return (rc);
440*49ef7e06SGarrett D'Amore }
441*49ef7e06SGarrett D'Amore 
442*49ef7e06SGarrett D'Amore 				void
ef10_vpd_fini(__in efx_nic_t * enp)443*49ef7e06SGarrett D'Amore ef10_vpd_fini(
444*49ef7e06SGarrett D'Amore 	__in			efx_nic_t *enp)
445*49ef7e06SGarrett D'Amore {
446*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
447*49ef7e06SGarrett D'Amore 		    enp->en_family == EFX_FAMILY_MEDFORD);
448*49ef7e06SGarrett D'Amore 
449*49ef7e06SGarrett D'Amore 	if (enp->en_arch.ef10.ena_svpd_length > 0) {
450*49ef7e06SGarrett D'Amore 		EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length,
451*49ef7e06SGarrett D'Amore 				enp->en_arch.ef10.ena_svpd);
452*49ef7e06SGarrett D'Amore 
453*49ef7e06SGarrett D'Amore 		enp->en_arch.ef10.ena_svpd = NULL;
454*49ef7e06SGarrett D'Amore 		enp->en_arch.ef10.ena_svpd_length = 0;
455*49ef7e06SGarrett D'Amore 	}
456*49ef7e06SGarrett D'Amore }
457*49ef7e06SGarrett D'Amore 
458*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
459*49ef7e06SGarrett D'Amore 
460*49ef7e06SGarrett D'Amore #endif	/* EFSYS_OPT_VPD */
461