1227569Sphilip/*-
2300607Sarybchik * Copyright (c) 2009-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/efx_vpd.c 342428 2018-12-25 07:03:01Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36227569Sphilip
37227569Sphilip#if EFSYS_OPT_VPD
38227569Sphilip
39227569Sphilip#define	TAG_TYPE_LBN 7
40227569Sphilip#define	TAG_TYPE_WIDTH 1
41227569Sphilip#define	TAG_TYPE_LARGE_ITEM_DECODE 1
42227569Sphilip#define	TAG_TYPE_SMALL_ITEM_DECODE 0
43227569Sphilip
44227569Sphilip#define	TAG_SMALL_ITEM_NAME_LBN 3
45227569Sphilip#define	TAG_SMALL_ITEM_NAME_WIDTH 4
46227569Sphilip#define	TAG_SMALL_ITEM_SIZE_LBN 0
47227569Sphilip#define	TAG_SMALL_ITEM_SIZE_WIDTH 3
48227569Sphilip
49227569Sphilip#define	TAG_LARGE_ITEM_NAME_LBN 0
50227569Sphilip#define	TAG_LARGE_ITEM_NAME_WIDTH 7
51227569Sphilip
52227569Sphilip#define	TAG_NAME_END_DECODE 0x0f
53227569Sphilip#define	TAG_NAME_ID_STRING_DECODE 0x02
54227569Sphilip#define	TAG_NAME_VPD_R_DECODE 0x10
55227569Sphilip#define	TAG_NAME_VPD_W_DECODE 0x11
56227569Sphilip
57227569Sphilip#if EFSYS_OPT_SIENA
58227569Sphilip
59299517Sarybchikstatic const efx_vpd_ops_t	__efx_vpd_siena_ops = {
60227569Sphilip	siena_vpd_init,		/* evpdo_init */
61227569Sphilip	siena_vpd_size,		/* evpdo_size */
62227569Sphilip	siena_vpd_read,		/* evpdo_read */
63227569Sphilip	siena_vpd_verify,	/* evpdo_verify */
64227569Sphilip	siena_vpd_reinit,	/* evpdo_reinit */
65227569Sphilip	siena_vpd_get,		/* evpdo_get */
66227569Sphilip	siena_vpd_set,		/* evpdo_set */
67227569Sphilip	siena_vpd_next,		/* evpdo_next */
68227569Sphilip	siena_vpd_write,	/* evpdo_write */
69227569Sphilip	siena_vpd_fini,		/* evpdo_fini */
70227569Sphilip};
71227569Sphilip
72227569Sphilip#endif	/* EFSYS_OPT_SIENA */
73227569Sphilip
74293755Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
75283514Sarybchik
76299517Sarybchikstatic const efx_vpd_ops_t	__efx_vpd_ef10_ops = {
77293755Sarybchik	ef10_vpd_init,		/* evpdo_init */
78293755Sarybchik	ef10_vpd_size,		/* evpdo_size */
79293755Sarybchik	ef10_vpd_read,		/* evpdo_read */
80293755Sarybchik	ef10_vpd_verify,	/* evpdo_verify */
81293755Sarybchik	ef10_vpd_reinit,	/* evpdo_reinit */
82293755Sarybchik	ef10_vpd_get,		/* evpdo_get */
83293755Sarybchik	ef10_vpd_set,		/* evpdo_set */
84293755Sarybchik	ef10_vpd_next,		/* evpdo_next */
85293755Sarybchik	ef10_vpd_write,		/* evpdo_write */
86293755Sarybchik	ef10_vpd_fini,		/* evpdo_fini */
87283514Sarybchik};
88283514Sarybchik
89293755Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
90283514Sarybchik
91291436Sarybchik	__checkReturn		efx_rc_t
92227569Sphilipefx_vpd_init(
93227569Sphilip	__in			efx_nic_t *enp)
94227569Sphilip{
95299517Sarybchik	const efx_vpd_ops_t *evpdop;
96291436Sarybchik	efx_rc_t rc;
97227569Sphilip
98227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
99227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
100227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
101227569Sphilip
102227569Sphilip	switch (enp->en_family) {
103227569Sphilip#if EFSYS_OPT_SIENA
104227569Sphilip	case EFX_FAMILY_SIENA:
105299517Sarybchik		evpdop = &__efx_vpd_siena_ops;
106227569Sphilip		break;
107227569Sphilip#endif	/* EFSYS_OPT_SIENA */
108227569Sphilip
109283514Sarybchik#if EFSYS_OPT_HUNTINGTON
110283514Sarybchik	case EFX_FAMILY_HUNTINGTON:
111299517Sarybchik		evpdop = &__efx_vpd_ef10_ops;
112283514Sarybchik		break;
113283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
114283514Sarybchik
115293755Sarybchik#if EFSYS_OPT_MEDFORD
116293755Sarybchik	case EFX_FAMILY_MEDFORD:
117299517Sarybchik		evpdop = &__efx_vpd_ef10_ops;
118293755Sarybchik		break;
119293755Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
120293755Sarybchik
121227569Sphilip	default:
122227569Sphilip		EFSYS_ASSERT(0);
123227569Sphilip		rc = ENOTSUP;
124227569Sphilip		goto fail1;
125227569Sphilip	}
126227569Sphilip
127227569Sphilip	if (evpdop->evpdo_init != NULL) {
128227569Sphilip		if ((rc = evpdop->evpdo_init(enp)) != 0)
129227569Sphilip			goto fail2;
130227569Sphilip	}
131227569Sphilip
132227569Sphilip	enp->en_evpdop = evpdop;
133227569Sphilip	enp->en_mod_flags |= EFX_MOD_VPD;
134227569Sphilip
135227569Sphilip	return (0);
136227569Sphilip
137227569Sphilipfail2:
138227569Sphilip	EFSYS_PROBE(fail2);
139227569Sphilipfail1:
140291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
141227569Sphilip
142227569Sphilip	return (rc);
143227569Sphilip}
144227569Sphilip
145291436Sarybchik	__checkReturn		efx_rc_t
146227569Sphilipefx_vpd_size(
147227569Sphilip	__in			efx_nic_t *enp,
148227569Sphilip	__out			size_t *sizep)
149227569Sphilip{
150299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
151291436Sarybchik	efx_rc_t rc;
152227569Sphilip
153227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
154227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
155227569Sphilip
156227569Sphilip	if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
157227569Sphilip		goto fail1;
158227569Sphilip
159227569Sphilip	return (0);
160227569Sphilip
161227569Sphilipfail1:
162291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
163227569Sphilip
164227569Sphilip	return (rc);
165227569Sphilip}
166227569Sphilip
167291436Sarybchik	__checkReturn		efx_rc_t
168227569Sphilipefx_vpd_read(
169227569Sphilip	__in			efx_nic_t *enp,
170227569Sphilip	__out_bcount(size)	caddr_t data,
171227569Sphilip	__in			size_t size)
172227569Sphilip{
173299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
174291436Sarybchik	efx_rc_t rc;
175227569Sphilip
176227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
177227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
178227569Sphilip
179227569Sphilip	if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
180227569Sphilip		goto fail1;
181227569Sphilip
182227569Sphilip	return (0);
183227569Sphilip
184227569Sphilipfail1:
185291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
186227569Sphilip
187227569Sphilip	return (rc);
188227569Sphilip}
189227569Sphilip
190291436Sarybchik	__checkReturn		efx_rc_t
191227569Sphilipefx_vpd_verify(
192227569Sphilip	__in			efx_nic_t *enp,
193227569Sphilip	__in_bcount(size)	caddr_t data,
194227569Sphilip	__in			size_t size)
195227569Sphilip{
196299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
197291436Sarybchik	efx_rc_t rc;
198227569Sphilip
199227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
200227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
201227569Sphilip
202227569Sphilip	if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
203227569Sphilip		goto fail1;
204227569Sphilip
205227569Sphilip	return (0);
206227569Sphilip
207227569Sphilipfail1:
208291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
209227569Sphilip
210227569Sphilip	return (rc);
211227569Sphilip}
212227569Sphilip
213291436Sarybchik	__checkReturn		efx_rc_t
214227569Sphilipefx_vpd_reinit(
215227569Sphilip	__in			efx_nic_t *enp,
216227569Sphilip	__in_bcount(size)	caddr_t data,
217227569Sphilip	__in			size_t size)
218227569Sphilip{
219299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
220291436Sarybchik	efx_rc_t rc;
221227569Sphilip
222227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
223227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
224227569Sphilip
225227569Sphilip	if (evpdop->evpdo_reinit == NULL) {
226227569Sphilip		rc = ENOTSUP;
227227569Sphilip		goto fail1;
228227569Sphilip	}
229227569Sphilip
230227569Sphilip	if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
231227569Sphilip		goto fail2;
232227569Sphilip
233227569Sphilip	return (0);
234227569Sphilip
235227569Sphilipfail2:
236227569Sphilip	EFSYS_PROBE(fail2);
237227569Sphilipfail1:
238291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
239227569Sphilip
240227569Sphilip	return (rc);
241227569Sphilip}
242227569Sphilip
243291436Sarybchik	__checkReturn		efx_rc_t
244227569Sphilipefx_vpd_get(
245227569Sphilip	__in			efx_nic_t *enp,
246227569Sphilip	__in_bcount(size)	caddr_t data,
247227569Sphilip	__in			size_t size,
248227569Sphilip	__inout			efx_vpd_value_t *evvp)
249227569Sphilip{
250299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
251291436Sarybchik	efx_rc_t rc;
252227569Sphilip
253227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
254227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
255227569Sphilip
256299901Sarybchik	if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
257299901Sarybchik		if (rc == ENOENT)
258299901Sarybchik			return (rc);
259299901Sarybchik
260227569Sphilip		goto fail1;
261299901Sarybchik	}
262227569Sphilip
263227569Sphilip	return (0);
264227569Sphilip
265227569Sphilipfail1:
266291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
267227569Sphilip
268227569Sphilip	return (rc);
269227569Sphilip}
270227569Sphilip
271291436Sarybchik	__checkReturn		efx_rc_t
272227569Sphilipefx_vpd_set(
273227569Sphilip	__in			efx_nic_t *enp,
274227569Sphilip	__inout_bcount(size)	caddr_t data,
275227569Sphilip	__in			size_t size,
276227569Sphilip	__in			efx_vpd_value_t *evvp)
277227569Sphilip{
278299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
279291436Sarybchik	efx_rc_t rc;
280227569Sphilip
281227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
282227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
283227569Sphilip
284227569Sphilip	if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
285227569Sphilip		goto fail1;
286227569Sphilip
287227569Sphilip	return (0);
288227569Sphilip
289227569Sphilipfail1:
290291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
291227569Sphilip
292227569Sphilip	return (rc);
293227569Sphilip}
294227569Sphilip
295291436Sarybchik	__checkReturn		efx_rc_t
296227569Sphilipefx_vpd_next(
297227569Sphilip	__in			efx_nic_t *enp,
298227569Sphilip	__inout_bcount(size)	caddr_t data,
299227569Sphilip	__in			size_t size,
300227569Sphilip	__out			efx_vpd_value_t *evvp,
301227569Sphilip	__inout			unsigned int *contp)
302227569Sphilip{
303299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
304291436Sarybchik	efx_rc_t rc;
305227569Sphilip
306227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
307227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
308227569Sphilip
309227569Sphilip	if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
310227569Sphilip		goto fail1;
311227569Sphilip
312227569Sphilip	return (0);
313227569Sphilip
314227569Sphilipfail1:
315291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
316227569Sphilip
317227569Sphilip	return (rc);
318227569Sphilip}
319227569Sphilip
320291436Sarybchik	__checkReturn		efx_rc_t
321227569Sphilipefx_vpd_write(
322227569Sphilip	__in			efx_nic_t *enp,
323227569Sphilip	__in_bcount(size)	caddr_t data,
324227569Sphilip	__in			size_t size)
325227569Sphilip{
326299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
327291436Sarybchik	efx_rc_t rc;
328227569Sphilip
329227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
330227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
331227569Sphilip
332227569Sphilip	if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
333227569Sphilip		goto fail1;
334227569Sphilip
335227569Sphilip	return (0);
336227569Sphilip
337227569Sphilipfail1:
338291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
339227569Sphilip
340227569Sphilip	return (rc);
341227569Sphilip}
342227569Sphilip
343291436Sarybchikstatic	__checkReturn		efx_rc_t
344227569Sphilipefx_vpd_next_tag(
345227569Sphilip	__in			caddr_t data,
346227569Sphilip	__in			size_t size,
347227569Sphilip	__inout			unsigned int *offsetp,
348227569Sphilip	__out			efx_vpd_tag_t *tagp,
349227569Sphilip	__out			uint16_t *lengthp)
350227569Sphilip{
351227569Sphilip	efx_byte_t byte;
352227569Sphilip	efx_word_t word;
353227569Sphilip	uint8_t name;
354227569Sphilip	uint16_t length;
355227569Sphilip	size_t headlen;
356291436Sarybchik	efx_rc_t rc;
357227569Sphilip
358227569Sphilip	if (*offsetp >= size) {
359227569Sphilip		rc = EFAULT;
360227569Sphilip		goto fail1;
361227569Sphilip	}
362227569Sphilip
363227569Sphilip	EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
364227569Sphilip
365227569Sphilip	switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
366227569Sphilip	case TAG_TYPE_SMALL_ITEM_DECODE:
367227569Sphilip		headlen = 1;
368227569Sphilip
369227569Sphilip		name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
370227569Sphilip		length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
371227569Sphilip
372227569Sphilip		break;
373227569Sphilip
374227569Sphilip	case TAG_TYPE_LARGE_ITEM_DECODE:
375227569Sphilip		headlen = 3;
376227569Sphilip
377227569Sphilip		if (*offsetp + headlen > size) {
378227569Sphilip			rc = EFAULT;
379227569Sphilip			goto fail2;
380227569Sphilip		}
381227569Sphilip
382227569Sphilip		name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
383227569Sphilip		EFX_POPULATE_WORD_2(word,
384227569Sphilip				    EFX_BYTE_0, data[*offsetp + 1],
385227569Sphilip				    EFX_BYTE_1, data[*offsetp + 2]);
386227569Sphilip		length = EFX_WORD_FIELD(word, EFX_WORD_0);
387227569Sphilip
388227569Sphilip		break;
389227569Sphilip
390227569Sphilip	default:
391227569Sphilip		rc = EFAULT;
392227569Sphilip		goto fail2;
393227569Sphilip	}
394227569Sphilip
395227569Sphilip	if (*offsetp + headlen + length > size) {
396227569Sphilip		rc = EFAULT;
397227569Sphilip		goto fail3;
398227569Sphilip	}
399227569Sphilip
400227569Sphilip	EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
401227569Sphilip	EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
402227569Sphilip	EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
403227569Sphilip	EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
404227569Sphilip	if (name != EFX_VPD_END && name != EFX_VPD_ID &&
405227569Sphilip	    name != EFX_VPD_RO) {
406227569Sphilip		rc = EFAULT;
407227569Sphilip		goto fail4;
408227569Sphilip	}
409227569Sphilip
410227569Sphilip	*tagp = name;
411227569Sphilip	*lengthp = length;
412227569Sphilip	*offsetp += headlen;
413227569Sphilip
414227569Sphilip	return (0);
415227569Sphilip
416227569Sphilipfail4:
417227569Sphilip	EFSYS_PROBE(fail4);
418227569Sphilipfail3:
419227569Sphilip	EFSYS_PROBE(fail3);
420227569Sphilipfail2:
421227569Sphilip	EFSYS_PROBE(fail2);
422227569Sphilipfail1:
423291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
424227569Sphilip
425227569Sphilip	return (rc);
426227569Sphilip}
427227569Sphilip
428291436Sarybchikstatic	__checkReturn		efx_rc_t
429227569Sphilipefx_vpd_next_keyword(
430227569Sphilip	__in_bcount(size)	caddr_t tag,
431227569Sphilip	__in			size_t size,
432227569Sphilip	__in			unsigned int pos,
433227569Sphilip	__out			efx_vpd_keyword_t *keywordp,
434227569Sphilip	__out			uint8_t *lengthp)
435227569Sphilip{
436227569Sphilip	efx_vpd_keyword_t keyword;
437227569Sphilip	uint8_t length;
438291436Sarybchik	efx_rc_t rc;
439227569Sphilip
440227569Sphilip	if (pos + 3U > size) {
441227569Sphilip		rc = EFAULT;
442227569Sphilip		goto fail1;
443227569Sphilip	}
444227569Sphilip
445227569Sphilip	keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
446227569Sphilip	length = tag[pos + 2];
447227569Sphilip
448227569Sphilip	if (length == 0 || pos + 3U + length > size) {
449227569Sphilip		rc = EFAULT;
450227569Sphilip		goto fail2;
451227569Sphilip	}
452227569Sphilip
453227569Sphilip	*keywordp = keyword;
454227569Sphilip	*lengthp = length;
455227569Sphilip
456227569Sphilip	return (0);
457227569Sphilip
458227569Sphilipfail2:
459227569Sphilip	EFSYS_PROBE(fail2);
460227569Sphilipfail1:
461291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
462227569Sphilip
463227569Sphilip	return (rc);
464227569Sphilip}
465227569Sphilip
466291436Sarybchik	__checkReturn		efx_rc_t
467227569Sphilipefx_vpd_hunk_length(
468227569Sphilip	__in_bcount(size)	caddr_t data,
469227569Sphilip	__in			size_t size,
470227569Sphilip	__out			size_t *lengthp)
471227569Sphilip{
472227569Sphilip	efx_vpd_tag_t tag;
473227569Sphilip	unsigned int offset;
474227569Sphilip	uint16_t taglen;
475291436Sarybchik	efx_rc_t rc;
476227569Sphilip
477227569Sphilip	offset = 0;
478227569Sphilip	_NOTE(CONSTANTCONDITION)
479227569Sphilip	while (1) {
480227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
481227569Sphilip		    &tag, &taglen)) != 0)
482227569Sphilip			goto fail1;
483227569Sphilip		offset += taglen;
484227569Sphilip		if (tag == EFX_VPD_END)
485227569Sphilip			break;
486227569Sphilip	}
487227569Sphilip
488227569Sphilip	*lengthp = offset;
489227569Sphilip
490227569Sphilip	return (0);
491227569Sphilip
492227569Sphilipfail1:
493291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
494227569Sphilip
495227569Sphilip	return (rc);
496227569Sphilip}
497227569Sphilip
498291436Sarybchik	__checkReturn		efx_rc_t
499227569Sphilipefx_vpd_hunk_verify(
500227569Sphilip	__in_bcount(size)	caddr_t data,
501227569Sphilip	__in			size_t size,
502227569Sphilip	__out_opt		boolean_t *cksummedp)
503227569Sphilip{
504227569Sphilip	efx_vpd_tag_t tag;
505227569Sphilip	efx_vpd_keyword_t keyword;
506227569Sphilip	unsigned int offset;
507227569Sphilip	unsigned int pos;
508227569Sphilip	unsigned int i;
509227569Sphilip	uint16_t taglen;
510227569Sphilip	uint8_t keylen;
511227569Sphilip	uint8_t cksum;
512227569Sphilip	boolean_t cksummed = B_FALSE;
513291436Sarybchik	efx_rc_t rc;
514227569Sphilip
515227569Sphilip	/*
516227569Sphilip	 * Parse every tag,keyword in the existing VPD. If the csum is present,
517227569Sphilip	 * the assert it is correct, and is the final keyword in the RO block.
518227569Sphilip	 */
519227569Sphilip	offset = 0;
520227569Sphilip	_NOTE(CONSTANTCONDITION)
521227569Sphilip	while (1) {
522227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
523227569Sphilip		    &tag, &taglen)) != 0)
524227569Sphilip			goto fail1;
525227569Sphilip		if (tag == EFX_VPD_END)
526227569Sphilip			break;
527227569Sphilip		else if (tag == EFX_VPD_ID)
528227569Sphilip			goto done;
529227569Sphilip
530227569Sphilip		for (pos = 0; pos != taglen; pos += 3 + keylen) {
531227569Sphilip			/* RV keyword must be the last in the block */
532291398Sarybchik			if (cksummed) {
533291398Sarybchik				rc = EFAULT;
534227569Sphilip				goto fail2;
535291398Sarybchik			}
536227569Sphilip
537227569Sphilip			if ((rc = efx_vpd_next_keyword(data + offset,
538227569Sphilip			    taglen, pos, &keyword, &keylen)) != 0)
539227569Sphilip				goto fail3;
540227569Sphilip
541227569Sphilip			if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
542227569Sphilip				cksum = 0;
543227569Sphilip				for (i = 0; i < offset + pos + 4; i++)
544227569Sphilip					cksum += data[i];
545227569Sphilip
546227569Sphilip				if (cksum != 0) {
547227569Sphilip					rc = EFAULT;
548227569Sphilip					goto fail4;
549227569Sphilip				}
550227569Sphilip
551227569Sphilip				cksummed = B_TRUE;
552227569Sphilip			}
553227569Sphilip		}
554227569Sphilip
555227569Sphilip	done:
556227569Sphilip		offset += taglen;
557227569Sphilip	}
558227569Sphilip
559227569Sphilip	if (!cksummed) {
560227569Sphilip		rc = EFAULT;
561227569Sphilip		goto fail5;
562227569Sphilip	}
563227569Sphilip
564227569Sphilip	if (cksummedp != NULL)
565227569Sphilip		*cksummedp = cksummed;
566227569Sphilip
567227569Sphilip	return (0);
568227569Sphilip
569227569Sphilipfail5:
570227569Sphilip	EFSYS_PROBE(fail5);
571227569Sphilipfail4:
572227569Sphilip	EFSYS_PROBE(fail4);
573227569Sphilipfail3:
574227569Sphilip	EFSYS_PROBE(fail3);
575227569Sphilipfail2:
576227569Sphilip	EFSYS_PROBE(fail2);
577227569Sphilipfail1:
578291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
579227569Sphilip
580227569Sphilip	return (rc);
581227569Sphilip}
582227569Sphilip
583283514Sarybchikstatic	uint8_t	__efx_vpd_blank_pid[] = {
584227569Sphilip	/* Large resource type ID length 1 */
585227569Sphilip	0x82, 0x01, 0x00,
586227569Sphilip	/* Product name ' ' */
587227569Sphilip	0x32,
588227569Sphilip};
589227569Sphilip
590283514Sarybchikstatic uint8_t __efx_vpd_blank_r[] = {
591227569Sphilip	/* Large resource type VPD-R length 4 */
592227569Sphilip	0x90, 0x04, 0x00,
593227569Sphilip	/* RV keyword length 1 */
594227569Sphilip	'R', 'V', 0x01,
595227569Sphilip	/* RV payload checksum */
596227569Sphilip	0x00,
597227569Sphilip};
598227569Sphilip
599291436Sarybchik	__checkReturn		efx_rc_t
600227569Sphilipefx_vpd_hunk_reinit(
601283514Sarybchik	__in_bcount(size)	caddr_t data,
602227569Sphilip	__in			size_t size,
603227569Sphilip	__in			boolean_t wantpid)
604227569Sphilip{
605227569Sphilip	unsigned int offset = 0;
606227569Sphilip	unsigned int pos;
607227569Sphilip	efx_byte_t byte;
608227569Sphilip	uint8_t cksum;
609291436Sarybchik	efx_rc_t rc;
610227569Sphilip
611227569Sphilip	if (size < 0x100) {
612227569Sphilip		rc = ENOSPC;
613227569Sphilip		goto fail1;
614227569Sphilip	}
615227569Sphilip
616227569Sphilip	if (wantpid) {
617227569Sphilip		memcpy(data + offset, __efx_vpd_blank_pid,
618227569Sphilip		    sizeof (__efx_vpd_blank_pid));
619227569Sphilip		offset += sizeof (__efx_vpd_blank_pid);
620227569Sphilip	}
621227569Sphilip
622227569Sphilip	memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
623227569Sphilip	offset += sizeof (__efx_vpd_blank_r);
624227569Sphilip
625227569Sphilip	/* Update checksum */
626227569Sphilip	cksum = 0;
627227569Sphilip	for (pos = 0; pos < offset; pos++)
628227569Sphilip		cksum += data[pos];
629227569Sphilip	data[offset - 1] -= cksum;
630227569Sphilip
631227569Sphilip	/* Append trailing tag */
632227569Sphilip	EFX_POPULATE_BYTE_3(byte,
633227569Sphilip			    TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
634227569Sphilip			    TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
635227569Sphilip			    TAG_SMALL_ITEM_SIZE, 0);
636227569Sphilip	data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
637227569Sphilip	offset++;
638227569Sphilip
639227569Sphilip	return (0);
640227569Sphilip
641227569Sphilipfail1:
642291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
643227569Sphilip
644227569Sphilip	return (rc);
645227569Sphilip}
646227569Sphilip
647291436Sarybchik	__checkReturn			efx_rc_t
648227569Sphilipefx_vpd_hunk_next(
649227569Sphilip	__in_bcount(size)		caddr_t data,
650227569Sphilip	__in				size_t size,
651227569Sphilip	__out				efx_vpd_tag_t *tagp,
652227569Sphilip	__out				efx_vpd_keyword_t *keywordp,
653293895Sarybchik	__out_opt			unsigned int *payloadp,
654227569Sphilip	__out_opt			uint8_t *paylenp,
655227569Sphilip	__inout				unsigned int *contp)
656227569Sphilip{
657227569Sphilip	efx_vpd_tag_t tag;
658227569Sphilip	efx_vpd_keyword_t keyword = 0;
659227569Sphilip	unsigned int offset;
660227569Sphilip	unsigned int pos;
661227569Sphilip	unsigned int index;
662227569Sphilip	uint16_t taglen;
663227569Sphilip	uint8_t keylen;
664227569Sphilip	uint8_t paylen;
665291436Sarybchik	efx_rc_t rc;
666227569Sphilip
667227569Sphilip	offset = index = 0;
668227569Sphilip	_NOTE(CONSTANTCONDITION)
669227569Sphilip	while (1) {
670227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
671227569Sphilip		    &tag, &taglen)) != 0)
672227569Sphilip			goto fail1;
673293895Sarybchik
674293895Sarybchik		if (tag == EFX_VPD_END) {
675293895Sarybchik			keyword = 0;
676293895Sarybchik			paylen = 0;
677293895Sarybchik			index = 0;
678227569Sphilip			break;
679293895Sarybchik		}
680227569Sphilip
681227569Sphilip		if (tag == EFX_VPD_ID) {
682293895Sarybchik			if (index++ == *contp) {
683227569Sphilip				EFSYS_ASSERT3U(taglen, <, 0x100);
684293895Sarybchik				keyword = 0;
685227569Sphilip				paylen = (uint8_t)MIN(taglen, 0xff);
686227569Sphilip
687227569Sphilip				goto done;
688227569Sphilip			}
689227569Sphilip		} else {
690227569Sphilip			for (pos = 0; pos != taglen; pos += 3 + keylen) {
691227569Sphilip				if ((rc = efx_vpd_next_keyword(data + offset,
692227569Sphilip				    taglen, pos, &keyword, &keylen)) != 0)
693227569Sphilip					goto fail2;
694227569Sphilip
695293895Sarybchik				if (index++ == *contp) {
696227569Sphilip					offset += pos + 3;
697227569Sphilip					paylen = keylen;
698227569Sphilip
699227569Sphilip					goto done;
700227569Sphilip				}
701227569Sphilip			}
702227569Sphilip		}
703227569Sphilip
704227569Sphilip		offset += taglen;
705227569Sphilip	}
706227569Sphilip
707227569Sphilipdone:
708227569Sphilip	*tagp = tag;
709227569Sphilip	*keywordp = keyword;
710227569Sphilip	if (payloadp != NULL)
711227569Sphilip		*payloadp = offset;
712227569Sphilip	if (paylenp != NULL)
713227569Sphilip		*paylenp = paylen;
714227569Sphilip
715293895Sarybchik	*contp = index;
716227569Sphilip	return (0);
717227569Sphilip
718227569Sphilipfail2:
719227569Sphilip	EFSYS_PROBE(fail2);
720227569Sphilipfail1:
721291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
722227569Sphilip
723227569Sphilip	return (rc);
724227569Sphilip}
725227569Sphilip
726291436Sarybchik	__checkReturn		efx_rc_t
727227569Sphilipefx_vpd_hunk_get(
728227569Sphilip	__in_bcount(size)	caddr_t data,
729227569Sphilip	__in			size_t size,
730227569Sphilip	__in			efx_vpd_tag_t tag,
731227569Sphilip	__in			efx_vpd_keyword_t keyword,
732227569Sphilip	__out			unsigned int *payloadp,
733227569Sphilip	__out			uint8_t *paylenp)
734227569Sphilip{
735227569Sphilip	efx_vpd_tag_t itag;
736227569Sphilip	efx_vpd_keyword_t ikeyword;
737227569Sphilip	unsigned int offset;
738227569Sphilip	unsigned int pos;
739227569Sphilip	uint16_t taglen;
740227569Sphilip	uint8_t keylen;
741291436Sarybchik	efx_rc_t rc;
742227569Sphilip
743227569Sphilip	offset = 0;
744227569Sphilip	_NOTE(CONSTANTCONDITION)
745227569Sphilip	while (1) {
746227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
747227569Sphilip		    &itag, &taglen)) != 0)
748227569Sphilip			goto fail1;
749227569Sphilip		if (itag == EFX_VPD_END)
750227569Sphilip			break;
751227569Sphilip
752227569Sphilip		if (itag == tag) {
753227569Sphilip			if (itag == EFX_VPD_ID) {
754227569Sphilip				EFSYS_ASSERT3U(taglen, <, 0x100);
755227569Sphilip
756227569Sphilip				*paylenp = (uint8_t)MIN(taglen, 0xff);
757227569Sphilip				*payloadp = offset;
758227569Sphilip				return (0);
759227569Sphilip			}
760227569Sphilip
761227569Sphilip			for (pos = 0; pos != taglen; pos += 3 + keylen) {
762227569Sphilip				if ((rc = efx_vpd_next_keyword(data + offset,
763227569Sphilip				    taglen, pos, &ikeyword, &keylen)) != 0)
764227569Sphilip					goto fail2;
765227569Sphilip
766227569Sphilip				if (ikeyword == keyword) {
767227569Sphilip					*paylenp = keylen;
768227569Sphilip					*payloadp = offset + pos + 3;
769227569Sphilip					return (0);
770227569Sphilip				}
771227569Sphilip			}
772227569Sphilip		}
773227569Sphilip
774227569Sphilip		offset += taglen;
775227569Sphilip	}
776227569Sphilip
777227569Sphilip	/* Not an error */
778227569Sphilip	return (ENOENT);
779227569Sphilip
780227569Sphilipfail2:
781227569Sphilip	EFSYS_PROBE(fail2);
782227569Sphilipfail1:
783291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
784227569Sphilip
785227569Sphilip	return (rc);
786227569Sphilip}
787227569Sphilip
788291436Sarybchik	__checkReturn		efx_rc_t
789227569Sphilipefx_vpd_hunk_set(
790227569Sphilip	__in_bcount(size)	caddr_t data,
791227569Sphilip	__in			size_t size,
792227569Sphilip	__in			efx_vpd_value_t *evvp)
793227569Sphilip{
794227569Sphilip	efx_word_t word;
795227569Sphilip	efx_vpd_tag_t tag;
796227569Sphilip	efx_vpd_keyword_t keyword;
797227569Sphilip	unsigned int offset;
798227569Sphilip	unsigned int pos;
799227569Sphilip	unsigned int taghead;
800227569Sphilip	unsigned int source;
801227569Sphilip	unsigned int dest;
802227569Sphilip	unsigned int i;
803227569Sphilip	uint16_t taglen;
804227569Sphilip	uint8_t keylen;
805227569Sphilip	uint8_t cksum;
806227569Sphilip	size_t used;
807291436Sarybchik	efx_rc_t rc;
808227569Sphilip
809227569Sphilip	switch (evvp->evv_tag) {
810227569Sphilip	case EFX_VPD_ID:
811227569Sphilip		if (evvp->evv_keyword != 0) {
812227569Sphilip			rc = EINVAL;
813227569Sphilip			goto fail1;
814227569Sphilip		}
815227569Sphilip
816227569Sphilip		/* Can't delete the ID keyword */
817227569Sphilip		if (evvp->evv_length == 0) {
818227569Sphilip			rc = EINVAL;
819227569Sphilip			goto fail1;
820227569Sphilip		}
821227569Sphilip		break;
822227569Sphilip
823227569Sphilip	case EFX_VPD_RO:
824227569Sphilip		if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
825227569Sphilip			rc = EINVAL;
826227569Sphilip			goto fail1;
827227569Sphilip		}
828227569Sphilip		break;
829227569Sphilip
830227569Sphilip	default:
831227569Sphilip		rc = EINVAL;
832227569Sphilip		goto fail1;
833227569Sphilip	}
834227569Sphilip
835227569Sphilip	/* Determine total size of all current tags */
836227569Sphilip	if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
837227569Sphilip		goto fail2;
838227569Sphilip
839227569Sphilip	offset = 0;
840227569Sphilip	_NOTE(CONSTANTCONDITION)
841227569Sphilip	while (1) {
842227569Sphilip		taghead = offset;
843227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
844227569Sphilip		    &tag, &taglen)) != 0)
845227569Sphilip			goto fail3;
846227569Sphilip		if (tag == EFX_VPD_END)
847227569Sphilip			break;
848227569Sphilip		else if (tag != evvp->evv_tag) {
849227569Sphilip			offset += taglen;
850227569Sphilip			continue;
851227569Sphilip		}
852227569Sphilip
853227569Sphilip		/* We only support modifying large resource tags */
854227569Sphilip		if (offset - taghead != 3) {
855227569Sphilip			rc = EINVAL;
856227569Sphilip			goto fail4;
857227569Sphilip		}
858227569Sphilip
859227569Sphilip		/*
860227569Sphilip		 * Work out the offset of the byte immediately after the
861227569Sphilip		 * old (=source) and new (=dest) new keyword/tag
862227569Sphilip		 */
863227569Sphilip		pos = 0;
864227569Sphilip		if (tag == EFX_VPD_ID) {
865227569Sphilip			source = offset + taglen;
866227569Sphilip			dest = offset + evvp->evv_length;
867227569Sphilip			goto check_space;
868227569Sphilip		}
869227569Sphilip
870227569Sphilip		EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
871227569Sphilip		source = dest = 0;
872227569Sphilip		for (pos = 0; pos != taglen; pos += 3 + keylen) {
873227569Sphilip			if ((rc = efx_vpd_next_keyword(data + offset,
874227569Sphilip			    taglen, pos, &keyword, &keylen)) != 0)
875227569Sphilip				goto fail5;
876227569Sphilip
877227569Sphilip			if (keyword == evvp->evv_keyword &&
878227569Sphilip			    evvp->evv_length == 0) {
879227569Sphilip				/* Deleting this keyword */
880227569Sphilip				source = offset + pos + 3 + keylen;
881227569Sphilip				dest = offset + pos;
882227569Sphilip				break;
883227569Sphilip
884227569Sphilip			} else if (keyword == evvp->evv_keyword) {
885227569Sphilip				/* Adjusting this keyword */
886227569Sphilip				source = offset + pos + 3 + keylen;
887227569Sphilip				dest = offset + pos + 3 + evvp->evv_length;
888227569Sphilip				break;
889227569Sphilip
890227569Sphilip			} else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
891227569Sphilip				/* The RV keyword must be at the end */
892227569Sphilip				EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
893227569Sphilip
894227569Sphilip				/*
895227569Sphilip				 * The keyword doesn't already exist. If the
896227569Sphilip				 * user deleting a non-existant keyword then
897227569Sphilip				 * this is a no-op.
898227569Sphilip				 */
899227569Sphilip				if (evvp->evv_length == 0)
900227569Sphilip					return (0);
901227569Sphilip
902227569Sphilip				/* Insert this keyword before the RV keyword */
903227569Sphilip				source = offset + pos;
904227569Sphilip				dest = offset + pos + 3 + evvp->evv_length;
905227569Sphilip				break;
906227569Sphilip			}
907227569Sphilip		}
908227569Sphilip
909227569Sphilip	check_space:
910227569Sphilip		if (used + dest > size + source) {
911227569Sphilip			rc = ENOSPC;
912227569Sphilip			goto fail6;
913227569Sphilip		}
914227569Sphilip
915227569Sphilip		/* Move trailing data */
916227569Sphilip		(void) memmove(data + dest, data + source, used - source);
917227569Sphilip
918227569Sphilip		/* Copy contents */
919227569Sphilip		memcpy(data + dest - evvp->evv_length, evvp->evv_value,
920227569Sphilip		    evvp->evv_length);
921227569Sphilip
922227569Sphilip		/* Insert new keyword header if required */
923227569Sphilip		if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
924227569Sphilip			EFX_POPULATE_WORD_1(word, EFX_WORD_0,
925227569Sphilip					    evvp->evv_keyword);
926227569Sphilip			data[offset + pos + 0] =
927227569Sphilip			    EFX_WORD_FIELD(word, EFX_BYTE_0);
928227569Sphilip			data[offset + pos + 1] =
929227569Sphilip			    EFX_WORD_FIELD(word, EFX_BYTE_1);
930227569Sphilip			data[offset + pos + 2] = evvp->evv_length;
931227569Sphilip		}
932227569Sphilip
933227569Sphilip		/* Modify tag length (large resource type) */
934342428Sarybchik		taglen += (uint16_t)(dest - source);
935227569Sphilip		EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
936227569Sphilip		data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
937227569Sphilip		data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
938227569Sphilip
939227569Sphilip		goto checksum;
940227569Sphilip	}
941227569Sphilip
942227569Sphilip	/* Unable to find the matching tag */
943227569Sphilip	rc = ENOENT;
944227569Sphilip	goto fail7;
945227569Sphilip
946227569Sphilipchecksum:
947227569Sphilip	/* Find the RV tag, and update the checksum */
948227569Sphilip	offset = 0;
949227569Sphilip	_NOTE(CONSTANTCONDITION)
950227569Sphilip	while (1) {
951227569Sphilip		if ((rc = efx_vpd_next_tag(data, size, &offset,
952227569Sphilip		    &tag, &taglen)) != 0)
953227569Sphilip			goto fail8;
954227569Sphilip		if (tag == EFX_VPD_END)
955227569Sphilip			break;
956227569Sphilip		if (tag == EFX_VPD_RO) {
957227569Sphilip			for (pos = 0; pos != taglen; pos += 3 + keylen) {
958227569Sphilip				if ((rc = efx_vpd_next_keyword(data + offset,
959227569Sphilip				    taglen, pos, &keyword, &keylen)) != 0)
960227569Sphilip					goto fail9;
961227569Sphilip
962227569Sphilip				if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
963227569Sphilip					cksum = 0;
964227569Sphilip					for (i = 0; i < offset + pos + 3; i++)
965227569Sphilip						cksum += data[i];
966227569Sphilip					data[i] = -cksum;
967227569Sphilip					break;
968227569Sphilip				}
969227569Sphilip			}
970227569Sphilip		}
971227569Sphilip
972227569Sphilip		offset += taglen;
973227569Sphilip	}
974227569Sphilip
975227569Sphilip	/* Zero out the unused portion */
976227569Sphilip	(void) memset(data + offset + taglen, 0xff, size - offset - taglen);
977227569Sphilip
978227569Sphilip	return (0);
979227569Sphilip
980227569Sphilipfail9:
981227569Sphilip	EFSYS_PROBE(fail9);
982227569Sphilipfail8:
983227569Sphilip	EFSYS_PROBE(fail8);
984227569Sphilipfail7:
985227569Sphilip	EFSYS_PROBE(fail7);
986227569Sphilipfail6:
987227569Sphilip	EFSYS_PROBE(fail6);
988227569Sphilipfail5:
989227569Sphilip	EFSYS_PROBE(fail5);
990227569Sphilipfail4:
991227569Sphilip	EFSYS_PROBE(fail4);
992227569Sphilipfail3:
993227569Sphilip	EFSYS_PROBE(fail3);
994227569Sphilipfail2:
995227569Sphilip	EFSYS_PROBE(fail2);
996227569Sphilipfail1:
997291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
998227569Sphilip
999227569Sphilip	return (rc);
1000227569Sphilip}
1001227569Sphilip
1002227569Sphilip				void
1003227569Sphilipefx_vpd_fini(
1004227569Sphilip	__in			efx_nic_t *enp)
1005227569Sphilip{
1006299517Sarybchik	const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1007227569Sphilip
1008227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1009227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1010227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1011227569Sphilip
1012227569Sphilip	if (evpdop->evpdo_fini != NULL)
1013227569Sphilip		evpdop->evpdo_fini(enp);
1014227569Sphilip
1015227569Sphilip	enp->en_evpdop = NULL;
1016227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_VPD;
1017227569Sphilip}
1018227569Sphilip
1019227569Sphilip#endif	/* EFSYS_OPT_VPD */
1020