1e948693eSPhilip Paeps /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4929c7febSAndrew Rybchenko * Copyright (c) 2009-2016 Solarflare Communications Inc.
53c838a9fSAndrew Rybchenko * All rights reserved.
6e948693eSPhilip Paeps *
7e948693eSPhilip Paeps * Redistribution and use in source and binary forms, with or without
83c838a9fSAndrew Rybchenko * modification, are permitted provided that the following conditions are met:
9e948693eSPhilip Paeps *
103c838a9fSAndrew Rybchenko * 1. Redistributions of source code must retain the above copyright notice,
113c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer.
123c838a9fSAndrew Rybchenko * 2. Redistributions in binary form must reproduce the above copyright notice,
133c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer in the documentation
143c838a9fSAndrew Rybchenko * and/or other materials provided with the distribution.
153c838a9fSAndrew Rybchenko *
163c838a9fSAndrew Rybchenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173c838a9fSAndrew Rybchenko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
183c838a9fSAndrew Rybchenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193c838a9fSAndrew Rybchenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
203c838a9fSAndrew Rybchenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213c838a9fSAndrew Rybchenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223c838a9fSAndrew Rybchenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
233c838a9fSAndrew Rybchenko * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243c838a9fSAndrew Rybchenko * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
253c838a9fSAndrew Rybchenko * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
263c838a9fSAndrew Rybchenko * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273c838a9fSAndrew Rybchenko *
283c838a9fSAndrew Rybchenko * The views and conclusions contained in the software and documentation are
293c838a9fSAndrew Rybchenko * those of the authors and should not be interpreted as representing official
303c838a9fSAndrew Rybchenko * policies, either expressed or implied, of the FreeBSD Project.
31e948693eSPhilip Paeps */
32e948693eSPhilip Paeps
335dee87d7SPhilip Paeps #include <sys/cdefs.h>
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps
37e948693eSPhilip Paeps #if EFSYS_OPT_VPD
38e948693eSPhilip Paeps
39e948693eSPhilip Paeps #define TAG_TYPE_LBN 7
40e948693eSPhilip Paeps #define TAG_TYPE_WIDTH 1
41e948693eSPhilip Paeps #define TAG_TYPE_LARGE_ITEM_DECODE 1
42e948693eSPhilip Paeps #define TAG_TYPE_SMALL_ITEM_DECODE 0
43e948693eSPhilip Paeps
44e948693eSPhilip Paeps #define TAG_SMALL_ITEM_NAME_LBN 3
45e948693eSPhilip Paeps #define TAG_SMALL_ITEM_NAME_WIDTH 4
46e948693eSPhilip Paeps #define TAG_SMALL_ITEM_SIZE_LBN 0
47e948693eSPhilip Paeps #define TAG_SMALL_ITEM_SIZE_WIDTH 3
48e948693eSPhilip Paeps
49e948693eSPhilip Paeps #define TAG_LARGE_ITEM_NAME_LBN 0
50e948693eSPhilip Paeps #define TAG_LARGE_ITEM_NAME_WIDTH 7
51e948693eSPhilip Paeps
52e948693eSPhilip Paeps #define TAG_NAME_END_DECODE 0x0f
53e948693eSPhilip Paeps #define TAG_NAME_ID_STRING_DECODE 0x02
54e948693eSPhilip Paeps #define TAG_NAME_VPD_R_DECODE 0x10
55e948693eSPhilip Paeps #define TAG_NAME_VPD_W_DECODE 0x11
56e948693eSPhilip Paeps
57e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
58e948693eSPhilip Paeps
59ec831f7fSAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_siena_ops = {
60e948693eSPhilip Paeps siena_vpd_init, /* evpdo_init */
61e948693eSPhilip Paeps siena_vpd_size, /* evpdo_size */
62e948693eSPhilip Paeps siena_vpd_read, /* evpdo_read */
63e948693eSPhilip Paeps siena_vpd_verify, /* evpdo_verify */
64e948693eSPhilip Paeps siena_vpd_reinit, /* evpdo_reinit */
65e948693eSPhilip Paeps siena_vpd_get, /* evpdo_get */
66e948693eSPhilip Paeps siena_vpd_set, /* evpdo_set */
67e948693eSPhilip Paeps siena_vpd_next, /* evpdo_next */
68e948693eSPhilip Paeps siena_vpd_write, /* evpdo_write */
69e948693eSPhilip Paeps siena_vpd_fini, /* evpdo_fini */
70e948693eSPhilip Paeps };
71e948693eSPhilip Paeps
72e948693eSPhilip Paeps #endif /* EFSYS_OPT_SIENA */
73e948693eSPhilip Paeps
7477226f89SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
753c838a9fSAndrew Rybchenko
76ec831f7fSAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
775311abfaSAndrew Rybchenko ef10_vpd_init, /* evpdo_init */
785311abfaSAndrew Rybchenko ef10_vpd_size, /* evpdo_size */
795311abfaSAndrew Rybchenko ef10_vpd_read, /* evpdo_read */
805311abfaSAndrew Rybchenko ef10_vpd_verify, /* evpdo_verify */
815311abfaSAndrew Rybchenko ef10_vpd_reinit, /* evpdo_reinit */
825311abfaSAndrew Rybchenko ef10_vpd_get, /* evpdo_get */
835311abfaSAndrew Rybchenko ef10_vpd_set, /* evpdo_set */
845311abfaSAndrew Rybchenko ef10_vpd_next, /* evpdo_next */
855311abfaSAndrew Rybchenko ef10_vpd_write, /* evpdo_write */
865311abfaSAndrew Rybchenko ef10_vpd_fini, /* evpdo_fini */
873c838a9fSAndrew Rybchenko };
883c838a9fSAndrew Rybchenko
8977226f89SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
903c838a9fSAndrew Rybchenko
91460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_init(__in efx_nic_t * enp)92e948693eSPhilip Paeps efx_vpd_init(
93e948693eSPhilip Paeps __in efx_nic_t *enp)
94e948693eSPhilip Paeps {
95ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop;
96460cb568SAndrew Rybchenko efx_rc_t rc;
97e948693eSPhilip Paeps
98e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
99e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
100e948693eSPhilip Paeps EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
101e948693eSPhilip Paeps
102e948693eSPhilip Paeps switch (enp->en_family) {
103e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
104e948693eSPhilip Paeps case EFX_FAMILY_SIENA:
105ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_siena_ops;
106e948693eSPhilip Paeps break;
107e948693eSPhilip Paeps #endif /* EFSYS_OPT_SIENA */
108e948693eSPhilip Paeps
1093c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1103c838a9fSAndrew Rybchenko case EFX_FAMILY_HUNTINGTON:
111ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
1123c838a9fSAndrew Rybchenko break;
1133c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
1143c838a9fSAndrew Rybchenko
1155311abfaSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
1165311abfaSAndrew Rybchenko case EFX_FAMILY_MEDFORD:
117ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
1185311abfaSAndrew Rybchenko break;
1195311abfaSAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
1205311abfaSAndrew Rybchenko
12177226f89SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
12277226f89SAndrew Rybchenko case EFX_FAMILY_MEDFORD2:
12377226f89SAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
12477226f89SAndrew Rybchenko break;
12577226f89SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
12677226f89SAndrew Rybchenko
127e948693eSPhilip Paeps default:
128e948693eSPhilip Paeps EFSYS_ASSERT(0);
129e948693eSPhilip Paeps rc = ENOTSUP;
130e948693eSPhilip Paeps goto fail1;
131e948693eSPhilip Paeps }
132e948693eSPhilip Paeps
133e948693eSPhilip Paeps if (evpdop->evpdo_init != NULL) {
134e948693eSPhilip Paeps if ((rc = evpdop->evpdo_init(enp)) != 0)
135e948693eSPhilip Paeps goto fail2;
136e948693eSPhilip Paeps }
137e948693eSPhilip Paeps
138e948693eSPhilip Paeps enp->en_evpdop = evpdop;
139e948693eSPhilip Paeps enp->en_mod_flags |= EFX_MOD_VPD;
140e948693eSPhilip Paeps
141e948693eSPhilip Paeps return (0);
142e948693eSPhilip Paeps
143e948693eSPhilip Paeps fail2:
144e948693eSPhilip Paeps EFSYS_PROBE(fail2);
145e948693eSPhilip Paeps fail1:
146460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
147e948693eSPhilip Paeps
148e948693eSPhilip Paeps return (rc);
149e948693eSPhilip Paeps }
150e948693eSPhilip Paeps
151460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_size(__in efx_nic_t * enp,__out size_t * sizep)152e948693eSPhilip Paeps efx_vpd_size(
153e948693eSPhilip Paeps __in efx_nic_t *enp,
154e948693eSPhilip Paeps __out size_t *sizep)
155e948693eSPhilip Paeps {
156ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
157460cb568SAndrew Rybchenko efx_rc_t rc;
158e948693eSPhilip Paeps
159e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
160e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
161e948693eSPhilip Paeps
162e948693eSPhilip Paeps if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
163e948693eSPhilip Paeps goto fail1;
164e948693eSPhilip Paeps
165e948693eSPhilip Paeps return (0);
166e948693eSPhilip Paeps
167e948693eSPhilip Paeps fail1:
168460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
169e948693eSPhilip Paeps
170e948693eSPhilip Paeps return (rc);
171e948693eSPhilip Paeps }
172e948693eSPhilip Paeps
173460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_read(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size)174e948693eSPhilip Paeps efx_vpd_read(
175e948693eSPhilip Paeps __in efx_nic_t *enp,
176e948693eSPhilip Paeps __out_bcount(size) caddr_t data,
177e948693eSPhilip Paeps __in size_t size)
178e948693eSPhilip Paeps {
179ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
180460cb568SAndrew Rybchenko efx_rc_t rc;
181e948693eSPhilip Paeps
182e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
183e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
184e948693eSPhilip Paeps
185e948693eSPhilip Paeps if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
186e948693eSPhilip Paeps goto fail1;
187e948693eSPhilip Paeps
188e948693eSPhilip Paeps return (0);
189e948693eSPhilip Paeps
190e948693eSPhilip Paeps fail1:
191460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
192e948693eSPhilip Paeps
193e948693eSPhilip Paeps return (rc);
194e948693eSPhilip Paeps }
195e948693eSPhilip Paeps
196460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_verify(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)197e948693eSPhilip Paeps efx_vpd_verify(
198e948693eSPhilip Paeps __in efx_nic_t *enp,
199e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
200e948693eSPhilip Paeps __in size_t size)
201e948693eSPhilip Paeps {
202ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
203460cb568SAndrew Rybchenko efx_rc_t rc;
204e948693eSPhilip Paeps
205e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
206e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
207e948693eSPhilip Paeps
208e948693eSPhilip Paeps if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
209e948693eSPhilip Paeps goto fail1;
210e948693eSPhilip Paeps
211e948693eSPhilip Paeps return (0);
212e948693eSPhilip Paeps
213e948693eSPhilip Paeps fail1:
214460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
215e948693eSPhilip Paeps
216e948693eSPhilip Paeps return (rc);
217e948693eSPhilip Paeps }
218e948693eSPhilip Paeps
219460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_reinit(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)220e948693eSPhilip Paeps efx_vpd_reinit(
221e948693eSPhilip Paeps __in efx_nic_t *enp,
222e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
223e948693eSPhilip Paeps __in size_t size)
224e948693eSPhilip Paeps {
225ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
226460cb568SAndrew Rybchenko efx_rc_t rc;
227e948693eSPhilip Paeps
228e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
229e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
230e948693eSPhilip Paeps
231e948693eSPhilip Paeps if (evpdop->evpdo_reinit == NULL) {
232e948693eSPhilip Paeps rc = ENOTSUP;
233e948693eSPhilip Paeps goto fail1;
234e948693eSPhilip Paeps }
235e948693eSPhilip Paeps
236e948693eSPhilip Paeps if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
237e948693eSPhilip Paeps goto fail2;
238e948693eSPhilip Paeps
239e948693eSPhilip Paeps return (0);
240e948693eSPhilip Paeps
241e948693eSPhilip Paeps fail2:
242e948693eSPhilip Paeps EFSYS_PROBE(fail2);
243e948693eSPhilip Paeps fail1:
244460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
245e948693eSPhilip Paeps
246e948693eSPhilip Paeps return (rc);
247e948693eSPhilip Paeps }
248e948693eSPhilip Paeps
249460cb568SAndrew Rybchenko __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)250e948693eSPhilip Paeps efx_vpd_get(
251e948693eSPhilip Paeps __in efx_nic_t *enp,
252e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
253e948693eSPhilip Paeps __in size_t size,
254e948693eSPhilip Paeps __inout efx_vpd_value_t *evvp)
255e948693eSPhilip Paeps {
256ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
257460cb568SAndrew Rybchenko efx_rc_t rc;
258e948693eSPhilip Paeps
259e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
260e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
261e948693eSPhilip Paeps
26201215be2SAndrew Rybchenko if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
26301215be2SAndrew Rybchenko if (rc == ENOENT)
26401215be2SAndrew Rybchenko return (rc);
26501215be2SAndrew Rybchenko
266e948693eSPhilip Paeps goto fail1;
26701215be2SAndrew Rybchenko }
268e948693eSPhilip Paeps
269e948693eSPhilip Paeps return (0);
270e948693eSPhilip Paeps
271e948693eSPhilip Paeps fail1:
272460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
273e948693eSPhilip Paeps
274e948693eSPhilip Paeps return (rc);
275e948693eSPhilip Paeps }
276e948693eSPhilip Paeps
277460cb568SAndrew Rybchenko __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)278e948693eSPhilip Paeps efx_vpd_set(
279e948693eSPhilip Paeps __in efx_nic_t *enp,
280e948693eSPhilip Paeps __inout_bcount(size) caddr_t data,
281e948693eSPhilip Paeps __in size_t size,
282e948693eSPhilip Paeps __in efx_vpd_value_t *evvp)
283e948693eSPhilip Paeps {
284ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
285460cb568SAndrew Rybchenko efx_rc_t rc;
286e948693eSPhilip Paeps
287e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
288e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
289e948693eSPhilip Paeps
290e948693eSPhilip Paeps if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
291e948693eSPhilip Paeps goto fail1;
292e948693eSPhilip Paeps
293e948693eSPhilip Paeps return (0);
294e948693eSPhilip Paeps
295e948693eSPhilip Paeps fail1:
296460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
297e948693eSPhilip Paeps
298e948693eSPhilip Paeps return (rc);
299e948693eSPhilip Paeps }
300e948693eSPhilip Paeps
301460cb568SAndrew Rybchenko __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)302e948693eSPhilip Paeps efx_vpd_next(
303e948693eSPhilip Paeps __in efx_nic_t *enp,
304e948693eSPhilip Paeps __inout_bcount(size) caddr_t data,
305e948693eSPhilip Paeps __in size_t size,
306e948693eSPhilip Paeps __out efx_vpd_value_t *evvp,
307e948693eSPhilip Paeps __inout unsigned int *contp)
308e948693eSPhilip Paeps {
309ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
310460cb568SAndrew Rybchenko efx_rc_t rc;
311e948693eSPhilip Paeps
312e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
313e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
314e948693eSPhilip Paeps
315e948693eSPhilip Paeps if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
316e948693eSPhilip Paeps goto fail1;
317e948693eSPhilip Paeps
318e948693eSPhilip Paeps return (0);
319e948693eSPhilip Paeps
320e948693eSPhilip Paeps fail1:
321460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
322e948693eSPhilip Paeps
323e948693eSPhilip Paeps return (rc);
324e948693eSPhilip Paeps }
325e948693eSPhilip Paeps
326460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_write(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)327e948693eSPhilip Paeps efx_vpd_write(
328e948693eSPhilip Paeps __in efx_nic_t *enp,
329e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
330e948693eSPhilip Paeps __in size_t size)
331e948693eSPhilip Paeps {
332ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
333460cb568SAndrew Rybchenko efx_rc_t rc;
334e948693eSPhilip Paeps
335e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
336e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
337e948693eSPhilip Paeps
338e948693eSPhilip Paeps if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
339e948693eSPhilip Paeps goto fail1;
340e948693eSPhilip Paeps
341e948693eSPhilip Paeps return (0);
342e948693eSPhilip Paeps
343e948693eSPhilip Paeps fail1:
344460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
345e948693eSPhilip Paeps
346e948693eSPhilip Paeps return (rc);
347e948693eSPhilip Paeps }
348e948693eSPhilip Paeps
349460cb568SAndrew Rybchenko 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)350e948693eSPhilip Paeps efx_vpd_next_tag(
351e948693eSPhilip Paeps __in caddr_t data,
352e948693eSPhilip Paeps __in size_t size,
353e948693eSPhilip Paeps __inout unsigned int *offsetp,
354e948693eSPhilip Paeps __out efx_vpd_tag_t *tagp,
355e948693eSPhilip Paeps __out uint16_t *lengthp)
356e948693eSPhilip Paeps {
357e948693eSPhilip Paeps efx_byte_t byte;
358e948693eSPhilip Paeps efx_word_t word;
359e948693eSPhilip Paeps uint8_t name;
360e948693eSPhilip Paeps uint16_t length;
361e948693eSPhilip Paeps size_t headlen;
362460cb568SAndrew Rybchenko efx_rc_t rc;
363e948693eSPhilip Paeps
364e948693eSPhilip Paeps if (*offsetp >= size) {
365e948693eSPhilip Paeps rc = EFAULT;
366e948693eSPhilip Paeps goto fail1;
367e948693eSPhilip Paeps }
368e948693eSPhilip Paeps
369e948693eSPhilip Paeps EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
370e948693eSPhilip Paeps
371e948693eSPhilip Paeps switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
372e948693eSPhilip Paeps case TAG_TYPE_SMALL_ITEM_DECODE:
373e948693eSPhilip Paeps headlen = 1;
374e948693eSPhilip Paeps
375e948693eSPhilip Paeps name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
376e948693eSPhilip Paeps length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
377e948693eSPhilip Paeps
378e948693eSPhilip Paeps break;
379e948693eSPhilip Paeps
380e948693eSPhilip Paeps case TAG_TYPE_LARGE_ITEM_DECODE:
381e948693eSPhilip Paeps headlen = 3;
382e948693eSPhilip Paeps
383e948693eSPhilip Paeps if (*offsetp + headlen > size) {
384e948693eSPhilip Paeps rc = EFAULT;
385e948693eSPhilip Paeps goto fail2;
386e948693eSPhilip Paeps }
387e948693eSPhilip Paeps
388e948693eSPhilip Paeps name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
389e948693eSPhilip Paeps EFX_POPULATE_WORD_2(word,
390e948693eSPhilip Paeps EFX_BYTE_0, data[*offsetp + 1],
391e948693eSPhilip Paeps EFX_BYTE_1, data[*offsetp + 2]);
392e948693eSPhilip Paeps length = EFX_WORD_FIELD(word, EFX_WORD_0);
393e948693eSPhilip Paeps
394e948693eSPhilip Paeps break;
395e948693eSPhilip Paeps
396e948693eSPhilip Paeps default:
397e948693eSPhilip Paeps rc = EFAULT;
398e948693eSPhilip Paeps goto fail2;
399e948693eSPhilip Paeps }
400e948693eSPhilip Paeps
401e948693eSPhilip Paeps if (*offsetp + headlen + length > size) {
402e948693eSPhilip Paeps rc = EFAULT;
403e948693eSPhilip Paeps goto fail3;
404e948693eSPhilip Paeps }
405e948693eSPhilip Paeps
406e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
407e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
408e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
409e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
410e948693eSPhilip Paeps if (name != EFX_VPD_END && name != EFX_VPD_ID &&
411e948693eSPhilip Paeps name != EFX_VPD_RO) {
412e948693eSPhilip Paeps rc = EFAULT;
413e948693eSPhilip Paeps goto fail4;
414e948693eSPhilip Paeps }
415e948693eSPhilip Paeps
416e948693eSPhilip Paeps *tagp = name;
417e948693eSPhilip Paeps *lengthp = length;
418e948693eSPhilip Paeps *offsetp += headlen;
419e948693eSPhilip Paeps
420e948693eSPhilip Paeps return (0);
421e948693eSPhilip Paeps
422e948693eSPhilip Paeps fail4:
423e948693eSPhilip Paeps EFSYS_PROBE(fail4);
424e948693eSPhilip Paeps fail3:
425e948693eSPhilip Paeps EFSYS_PROBE(fail3);
426e948693eSPhilip Paeps fail2:
427e948693eSPhilip Paeps EFSYS_PROBE(fail2);
428e948693eSPhilip Paeps fail1:
429460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
430e948693eSPhilip Paeps
431e948693eSPhilip Paeps return (rc);
432e948693eSPhilip Paeps }
433e948693eSPhilip Paeps
434460cb568SAndrew Rybchenko 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)435e948693eSPhilip Paeps efx_vpd_next_keyword(
436e948693eSPhilip Paeps __in_bcount(size) caddr_t tag,
437e948693eSPhilip Paeps __in size_t size,
438e948693eSPhilip Paeps __in unsigned int pos,
439e948693eSPhilip Paeps __out efx_vpd_keyword_t *keywordp,
440e948693eSPhilip Paeps __out uint8_t *lengthp)
441e948693eSPhilip Paeps {
442e948693eSPhilip Paeps efx_vpd_keyword_t keyword;
443e948693eSPhilip Paeps uint8_t length;
444460cb568SAndrew Rybchenko efx_rc_t rc;
445e948693eSPhilip Paeps
446e948693eSPhilip Paeps if (pos + 3U > size) {
447e948693eSPhilip Paeps rc = EFAULT;
448e948693eSPhilip Paeps goto fail1;
449e948693eSPhilip Paeps }
450e948693eSPhilip Paeps
451e948693eSPhilip Paeps keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
452e948693eSPhilip Paeps length = tag[pos + 2];
453e948693eSPhilip Paeps
454e948693eSPhilip Paeps if (length == 0 || pos + 3U + length > size) {
455e948693eSPhilip Paeps rc = EFAULT;
456e948693eSPhilip Paeps goto fail2;
457e948693eSPhilip Paeps }
458e948693eSPhilip Paeps
459e948693eSPhilip Paeps *keywordp = keyword;
460e948693eSPhilip Paeps *lengthp = length;
461e948693eSPhilip Paeps
462e948693eSPhilip Paeps return (0);
463e948693eSPhilip Paeps
464e948693eSPhilip Paeps fail2:
465e948693eSPhilip Paeps EFSYS_PROBE(fail2);
466e948693eSPhilip Paeps fail1:
467460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
468e948693eSPhilip Paeps
469e948693eSPhilip Paeps return (rc);
470e948693eSPhilip Paeps }
471e948693eSPhilip Paeps
472460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_length(__in_bcount (size)caddr_t data,__in size_t size,__out size_t * lengthp)473e948693eSPhilip Paeps efx_vpd_hunk_length(
474e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
475e948693eSPhilip Paeps __in size_t size,
476e948693eSPhilip Paeps __out size_t *lengthp)
477e948693eSPhilip Paeps {
478e948693eSPhilip Paeps efx_vpd_tag_t tag;
479e948693eSPhilip Paeps unsigned int offset;
480e948693eSPhilip Paeps uint16_t taglen;
481460cb568SAndrew Rybchenko efx_rc_t rc;
482e948693eSPhilip Paeps
483e948693eSPhilip Paeps offset = 0;
484e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
485e948693eSPhilip Paeps while (1) {
486e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
487e948693eSPhilip Paeps &tag, &taglen)) != 0)
488e948693eSPhilip Paeps goto fail1;
489e948693eSPhilip Paeps offset += taglen;
490e948693eSPhilip Paeps if (tag == EFX_VPD_END)
491e948693eSPhilip Paeps break;
492e948693eSPhilip Paeps }
493e948693eSPhilip Paeps
494e948693eSPhilip Paeps *lengthp = offset;
495e948693eSPhilip Paeps
496e948693eSPhilip Paeps return (0);
497e948693eSPhilip Paeps
498e948693eSPhilip Paeps fail1:
499460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
500e948693eSPhilip Paeps
501e948693eSPhilip Paeps return (rc);
502e948693eSPhilip Paeps }
503e948693eSPhilip Paeps
504460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_verify(__in_bcount (size)caddr_t data,__in size_t size,__out_opt boolean_t * cksummedp)505e948693eSPhilip Paeps efx_vpd_hunk_verify(
506e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
507e948693eSPhilip Paeps __in size_t size,
508e948693eSPhilip Paeps __out_opt boolean_t *cksummedp)
509e948693eSPhilip Paeps {
510e948693eSPhilip Paeps efx_vpd_tag_t tag;
511e948693eSPhilip Paeps efx_vpd_keyword_t keyword;
512e948693eSPhilip Paeps unsigned int offset;
513e948693eSPhilip Paeps unsigned int pos;
514e948693eSPhilip Paeps unsigned int i;
515e948693eSPhilip Paeps uint16_t taglen;
516e948693eSPhilip Paeps uint8_t keylen;
517e948693eSPhilip Paeps uint8_t cksum;
518e948693eSPhilip Paeps boolean_t cksummed = B_FALSE;
519460cb568SAndrew Rybchenko efx_rc_t rc;
520e948693eSPhilip Paeps
521e948693eSPhilip Paeps /*
522e948693eSPhilip Paeps * Parse every tag,keyword in the existing VPD. If the csum is present,
523e948693eSPhilip Paeps * the assert it is correct, and is the final keyword in the RO block.
524e948693eSPhilip Paeps */
525e948693eSPhilip Paeps offset = 0;
526e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
527e948693eSPhilip Paeps while (1) {
528e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
529e948693eSPhilip Paeps &tag, &taglen)) != 0)
530e948693eSPhilip Paeps goto fail1;
531e948693eSPhilip Paeps if (tag == EFX_VPD_END)
532e948693eSPhilip Paeps break;
533e948693eSPhilip Paeps else if (tag == EFX_VPD_ID)
534e948693eSPhilip Paeps goto done;
535e948693eSPhilip Paeps
536e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) {
537e948693eSPhilip Paeps /* RV keyword must be the last in the block */
5389dbc22c5SAndrew Rybchenko if (cksummed) {
5399dbc22c5SAndrew Rybchenko rc = EFAULT;
540e948693eSPhilip Paeps goto fail2;
5419dbc22c5SAndrew Rybchenko }
542e948693eSPhilip Paeps
543e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset,
544e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0)
545e948693eSPhilip Paeps goto fail3;
546e948693eSPhilip Paeps
547e948693eSPhilip Paeps if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
548e948693eSPhilip Paeps cksum = 0;
549e948693eSPhilip Paeps for (i = 0; i < offset + pos + 4; i++)
550e948693eSPhilip Paeps cksum += data[i];
551e948693eSPhilip Paeps
552e948693eSPhilip Paeps if (cksum != 0) {
553e948693eSPhilip Paeps rc = EFAULT;
554e948693eSPhilip Paeps goto fail4;
555e948693eSPhilip Paeps }
556e948693eSPhilip Paeps
557e948693eSPhilip Paeps cksummed = B_TRUE;
558e948693eSPhilip Paeps }
559e948693eSPhilip Paeps }
560e948693eSPhilip Paeps
561e948693eSPhilip Paeps done:
562e948693eSPhilip Paeps offset += taglen;
563e948693eSPhilip Paeps }
564e948693eSPhilip Paeps
565e948693eSPhilip Paeps if (!cksummed) {
566e948693eSPhilip Paeps rc = EFAULT;
567e948693eSPhilip Paeps goto fail5;
568e948693eSPhilip Paeps }
569e948693eSPhilip Paeps
570e948693eSPhilip Paeps if (cksummedp != NULL)
571e948693eSPhilip Paeps *cksummedp = cksummed;
572e948693eSPhilip Paeps
573e948693eSPhilip Paeps return (0);
574e948693eSPhilip Paeps
575e948693eSPhilip Paeps fail5:
576e948693eSPhilip Paeps EFSYS_PROBE(fail5);
577e948693eSPhilip Paeps fail4:
578e948693eSPhilip Paeps EFSYS_PROBE(fail4);
579e948693eSPhilip Paeps fail3:
580e948693eSPhilip Paeps EFSYS_PROBE(fail3);
581e948693eSPhilip Paeps fail2:
582e948693eSPhilip Paeps EFSYS_PROBE(fail2);
583e948693eSPhilip Paeps fail1:
584460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
585e948693eSPhilip Paeps
586e948693eSPhilip Paeps return (rc);
587e948693eSPhilip Paeps }
588e948693eSPhilip Paeps
5893c838a9fSAndrew Rybchenko static uint8_t __efx_vpd_blank_pid[] = {
590e948693eSPhilip Paeps /* Large resource type ID length 1 */
591e948693eSPhilip Paeps 0x82, 0x01, 0x00,
592e948693eSPhilip Paeps /* Product name ' ' */
593e948693eSPhilip Paeps 0x32,
594e948693eSPhilip Paeps };
595e948693eSPhilip Paeps
5963c838a9fSAndrew Rybchenko static uint8_t __efx_vpd_blank_r[] = {
597e948693eSPhilip Paeps /* Large resource type VPD-R length 4 */
598e948693eSPhilip Paeps 0x90, 0x04, 0x00,
599e948693eSPhilip Paeps /* RV keyword length 1 */
600e948693eSPhilip Paeps 'R', 'V', 0x01,
601e948693eSPhilip Paeps /* RV payload checksum */
602e948693eSPhilip Paeps 0x00,
603e948693eSPhilip Paeps };
604e948693eSPhilip Paeps
605460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_reinit(__in_bcount (size)caddr_t data,__in size_t size,__in boolean_t wantpid)606e948693eSPhilip Paeps efx_vpd_hunk_reinit(
6073c838a9fSAndrew Rybchenko __in_bcount(size) caddr_t data,
608e948693eSPhilip Paeps __in size_t size,
609e948693eSPhilip Paeps __in boolean_t wantpid)
610e948693eSPhilip Paeps {
611e948693eSPhilip Paeps unsigned int offset = 0;
612e948693eSPhilip Paeps unsigned int pos;
613e948693eSPhilip Paeps efx_byte_t byte;
614e948693eSPhilip Paeps uint8_t cksum;
615460cb568SAndrew Rybchenko efx_rc_t rc;
616e948693eSPhilip Paeps
617e948693eSPhilip Paeps if (size < 0x100) {
618e948693eSPhilip Paeps rc = ENOSPC;
619e948693eSPhilip Paeps goto fail1;
620e948693eSPhilip Paeps }
621e948693eSPhilip Paeps
622e948693eSPhilip Paeps if (wantpid) {
623e948693eSPhilip Paeps memcpy(data + offset, __efx_vpd_blank_pid,
624e948693eSPhilip Paeps sizeof (__efx_vpd_blank_pid));
625e948693eSPhilip Paeps offset += sizeof (__efx_vpd_blank_pid);
626e948693eSPhilip Paeps }
627e948693eSPhilip Paeps
628e948693eSPhilip Paeps memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
629e948693eSPhilip Paeps offset += sizeof (__efx_vpd_blank_r);
630e948693eSPhilip Paeps
631e948693eSPhilip Paeps /* Update checksum */
632e948693eSPhilip Paeps cksum = 0;
633e948693eSPhilip Paeps for (pos = 0; pos < offset; pos++)
634e948693eSPhilip Paeps cksum += data[pos];
635e948693eSPhilip Paeps data[offset - 1] -= cksum;
636e948693eSPhilip Paeps
637e948693eSPhilip Paeps /* Append trailing tag */
638e948693eSPhilip Paeps EFX_POPULATE_BYTE_3(byte,
639e948693eSPhilip Paeps TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
640e948693eSPhilip Paeps TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
641e948693eSPhilip Paeps TAG_SMALL_ITEM_SIZE, 0);
642e948693eSPhilip Paeps data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
643e948693eSPhilip Paeps offset++;
644e948693eSPhilip Paeps
645e948693eSPhilip Paeps return (0);
646e948693eSPhilip Paeps
647e948693eSPhilip Paeps fail1:
648460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
649e948693eSPhilip Paeps
650e948693eSPhilip Paeps return (rc);
651e948693eSPhilip Paeps }
652e948693eSPhilip Paeps
653460cb568SAndrew Rybchenko __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)654e948693eSPhilip Paeps efx_vpd_hunk_next(
655e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
656e948693eSPhilip Paeps __in size_t size,
657e948693eSPhilip Paeps __out efx_vpd_tag_t *tagp,
658e948693eSPhilip Paeps __out efx_vpd_keyword_t *keywordp,
65972cda832SAndrew Rybchenko __out_opt unsigned int *payloadp,
660e948693eSPhilip Paeps __out_opt uint8_t *paylenp,
661e948693eSPhilip Paeps __inout unsigned int *contp)
662e948693eSPhilip Paeps {
663e948693eSPhilip Paeps efx_vpd_tag_t tag;
664e948693eSPhilip Paeps efx_vpd_keyword_t keyword = 0;
665e948693eSPhilip Paeps unsigned int offset;
666e948693eSPhilip Paeps unsigned int pos;
667e948693eSPhilip Paeps unsigned int index;
668e948693eSPhilip Paeps uint16_t taglen;
669e948693eSPhilip Paeps uint8_t keylen;
670e948693eSPhilip Paeps uint8_t paylen;
671460cb568SAndrew Rybchenko efx_rc_t rc;
672e948693eSPhilip Paeps
673e948693eSPhilip Paeps offset = index = 0;
674e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
675e948693eSPhilip Paeps while (1) {
676e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
677e948693eSPhilip Paeps &tag, &taglen)) != 0)
678e948693eSPhilip Paeps goto fail1;
67972cda832SAndrew Rybchenko
68072cda832SAndrew Rybchenko if (tag == EFX_VPD_END) {
68172cda832SAndrew Rybchenko keyword = 0;
68272cda832SAndrew Rybchenko paylen = 0;
68372cda832SAndrew Rybchenko index = 0;
684e948693eSPhilip Paeps break;
68572cda832SAndrew Rybchenko }
686e948693eSPhilip Paeps
687e948693eSPhilip Paeps if (tag == EFX_VPD_ID) {
68872cda832SAndrew Rybchenko if (index++ == *contp) {
689e948693eSPhilip Paeps EFSYS_ASSERT3U(taglen, <, 0x100);
69072cda832SAndrew Rybchenko keyword = 0;
691e948693eSPhilip Paeps paylen = (uint8_t)MIN(taglen, 0xff);
692e948693eSPhilip Paeps
693e948693eSPhilip Paeps goto done;
694e948693eSPhilip Paeps }
695e948693eSPhilip Paeps } else {
696e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) {
697e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset,
698e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0)
699e948693eSPhilip Paeps goto fail2;
700e948693eSPhilip Paeps
70172cda832SAndrew Rybchenko if (index++ == *contp) {
702e948693eSPhilip Paeps offset += pos + 3;
703e948693eSPhilip Paeps paylen = keylen;
704e948693eSPhilip Paeps
705e948693eSPhilip Paeps goto done;
706e948693eSPhilip Paeps }
707e948693eSPhilip Paeps }
708e948693eSPhilip Paeps }
709e948693eSPhilip Paeps
710e948693eSPhilip Paeps offset += taglen;
711e948693eSPhilip Paeps }
712e948693eSPhilip Paeps
713e948693eSPhilip Paeps done:
714e948693eSPhilip Paeps *tagp = tag;
715e948693eSPhilip Paeps *keywordp = keyword;
716e948693eSPhilip Paeps if (payloadp != NULL)
717e948693eSPhilip Paeps *payloadp = offset;
718e948693eSPhilip Paeps if (paylenp != NULL)
719e948693eSPhilip Paeps *paylenp = paylen;
720e948693eSPhilip Paeps
72172cda832SAndrew Rybchenko *contp = index;
722e948693eSPhilip Paeps return (0);
723e948693eSPhilip Paeps
724e948693eSPhilip Paeps fail2:
725e948693eSPhilip Paeps EFSYS_PROBE(fail2);
726e948693eSPhilip Paeps fail1:
727460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
728e948693eSPhilip Paeps
729e948693eSPhilip Paeps return (rc);
730e948693eSPhilip Paeps }
731e948693eSPhilip Paeps
732460cb568SAndrew Rybchenko __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)733e948693eSPhilip Paeps efx_vpd_hunk_get(
734e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
735e948693eSPhilip Paeps __in size_t size,
736e948693eSPhilip Paeps __in efx_vpd_tag_t tag,
737e948693eSPhilip Paeps __in efx_vpd_keyword_t keyword,
738e948693eSPhilip Paeps __out unsigned int *payloadp,
739e948693eSPhilip Paeps __out uint8_t *paylenp)
740e948693eSPhilip Paeps {
741e948693eSPhilip Paeps efx_vpd_tag_t itag;
742e948693eSPhilip Paeps efx_vpd_keyword_t ikeyword;
743e948693eSPhilip Paeps unsigned int offset;
744e948693eSPhilip Paeps unsigned int pos;
745e948693eSPhilip Paeps uint16_t taglen;
746e948693eSPhilip Paeps uint8_t keylen;
747460cb568SAndrew Rybchenko efx_rc_t rc;
748e948693eSPhilip Paeps
749e948693eSPhilip Paeps offset = 0;
750e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
751e948693eSPhilip Paeps while (1) {
752e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
753e948693eSPhilip Paeps &itag, &taglen)) != 0)
754e948693eSPhilip Paeps goto fail1;
755e948693eSPhilip Paeps if (itag == EFX_VPD_END)
756e948693eSPhilip Paeps break;
757e948693eSPhilip Paeps
758e948693eSPhilip Paeps if (itag == tag) {
759e948693eSPhilip Paeps if (itag == EFX_VPD_ID) {
760e948693eSPhilip Paeps EFSYS_ASSERT3U(taglen, <, 0x100);
761e948693eSPhilip Paeps
762e948693eSPhilip Paeps *paylenp = (uint8_t)MIN(taglen, 0xff);
763e948693eSPhilip Paeps *payloadp = offset;
764e948693eSPhilip Paeps return (0);
765e948693eSPhilip Paeps }
766e948693eSPhilip Paeps
767e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) {
768e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset,
769e948693eSPhilip Paeps taglen, pos, &ikeyword, &keylen)) != 0)
770e948693eSPhilip Paeps goto fail2;
771e948693eSPhilip Paeps
772e948693eSPhilip Paeps if (ikeyword == keyword) {
773e948693eSPhilip Paeps *paylenp = keylen;
774e948693eSPhilip Paeps *payloadp = offset + pos + 3;
775e948693eSPhilip Paeps return (0);
776e948693eSPhilip Paeps }
777e948693eSPhilip Paeps }
778e948693eSPhilip Paeps }
779e948693eSPhilip Paeps
780e948693eSPhilip Paeps offset += taglen;
781e948693eSPhilip Paeps }
782e948693eSPhilip Paeps
783e948693eSPhilip Paeps /* Not an error */
784e948693eSPhilip Paeps return (ENOENT);
785e948693eSPhilip Paeps
786e948693eSPhilip Paeps fail2:
787e948693eSPhilip Paeps EFSYS_PROBE(fail2);
788e948693eSPhilip Paeps fail1:
789460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
790e948693eSPhilip Paeps
791e948693eSPhilip Paeps return (rc);
792e948693eSPhilip Paeps }
793e948693eSPhilip Paeps
794460cb568SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_set(__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)795e948693eSPhilip Paeps efx_vpd_hunk_set(
796e948693eSPhilip Paeps __in_bcount(size) caddr_t data,
797e948693eSPhilip Paeps __in size_t size,
798e948693eSPhilip Paeps __in efx_vpd_value_t *evvp)
799e948693eSPhilip Paeps {
800e948693eSPhilip Paeps efx_word_t word;
801e948693eSPhilip Paeps efx_vpd_tag_t tag;
802e948693eSPhilip Paeps efx_vpd_keyword_t keyword;
803e948693eSPhilip Paeps unsigned int offset;
804e948693eSPhilip Paeps unsigned int pos;
805e948693eSPhilip Paeps unsigned int taghead;
806e948693eSPhilip Paeps unsigned int source;
807e948693eSPhilip Paeps unsigned int dest;
808e948693eSPhilip Paeps unsigned int i;
809e948693eSPhilip Paeps uint16_t taglen;
810e948693eSPhilip Paeps uint8_t keylen;
811e948693eSPhilip Paeps uint8_t cksum;
812e948693eSPhilip Paeps size_t used;
813460cb568SAndrew Rybchenko efx_rc_t rc;
814e948693eSPhilip Paeps
815e948693eSPhilip Paeps switch (evvp->evv_tag) {
816e948693eSPhilip Paeps case EFX_VPD_ID:
817e948693eSPhilip Paeps if (evvp->evv_keyword != 0) {
818e948693eSPhilip Paeps rc = EINVAL;
819e948693eSPhilip Paeps goto fail1;
820e948693eSPhilip Paeps }
821e948693eSPhilip Paeps
822e948693eSPhilip Paeps /* Can't delete the ID keyword */
823e948693eSPhilip Paeps if (evvp->evv_length == 0) {
824e948693eSPhilip Paeps rc = EINVAL;
825e948693eSPhilip Paeps goto fail1;
826e948693eSPhilip Paeps }
827e948693eSPhilip Paeps break;
828e948693eSPhilip Paeps
829e948693eSPhilip Paeps case EFX_VPD_RO:
830e948693eSPhilip Paeps if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
831e948693eSPhilip Paeps rc = EINVAL;
832e948693eSPhilip Paeps goto fail1;
833e948693eSPhilip Paeps }
834e948693eSPhilip Paeps break;
835e948693eSPhilip Paeps
836e948693eSPhilip Paeps default:
837e948693eSPhilip Paeps rc = EINVAL;
838e948693eSPhilip Paeps goto fail1;
839e948693eSPhilip Paeps }
840e948693eSPhilip Paeps
841e948693eSPhilip Paeps /* Determine total size of all current tags */
842e948693eSPhilip Paeps if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
843e948693eSPhilip Paeps goto fail2;
844e948693eSPhilip Paeps
845e948693eSPhilip Paeps offset = 0;
846e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
847e948693eSPhilip Paeps while (1) {
848e948693eSPhilip Paeps taghead = offset;
849e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
850e948693eSPhilip Paeps &tag, &taglen)) != 0)
851e948693eSPhilip Paeps goto fail3;
852e948693eSPhilip Paeps if (tag == EFX_VPD_END)
853e948693eSPhilip Paeps break;
854e948693eSPhilip Paeps else if (tag != evvp->evv_tag) {
855e948693eSPhilip Paeps offset += taglen;
856e948693eSPhilip Paeps continue;
857e948693eSPhilip Paeps }
858e948693eSPhilip Paeps
859e948693eSPhilip Paeps /* We only support modifying large resource tags */
860e948693eSPhilip Paeps if (offset - taghead != 3) {
861e948693eSPhilip Paeps rc = EINVAL;
862e948693eSPhilip Paeps goto fail4;
863e948693eSPhilip Paeps }
864e948693eSPhilip Paeps
865e948693eSPhilip Paeps /*
866e948693eSPhilip Paeps * Work out the offset of the byte immediately after the
867e948693eSPhilip Paeps * old (=source) and new (=dest) new keyword/tag
868e948693eSPhilip Paeps */
869e948693eSPhilip Paeps pos = 0;
870e948693eSPhilip Paeps if (tag == EFX_VPD_ID) {
871e948693eSPhilip Paeps source = offset + taglen;
872e948693eSPhilip Paeps dest = offset + evvp->evv_length;
873e948693eSPhilip Paeps goto check_space;
874e948693eSPhilip Paeps }
875e948693eSPhilip Paeps
876e948693eSPhilip Paeps EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
877e948693eSPhilip Paeps source = dest = 0;
878e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) {
879e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset,
880e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0)
881e948693eSPhilip Paeps goto fail5;
882e948693eSPhilip Paeps
883e948693eSPhilip Paeps if (keyword == evvp->evv_keyword &&
884e948693eSPhilip Paeps evvp->evv_length == 0) {
885e948693eSPhilip Paeps /* Deleting this keyword */
886e948693eSPhilip Paeps source = offset + pos + 3 + keylen;
887e948693eSPhilip Paeps dest = offset + pos;
888e948693eSPhilip Paeps break;
889e948693eSPhilip Paeps
890e948693eSPhilip Paeps } else if (keyword == evvp->evv_keyword) {
891e948693eSPhilip Paeps /* Adjusting this keyword */
892e948693eSPhilip Paeps source = offset + pos + 3 + keylen;
893e948693eSPhilip Paeps dest = offset + pos + 3 + evvp->evv_length;
894e948693eSPhilip Paeps break;
895e948693eSPhilip Paeps
896e948693eSPhilip Paeps } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
897e948693eSPhilip Paeps /* The RV keyword must be at the end */
898e948693eSPhilip Paeps EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
899e948693eSPhilip Paeps
900e948693eSPhilip Paeps /*
901e948693eSPhilip Paeps * The keyword doesn't already exist. If the
902631504fbSGordon Bergling * user deleting a non-existent keyword then
903e948693eSPhilip Paeps * this is a no-op.
904e948693eSPhilip Paeps */
905e948693eSPhilip Paeps if (evvp->evv_length == 0)
906e948693eSPhilip Paeps return (0);
907e948693eSPhilip Paeps
908e948693eSPhilip Paeps /* Insert this keyword before the RV keyword */
909e948693eSPhilip Paeps source = offset + pos;
910e948693eSPhilip Paeps dest = offset + pos + 3 + evvp->evv_length;
911e948693eSPhilip Paeps break;
912e948693eSPhilip Paeps }
913e948693eSPhilip Paeps }
914e948693eSPhilip Paeps
915e948693eSPhilip Paeps check_space:
916e948693eSPhilip Paeps if (used + dest > size + source) {
917e948693eSPhilip Paeps rc = ENOSPC;
918e948693eSPhilip Paeps goto fail6;
919e948693eSPhilip Paeps }
920e948693eSPhilip Paeps
921e948693eSPhilip Paeps /* Move trailing data */
922e948693eSPhilip Paeps (void) memmove(data + dest, data + source, used - source);
923e948693eSPhilip Paeps
924e948693eSPhilip Paeps /* Copy contents */
925e948693eSPhilip Paeps memcpy(data + dest - evvp->evv_length, evvp->evv_value,
926e948693eSPhilip Paeps evvp->evv_length);
927e948693eSPhilip Paeps
928e948693eSPhilip Paeps /* Insert new keyword header if required */
929e948693eSPhilip Paeps if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
930e948693eSPhilip Paeps EFX_POPULATE_WORD_1(word, EFX_WORD_0,
931e948693eSPhilip Paeps evvp->evv_keyword);
932e948693eSPhilip Paeps data[offset + pos + 0] =
933e948693eSPhilip Paeps EFX_WORD_FIELD(word, EFX_BYTE_0);
934e948693eSPhilip Paeps data[offset + pos + 1] =
935e948693eSPhilip Paeps EFX_WORD_FIELD(word, EFX_BYTE_1);
936e948693eSPhilip Paeps data[offset + pos + 2] = evvp->evv_length;
937e948693eSPhilip Paeps }
938e948693eSPhilip Paeps
939e948693eSPhilip Paeps /* Modify tag length (large resource type) */
9405ef1830cSAndrew Rybchenko taglen += (uint16_t)(dest - source);
941e948693eSPhilip Paeps EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
942e948693eSPhilip Paeps data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
943e948693eSPhilip Paeps data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
944e948693eSPhilip Paeps
945e948693eSPhilip Paeps goto checksum;
946e948693eSPhilip Paeps }
947e948693eSPhilip Paeps
948e948693eSPhilip Paeps /* Unable to find the matching tag */
949e948693eSPhilip Paeps rc = ENOENT;
950e948693eSPhilip Paeps goto fail7;
951e948693eSPhilip Paeps
952e948693eSPhilip Paeps checksum:
953e948693eSPhilip Paeps /* Find the RV tag, and update the checksum */
954e948693eSPhilip Paeps offset = 0;
955e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION)
956e948693eSPhilip Paeps while (1) {
957e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset,
958e948693eSPhilip Paeps &tag, &taglen)) != 0)
959e948693eSPhilip Paeps goto fail8;
960e948693eSPhilip Paeps if (tag == EFX_VPD_END)
961e948693eSPhilip Paeps break;
962e948693eSPhilip Paeps if (tag == EFX_VPD_RO) {
963e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) {
964e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset,
965e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0)
966e948693eSPhilip Paeps goto fail9;
967e948693eSPhilip Paeps
968e948693eSPhilip Paeps if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
969e948693eSPhilip Paeps cksum = 0;
970e948693eSPhilip Paeps for (i = 0; i < offset + pos + 3; i++)
971e948693eSPhilip Paeps cksum += data[i];
972e948693eSPhilip Paeps data[i] = -cksum;
973e948693eSPhilip Paeps break;
974e948693eSPhilip Paeps }
975e948693eSPhilip Paeps }
976e948693eSPhilip Paeps }
977e948693eSPhilip Paeps
978e948693eSPhilip Paeps offset += taglen;
979e948693eSPhilip Paeps }
980e948693eSPhilip Paeps
981e948693eSPhilip Paeps /* Zero out the unused portion */
982e948693eSPhilip Paeps (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
983e948693eSPhilip Paeps
984e948693eSPhilip Paeps return (0);
985e948693eSPhilip Paeps
986e948693eSPhilip Paeps fail9:
987e948693eSPhilip Paeps EFSYS_PROBE(fail9);
988e948693eSPhilip Paeps fail8:
989e948693eSPhilip Paeps EFSYS_PROBE(fail8);
990e948693eSPhilip Paeps fail7:
991e948693eSPhilip Paeps EFSYS_PROBE(fail7);
992e948693eSPhilip Paeps fail6:
993e948693eSPhilip Paeps EFSYS_PROBE(fail6);
994e948693eSPhilip Paeps fail5:
995e948693eSPhilip Paeps EFSYS_PROBE(fail5);
996e948693eSPhilip Paeps fail4:
997e948693eSPhilip Paeps EFSYS_PROBE(fail4);
998e948693eSPhilip Paeps fail3:
999e948693eSPhilip Paeps EFSYS_PROBE(fail3);
1000e948693eSPhilip Paeps fail2:
1001e948693eSPhilip Paeps EFSYS_PROBE(fail2);
1002e948693eSPhilip Paeps fail1:
1003460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1004e948693eSPhilip Paeps
1005e948693eSPhilip Paeps return (rc);
1006e948693eSPhilip Paeps }
1007e948693eSPhilip Paeps
1008e948693eSPhilip Paeps void
efx_vpd_fini(__in efx_nic_t * enp)1009e948693eSPhilip Paeps efx_vpd_fini(
1010e948693eSPhilip Paeps __in efx_nic_t *enp)
1011e948693eSPhilip Paeps {
1012ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1013e948693eSPhilip Paeps
1014e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1015e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1016e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1017e948693eSPhilip Paeps
1018e948693eSPhilip Paeps if (evpdop->evpdo_fini != NULL)
1019e948693eSPhilip Paeps evpdop->evpdo_fini(enp);
1020e948693eSPhilip Paeps
1021e948693eSPhilip Paeps enp->en_evpdop = NULL;
1022e948693eSPhilip Paeps enp->en_mod_flags &= ~EFX_MOD_VPD;
1023e948693eSPhilip Paeps }
1024e948693eSPhilip Paeps
1025e948693eSPhilip Paeps #endif /* EFSYS_OPT_VPD */
1026