xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision e919b7ec20480ba1050d28ac19f9bd677a954105)
1e948693eSPhilip Paeps /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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>
345dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
355dee87d7SPhilip Paeps 
36e948693eSPhilip Paeps #include "efx.h"
37e948693eSPhilip Paeps #include "efx_impl.h"
38e948693eSPhilip Paeps 
39e948693eSPhilip Paeps #if EFSYS_OPT_NVRAM
40e948693eSPhilip Paeps 
41e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
42e948693eSPhilip Paeps 
43ec831f7fSAndrew Rybchenko static const efx_nvram_ops_t	__efx_nvram_siena_ops = {
44e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
45e948693eSPhilip Paeps 	siena_nvram_test,		/* envo_test */
46e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
47bce88e31SAndrew Rybchenko 	siena_nvram_type_to_partn,	/* envo_type_to_partn */
4856bd83b0SAndrew Rybchenko 	siena_nvram_partn_size,		/* envo_partn_size */
495d846e87SAndrew Rybchenko 	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
500afdf29cSAndrew Rybchenko 	siena_nvram_partn_read,		/* envo_partn_read */
51ede1a3edSAndrew Rybchenko 	siena_nvram_partn_read,		/* envo_partn_read_backup */
52b60ff840SAndrew Rybchenko 	siena_nvram_partn_erase,	/* envo_partn_erase */
53134c4c4aSAndrew Rybchenko 	siena_nvram_partn_write,	/* envo_partn_write */
54eb9703daSAndrew Rybchenko 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
5592187119SAndrew Rybchenko 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
566d0b856cSAndrew Rybchenko 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
575abce2b9SAndrew Rybchenko 	NULL,				/* envo_partn_validate */
58e948693eSPhilip Paeps };
59e948693eSPhilip Paeps 
60e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
61e948693eSPhilip Paeps 
62824c97edSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
633c838a9fSAndrew Rybchenko 
64ec831f7fSAndrew Rybchenko static const efx_nvram_ops_t	__efx_nvram_ef10_ops = {
653c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
66de9775adSAndrew Rybchenko 	ef10_nvram_test,		/* envo_test */
673c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
68bce88e31SAndrew Rybchenko 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
6956bd83b0SAndrew Rybchenko 	ef10_nvram_partn_size,		/* envo_partn_size */
705d846e87SAndrew Rybchenko 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
710afdf29cSAndrew Rybchenko 	ef10_nvram_partn_read,		/* envo_partn_read */
72ede1a3edSAndrew Rybchenko 	ef10_nvram_partn_read_backup,	/* envo_partn_read_backup */
73b60ff840SAndrew Rybchenko 	ef10_nvram_partn_erase,		/* envo_partn_erase */
74134c4c4aSAndrew Rybchenko 	ef10_nvram_partn_write,		/* envo_partn_write */
75eb9703daSAndrew Rybchenko 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
7692187119SAndrew Rybchenko 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
776d0b856cSAndrew Rybchenko 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
785abce2b9SAndrew Rybchenko 	ef10_nvram_buffer_validate,	/* envo_buffer_validate */
793c838a9fSAndrew Rybchenko };
803c838a9fSAndrew Rybchenko 
81824c97edSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
823c838a9fSAndrew Rybchenko 
83460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
84e948693eSPhilip Paeps efx_nvram_init(
85e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
86e948693eSPhilip Paeps {
87ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop;
88460cb568SAndrew Rybchenko 	efx_rc_t rc;
89e948693eSPhilip Paeps 
90e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
91e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
92e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
93e948693eSPhilip Paeps 
94e948693eSPhilip Paeps 	switch (enp->en_family) {
95e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
96e948693eSPhilip Paeps 	case EFX_FAMILY_SIENA:
97ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_siena_ops;
98e948693eSPhilip Paeps 		break;
99e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
100e948693eSPhilip Paeps 
1013c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1023c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
103ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
1043c838a9fSAndrew Rybchenko 		break;
1053c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
1063c838a9fSAndrew Rybchenko 
107de9775adSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
108de9775adSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
109ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
110de9775adSAndrew Rybchenko 		break;
111de9775adSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD */
112de9775adSAndrew Rybchenko 
113824c97edSAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
114824c97edSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD2:
115824c97edSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
116824c97edSAndrew Rybchenko 		break;
117824c97edSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD2 */
118824c97edSAndrew Rybchenko 
119e948693eSPhilip Paeps 	default:
120e948693eSPhilip Paeps 		EFSYS_ASSERT(0);
121e948693eSPhilip Paeps 		rc = ENOTSUP;
122e948693eSPhilip Paeps 		goto fail1;
123e948693eSPhilip Paeps 	}
124e948693eSPhilip Paeps 
125e948693eSPhilip Paeps 	enp->en_envop = envop;
126e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_NVRAM;
127e948693eSPhilip Paeps 
1283d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
1293d670ff5SAndrew Rybchenko 
130e948693eSPhilip Paeps 	return (0);
131e948693eSPhilip Paeps 
132e948693eSPhilip Paeps fail1:
133460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
134e948693eSPhilip Paeps 
135e948693eSPhilip Paeps 	return (rc);
136e948693eSPhilip Paeps }
137e948693eSPhilip Paeps 
138e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
139e948693eSPhilip Paeps 
140460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
141e948693eSPhilip Paeps efx_nvram_test(
142e948693eSPhilip Paeps 	__in			efx_nic_t *enp)
143e948693eSPhilip Paeps {
144ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
145460cb568SAndrew Rybchenko 	efx_rc_t rc;
146e948693eSPhilip Paeps 
147e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
148e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
149e948693eSPhilip Paeps 
150e948693eSPhilip Paeps 	if ((rc = envop->envo_test(enp)) != 0)
151e948693eSPhilip Paeps 		goto fail1;
152e948693eSPhilip Paeps 
153e948693eSPhilip Paeps 	return (0);
154e948693eSPhilip Paeps 
155e948693eSPhilip Paeps fail1:
156460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
157e948693eSPhilip Paeps 
158e948693eSPhilip Paeps 	return (rc);
159e948693eSPhilip Paeps }
160e948693eSPhilip Paeps 
161e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
162e948693eSPhilip Paeps 
163460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
164e948693eSPhilip Paeps efx_nvram_size(
165e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
166e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
167e948693eSPhilip Paeps 	__out			size_t *sizep)
168e948693eSPhilip Paeps {
169ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
17056bd83b0SAndrew Rybchenko 	uint32_t partn;
171460cb568SAndrew Rybchenko 	efx_rc_t rc;
172e948693eSPhilip Paeps 
173e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
174e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
175e948693eSPhilip Paeps 
17656bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
177e948693eSPhilip Paeps 		goto fail1;
178e948693eSPhilip Paeps 
17956bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
18056bd83b0SAndrew Rybchenko 		goto fail2;
18156bd83b0SAndrew Rybchenko 
182e948693eSPhilip Paeps 	return (0);
183e948693eSPhilip Paeps 
18456bd83b0SAndrew Rybchenko fail2:
18556bd83b0SAndrew Rybchenko 	EFSYS_PROBE(fail2);
186e948693eSPhilip Paeps fail1:
187460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
18856bd83b0SAndrew Rybchenko 	*sizep = 0;
189e948693eSPhilip Paeps 
190e948693eSPhilip Paeps 	return (rc);
191e948693eSPhilip Paeps }
192e948693eSPhilip Paeps 
193460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
194e948693eSPhilip Paeps efx_nvram_get_version(
195e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
196e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
197e948693eSPhilip Paeps 	__out			uint32_t *subtypep,
198e948693eSPhilip Paeps 	__out_ecount(4)		uint16_t version[4])
199e948693eSPhilip Paeps {
200ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
20192187119SAndrew Rybchenko 	uint32_t partn;
202460cb568SAndrew Rybchenko 	efx_rc_t rc;
203e948693eSPhilip Paeps 
204e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
205e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
206e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
207e948693eSPhilip Paeps 
20892187119SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
209e948693eSPhilip Paeps 		goto fail1;
210e948693eSPhilip Paeps 
21192187119SAndrew Rybchenko 	if ((rc = envop->envo_partn_get_version(enp, partn,
21292187119SAndrew Rybchenko 		    subtypep, version)) != 0)
21392187119SAndrew Rybchenko 		goto fail2;
21492187119SAndrew Rybchenko 
215e948693eSPhilip Paeps 	return (0);
216e948693eSPhilip Paeps 
21792187119SAndrew Rybchenko fail2:
21892187119SAndrew Rybchenko 	EFSYS_PROBE(fail2);
219e948693eSPhilip Paeps fail1:
220460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
221e948693eSPhilip Paeps 
222e948693eSPhilip Paeps 	return (rc);
223e948693eSPhilip Paeps }
224e948693eSPhilip Paeps 
225460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
226e948693eSPhilip Paeps efx_nvram_rw_start(
227e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
228e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
229e948693eSPhilip Paeps 	__out_opt		size_t *chunk_sizep)
230e948693eSPhilip Paeps {
231ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2325d846e87SAndrew Rybchenko 	uint32_t partn;
233460cb568SAndrew Rybchenko 	efx_rc_t rc;
234e948693eSPhilip Paeps 
235e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
236e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
237e948693eSPhilip Paeps 
2385d846e87SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
239e948693eSPhilip Paeps 		goto fail1;
240e948693eSPhilip Paeps 
2413d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
2423d670ff5SAndrew Rybchenko 
2435d846e87SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
2445d846e87SAndrew Rybchenko 		goto fail2;
2455d846e87SAndrew Rybchenko 
2463d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = partn;
247e948693eSPhilip Paeps 
248e948693eSPhilip Paeps 	return (0);
249e948693eSPhilip Paeps 
2505d846e87SAndrew Rybchenko fail2:
2515d846e87SAndrew Rybchenko 	EFSYS_PROBE(fail2);
252e948693eSPhilip Paeps fail1:
253460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
254e948693eSPhilip Paeps 
255e948693eSPhilip Paeps 	return (rc);
256e948693eSPhilip Paeps }
257e948693eSPhilip Paeps 
258460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
259e948693eSPhilip Paeps efx_nvram_read_chunk(
260e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
261e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
262e948693eSPhilip Paeps 	__in			unsigned int offset,
263e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
264e948693eSPhilip Paeps 	__in			size_t size)
265e948693eSPhilip Paeps {
266ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2670afdf29cSAndrew Rybchenko 	uint32_t partn;
268460cb568SAndrew Rybchenko 	efx_rc_t rc;
269e948693eSPhilip Paeps 
270e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
271e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
272e948693eSPhilip Paeps 
2730afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
274e948693eSPhilip Paeps 		goto fail1;
275e948693eSPhilip Paeps 
2763d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
2773d670ff5SAndrew Rybchenko 
2780afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
2790afdf29cSAndrew Rybchenko 		goto fail2;
2800afdf29cSAndrew Rybchenko 
281e948693eSPhilip Paeps 	return (0);
282e948693eSPhilip Paeps 
2830afdf29cSAndrew Rybchenko fail2:
2840afdf29cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
285e948693eSPhilip Paeps fail1:
286460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
287e948693eSPhilip Paeps 
288e948693eSPhilip Paeps 	return (rc);
289e948693eSPhilip Paeps }
290e948693eSPhilip Paeps 
291ede1a3edSAndrew Rybchenko /*
292ede1a3edSAndrew Rybchenko  * Read from the backup (writeable) store of an A/B partition.
293ede1a3edSAndrew Rybchenko  * For non A/B partitions, there is only a single store, and so this
294ede1a3edSAndrew Rybchenko  * function has the same behaviour as efx_nvram_read_chunk().
295ede1a3edSAndrew Rybchenko  */
296ede1a3edSAndrew Rybchenko 	__checkReturn		efx_rc_t
297ede1a3edSAndrew Rybchenko efx_nvram_read_backup(
298ede1a3edSAndrew Rybchenko 	__in			efx_nic_t *enp,
299ede1a3edSAndrew Rybchenko 	__in			efx_nvram_type_t type,
300ede1a3edSAndrew Rybchenko 	__in			unsigned int offset,
301ede1a3edSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
302ede1a3edSAndrew Rybchenko 	__in			size_t size)
303ede1a3edSAndrew Rybchenko {
304ede1a3edSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
305ede1a3edSAndrew Rybchenko 	uint32_t partn;
306ede1a3edSAndrew Rybchenko 	efx_rc_t rc;
307ede1a3edSAndrew Rybchenko 
308ede1a3edSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
309ede1a3edSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
310ede1a3edSAndrew Rybchenko 
311ede1a3edSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
312ede1a3edSAndrew Rybchenko 		goto fail1;
313ede1a3edSAndrew Rybchenko 
314ede1a3edSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
315ede1a3edSAndrew Rybchenko 
316ede1a3edSAndrew Rybchenko 	if ((rc = envop->envo_partn_read_backup(enp, partn, offset,
317ede1a3edSAndrew Rybchenko 		    data, size)) != 0)
318ede1a3edSAndrew Rybchenko 		goto fail2;
319ede1a3edSAndrew Rybchenko 
320ede1a3edSAndrew Rybchenko 	return (0);
321ede1a3edSAndrew Rybchenko 
322ede1a3edSAndrew Rybchenko fail2:
323ede1a3edSAndrew Rybchenko 	EFSYS_PROBE(fail2);
324ede1a3edSAndrew Rybchenko fail1:
325ede1a3edSAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
326ede1a3edSAndrew Rybchenko 
327ede1a3edSAndrew Rybchenko 	return (rc);
328ede1a3edSAndrew Rybchenko }
329ede1a3edSAndrew Rybchenko 
330460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
331e948693eSPhilip Paeps efx_nvram_erase(
332e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
333e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
334e948693eSPhilip Paeps {
335ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
336b60ff840SAndrew Rybchenko 	unsigned int offset = 0;
337b60ff840SAndrew Rybchenko 	size_t size = 0;
338b60ff840SAndrew Rybchenko 	uint32_t partn;
339460cb568SAndrew Rybchenko 	efx_rc_t rc;
340e948693eSPhilip Paeps 
341e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
342e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
343e948693eSPhilip Paeps 
344b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
345e948693eSPhilip Paeps 		goto fail1;
346e948693eSPhilip Paeps 
3473d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
3483d670ff5SAndrew Rybchenko 
349b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
350b60ff840SAndrew Rybchenko 		goto fail2;
351b60ff840SAndrew Rybchenko 
352b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
353b60ff840SAndrew Rybchenko 		goto fail3;
354b60ff840SAndrew Rybchenko 
355e948693eSPhilip Paeps 	return (0);
356e948693eSPhilip Paeps 
357b60ff840SAndrew Rybchenko fail3:
358b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail3);
359b60ff840SAndrew Rybchenko fail2:
360b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail2);
361e948693eSPhilip Paeps fail1:
362460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
363e948693eSPhilip Paeps 
364e948693eSPhilip Paeps 	return (rc);
365e948693eSPhilip Paeps }
366e948693eSPhilip Paeps 
367460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
368e948693eSPhilip Paeps efx_nvram_write_chunk(
369e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
370e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
371e948693eSPhilip Paeps 	__in			unsigned int offset,
372e948693eSPhilip Paeps 	__in_bcount(size)	caddr_t data,
373e948693eSPhilip Paeps 	__in			size_t size)
374e948693eSPhilip Paeps {
375ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
376134c4c4aSAndrew Rybchenko 	uint32_t partn;
377460cb568SAndrew Rybchenko 	efx_rc_t rc;
378e948693eSPhilip Paeps 
379e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
380e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
381e948693eSPhilip Paeps 
382134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
383e948693eSPhilip Paeps 		goto fail1;
384e948693eSPhilip Paeps 
3853d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
3863d670ff5SAndrew Rybchenko 
387134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
388134c4c4aSAndrew Rybchenko 		goto fail2;
389134c4c4aSAndrew Rybchenko 
390e948693eSPhilip Paeps 	return (0);
391e948693eSPhilip Paeps 
392134c4c4aSAndrew Rybchenko fail2:
393134c4c4aSAndrew Rybchenko 	EFSYS_PROBE(fail2);
394e948693eSPhilip Paeps fail1:
395460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
396e948693eSPhilip Paeps 
397e948693eSPhilip Paeps 	return (rc);
398e948693eSPhilip Paeps }
399e948693eSPhilip Paeps 
400e9c123a5SAndrew Rybchenko 	__checkReturn		efx_rc_t
401e948693eSPhilip Paeps efx_nvram_rw_finish(
402e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
403d5106d05SAndrew Rybchenko 	__in			efx_nvram_type_t type,
404d5106d05SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
405e948693eSPhilip Paeps {
406ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
407eb9703daSAndrew Rybchenko 	uint32_t partn;
408d5106d05SAndrew Rybchenko 	uint32_t verify_result = 0;
409e9c123a5SAndrew Rybchenko 	efx_rc_t rc;
410e948693eSPhilip Paeps 
411e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
412e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
413e948693eSPhilip Paeps 
414e9c123a5SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
415e9c123a5SAndrew Rybchenko 		goto fail1;
416e9c123a5SAndrew Rybchenko 
4173d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
4183d670ff5SAndrew Rybchenko 
419a21b2f20SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_finish(enp, partn, &verify_result)) != 0)
420e9c123a5SAndrew Rybchenko 		goto fail2;
421e948693eSPhilip Paeps 
4223d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
423e9c123a5SAndrew Rybchenko 
424d5106d05SAndrew Rybchenko 	if (verify_resultp != NULL)
425d5106d05SAndrew Rybchenko 		*verify_resultp = verify_result;
426d5106d05SAndrew Rybchenko 
427e9c123a5SAndrew Rybchenko 	return (0);
428e9c123a5SAndrew Rybchenko 
429e9c123a5SAndrew Rybchenko fail2:
430e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
4313d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
432e9c123a5SAndrew Rybchenko 
433e9c123a5SAndrew Rybchenko fail1:
434e9c123a5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
435e9c123a5SAndrew Rybchenko 
436d5106d05SAndrew Rybchenko 	/* Always report verification result */
437d5106d05SAndrew Rybchenko 	if (verify_resultp != NULL)
438d5106d05SAndrew Rybchenko 		*verify_resultp = verify_result;
439d5106d05SAndrew Rybchenko 
440e9c123a5SAndrew Rybchenko 	return (rc);
441e948693eSPhilip Paeps }
442e948693eSPhilip Paeps 
443460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
444e948693eSPhilip Paeps efx_nvram_set_version(
445e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
446e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
4473c838a9fSAndrew Rybchenko 	__in_ecount(4)		uint16_t version[4])
448e948693eSPhilip Paeps {
449ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4506d0b856cSAndrew Rybchenko 	uint32_t partn;
451460cb568SAndrew Rybchenko 	efx_rc_t rc;
452e948693eSPhilip Paeps 
453e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
455e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
456e948693eSPhilip Paeps 
4576d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
458e948693eSPhilip Paeps 		goto fail1;
459e948693eSPhilip Paeps 
4603d670ff5SAndrew Rybchenko 	/*
4613d670ff5SAndrew Rybchenko 	 * The Siena implementation of envo_set_version() will attempt to
4623d670ff5SAndrew Rybchenko 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG partition.
4633d670ff5SAndrew Rybchenko 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
4643d670ff5SAndrew Rybchenko 	 */
4653d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
4663d670ff5SAndrew Rybchenko 
4676d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
4686d0b856cSAndrew Rybchenko 		goto fail2;
4696d0b856cSAndrew Rybchenko 
470e948693eSPhilip Paeps 	return (0);
471e948693eSPhilip Paeps 
4726d0b856cSAndrew Rybchenko fail2:
4736d0b856cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
474e948693eSPhilip Paeps fail1:
475460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
476e948693eSPhilip Paeps 
477e948693eSPhilip Paeps 	return (rc);
478e948693eSPhilip Paeps }
479e948693eSPhilip Paeps 
4805abce2b9SAndrew Rybchenko /* Validate buffer contents (before writing to flash) */
4815abce2b9SAndrew Rybchenko 	__checkReturn		efx_rc_t
4825abce2b9SAndrew Rybchenko efx_nvram_validate(
4835abce2b9SAndrew Rybchenko 	__in			efx_nic_t *enp,
4845abce2b9SAndrew Rybchenko 	__in			efx_nvram_type_t type,
4855abce2b9SAndrew Rybchenko 	__in_bcount(partn_size)	caddr_t partn_data,
4865abce2b9SAndrew Rybchenko 	__in			size_t partn_size)
4875abce2b9SAndrew Rybchenko {
488ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4895abce2b9SAndrew Rybchenko 	uint32_t partn;
4905abce2b9SAndrew Rybchenko 	efx_rc_t rc;
4915abce2b9SAndrew Rybchenko 
4925abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4935abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4945abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
4955abce2b9SAndrew Rybchenko 
4965abce2b9SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
4975abce2b9SAndrew Rybchenko 		goto fail1;
4985abce2b9SAndrew Rybchenko 
4996a869fecSAndrew Rybchenko 	if (envop->envo_buffer_validate != NULL) {
500*e919b7ecSAndrew Rybchenko 		if ((rc = envop->envo_buffer_validate(partn,
5016a869fecSAndrew Rybchenko 			    partn_data, partn_size)) != 0)
5025abce2b9SAndrew Rybchenko 			goto fail2;
5036a869fecSAndrew Rybchenko 	}
5045abce2b9SAndrew Rybchenko 
5055abce2b9SAndrew Rybchenko 	return (0);
5065abce2b9SAndrew Rybchenko 
5075abce2b9SAndrew Rybchenko fail2:
5085abce2b9SAndrew Rybchenko 	EFSYS_PROBE(fail2);
5095abce2b9SAndrew Rybchenko fail1:
5105abce2b9SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5115abce2b9SAndrew Rybchenko 
5125abce2b9SAndrew Rybchenko 	return (rc);
5135abce2b9SAndrew Rybchenko }
5145abce2b9SAndrew Rybchenko 
5155abce2b9SAndrew Rybchenko 
516e948693eSPhilip Paeps void
517e948693eSPhilip Paeps efx_nvram_fini(
518e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
519e948693eSPhilip Paeps {
520e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
521e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
522e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
523e948693eSPhilip Paeps 
5243d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
525e948693eSPhilip Paeps 
526e948693eSPhilip Paeps 	enp->en_envop = NULL;
527e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
528e948693eSPhilip Paeps }
529e948693eSPhilip Paeps 
530e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NVRAM */
5313c838a9fSAndrew Rybchenko 
5323c838a9fSAndrew Rybchenko #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
5333c838a9fSAndrew Rybchenko 
5343c838a9fSAndrew Rybchenko /*
5353c838a9fSAndrew Rybchenko  * Internal MCDI request handling
5363c838a9fSAndrew Rybchenko  */
5373c838a9fSAndrew Rybchenko 
538460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5393c838a9fSAndrew Rybchenko efx_mcdi_nvram_partitions(
5403c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5413c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
5423c838a9fSAndrew Rybchenko 	__in			size_t size,
5433c838a9fSAndrew Rybchenko 	__out			unsigned int *npartnp)
5443c838a9fSAndrew Rybchenko {
5453c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
5463c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
5473c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
5483c838a9fSAndrew Rybchenko 	unsigned int npartn;
549460cb568SAndrew Rybchenko 	efx_rc_t rc;
5503c838a9fSAndrew Rybchenko 
5513c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5523c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
5533c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5543c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
5553c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5563c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
5573c838a9fSAndrew Rybchenko 
5583c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
5593c838a9fSAndrew Rybchenko 
5603c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
5613c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5623c838a9fSAndrew Rybchenko 		goto fail1;
5633c838a9fSAndrew Rybchenko 	}
5643c838a9fSAndrew Rybchenko 
5653c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
5663c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5673c838a9fSAndrew Rybchenko 		goto fail2;
5683c838a9fSAndrew Rybchenko 	}
5693c838a9fSAndrew Rybchenko 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
5703c838a9fSAndrew Rybchenko 
5713c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
5723c838a9fSAndrew Rybchenko 		rc = ENOENT;
5733c838a9fSAndrew Rybchenko 		goto fail3;
5743c838a9fSAndrew Rybchenko 	}
5753c838a9fSAndrew Rybchenko 
5763c838a9fSAndrew Rybchenko 	if (size < npartn * sizeof (uint32_t)) {
5773c838a9fSAndrew Rybchenko 		rc = ENOSPC;
5783c838a9fSAndrew Rybchenko 		goto fail3;
5793c838a9fSAndrew Rybchenko 	}
5803c838a9fSAndrew Rybchenko 
5813c838a9fSAndrew Rybchenko 	*npartnp = npartn;
5823c838a9fSAndrew Rybchenko 
5833c838a9fSAndrew Rybchenko 	memcpy(data,
5843c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
5853c838a9fSAndrew Rybchenko 	    (npartn * sizeof (uint32_t)));
5863c838a9fSAndrew Rybchenko 
5873c838a9fSAndrew Rybchenko 	return (0);
5883c838a9fSAndrew Rybchenko 
5893c838a9fSAndrew Rybchenko fail3:
5903c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
5913c838a9fSAndrew Rybchenko fail2:
5923c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
5933c838a9fSAndrew Rybchenko fail1:
594460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5953c838a9fSAndrew Rybchenko 
5963c838a9fSAndrew Rybchenko 	return (rc);
5973c838a9fSAndrew Rybchenko }
5983c838a9fSAndrew Rybchenko 
599460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6003c838a9fSAndrew Rybchenko efx_mcdi_nvram_metadata(
6013c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6023c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
6033c838a9fSAndrew Rybchenko 	__out			uint32_t *subtypep,
6043c838a9fSAndrew Rybchenko 	__out_ecount(4)		uint16_t version[4],
6053c838a9fSAndrew Rybchenko 	__out_bcount_opt(size)	char *descp,
6063c838a9fSAndrew Rybchenko 	__in			size_t size)
6073c838a9fSAndrew Rybchenko {
6083c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
6093c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
6103c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
611460cb568SAndrew Rybchenko 	efx_rc_t rc;
6123c838a9fSAndrew Rybchenko 
6133c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
6143c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
6153c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
6163c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
6173c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
6183c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
6193c838a9fSAndrew Rybchenko 
6203c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
6213c838a9fSAndrew Rybchenko 
622e7144483SAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
6233c838a9fSAndrew Rybchenko 
6243c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6253c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6263c838a9fSAndrew Rybchenko 		goto fail1;
6273c838a9fSAndrew Rybchenko 	}
6283c838a9fSAndrew Rybchenko 
6293c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
6303c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
6313c838a9fSAndrew Rybchenko 		goto fail2;
6323c838a9fSAndrew Rybchenko 	}
6333c838a9fSAndrew Rybchenko 
6343c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6353c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
6363c838a9fSAndrew Rybchenko 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
6373c838a9fSAndrew Rybchenko 	} else {
6383c838a9fSAndrew Rybchenko 		*subtypep = 0;
6393c838a9fSAndrew Rybchenko 	}
6403c838a9fSAndrew Rybchenko 
6413c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6423c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_VERSION_VALID)) {
6433c838a9fSAndrew Rybchenko 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
6443c838a9fSAndrew Rybchenko 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
6453c838a9fSAndrew Rybchenko 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
6463c838a9fSAndrew Rybchenko 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
6473c838a9fSAndrew Rybchenko 	} else {
6483c838a9fSAndrew Rybchenko 		version[0] = version[1] = version[2] = version[3] = 0;
6493c838a9fSAndrew Rybchenko 	}
6503c838a9fSAndrew Rybchenko 
6513c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6523c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
6533c838a9fSAndrew Rybchenko 		/* Return optional descrition string */
6543c838a9fSAndrew Rybchenko 		if ((descp != NULL) && (size > 0)) {
6553c838a9fSAndrew Rybchenko 			size_t desclen;
6563c838a9fSAndrew Rybchenko 
6573c838a9fSAndrew Rybchenko 			descp[0] = '\0';
6583c838a9fSAndrew Rybchenko 			desclen = (req.emr_out_length_used
6593c838a9fSAndrew Rybchenko 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
6603c838a9fSAndrew Rybchenko 
6613c838a9fSAndrew Rybchenko 			EFSYS_ASSERT3U(desclen, <=,
6623c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
6633c838a9fSAndrew Rybchenko 
6643c838a9fSAndrew Rybchenko 			if (size < desclen) {
6653c838a9fSAndrew Rybchenko 				rc = ENOSPC;
6663c838a9fSAndrew Rybchenko 				goto fail3;
6673c838a9fSAndrew Rybchenko 			}
6683c838a9fSAndrew Rybchenko 
6693c838a9fSAndrew Rybchenko 			memcpy(descp, MCDI_OUT2(req, char,
6703c838a9fSAndrew Rybchenko 				NVRAM_METADATA_OUT_DESCRIPTION),
6713c838a9fSAndrew Rybchenko 			    desclen);
6723c838a9fSAndrew Rybchenko 
6733c838a9fSAndrew Rybchenko 			/* Ensure string is NUL terminated */
6743c838a9fSAndrew Rybchenko 			descp[desclen] = '\0';
6753c838a9fSAndrew Rybchenko 		}
6763c838a9fSAndrew Rybchenko 	}
6773c838a9fSAndrew Rybchenko 
6783c838a9fSAndrew Rybchenko 	return (0);
6793c838a9fSAndrew Rybchenko 
6803c838a9fSAndrew Rybchenko fail3:
6813c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
6823c838a9fSAndrew Rybchenko fail2:
6833c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
6843c838a9fSAndrew Rybchenko fail1:
685460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6863c838a9fSAndrew Rybchenko 
6873c838a9fSAndrew Rybchenko 	return (rc);
6883c838a9fSAndrew Rybchenko }
6893c838a9fSAndrew Rybchenko 
690460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6913c838a9fSAndrew Rybchenko efx_mcdi_nvram_info(
6923c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6933c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
6943c838a9fSAndrew Rybchenko 	__out_opt		size_t *sizep,
6953c838a9fSAndrew Rybchenko 	__out_opt		uint32_t *addressp,
6969cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *erase_sizep,
6979cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *write_sizep)
6983c838a9fSAndrew Rybchenko {
6993c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
7009cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
7013c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
702460cb568SAndrew Rybchenko 	efx_rc_t rc;
7033c838a9fSAndrew Rybchenko 
7043c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7053c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_INFO;
7063c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
7073c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
7083c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7099cb71b16SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
7103c838a9fSAndrew Rybchenko 
7113c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
7123c838a9fSAndrew Rybchenko 
7133c838a9fSAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
7143c838a9fSAndrew Rybchenko 
7153c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7163c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7173c838a9fSAndrew Rybchenko 		goto fail1;
7183c838a9fSAndrew Rybchenko 	}
7193c838a9fSAndrew Rybchenko 
7203c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
7213c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
7223c838a9fSAndrew Rybchenko 		goto fail2;
7233c838a9fSAndrew Rybchenko 	}
7243c838a9fSAndrew Rybchenko 
7253c838a9fSAndrew Rybchenko 	if (sizep)
7263c838a9fSAndrew Rybchenko 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
7273c838a9fSAndrew Rybchenko 
7283c838a9fSAndrew Rybchenko 	if (addressp)
7293c838a9fSAndrew Rybchenko 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
7303c838a9fSAndrew Rybchenko 
7313c838a9fSAndrew Rybchenko 	if (erase_sizep)
7323c838a9fSAndrew Rybchenko 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
7333c838a9fSAndrew Rybchenko 
7349cb71b16SAndrew Rybchenko 	if (write_sizep) {
7359cb71b16SAndrew Rybchenko 		*write_sizep =
7369cb71b16SAndrew Rybchenko 			(req.emr_out_length_used <
7379cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
7389cb71b16SAndrew Rybchenko 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
7399cb71b16SAndrew Rybchenko 	}
7409cb71b16SAndrew Rybchenko 
7413c838a9fSAndrew Rybchenko 	return (0);
7423c838a9fSAndrew Rybchenko 
7433c838a9fSAndrew Rybchenko fail2:
7443c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
7453c838a9fSAndrew Rybchenko fail1:
746460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7473c838a9fSAndrew Rybchenko 
7483c838a9fSAndrew Rybchenko 	return (rc);
7493c838a9fSAndrew Rybchenko }
7503c838a9fSAndrew Rybchenko 
751e9c123a5SAndrew Rybchenko /*
752e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
753e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
754e9c123a5SAndrew Rybchenko  */
755460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7563c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_start(
7573c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7583c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
7593c838a9fSAndrew Rybchenko {
760e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
7613c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
7623c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
763460cb568SAndrew Rybchenko 	efx_rc_t rc;
7643c838a9fSAndrew Rybchenko 
7653c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7663c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
7673c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
768e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
7693c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7703c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
7713c838a9fSAndrew Rybchenko 
772e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
773e9c123a5SAndrew Rybchenko 
774e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
775e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
7763c838a9fSAndrew Rybchenko 
7773c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7783c838a9fSAndrew Rybchenko 
7793c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7803c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7813c838a9fSAndrew Rybchenko 		goto fail1;
7823c838a9fSAndrew Rybchenko 	}
7833c838a9fSAndrew Rybchenko 
7843c838a9fSAndrew Rybchenko 	return (0);
7853c838a9fSAndrew Rybchenko 
7863c838a9fSAndrew Rybchenko fail1:
787460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7883c838a9fSAndrew Rybchenko 
7893c838a9fSAndrew Rybchenko 	return (rc);
7903c838a9fSAndrew Rybchenko }
7913c838a9fSAndrew Rybchenko 
792460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7933c838a9fSAndrew Rybchenko efx_mcdi_nvram_read(
7943c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7953c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7963c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
7973c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
7989ad7e03fSAndrew Rybchenko 	__in			size_t size,
7999ad7e03fSAndrew Rybchenko 	__in			uint32_t mode)
8003c838a9fSAndrew Rybchenko {
8013c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8029ad7e03fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
8033c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
804460cb568SAndrew Rybchenko 	efx_rc_t rc;
8053c838a9fSAndrew Rybchenko 
8063c838a9fSAndrew Rybchenko 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
8073c838a9fSAndrew Rybchenko 		rc = EINVAL;
8083c838a9fSAndrew Rybchenko 		goto fail1;
8093c838a9fSAndrew Rybchenko 	}
8103c838a9fSAndrew Rybchenko 
8113c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8123c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_READ;
8133c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8149ad7e03fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
8153c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8163c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
8173c838a9fSAndrew Rybchenko 
8189ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
8199ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
8209ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
8219ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
8223c838a9fSAndrew Rybchenko 
8233c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8243c838a9fSAndrew Rybchenko 
8253c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8263c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8273c838a9fSAndrew Rybchenko 		goto fail1;
8283c838a9fSAndrew Rybchenko 	}
8293c838a9fSAndrew Rybchenko 
8303c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
8313c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
8323c838a9fSAndrew Rybchenko 		goto fail2;
8333c838a9fSAndrew Rybchenko 	}
8343c838a9fSAndrew Rybchenko 
8353c838a9fSAndrew Rybchenko 	memcpy(data,
8363c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
8373c838a9fSAndrew Rybchenko 	    size);
8383c838a9fSAndrew Rybchenko 
8393c838a9fSAndrew Rybchenko 	return (0);
8403c838a9fSAndrew Rybchenko 
8413c838a9fSAndrew Rybchenko fail2:
8423c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
8433c838a9fSAndrew Rybchenko fail1:
844460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8453c838a9fSAndrew Rybchenko 
8463c838a9fSAndrew Rybchenko 	return (rc);
8473c838a9fSAndrew Rybchenko }
8483c838a9fSAndrew Rybchenko 
849460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8503c838a9fSAndrew Rybchenko efx_mcdi_nvram_erase(
8513c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8523c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8533c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
8543c838a9fSAndrew Rybchenko 	__in			size_t size)
8553c838a9fSAndrew Rybchenko {
8563c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8573c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
8583c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
859460cb568SAndrew Rybchenko 	efx_rc_t rc;
8603c838a9fSAndrew Rybchenko 
8613c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8623c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
8633c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8643c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
8653c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8663c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
8673c838a9fSAndrew Rybchenko 
8683c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
8693c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
8703c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
8713c838a9fSAndrew Rybchenko 
8723c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8733c838a9fSAndrew Rybchenko 
8743c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8753c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8763c838a9fSAndrew Rybchenko 		goto fail1;
8773c838a9fSAndrew Rybchenko 	}
8783c838a9fSAndrew Rybchenko 
8793c838a9fSAndrew Rybchenko 	return (0);
8803c838a9fSAndrew Rybchenko 
8813c838a9fSAndrew Rybchenko fail1:
882460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8833c838a9fSAndrew Rybchenko 
8843c838a9fSAndrew Rybchenko 	return (rc);
8853c838a9fSAndrew Rybchenko }
8863c838a9fSAndrew Rybchenko 
88757396b7aSAndrew Rybchenko /*
88857396b7aSAndrew Rybchenko  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
88957396b7aSAndrew Rybchenko  * Sienna and EF10 based boards.  However EF10 based boards support the use
89057396b7aSAndrew Rybchenko  * of this command with payloads up to the maximum MCDI V2 payload length.
89157396b7aSAndrew Rybchenko  */
892460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8933c838a9fSAndrew Rybchenko efx_mcdi_nvram_write(
8943c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8953c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8963c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
897dbcc3c8fSAndrew Rybchenko 	__in_bcount(size)	caddr_t data,
8983c838a9fSAndrew Rybchenko 	__in			size_t size)
8993c838a9fSAndrew Rybchenko {
9003c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
90157396b7aSAndrew Rybchenko 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
90257396b7aSAndrew Rybchenko 			    MCDI_CTL_SDU_LEN_MAX_V2)];
903460cb568SAndrew Rybchenko 	efx_rc_t rc;
90457396b7aSAndrew Rybchenko 	size_t max_data_size;
9053c838a9fSAndrew Rybchenko 
90657396b7aSAndrew Rybchenko 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
90757396b7aSAndrew Rybchenko 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
90857396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
90957396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(max_data_size, <,
91057396b7aSAndrew Rybchenko 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
91157396b7aSAndrew Rybchenko 
91257396b7aSAndrew Rybchenko 	if (size > max_data_size) {
9133c838a9fSAndrew Rybchenko 		rc = EINVAL;
9143c838a9fSAndrew Rybchenko 		goto fail1;
9153c838a9fSAndrew Rybchenko 	}
9163c838a9fSAndrew Rybchenko 
9173c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
9183c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
9193c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
9203c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
9213c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
9223c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
9233c838a9fSAndrew Rybchenko 
9243c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
9253c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
9263c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
9273c838a9fSAndrew Rybchenko 
9283c838a9fSAndrew Rybchenko 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
9293c838a9fSAndrew Rybchenko 	    data, size);
9303c838a9fSAndrew Rybchenko 
9313c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
9323c838a9fSAndrew Rybchenko 
9333c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
9343c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
9353c838a9fSAndrew Rybchenko 		goto fail2;
9363c838a9fSAndrew Rybchenko 	}
9373c838a9fSAndrew Rybchenko 
9383c838a9fSAndrew Rybchenko 	return (0);
9393c838a9fSAndrew Rybchenko 
9403c838a9fSAndrew Rybchenko fail2:
9413c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
9423c838a9fSAndrew Rybchenko fail1:
943460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9443c838a9fSAndrew Rybchenko 
9453c838a9fSAndrew Rybchenko 	return (rc);
9463c838a9fSAndrew Rybchenko }
9473c838a9fSAndrew Rybchenko 
948e9c123a5SAndrew Rybchenko 
949e9c123a5SAndrew Rybchenko /*
950e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
951e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
952e9c123a5SAndrew Rybchenko  */
953460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
9543c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_finish(
9553c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
9563c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
957e9c123a5SAndrew Rybchenko 	__in			boolean_t reboot,
958a21b2f20SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
9593c838a9fSAndrew Rybchenko {
960e9c123a5SAndrew Rybchenko 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
9613c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
962e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
963e9c123a5SAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
964a21b2f20SAndrew Rybchenko 	uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
965460cb568SAndrew Rybchenko 	efx_rc_t rc;
9663c838a9fSAndrew Rybchenko 
9673c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
9683c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
9693c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
970e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
9713c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
972e9c123a5SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
9733c838a9fSAndrew Rybchenko 
974e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
975e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
976e9c123a5SAndrew Rybchenko 
977e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
978e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
9793c838a9fSAndrew Rybchenko 
9803c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
9813c838a9fSAndrew Rybchenko 
9823c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
9833c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
9843c838a9fSAndrew Rybchenko 		goto fail1;
9853c838a9fSAndrew Rybchenko 	}
9863c838a9fSAndrew Rybchenko 
987f0d3455bSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
988a21b2f20SAndrew Rybchenko 		verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
989348d3529SAndrew Rybchenko 		if (encp->enc_nvram_update_verify_result_supported) {
990348d3529SAndrew Rybchenko 			/* Result of update verification is missing */
991e9c123a5SAndrew Rybchenko 			rc = EMSGSIZE;
992e9c123a5SAndrew Rybchenko 			goto fail2;
993e9c123a5SAndrew Rybchenko 		}
994f0d3455bSAndrew Rybchenko 	} else {
995a21b2f20SAndrew Rybchenko 		verify_result =
996e9c123a5SAndrew Rybchenko 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
997f0d3455bSAndrew Rybchenko 	}
998e9c123a5SAndrew Rybchenko 
999348d3529SAndrew Rybchenko 	if ((encp->enc_nvram_update_verify_result_supported) &&
1000a21b2f20SAndrew Rybchenko 	    (verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)) {
1001348d3529SAndrew Rybchenko 		/* Update verification failed */
1002e9c123a5SAndrew Rybchenko 		rc = EINVAL;
1003e9c123a5SAndrew Rybchenko 		goto fail3;
1004e9c123a5SAndrew Rybchenko 	}
1005e9c123a5SAndrew Rybchenko 
1006a21b2f20SAndrew Rybchenko 	if (verify_resultp != NULL)
1007a21b2f20SAndrew Rybchenko 		*verify_resultp = verify_result;
1008e9c123a5SAndrew Rybchenko 
10093c838a9fSAndrew Rybchenko 	return (0);
10103c838a9fSAndrew Rybchenko 
1011e9c123a5SAndrew Rybchenko fail3:
1012e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail3);
1013e9c123a5SAndrew Rybchenko fail2:
1014e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
10153c838a9fSAndrew Rybchenko fail1:
1016460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10173c838a9fSAndrew Rybchenko 
1018e9c123a5SAndrew Rybchenko 	/* Always report verification result */
1019a21b2f20SAndrew Rybchenko 	if (verify_resultp != NULL)
1020a21b2f20SAndrew Rybchenko 		*verify_resultp = verify_result;
1021e9c123a5SAndrew Rybchenko 
10223c838a9fSAndrew Rybchenko 	return (rc);
10233c838a9fSAndrew Rybchenko }
10243c838a9fSAndrew Rybchenko 
10253c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
10263c838a9fSAndrew Rybchenko 
1027460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
10283c838a9fSAndrew Rybchenko efx_mcdi_nvram_test(
10293c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
10303c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
10313c838a9fSAndrew Rybchenko {
10323c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
10333c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
10343c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
10353c838a9fSAndrew Rybchenko 	int result;
1036460cb568SAndrew Rybchenko 	efx_rc_t rc;
10373c838a9fSAndrew Rybchenko 
10383c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
10393c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_TEST;
10403c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
10413c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
10423c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
10433c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
10443c838a9fSAndrew Rybchenko 
10453c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
10463c838a9fSAndrew Rybchenko 
10473c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
10483c838a9fSAndrew Rybchenko 
10493c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
10503c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
10513c838a9fSAndrew Rybchenko 		goto fail1;
10523c838a9fSAndrew Rybchenko 	}
10533c838a9fSAndrew Rybchenko 
10543c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
10553c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
10563c838a9fSAndrew Rybchenko 		goto fail2;
10573c838a9fSAndrew Rybchenko 	}
10583c838a9fSAndrew Rybchenko 
10593c838a9fSAndrew Rybchenko 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
10603c838a9fSAndrew Rybchenko 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
10613c838a9fSAndrew Rybchenko 
10623c838a9fSAndrew Rybchenko 		EFSYS_PROBE1(nvram_test_failure, int, partn);
10633c838a9fSAndrew Rybchenko 
10643c838a9fSAndrew Rybchenko 		rc = (EINVAL);
10653c838a9fSAndrew Rybchenko 		goto fail3;
10663c838a9fSAndrew Rybchenko 	}
10673c838a9fSAndrew Rybchenko 
10683c838a9fSAndrew Rybchenko 	return (0);
10693c838a9fSAndrew Rybchenko 
10703c838a9fSAndrew Rybchenko fail3:
10713c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
10723c838a9fSAndrew Rybchenko fail2:
10733c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
10743c838a9fSAndrew Rybchenko fail1:
1075460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10763c838a9fSAndrew Rybchenko 
10773c838a9fSAndrew Rybchenko 	return (rc);
10783c838a9fSAndrew Rybchenko }
10793c838a9fSAndrew Rybchenko 
10803c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
10813c838a9fSAndrew Rybchenko 
10823c838a9fSAndrew Rybchenko 
10833c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1084