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 #if EFSYS_OPT_SIENA
37*49ef7e06SGarrett D'Amore
38*49ef7e06SGarrett D'Amore static __checkReturn efx_rc_t
siena_vpd_get_static(__in efx_nic_t * enp,__in uint32_t partn,__deref_out_bcount_opt (* sizep)caddr_t * svpdp,__out size_t * sizep)39*49ef7e06SGarrett D'Amore siena_vpd_get_static(
40*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
41*49ef7e06SGarrett D'Amore __in uint32_t partn,
42*49ef7e06SGarrett D'Amore __deref_out_bcount_opt(*sizep) caddr_t *svpdp,
43*49ef7e06SGarrett D'Amore __out size_t *sizep)
44*49ef7e06SGarrett D'Amore {
45*49ef7e06SGarrett D'Amore siena_mc_static_config_hdr_t *scfg;
46*49ef7e06SGarrett D'Amore caddr_t svpd;
47*49ef7e06SGarrett D'Amore size_t size;
48*49ef7e06SGarrett D'Amore uint8_t cksum;
49*49ef7e06SGarrett D'Amore unsigned int vpd_offset;
50*49ef7e06SGarrett D'Amore unsigned int vpd_length;
51*49ef7e06SGarrett D'Amore unsigned int hdr_length;
52*49ef7e06SGarrett D'Amore unsigned int pos;
53*49ef7e06SGarrett D'Amore unsigned int region;
54*49ef7e06SGarrett D'Amore efx_rc_t rc;
55*49ef7e06SGarrett D'Amore
56*49ef7e06SGarrett D'Amore EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
57*49ef7e06SGarrett D'Amore partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
58*49ef7e06SGarrett D'Amore
59*49ef7e06SGarrett D'Amore /* Allocate sufficient memory for the entire static cfg area */
60*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
61*49ef7e06SGarrett D'Amore goto fail1;
62*49ef7e06SGarrett D'Amore
63*49ef7e06SGarrett D'Amore EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
64*49ef7e06SGarrett D'Amore if (scfg == NULL) {
65*49ef7e06SGarrett D'Amore rc = ENOMEM;
66*49ef7e06SGarrett D'Amore goto fail2;
67*49ef7e06SGarrett D'Amore }
68*49ef7e06SGarrett D'Amore
69*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_read(enp, partn, 0,
70*49ef7e06SGarrett D'Amore (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
71*49ef7e06SGarrett D'Amore goto fail3;
72*49ef7e06SGarrett D'Amore
73*49ef7e06SGarrett D'Amore /* Verify the magic number */
74*49ef7e06SGarrett D'Amore if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
75*49ef7e06SGarrett D'Amore SIENA_MC_STATIC_CONFIG_MAGIC) {
76*49ef7e06SGarrett D'Amore rc = EINVAL;
77*49ef7e06SGarrett D'Amore goto fail4;
78*49ef7e06SGarrett D'Amore }
79*49ef7e06SGarrett D'Amore
80*49ef7e06SGarrett D'Amore /* All future versions of the structure must be backwards compatable */
81*49ef7e06SGarrett D'Amore EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
82*49ef7e06SGarrett D'Amore
83*49ef7e06SGarrett D'Amore hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
84*49ef7e06SGarrett D'Amore vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
85*49ef7e06SGarrett D'Amore vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
86*49ef7e06SGarrett D'Amore
87*49ef7e06SGarrett D'Amore /* Verify the hdr doesn't overflow the sector size */
88*49ef7e06SGarrett D'Amore if (hdr_length > size || vpd_offset > size || vpd_length > size ||
89*49ef7e06SGarrett D'Amore vpd_length + vpd_offset > size) {
90*49ef7e06SGarrett D'Amore rc = EINVAL;
91*49ef7e06SGarrett D'Amore goto fail5;
92*49ef7e06SGarrett D'Amore }
93*49ef7e06SGarrett D'Amore
94*49ef7e06SGarrett D'Amore /* Read the remainder of scfg + static vpd */
95*49ef7e06SGarrett D'Amore region = vpd_offset + vpd_length;
96*49ef7e06SGarrett D'Amore if (region > SIENA_NVRAM_CHUNK) {
97*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
98*49ef7e06SGarrett D'Amore (caddr_t)scfg + SIENA_NVRAM_CHUNK,
99*49ef7e06SGarrett D'Amore region - SIENA_NVRAM_CHUNK)) != 0)
100*49ef7e06SGarrett D'Amore goto fail6;
101*49ef7e06SGarrett D'Amore }
102*49ef7e06SGarrett D'Amore
103*49ef7e06SGarrett D'Amore /* Verify checksum */
104*49ef7e06SGarrett D'Amore cksum = 0;
105*49ef7e06SGarrett D'Amore for (pos = 0; pos < hdr_length; pos++)
106*49ef7e06SGarrett D'Amore cksum += ((uint8_t *)scfg)[pos];
107*49ef7e06SGarrett D'Amore if (cksum != 0) {
108*49ef7e06SGarrett D'Amore rc = EINVAL;
109*49ef7e06SGarrett D'Amore goto fail7;
110*49ef7e06SGarrett D'Amore }
111*49ef7e06SGarrett D'Amore
112*49ef7e06SGarrett D'Amore if (vpd_length == 0)
113*49ef7e06SGarrett D'Amore svpd = NULL;
114*49ef7e06SGarrett D'Amore else {
115*49ef7e06SGarrett D'Amore /* Copy the vpd data out */
116*49ef7e06SGarrett D'Amore EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
117*49ef7e06SGarrett D'Amore if (svpd == NULL) {
118*49ef7e06SGarrett D'Amore rc = ENOMEM;
119*49ef7e06SGarrett D'Amore goto fail8;
120*49ef7e06SGarrett D'Amore }
121*49ef7e06SGarrett D'Amore (void) memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
122*49ef7e06SGarrett D'Amore }
123*49ef7e06SGarrett D'Amore
124*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
125*49ef7e06SGarrett D'Amore
126*49ef7e06SGarrett D'Amore *svpdp = svpd;
127*49ef7e06SGarrett D'Amore *sizep = vpd_length;
128*49ef7e06SGarrett D'Amore
129*49ef7e06SGarrett D'Amore return (0);
130*49ef7e06SGarrett D'Amore
131*49ef7e06SGarrett D'Amore fail8:
132*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail8);
133*49ef7e06SGarrett D'Amore fail7:
134*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail7);
135*49ef7e06SGarrett D'Amore fail6:
136*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail6);
137*49ef7e06SGarrett D'Amore fail5:
138*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail5);
139*49ef7e06SGarrett D'Amore fail4:
140*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail4);
141*49ef7e06SGarrett D'Amore fail3:
142*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail3);
143*49ef7e06SGarrett D'Amore
144*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
145*49ef7e06SGarrett D'Amore
146*49ef7e06SGarrett D'Amore fail2:
147*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
148*49ef7e06SGarrett D'Amore fail1:
149*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
150*49ef7e06SGarrett D'Amore
151*49ef7e06SGarrett D'Amore return (rc);
152*49ef7e06SGarrett D'Amore }
153*49ef7e06SGarrett D'Amore
154*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_init(__in efx_nic_t * enp)155*49ef7e06SGarrett D'Amore siena_vpd_init(
156*49ef7e06SGarrett D'Amore __in efx_nic_t *enp)
157*49ef7e06SGarrett D'Amore {
158*49ef7e06SGarrett D'Amore efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
159*49ef7e06SGarrett D'Amore caddr_t svpd = NULL;
160*49ef7e06SGarrett D'Amore unsigned partn;
161*49ef7e06SGarrett D'Amore size_t size = 0;
162*49ef7e06SGarrett D'Amore efx_rc_t rc;
163*49ef7e06SGarrett D'Amore
164*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
165*49ef7e06SGarrett D'Amore
166*49ef7e06SGarrett D'Amore partn = (emip->emi_port == 1)
167*49ef7e06SGarrett D'Amore ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
168*49ef7e06SGarrett D'Amore : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
169*49ef7e06SGarrett D'Amore
170*49ef7e06SGarrett D'Amore /*
171*49ef7e06SGarrett D'Amore * We need the static VPD sector to present a unified static+dynamic
172*49ef7e06SGarrett D'Amore * VPD, that is, basically on every read, write, verify cycle. Since
173*49ef7e06SGarrett D'Amore * it should *never* change we can just cache it here.
174*49ef7e06SGarrett D'Amore */
175*49ef7e06SGarrett D'Amore if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
176*49ef7e06SGarrett D'Amore goto fail1;
177*49ef7e06SGarrett D'Amore
178*49ef7e06SGarrett D'Amore if (svpd != NULL && size > 0) {
179*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
180*49ef7e06SGarrett D'Amore goto fail2;
181*49ef7e06SGarrett D'Amore }
182*49ef7e06SGarrett D'Amore
183*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd = svpd;
184*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length = size;
185*49ef7e06SGarrett D'Amore
186*49ef7e06SGarrett D'Amore return (0);
187*49ef7e06SGarrett D'Amore
188*49ef7e06SGarrett D'Amore fail2:
189*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
190*49ef7e06SGarrett D'Amore
191*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
192*49ef7e06SGarrett D'Amore fail1:
193*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
194*49ef7e06SGarrett D'Amore
195*49ef7e06SGarrett D'Amore return (rc);
196*49ef7e06SGarrett D'Amore }
197*49ef7e06SGarrett D'Amore
198*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_size(__in efx_nic_t * enp,__out size_t * sizep)199*49ef7e06SGarrett D'Amore siena_vpd_size(
200*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
201*49ef7e06SGarrett D'Amore __out size_t *sizep)
202*49ef7e06SGarrett D'Amore {
203*49ef7e06SGarrett D'Amore efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
204*49ef7e06SGarrett D'Amore uint32_t partn;
205*49ef7e06SGarrett D'Amore efx_rc_t rc;
206*49ef7e06SGarrett D'Amore
207*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
208*49ef7e06SGarrett D'Amore
209*49ef7e06SGarrett D'Amore /*
210*49ef7e06SGarrett D'Amore * This function returns the total size the user should allocate
211*49ef7e06SGarrett D'Amore * for all VPD operations. We've already cached the static vpd,
212*49ef7e06SGarrett D'Amore * so we just need to return an upper bound on the dynamic vpd.
213*49ef7e06SGarrett D'Amore * Since the dynamic_config structure can change under our feet,
214*49ef7e06SGarrett D'Amore * (as version numbers are inserted), just be safe and return the
215*49ef7e06SGarrett D'Amore * total size of the dynamic_config *sector*
216*49ef7e06SGarrett D'Amore */
217*49ef7e06SGarrett D'Amore partn = (emip->emi_port == 1)
218*49ef7e06SGarrett D'Amore ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
219*49ef7e06SGarrett D'Amore : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
220*49ef7e06SGarrett D'Amore
221*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
222*49ef7e06SGarrett D'Amore goto fail1;
223*49ef7e06SGarrett D'Amore
224*49ef7e06SGarrett D'Amore return (0);
225*49ef7e06SGarrett D'Amore
226*49ef7e06SGarrett D'Amore fail1:
227*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
228*49ef7e06SGarrett D'Amore
229*49ef7e06SGarrett D'Amore return (rc);
230*49ef7e06SGarrett D'Amore }
231*49ef7e06SGarrett D'Amore
232*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_read(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size)233*49ef7e06SGarrett D'Amore siena_vpd_read(
234*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
235*49ef7e06SGarrett D'Amore __out_bcount(size) caddr_t data,
236*49ef7e06SGarrett D'Amore __in size_t size)
237*49ef7e06SGarrett D'Amore {
238*49ef7e06SGarrett D'Amore efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
239*49ef7e06SGarrett D'Amore siena_mc_dynamic_config_hdr_t *dcfg = NULL;
240*49ef7e06SGarrett D'Amore unsigned int vpd_length;
241*49ef7e06SGarrett D'Amore unsigned int vpd_offset;
242*49ef7e06SGarrett D'Amore unsigned int dcfg_partn;
243*49ef7e06SGarrett D'Amore size_t dcfg_size;
244*49ef7e06SGarrett D'Amore efx_rc_t rc;
245*49ef7e06SGarrett D'Amore
246*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
247*49ef7e06SGarrett D'Amore
248*49ef7e06SGarrett D'Amore dcfg_partn = (emip->emi_port == 1)
249*49ef7e06SGarrett D'Amore ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
250*49ef7e06SGarrett D'Amore : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
251*49ef7e06SGarrett D'Amore
252*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
253*49ef7e06SGarrett D'Amore B_TRUE, &dcfg, &dcfg_size)) != 0)
254*49ef7e06SGarrett D'Amore goto fail1;
255*49ef7e06SGarrett D'Amore
256*49ef7e06SGarrett D'Amore vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
257*49ef7e06SGarrett D'Amore vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
258*49ef7e06SGarrett D'Amore
259*49ef7e06SGarrett D'Amore if (vpd_length > size) {
260*49ef7e06SGarrett D'Amore rc = EFAULT; /* Invalid dcfg: header bigger than sector */
261*49ef7e06SGarrett D'Amore goto fail2;
262*49ef7e06SGarrett D'Amore }
263*49ef7e06SGarrett D'Amore
264*49ef7e06SGarrett D'Amore EFSYS_ASSERT3U(vpd_length, <=, size);
265*49ef7e06SGarrett D'Amore (void) memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
266*49ef7e06SGarrett D'Amore
267*49ef7e06SGarrett D'Amore /* Pad data with all-1s, consistent with update operations */
268*49ef7e06SGarrett D'Amore (void) memset(data + vpd_length, 0xff, size - vpd_length);
269*49ef7e06SGarrett D'Amore
270*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
271*49ef7e06SGarrett D'Amore
272*49ef7e06SGarrett D'Amore return (0);
273*49ef7e06SGarrett D'Amore
274*49ef7e06SGarrett D'Amore fail2:
275*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
276*49ef7e06SGarrett D'Amore
277*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
278*49ef7e06SGarrett D'Amore fail1:
279*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
280*49ef7e06SGarrett D'Amore
281*49ef7e06SGarrett D'Amore return (rc);
282*49ef7e06SGarrett D'Amore }
283*49ef7e06SGarrett D'Amore
284*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_verify(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)285*49ef7e06SGarrett D'Amore siena_vpd_verify(
286*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
287*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
288*49ef7e06SGarrett D'Amore __in size_t size)
289*49ef7e06SGarrett D'Amore {
290*49ef7e06SGarrett D'Amore efx_vpd_tag_t stag;
291*49ef7e06SGarrett D'Amore efx_vpd_tag_t dtag;
292*49ef7e06SGarrett D'Amore efx_vpd_keyword_t skey;
293*49ef7e06SGarrett D'Amore efx_vpd_keyword_t dkey;
294*49ef7e06SGarrett D'Amore unsigned int scont;
295*49ef7e06SGarrett D'Amore unsigned int dcont;
296*49ef7e06SGarrett D'Amore
297*49ef7e06SGarrett D'Amore efx_rc_t rc;
298*49ef7e06SGarrett D'Amore
299*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
300*49ef7e06SGarrett D'Amore
301*49ef7e06SGarrett D'Amore /*
302*49ef7e06SGarrett D'Amore * Strictly you could take the view that dynamic vpd is optional.
303*49ef7e06SGarrett D'Amore * Instead, to conform more closely to the read/verify/reinit()
304*49ef7e06SGarrett D'Amore * paradigm, we require dynamic vpd. siena_vpd_reinit() will
305*49ef7e06SGarrett D'Amore * reinitialize it as required.
306*49ef7e06SGarrett D'Amore */
307*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
308*49ef7e06SGarrett D'Amore goto fail1;
309*49ef7e06SGarrett D'Amore
310*49ef7e06SGarrett D'Amore /*
311*49ef7e06SGarrett D'Amore * Verify that there is no duplication between the static and
312*49ef7e06SGarrett D'Amore * dynamic cfg sectors.
313*49ef7e06SGarrett D'Amore */
314*49ef7e06SGarrett D'Amore if (enp->en_u.siena.enu_svpd_length == 0)
315*49ef7e06SGarrett D'Amore goto done;
316*49ef7e06SGarrett D'Amore
317*49ef7e06SGarrett D'Amore dcont = 0;
318*49ef7e06SGarrett D'Amore _NOTE(CONSTANTCONDITION)
319*49ef7e06SGarrett D'Amore while (1) {
320*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_next(data, size, &dtag,
321*49ef7e06SGarrett D'Amore &dkey, NULL, NULL, &dcont)) != 0)
322*49ef7e06SGarrett D'Amore goto fail2;
323*49ef7e06SGarrett D'Amore if (dcont == 0)
324*49ef7e06SGarrett D'Amore break;
325*49ef7e06SGarrett D'Amore
326*49ef7e06SGarrett D'Amore /*
327*49ef7e06SGarrett D'Amore * Skip the RV keyword. It should be present in both the static
328*49ef7e06SGarrett D'Amore * and dynamic cfg sectors.
329*49ef7e06SGarrett D'Amore */
330*49ef7e06SGarrett D'Amore if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
331*49ef7e06SGarrett D'Amore continue;
332*49ef7e06SGarrett D'Amore
333*49ef7e06SGarrett D'Amore scont = 0;
334*49ef7e06SGarrett D'Amore _NOTE(CONSTANTCONDITION)
335*49ef7e06SGarrett D'Amore while (1) {
336*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_next(
337*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd,
338*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length, &stag, &skey,
339*49ef7e06SGarrett D'Amore NULL, NULL, &scont)) != 0)
340*49ef7e06SGarrett D'Amore goto fail3;
341*49ef7e06SGarrett D'Amore if (scont == 0)
342*49ef7e06SGarrett D'Amore break;
343*49ef7e06SGarrett D'Amore
344*49ef7e06SGarrett D'Amore if (stag == dtag && skey == dkey) {
345*49ef7e06SGarrett D'Amore rc = EEXIST;
346*49ef7e06SGarrett D'Amore goto fail4;
347*49ef7e06SGarrett D'Amore }
348*49ef7e06SGarrett D'Amore }
349*49ef7e06SGarrett D'Amore }
350*49ef7e06SGarrett D'Amore
351*49ef7e06SGarrett D'Amore done:
352*49ef7e06SGarrett D'Amore return (0);
353*49ef7e06SGarrett D'Amore
354*49ef7e06SGarrett D'Amore fail4:
355*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail4);
356*49ef7e06SGarrett D'Amore fail3:
357*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail3);
358*49ef7e06SGarrett D'Amore fail2:
359*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
360*49ef7e06SGarrett D'Amore fail1:
361*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
362*49ef7e06SGarrett D'Amore
363*49ef7e06SGarrett D'Amore return (rc);
364*49ef7e06SGarrett D'Amore }
365*49ef7e06SGarrett D'Amore
366*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_reinit(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)367*49ef7e06SGarrett D'Amore siena_vpd_reinit(
368*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
369*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
370*49ef7e06SGarrett D'Amore __in size_t size)
371*49ef7e06SGarrett D'Amore {
372*49ef7e06SGarrett D'Amore boolean_t wantpid;
373*49ef7e06SGarrett D'Amore efx_rc_t rc;
374*49ef7e06SGarrett D'Amore
375*49ef7e06SGarrett D'Amore /*
376*49ef7e06SGarrett D'Amore * Only create a PID if the dynamic cfg doesn't have one
377*49ef7e06SGarrett D'Amore */
378*49ef7e06SGarrett D'Amore if (enp->en_u.siena.enu_svpd_length == 0)
379*49ef7e06SGarrett D'Amore wantpid = B_TRUE;
380*49ef7e06SGarrett D'Amore else {
381*49ef7e06SGarrett D'Amore unsigned int offset;
382*49ef7e06SGarrett D'Amore uint8_t length;
383*49ef7e06SGarrett D'Amore
384*49ef7e06SGarrett D'Amore rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
385*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length,
386*49ef7e06SGarrett D'Amore EFX_VPD_ID, 0, &offset, &length);
387*49ef7e06SGarrett D'Amore if (rc == 0)
388*49ef7e06SGarrett D'Amore wantpid = B_FALSE;
389*49ef7e06SGarrett D'Amore else if (rc == ENOENT)
390*49ef7e06SGarrett D'Amore wantpid = B_TRUE;
391*49ef7e06SGarrett D'Amore else
392*49ef7e06SGarrett D'Amore goto fail1;
393*49ef7e06SGarrett D'Amore }
394*49ef7e06SGarrett D'Amore
395*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
396*49ef7e06SGarrett D'Amore goto fail2;
397*49ef7e06SGarrett D'Amore
398*49ef7e06SGarrett D'Amore return (0);
399*49ef7e06SGarrett D'Amore
400*49ef7e06SGarrett D'Amore fail2:
401*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
402*49ef7e06SGarrett D'Amore fail1:
403*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
404*49ef7e06SGarrett D'Amore
405*49ef7e06SGarrett D'Amore return (rc);
406*49ef7e06SGarrett D'Amore }
407*49ef7e06SGarrett D'Amore
408*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_get(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__inout efx_vpd_value_t * evvp)409*49ef7e06SGarrett D'Amore siena_vpd_get(
410*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
411*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
412*49ef7e06SGarrett D'Amore __in size_t size,
413*49ef7e06SGarrett D'Amore __inout efx_vpd_value_t *evvp)
414*49ef7e06SGarrett D'Amore {
415*49ef7e06SGarrett D'Amore unsigned int offset;
416*49ef7e06SGarrett D'Amore uint8_t length;
417*49ef7e06SGarrett D'Amore efx_rc_t rc;
418*49ef7e06SGarrett D'Amore
419*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
420*49ef7e06SGarrett D'Amore
421*49ef7e06SGarrett D'Amore /* Attempt to satisfy the request from svpd first */
422*49ef7e06SGarrett D'Amore if (enp->en_u.siena.enu_svpd_length > 0) {
423*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
424*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
425*49ef7e06SGarrett D'Amore evvp->evv_keyword, &offset, &length)) == 0) {
426*49ef7e06SGarrett D'Amore evvp->evv_length = length;
427*49ef7e06SGarrett D'Amore (void) memcpy(evvp->evv_value,
428*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd + offset, length);
429*49ef7e06SGarrett D'Amore return (0);
430*49ef7e06SGarrett D'Amore } else if (rc != ENOENT)
431*49ef7e06SGarrett D'Amore goto fail1;
432*49ef7e06SGarrett D'Amore }
433*49ef7e06SGarrett D'Amore
434*49ef7e06SGarrett D'Amore /* And then from the provided data buffer */
435*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
436*49ef7e06SGarrett D'Amore evvp->evv_keyword, &offset, &length)) != 0)
437*49ef7e06SGarrett D'Amore goto fail2;
438*49ef7e06SGarrett D'Amore
439*49ef7e06SGarrett D'Amore evvp->evv_length = length;
440*49ef7e06SGarrett D'Amore (void) memcpy(evvp->evv_value, data + offset, length);
441*49ef7e06SGarrett D'Amore
442*49ef7e06SGarrett D'Amore return (0);
443*49ef7e06SGarrett D'Amore
444*49ef7e06SGarrett D'Amore fail2:
445*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
446*49ef7e06SGarrett D'Amore fail1:
447*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
448*49ef7e06SGarrett D'Amore
449*49ef7e06SGarrett D'Amore return (rc);
450*49ef7e06SGarrett D'Amore }
451*49ef7e06SGarrett D'Amore
452*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_set(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)453*49ef7e06SGarrett D'Amore siena_vpd_set(
454*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
455*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
456*49ef7e06SGarrett D'Amore __in size_t size,
457*49ef7e06SGarrett D'Amore __in efx_vpd_value_t *evvp)
458*49ef7e06SGarrett D'Amore {
459*49ef7e06SGarrett D'Amore efx_rc_t rc;
460*49ef7e06SGarrett D'Amore
461*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
462*49ef7e06SGarrett D'Amore
463*49ef7e06SGarrett D'Amore /* If the provided (tag,keyword) exists in svpd, then it is readonly */
464*49ef7e06SGarrett D'Amore if (enp->en_u.siena.enu_svpd_length > 0) {
465*49ef7e06SGarrett D'Amore unsigned int offset;
466*49ef7e06SGarrett D'Amore uint8_t length;
467*49ef7e06SGarrett D'Amore
468*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
469*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
470*49ef7e06SGarrett D'Amore evvp->evv_keyword, &offset, &length)) == 0) {
471*49ef7e06SGarrett D'Amore rc = EACCES;
472*49ef7e06SGarrett D'Amore goto fail1;
473*49ef7e06SGarrett D'Amore }
474*49ef7e06SGarrett D'Amore }
475*49ef7e06SGarrett D'Amore
476*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
477*49ef7e06SGarrett D'Amore goto fail2;
478*49ef7e06SGarrett D'Amore
479*49ef7e06SGarrett D'Amore return (0);
480*49ef7e06SGarrett D'Amore
481*49ef7e06SGarrett D'Amore fail2:
482*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
483*49ef7e06SGarrett D'Amore fail1:
484*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
485*49ef7e06SGarrett D'Amore
486*49ef7e06SGarrett D'Amore return (rc);
487*49ef7e06SGarrett D'Amore }
488*49ef7e06SGarrett D'Amore
489*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_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)490*49ef7e06SGarrett D'Amore siena_vpd_next(
491*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
492*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
493*49ef7e06SGarrett D'Amore __in size_t size,
494*49ef7e06SGarrett D'Amore __out efx_vpd_value_t *evvp,
495*49ef7e06SGarrett D'Amore __inout unsigned int *contp)
496*49ef7e06SGarrett D'Amore {
497*49ef7e06SGarrett D'Amore _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
498*49ef7e06SGarrett D'Amore
499*49ef7e06SGarrett D'Amore return (ENOTSUP);
500*49ef7e06SGarrett D'Amore }
501*49ef7e06SGarrett D'Amore
502*49ef7e06SGarrett D'Amore __checkReturn efx_rc_t
siena_vpd_write(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)503*49ef7e06SGarrett D'Amore siena_vpd_write(
504*49ef7e06SGarrett D'Amore __in efx_nic_t *enp,
505*49ef7e06SGarrett D'Amore __in_bcount(size) caddr_t data,
506*49ef7e06SGarrett D'Amore __in size_t size)
507*49ef7e06SGarrett D'Amore {
508*49ef7e06SGarrett D'Amore efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
509*49ef7e06SGarrett D'Amore siena_mc_dynamic_config_hdr_t *dcfg = NULL;
510*49ef7e06SGarrett D'Amore unsigned int vpd_offset;
511*49ef7e06SGarrett D'Amore unsigned int dcfg_partn;
512*49ef7e06SGarrett D'Amore unsigned int hdr_length;
513*49ef7e06SGarrett D'Amore unsigned int pos;
514*49ef7e06SGarrett D'Amore uint8_t cksum;
515*49ef7e06SGarrett D'Amore size_t partn_size, dcfg_size;
516*49ef7e06SGarrett D'Amore size_t vpd_length;
517*49ef7e06SGarrett D'Amore efx_rc_t rc;
518*49ef7e06SGarrett D'Amore
519*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
520*49ef7e06SGarrett D'Amore
521*49ef7e06SGarrett D'Amore /* Determine total length of all tags */
522*49ef7e06SGarrett D'Amore if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
523*49ef7e06SGarrett D'Amore goto fail1;
524*49ef7e06SGarrett D'Amore
525*49ef7e06SGarrett D'Amore /* Lock dynamic config sector for write, and read structure only */
526*49ef7e06SGarrett D'Amore dcfg_partn = (emip->emi_port == 1)
527*49ef7e06SGarrett D'Amore ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
528*49ef7e06SGarrett D'Amore : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
529*49ef7e06SGarrett D'Amore
530*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
531*49ef7e06SGarrett D'Amore goto fail2;
532*49ef7e06SGarrett D'Amore
533*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
534*49ef7e06SGarrett D'Amore goto fail3;
535*49ef7e06SGarrett D'Amore
536*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
537*49ef7e06SGarrett D'Amore B_FALSE, &dcfg, &dcfg_size)) != 0)
538*49ef7e06SGarrett D'Amore goto fail4;
539*49ef7e06SGarrett D'Amore
540*49ef7e06SGarrett D'Amore hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
541*49ef7e06SGarrett D'Amore
542*49ef7e06SGarrett D'Amore /* Allocated memory should have room for the new VPD */
543*49ef7e06SGarrett D'Amore if (hdr_length + vpd_length > dcfg_size) {
544*49ef7e06SGarrett D'Amore rc = ENOSPC;
545*49ef7e06SGarrett D'Amore goto fail5;
546*49ef7e06SGarrett D'Amore }
547*49ef7e06SGarrett D'Amore
548*49ef7e06SGarrett D'Amore /* Copy in new vpd and update header */
549*49ef7e06SGarrett D'Amore vpd_offset = dcfg_size - vpd_length;
550*49ef7e06SGarrett D'Amore EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
551*49ef7e06SGarrett D'Amore (void) memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
552*49ef7e06SGarrett D'Amore EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
553*49ef7e06SGarrett D'Amore
554*49ef7e06SGarrett D'Amore /* Update the checksum */
555*49ef7e06SGarrett D'Amore cksum = 0;
556*49ef7e06SGarrett D'Amore for (pos = 0; pos < hdr_length; pos++)
557*49ef7e06SGarrett D'Amore cksum += ((uint8_t *)dcfg)[pos];
558*49ef7e06SGarrett D'Amore dcfg->csum.eb_u8[0] -= cksum;
559*49ef7e06SGarrett D'Amore
560*49ef7e06SGarrett D'Amore /* Erase and write the new sector */
561*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
562*49ef7e06SGarrett D'Amore goto fail6;
563*49ef7e06SGarrett D'Amore
564*49ef7e06SGarrett D'Amore /* Write out the new structure to nvram */
565*49ef7e06SGarrett D'Amore if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
566*49ef7e06SGarrett D'Amore vpd_offset + vpd_length)) != 0)
567*49ef7e06SGarrett D'Amore goto fail7;
568*49ef7e06SGarrett D'Amore
569*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
570*49ef7e06SGarrett D'Amore
571*49ef7e06SGarrett D'Amore siena_nvram_partn_unlock(enp, dcfg_partn);
572*49ef7e06SGarrett D'Amore
573*49ef7e06SGarrett D'Amore return (0);
574*49ef7e06SGarrett D'Amore
575*49ef7e06SGarrett D'Amore fail7:
576*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail7);
577*49ef7e06SGarrett D'Amore fail6:
578*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail6);
579*49ef7e06SGarrett D'Amore fail5:
580*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail5);
581*49ef7e06SGarrett D'Amore
582*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
583*49ef7e06SGarrett D'Amore fail4:
584*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail4);
585*49ef7e06SGarrett D'Amore
586*49ef7e06SGarrett D'Amore siena_nvram_partn_unlock(enp, dcfg_partn);
587*49ef7e06SGarrett D'Amore fail3:
588*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail3);
589*49ef7e06SGarrett D'Amore fail2:
590*49ef7e06SGarrett D'Amore EFSYS_PROBE(fail2);
591*49ef7e06SGarrett D'Amore fail1:
592*49ef7e06SGarrett D'Amore EFSYS_PROBE1(fail1, efx_rc_t, rc);
593*49ef7e06SGarrett D'Amore
594*49ef7e06SGarrett D'Amore return (rc);
595*49ef7e06SGarrett D'Amore }
596*49ef7e06SGarrett D'Amore
597*49ef7e06SGarrett D'Amore void
siena_vpd_fini(__in efx_nic_t * enp)598*49ef7e06SGarrett D'Amore siena_vpd_fini(
599*49ef7e06SGarrett D'Amore __in efx_nic_t *enp)
600*49ef7e06SGarrett D'Amore {
601*49ef7e06SGarrett D'Amore EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
602*49ef7e06SGarrett D'Amore
603*49ef7e06SGarrett D'Amore if (enp->en_u.siena.enu_svpd_length > 0) {
604*49ef7e06SGarrett D'Amore EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
605*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd);
606*49ef7e06SGarrett D'Amore
607*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd = NULL;
608*49ef7e06SGarrett D'Amore enp->en_u.siena.enu_svpd_length = 0;
609*49ef7e06SGarrett D'Amore }
610*49ef7e06SGarrett D'Amore }
611*49ef7e06SGarrett D'Amore
612*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_SIENA */
613*49ef7e06SGarrett D'Amore
614*49ef7e06SGarrett D'Amore #endif /* EFSYS_OPT_VPD */
615