xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision 3d670ff5319583e94b61f591b7b0c209295fe88a)
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 */
51b60ff840SAndrew Rybchenko 	siena_nvram_partn_erase,	/* envo_partn_erase */
52134c4c4aSAndrew Rybchenko 	siena_nvram_partn_write,	/* envo_partn_write */
53eb9703daSAndrew Rybchenko 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
5492187119SAndrew Rybchenko 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
556d0b856cSAndrew Rybchenko 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
565abce2b9SAndrew Rybchenko 	NULL,				/* envo_partn_validate */
57e948693eSPhilip Paeps };
58e948693eSPhilip Paeps 
59e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
60e948693eSPhilip Paeps 
61de9775adSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
623c838a9fSAndrew Rybchenko 
63ec831f7fSAndrew Rybchenko static const efx_nvram_ops_t	__efx_nvram_ef10_ops = {
643c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
65de9775adSAndrew Rybchenko 	ef10_nvram_test,		/* envo_test */
663c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
67bce88e31SAndrew Rybchenko 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
6856bd83b0SAndrew Rybchenko 	ef10_nvram_partn_size,		/* envo_partn_size */
695d846e87SAndrew Rybchenko 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
700afdf29cSAndrew Rybchenko 	ef10_nvram_partn_read,		/* envo_partn_read */
71b60ff840SAndrew Rybchenko 	ef10_nvram_partn_erase,		/* envo_partn_erase */
72134c4c4aSAndrew Rybchenko 	ef10_nvram_partn_write,		/* envo_partn_write */
73eb9703daSAndrew Rybchenko 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
7492187119SAndrew Rybchenko 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
756d0b856cSAndrew Rybchenko 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
765abce2b9SAndrew Rybchenko 	ef10_nvram_buffer_validate,	/* envo_buffer_validate */
773c838a9fSAndrew Rybchenko };
783c838a9fSAndrew Rybchenko 
79de9775adSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
803c838a9fSAndrew Rybchenko 
81460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
82e948693eSPhilip Paeps efx_nvram_init(
83e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
84e948693eSPhilip Paeps {
85ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop;
86460cb568SAndrew Rybchenko 	efx_rc_t rc;
87e948693eSPhilip Paeps 
88e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
89e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
90e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
91e948693eSPhilip Paeps 
92e948693eSPhilip Paeps 	switch (enp->en_family) {
93e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
94e948693eSPhilip Paeps 	case EFX_FAMILY_SIENA:
95ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_siena_ops;
96e948693eSPhilip Paeps 		break;
97e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
98e948693eSPhilip Paeps 
993c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1003c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
101ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
1023c838a9fSAndrew Rybchenko 		break;
1033c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
1043c838a9fSAndrew Rybchenko 
105de9775adSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
106de9775adSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
107ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
108de9775adSAndrew Rybchenko 		break;
109de9775adSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD */
110de9775adSAndrew Rybchenko 
111e948693eSPhilip Paeps 	default:
112e948693eSPhilip Paeps 		EFSYS_ASSERT(0);
113e948693eSPhilip Paeps 		rc = ENOTSUP;
114e948693eSPhilip Paeps 		goto fail1;
115e948693eSPhilip Paeps 	}
116e948693eSPhilip Paeps 
117e948693eSPhilip Paeps 	enp->en_envop = envop;
118e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_NVRAM;
119e948693eSPhilip Paeps 
120*3d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
121*3d670ff5SAndrew Rybchenko 
122e948693eSPhilip Paeps 	return (0);
123e948693eSPhilip Paeps 
124e948693eSPhilip Paeps fail1:
125460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
126e948693eSPhilip Paeps 
127e948693eSPhilip Paeps 	return (rc);
128e948693eSPhilip Paeps }
129e948693eSPhilip Paeps 
130e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
131e948693eSPhilip Paeps 
132460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
133e948693eSPhilip Paeps efx_nvram_test(
134e948693eSPhilip Paeps 	__in			efx_nic_t *enp)
135e948693eSPhilip Paeps {
136ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
137460cb568SAndrew Rybchenko 	efx_rc_t rc;
138e948693eSPhilip Paeps 
139e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
140e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
141e948693eSPhilip Paeps 
142e948693eSPhilip Paeps 	if ((rc = envop->envo_test(enp)) != 0)
143e948693eSPhilip Paeps 		goto fail1;
144e948693eSPhilip Paeps 
145e948693eSPhilip Paeps 	return (0);
146e948693eSPhilip Paeps 
147e948693eSPhilip Paeps fail1:
148460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
149e948693eSPhilip Paeps 
150e948693eSPhilip Paeps 	return (rc);
151e948693eSPhilip Paeps }
152e948693eSPhilip Paeps 
153e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
154e948693eSPhilip Paeps 
155460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
156e948693eSPhilip Paeps efx_nvram_size(
157e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
158e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
159e948693eSPhilip Paeps 	__out			size_t *sizep)
160e948693eSPhilip Paeps {
161ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
16256bd83b0SAndrew Rybchenko 	uint32_t partn;
163460cb568SAndrew Rybchenko 	efx_rc_t rc;
164e948693eSPhilip Paeps 
165e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
166e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
167e948693eSPhilip Paeps 
168e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
169e948693eSPhilip Paeps 
17056bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
171e948693eSPhilip Paeps 		goto fail1;
172e948693eSPhilip Paeps 
17356bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
17456bd83b0SAndrew Rybchenko 		goto fail2;
17556bd83b0SAndrew Rybchenko 
176e948693eSPhilip Paeps 	return (0);
177e948693eSPhilip Paeps 
17856bd83b0SAndrew Rybchenko fail2:
17956bd83b0SAndrew Rybchenko 	EFSYS_PROBE(fail2);
180e948693eSPhilip Paeps fail1:
181460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
18256bd83b0SAndrew Rybchenko 	*sizep = 0;
183e948693eSPhilip Paeps 
184e948693eSPhilip Paeps 	return (rc);
185e948693eSPhilip Paeps }
186e948693eSPhilip Paeps 
187460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
188e948693eSPhilip Paeps efx_nvram_get_version(
189e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
190e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
191e948693eSPhilip Paeps 	__out			uint32_t *subtypep,
192e948693eSPhilip Paeps 	__out_ecount(4)		uint16_t version[4])
193e948693eSPhilip Paeps {
194ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
19592187119SAndrew Rybchenko 	uint32_t partn;
196460cb568SAndrew Rybchenko 	efx_rc_t rc;
197e948693eSPhilip Paeps 
198e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
199e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
200e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
201e948693eSPhilip Paeps 
202e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
203e948693eSPhilip Paeps 
20492187119SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
205e948693eSPhilip Paeps 		goto fail1;
206e948693eSPhilip Paeps 
20792187119SAndrew Rybchenko 	if ((rc = envop->envo_partn_get_version(enp, partn,
20892187119SAndrew Rybchenko 		    subtypep, version)) != 0)
20992187119SAndrew Rybchenko 		goto fail2;
21092187119SAndrew Rybchenko 
211e948693eSPhilip Paeps 	return (0);
212e948693eSPhilip Paeps 
21392187119SAndrew Rybchenko fail2:
21492187119SAndrew Rybchenko 	EFSYS_PROBE(fail2);
215e948693eSPhilip Paeps fail1:
216460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
217e948693eSPhilip Paeps 
218e948693eSPhilip Paeps 	return (rc);
219e948693eSPhilip Paeps }
220e948693eSPhilip Paeps 
221460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
222e948693eSPhilip Paeps efx_nvram_rw_start(
223e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
224e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
225e948693eSPhilip Paeps 	__out_opt		size_t *chunk_sizep)
226e948693eSPhilip Paeps {
227ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2285d846e87SAndrew Rybchenko 	uint32_t partn;
229460cb568SAndrew Rybchenko 	efx_rc_t rc;
230e948693eSPhilip Paeps 
231e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
232e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
233e948693eSPhilip Paeps 
234e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
235e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
236e948693eSPhilip Paeps 
2375d846e87SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
238e948693eSPhilip Paeps 		goto fail1;
239e948693eSPhilip Paeps 
240*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
241*3d670ff5SAndrew Rybchenko 
2425d846e87SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
2435d846e87SAndrew Rybchenko 		goto fail2;
2445d846e87SAndrew Rybchenko 
245*3d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = partn;
246e948693eSPhilip Paeps 
247e948693eSPhilip Paeps 	return (0);
248e948693eSPhilip Paeps 
2495d846e87SAndrew Rybchenko fail2:
2505d846e87SAndrew Rybchenko 	EFSYS_PROBE(fail2);
251e948693eSPhilip Paeps fail1:
252460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
253e948693eSPhilip Paeps 
254e948693eSPhilip Paeps 	return (rc);
255e948693eSPhilip Paeps }
256e948693eSPhilip Paeps 
257460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
258e948693eSPhilip Paeps efx_nvram_read_chunk(
259e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
260e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
261e948693eSPhilip Paeps 	__in			unsigned int offset,
262e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
263e948693eSPhilip Paeps 	__in			size_t size)
264e948693eSPhilip Paeps {
265ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2660afdf29cSAndrew Rybchenko 	uint32_t partn;
267460cb568SAndrew Rybchenko 	efx_rc_t rc;
268e948693eSPhilip Paeps 
269e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
270e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
271e948693eSPhilip Paeps 
272e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
273e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
274e948693eSPhilip Paeps 
2750afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
276e948693eSPhilip Paeps 		goto fail1;
277e948693eSPhilip Paeps 
278*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
279*3d670ff5SAndrew Rybchenko 
2800afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
2810afdf29cSAndrew Rybchenko 		goto fail2;
2820afdf29cSAndrew Rybchenko 
283e948693eSPhilip Paeps 	return (0);
284e948693eSPhilip Paeps 
2850afdf29cSAndrew Rybchenko fail2:
2860afdf29cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
287e948693eSPhilip Paeps fail1:
288460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
289e948693eSPhilip Paeps 
290e948693eSPhilip Paeps 	return (rc);
291e948693eSPhilip Paeps }
292e948693eSPhilip Paeps 
293460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
294e948693eSPhilip Paeps efx_nvram_erase(
295e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
296e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
297e948693eSPhilip Paeps {
298ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
299b60ff840SAndrew Rybchenko 	unsigned int offset = 0;
300b60ff840SAndrew Rybchenko 	size_t size = 0;
301b60ff840SAndrew Rybchenko 	uint32_t partn;
302460cb568SAndrew Rybchenko 	efx_rc_t rc;
303e948693eSPhilip Paeps 
304e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
305e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
306e948693eSPhilip Paeps 
307e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
308e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
309e948693eSPhilip Paeps 
310b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
311e948693eSPhilip Paeps 		goto fail1;
312e948693eSPhilip Paeps 
313*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
314*3d670ff5SAndrew Rybchenko 
315b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
316b60ff840SAndrew Rybchenko 		goto fail2;
317b60ff840SAndrew Rybchenko 
318b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
319b60ff840SAndrew Rybchenko 		goto fail3;
320b60ff840SAndrew Rybchenko 
321e948693eSPhilip Paeps 	return (0);
322e948693eSPhilip Paeps 
323b60ff840SAndrew Rybchenko fail3:
324b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail3);
325b60ff840SAndrew Rybchenko fail2:
326b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail2);
327e948693eSPhilip Paeps fail1:
328460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
329e948693eSPhilip Paeps 
330e948693eSPhilip Paeps 	return (rc);
331e948693eSPhilip Paeps }
332e948693eSPhilip Paeps 
333460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
334e948693eSPhilip Paeps efx_nvram_write_chunk(
335e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
336e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
337e948693eSPhilip Paeps 	__in			unsigned int offset,
338e948693eSPhilip Paeps 	__in_bcount(size)	caddr_t data,
339e948693eSPhilip Paeps 	__in			size_t size)
340e948693eSPhilip Paeps {
341ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
342134c4c4aSAndrew Rybchenko 	uint32_t partn;
343460cb568SAndrew Rybchenko 	efx_rc_t rc;
344e948693eSPhilip Paeps 
345e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
346e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
347e948693eSPhilip Paeps 
348e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
349e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
350e948693eSPhilip Paeps 
351134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
352e948693eSPhilip Paeps 		goto fail1;
353e948693eSPhilip Paeps 
354*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
355*3d670ff5SAndrew Rybchenko 
356134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
357134c4c4aSAndrew Rybchenko 		goto fail2;
358134c4c4aSAndrew Rybchenko 
359e948693eSPhilip Paeps 	return (0);
360e948693eSPhilip Paeps 
361134c4c4aSAndrew Rybchenko fail2:
362134c4c4aSAndrew Rybchenko 	EFSYS_PROBE(fail2);
363e948693eSPhilip Paeps fail1:
364460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
365e948693eSPhilip Paeps 
366e948693eSPhilip Paeps 	return (rc);
367e948693eSPhilip Paeps }
368e948693eSPhilip Paeps 
369e9c123a5SAndrew Rybchenko 	__checkReturn		efx_rc_t
370e948693eSPhilip Paeps efx_nvram_rw_finish(
371e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
372d5106d05SAndrew Rybchenko 	__in			efx_nvram_type_t type,
373d5106d05SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
374e948693eSPhilip Paeps {
375ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
376eb9703daSAndrew Rybchenko 	uint32_t partn;
377d5106d05SAndrew Rybchenko 	uint32_t verify_result = 0;
378e9c123a5SAndrew Rybchenko 	efx_rc_t rc;
379e948693eSPhilip Paeps 
380e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
381e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
382e948693eSPhilip Paeps 
383e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
384e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
385e948693eSPhilip Paeps 
386e9c123a5SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
387e9c123a5SAndrew Rybchenko 		goto fail1;
388e9c123a5SAndrew Rybchenko 
389*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
390*3d670ff5SAndrew Rybchenko 
391a21b2f20SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_finish(enp, partn, &verify_result)) != 0)
392e9c123a5SAndrew Rybchenko 		goto fail2;
393e948693eSPhilip Paeps 
394*3d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
395e9c123a5SAndrew Rybchenko 
396d5106d05SAndrew Rybchenko 	if (verify_resultp != NULL)
397d5106d05SAndrew Rybchenko 		*verify_resultp = verify_result;
398d5106d05SAndrew Rybchenko 
399e9c123a5SAndrew Rybchenko 	return (0);
400e9c123a5SAndrew Rybchenko 
401e9c123a5SAndrew Rybchenko fail2:
402e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
403*3d670ff5SAndrew Rybchenko 	enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
404e9c123a5SAndrew Rybchenko 
405e9c123a5SAndrew Rybchenko fail1:
406e9c123a5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
407e9c123a5SAndrew Rybchenko 
408d5106d05SAndrew Rybchenko 	/* Always report verification result */
409d5106d05SAndrew Rybchenko 	if (verify_resultp != NULL)
410d5106d05SAndrew Rybchenko 		*verify_resultp = verify_result;
411d5106d05SAndrew Rybchenko 
412e9c123a5SAndrew Rybchenko 	return (rc);
413e948693eSPhilip Paeps }
414e948693eSPhilip Paeps 
415460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
416e948693eSPhilip Paeps efx_nvram_set_version(
417e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
418e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
4193c838a9fSAndrew Rybchenko 	__in_ecount(4)		uint16_t version[4])
420e948693eSPhilip Paeps {
421ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4226d0b856cSAndrew Rybchenko 	uint32_t partn;
423460cb568SAndrew Rybchenko 	efx_rc_t rc;
424e948693eSPhilip Paeps 
425e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
426e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
427e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
428e948693eSPhilip Paeps 
429e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
430e948693eSPhilip Paeps 
4316d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
432e948693eSPhilip Paeps 		goto fail1;
433e948693eSPhilip Paeps 
434*3d670ff5SAndrew Rybchenko 	/*
435*3d670ff5SAndrew Rybchenko 	 * The Siena implementation of envo_set_version() will attempt to
436*3d670ff5SAndrew Rybchenko 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG partition.
437*3d670ff5SAndrew Rybchenko 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
438*3d670ff5SAndrew Rybchenko 	 */
439*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
440*3d670ff5SAndrew Rybchenko 
4416d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
4426d0b856cSAndrew Rybchenko 		goto fail2;
4436d0b856cSAndrew Rybchenko 
444e948693eSPhilip Paeps 	return (0);
445e948693eSPhilip Paeps 
4466d0b856cSAndrew Rybchenko fail2:
4476d0b856cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
448e948693eSPhilip Paeps fail1:
449460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
450e948693eSPhilip Paeps 
451e948693eSPhilip Paeps 	return (rc);
452e948693eSPhilip Paeps }
453e948693eSPhilip Paeps 
4545abce2b9SAndrew Rybchenko /* Validate buffer contents (before writing to flash) */
4555abce2b9SAndrew Rybchenko 	__checkReturn		efx_rc_t
4565abce2b9SAndrew Rybchenko efx_nvram_validate(
4575abce2b9SAndrew Rybchenko 	__in			efx_nic_t *enp,
4585abce2b9SAndrew Rybchenko 	__in			efx_nvram_type_t type,
4595abce2b9SAndrew Rybchenko 	__in_bcount(partn_size)	caddr_t partn_data,
4605abce2b9SAndrew Rybchenko 	__in			size_t partn_size)
4615abce2b9SAndrew Rybchenko {
462ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4635abce2b9SAndrew Rybchenko 	uint32_t partn;
4645abce2b9SAndrew Rybchenko 	efx_rc_t rc;
4655abce2b9SAndrew Rybchenko 
4665abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4675abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4685abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
4695abce2b9SAndrew Rybchenko 
4705abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
4715abce2b9SAndrew Rybchenko 
4725abce2b9SAndrew Rybchenko 
4735abce2b9SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
4745abce2b9SAndrew Rybchenko 		goto fail1;
4755abce2b9SAndrew Rybchenko 
4765abce2b9SAndrew Rybchenko 	if (envop->envo_type_to_partn != NULL &&
4775abce2b9SAndrew Rybchenko 	    ((rc = envop->envo_buffer_validate(enp, partn,
4785abce2b9SAndrew Rybchenko 	    partn_data, partn_size)) != 0))
4795abce2b9SAndrew Rybchenko 		goto fail2;
4805abce2b9SAndrew Rybchenko 
4815abce2b9SAndrew Rybchenko 	return (0);
4825abce2b9SAndrew Rybchenko 
4835abce2b9SAndrew Rybchenko fail2:
4845abce2b9SAndrew Rybchenko 	EFSYS_PROBE(fail2);
4855abce2b9SAndrew Rybchenko fail1:
4865abce2b9SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4875abce2b9SAndrew Rybchenko 
4885abce2b9SAndrew Rybchenko 	return (rc);
4895abce2b9SAndrew Rybchenko }
4905abce2b9SAndrew Rybchenko 
4915abce2b9SAndrew Rybchenko 
492e948693eSPhilip Paeps void
493e948693eSPhilip Paeps efx_nvram_fini(
494e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
495e948693eSPhilip Paeps {
496e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
497e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
498e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
499e948693eSPhilip Paeps 
500*3d670ff5SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
501e948693eSPhilip Paeps 
502e948693eSPhilip Paeps 	enp->en_envop = NULL;
503e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
504e948693eSPhilip Paeps }
505e948693eSPhilip Paeps 
506e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NVRAM */
5073c838a9fSAndrew Rybchenko 
5083c838a9fSAndrew Rybchenko #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
5093c838a9fSAndrew Rybchenko 
5103c838a9fSAndrew Rybchenko /*
5113c838a9fSAndrew Rybchenko  * Internal MCDI request handling
5123c838a9fSAndrew Rybchenko  */
5133c838a9fSAndrew Rybchenko 
514460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5153c838a9fSAndrew Rybchenko efx_mcdi_nvram_partitions(
5163c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5173c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
5183c838a9fSAndrew Rybchenko 	__in			size_t size,
5193c838a9fSAndrew Rybchenko 	__out			unsigned int *npartnp)
5203c838a9fSAndrew Rybchenko {
5213c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
5223c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
5233c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
5243c838a9fSAndrew Rybchenko 	unsigned int npartn;
525460cb568SAndrew Rybchenko 	efx_rc_t rc;
5263c838a9fSAndrew Rybchenko 
5273c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5283c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
5293c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5303c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
5313c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5323c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
5333c838a9fSAndrew Rybchenko 
5343c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
5353c838a9fSAndrew Rybchenko 
5363c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
5373c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5383c838a9fSAndrew Rybchenko 		goto fail1;
5393c838a9fSAndrew Rybchenko 	}
5403c838a9fSAndrew Rybchenko 
5413c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
5423c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5433c838a9fSAndrew Rybchenko 		goto fail2;
5443c838a9fSAndrew Rybchenko 	}
5453c838a9fSAndrew Rybchenko 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
5463c838a9fSAndrew Rybchenko 
5473c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
5483c838a9fSAndrew Rybchenko 		rc = ENOENT;
5493c838a9fSAndrew Rybchenko 		goto fail3;
5503c838a9fSAndrew Rybchenko 	}
5513c838a9fSAndrew Rybchenko 
5523c838a9fSAndrew Rybchenko 	if (size < npartn * sizeof (uint32_t)) {
5533c838a9fSAndrew Rybchenko 		rc = ENOSPC;
5543c838a9fSAndrew Rybchenko 		goto fail3;
5553c838a9fSAndrew Rybchenko 	}
5563c838a9fSAndrew Rybchenko 
5573c838a9fSAndrew Rybchenko 	*npartnp = npartn;
5583c838a9fSAndrew Rybchenko 
5593c838a9fSAndrew Rybchenko 	memcpy(data,
5603c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
5613c838a9fSAndrew Rybchenko 	    (npartn * sizeof (uint32_t)));
5623c838a9fSAndrew Rybchenko 
5633c838a9fSAndrew Rybchenko 	return (0);
5643c838a9fSAndrew Rybchenko 
5653c838a9fSAndrew Rybchenko fail3:
5663c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
5673c838a9fSAndrew Rybchenko fail2:
5683c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
5693c838a9fSAndrew Rybchenko fail1:
570460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5713c838a9fSAndrew Rybchenko 
5723c838a9fSAndrew Rybchenko 	return (rc);
5733c838a9fSAndrew Rybchenko }
5743c838a9fSAndrew Rybchenko 
575460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5763c838a9fSAndrew Rybchenko efx_mcdi_nvram_metadata(
5773c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5783c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
5793c838a9fSAndrew Rybchenko 	__out			uint32_t *subtypep,
5803c838a9fSAndrew Rybchenko 	__out_ecount(4)		uint16_t version[4],
5813c838a9fSAndrew Rybchenko 	__out_bcount_opt(size)	char *descp,
5823c838a9fSAndrew Rybchenko 	__in			size_t size)
5833c838a9fSAndrew Rybchenko {
5843c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
5853c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
5863c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
587460cb568SAndrew Rybchenko 	efx_rc_t rc;
5883c838a9fSAndrew Rybchenko 
5893c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5903c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
5913c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5923c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
5933c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5943c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
5953c838a9fSAndrew Rybchenko 
5963c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
5973c838a9fSAndrew Rybchenko 
5983c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
5993c838a9fSAndrew Rybchenko 
6003c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6013c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6023c838a9fSAndrew Rybchenko 		goto fail1;
6033c838a9fSAndrew Rybchenko 	}
6043c838a9fSAndrew Rybchenko 
6053c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
6063c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
6073c838a9fSAndrew Rybchenko 		goto fail2;
6083c838a9fSAndrew Rybchenko 	}
6093c838a9fSAndrew Rybchenko 
6103c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6113c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
6123c838a9fSAndrew Rybchenko 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
6133c838a9fSAndrew Rybchenko 	} else {
6143c838a9fSAndrew Rybchenko 		*subtypep = 0;
6153c838a9fSAndrew Rybchenko 	}
6163c838a9fSAndrew Rybchenko 
6173c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6183c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_VERSION_VALID)) {
6193c838a9fSAndrew Rybchenko 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
6203c838a9fSAndrew Rybchenko 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
6213c838a9fSAndrew Rybchenko 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
6223c838a9fSAndrew Rybchenko 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
6233c838a9fSAndrew Rybchenko 	} else {
6243c838a9fSAndrew Rybchenko 		version[0] = version[1] = version[2] = version[3] = 0;
6253c838a9fSAndrew Rybchenko 	}
6263c838a9fSAndrew Rybchenko 
6273c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6283c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
6293c838a9fSAndrew Rybchenko 		/* Return optional descrition string */
6303c838a9fSAndrew Rybchenko 		if ((descp != NULL) && (size > 0)) {
6313c838a9fSAndrew Rybchenko 			size_t desclen;
6323c838a9fSAndrew Rybchenko 
6333c838a9fSAndrew Rybchenko 			descp[0] = '\0';
6343c838a9fSAndrew Rybchenko 			desclen = (req.emr_out_length_used
6353c838a9fSAndrew Rybchenko 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
6363c838a9fSAndrew Rybchenko 
6373c838a9fSAndrew Rybchenko 			EFSYS_ASSERT3U(desclen, <=,
6383c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
6393c838a9fSAndrew Rybchenko 
6403c838a9fSAndrew Rybchenko 			if (size < desclen) {
6413c838a9fSAndrew Rybchenko 				rc = ENOSPC;
6423c838a9fSAndrew Rybchenko 				goto fail3;
6433c838a9fSAndrew Rybchenko 			}
6443c838a9fSAndrew Rybchenko 
6453c838a9fSAndrew Rybchenko 			memcpy(descp, MCDI_OUT2(req, char,
6463c838a9fSAndrew Rybchenko 				NVRAM_METADATA_OUT_DESCRIPTION),
6473c838a9fSAndrew Rybchenko 			    desclen);
6483c838a9fSAndrew Rybchenko 
6493c838a9fSAndrew Rybchenko 			/* Ensure string is NUL terminated */
6503c838a9fSAndrew Rybchenko 			descp[desclen] = '\0';
6513c838a9fSAndrew Rybchenko 		}
6523c838a9fSAndrew Rybchenko 	}
6533c838a9fSAndrew Rybchenko 
6543c838a9fSAndrew Rybchenko 	return (0);
6553c838a9fSAndrew Rybchenko 
6563c838a9fSAndrew Rybchenko fail3:
6573c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
6583c838a9fSAndrew Rybchenko fail2:
6593c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
6603c838a9fSAndrew Rybchenko fail1:
661460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6623c838a9fSAndrew Rybchenko 
6633c838a9fSAndrew Rybchenko 	return (rc);
6643c838a9fSAndrew Rybchenko }
6653c838a9fSAndrew Rybchenko 
666460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6673c838a9fSAndrew Rybchenko efx_mcdi_nvram_info(
6683c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6693c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
6703c838a9fSAndrew Rybchenko 	__out_opt		size_t *sizep,
6713c838a9fSAndrew Rybchenko 	__out_opt		uint32_t *addressp,
6729cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *erase_sizep,
6739cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *write_sizep)
6743c838a9fSAndrew Rybchenko {
6753c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
6769cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
6773c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
678460cb568SAndrew Rybchenko 	efx_rc_t rc;
6793c838a9fSAndrew Rybchenko 
6803c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
6813c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_INFO;
6823c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
6833c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
6843c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
6859cb71b16SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
6863c838a9fSAndrew Rybchenko 
6873c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
6883c838a9fSAndrew Rybchenko 
6893c838a9fSAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
6903c838a9fSAndrew Rybchenko 
6913c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6923c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6933c838a9fSAndrew Rybchenko 		goto fail1;
6943c838a9fSAndrew Rybchenko 	}
6953c838a9fSAndrew Rybchenko 
6963c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
6973c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
6983c838a9fSAndrew Rybchenko 		goto fail2;
6993c838a9fSAndrew Rybchenko 	}
7003c838a9fSAndrew Rybchenko 
7013c838a9fSAndrew Rybchenko 	if (sizep)
7023c838a9fSAndrew Rybchenko 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
7033c838a9fSAndrew Rybchenko 
7043c838a9fSAndrew Rybchenko 	if (addressp)
7053c838a9fSAndrew Rybchenko 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
7063c838a9fSAndrew Rybchenko 
7073c838a9fSAndrew Rybchenko 	if (erase_sizep)
7083c838a9fSAndrew Rybchenko 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
7093c838a9fSAndrew Rybchenko 
7109cb71b16SAndrew Rybchenko 	if (write_sizep) {
7119cb71b16SAndrew Rybchenko 		*write_sizep =
7129cb71b16SAndrew Rybchenko 			(req.emr_out_length_used <
7139cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
7149cb71b16SAndrew Rybchenko 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
7159cb71b16SAndrew Rybchenko 	}
7169cb71b16SAndrew Rybchenko 
7173c838a9fSAndrew Rybchenko 	return (0);
7183c838a9fSAndrew Rybchenko 
7193c838a9fSAndrew Rybchenko fail2:
7203c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
7213c838a9fSAndrew Rybchenko fail1:
722460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7233c838a9fSAndrew Rybchenko 
7243c838a9fSAndrew Rybchenko 	return (rc);
7253c838a9fSAndrew Rybchenko }
7263c838a9fSAndrew Rybchenko 
727e9c123a5SAndrew Rybchenko /*
728e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
729e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
730e9c123a5SAndrew Rybchenko  */
731460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7323c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_start(
7333c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7343c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
7353c838a9fSAndrew Rybchenko {
736e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
7373c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
7383c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
739460cb568SAndrew Rybchenko 	efx_rc_t rc;
7403c838a9fSAndrew Rybchenko 
7413c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7423c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
7433c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
744e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
7453c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7463c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
7473c838a9fSAndrew Rybchenko 
748e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
749e9c123a5SAndrew Rybchenko 
750e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
751e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
7523c838a9fSAndrew Rybchenko 
7533c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7543c838a9fSAndrew Rybchenko 
7553c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7563c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7573c838a9fSAndrew Rybchenko 		goto fail1;
7583c838a9fSAndrew Rybchenko 	}
7593c838a9fSAndrew Rybchenko 
7603c838a9fSAndrew Rybchenko 	return (0);
7613c838a9fSAndrew Rybchenko 
7623c838a9fSAndrew Rybchenko fail1:
763460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7643c838a9fSAndrew Rybchenko 
7653c838a9fSAndrew Rybchenko 	return (rc);
7663c838a9fSAndrew Rybchenko }
7673c838a9fSAndrew Rybchenko 
768460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7693c838a9fSAndrew Rybchenko efx_mcdi_nvram_read(
7703c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7713c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7723c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
7733c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
7749ad7e03fSAndrew Rybchenko 	__in			size_t size,
7759ad7e03fSAndrew Rybchenko 	__in			uint32_t mode)
7763c838a9fSAndrew Rybchenko {
7773c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
7789ad7e03fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
7793c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
780460cb568SAndrew Rybchenko 	efx_rc_t rc;
7813c838a9fSAndrew Rybchenko 
7823c838a9fSAndrew Rybchenko 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
7833c838a9fSAndrew Rybchenko 		rc = EINVAL;
7843c838a9fSAndrew Rybchenko 		goto fail1;
7853c838a9fSAndrew Rybchenko 	}
7863c838a9fSAndrew Rybchenko 
7873c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7883c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_READ;
7893c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
7909ad7e03fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
7913c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7923c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
7933c838a9fSAndrew Rybchenko 
7949ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
7959ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
7969ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
7979ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
7983c838a9fSAndrew Rybchenko 
7993c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8003c838a9fSAndrew Rybchenko 
8013c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8023c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8033c838a9fSAndrew Rybchenko 		goto fail1;
8043c838a9fSAndrew Rybchenko 	}
8053c838a9fSAndrew Rybchenko 
8063c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
8073c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
8083c838a9fSAndrew Rybchenko 		goto fail2;
8093c838a9fSAndrew Rybchenko 	}
8103c838a9fSAndrew Rybchenko 
8113c838a9fSAndrew Rybchenko 	memcpy(data,
8123c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
8133c838a9fSAndrew Rybchenko 	    size);
8143c838a9fSAndrew Rybchenko 
8153c838a9fSAndrew Rybchenko 	return (0);
8163c838a9fSAndrew Rybchenko 
8173c838a9fSAndrew Rybchenko fail2:
8183c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
8193c838a9fSAndrew Rybchenko fail1:
820460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8213c838a9fSAndrew Rybchenko 
8223c838a9fSAndrew Rybchenko 	return (rc);
8233c838a9fSAndrew Rybchenko }
8243c838a9fSAndrew Rybchenko 
825460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8263c838a9fSAndrew Rybchenko efx_mcdi_nvram_erase(
8273c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8283c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8293c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
8303c838a9fSAndrew Rybchenko 	__in			size_t size)
8313c838a9fSAndrew Rybchenko {
8323c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8333c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
8343c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
835460cb568SAndrew Rybchenko 	efx_rc_t rc;
8363c838a9fSAndrew Rybchenko 
8373c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8383c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
8393c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8403c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
8413c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8423c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
8433c838a9fSAndrew Rybchenko 
8443c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
8453c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
8463c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
8473c838a9fSAndrew Rybchenko 
8483c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8493c838a9fSAndrew Rybchenko 
8503c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8513c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8523c838a9fSAndrew Rybchenko 		goto fail1;
8533c838a9fSAndrew Rybchenko 	}
8543c838a9fSAndrew Rybchenko 
8553c838a9fSAndrew Rybchenko 	return (0);
8563c838a9fSAndrew Rybchenko 
8573c838a9fSAndrew Rybchenko fail1:
858460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8593c838a9fSAndrew Rybchenko 
8603c838a9fSAndrew Rybchenko 	return (rc);
8613c838a9fSAndrew Rybchenko }
8623c838a9fSAndrew Rybchenko 
86357396b7aSAndrew Rybchenko /*
86457396b7aSAndrew Rybchenko  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
86557396b7aSAndrew Rybchenko  * Sienna and EF10 based boards.  However EF10 based boards support the use
86657396b7aSAndrew Rybchenko  * of this command with payloads up to the maximum MCDI V2 payload length.
86757396b7aSAndrew Rybchenko  */
868460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8693c838a9fSAndrew Rybchenko efx_mcdi_nvram_write(
8703c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8713c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8723c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
8733c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
8743c838a9fSAndrew Rybchenko 	__in			size_t size)
8753c838a9fSAndrew Rybchenko {
8763c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
87757396b7aSAndrew Rybchenko 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
87857396b7aSAndrew Rybchenko 			    MCDI_CTL_SDU_LEN_MAX_V2)];
879460cb568SAndrew Rybchenko 	efx_rc_t rc;
88057396b7aSAndrew Rybchenko 	size_t max_data_size;
8813c838a9fSAndrew Rybchenko 
88257396b7aSAndrew Rybchenko 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
88357396b7aSAndrew Rybchenko 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
88457396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
88557396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(max_data_size, <,
88657396b7aSAndrew Rybchenko 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
88757396b7aSAndrew Rybchenko 
88857396b7aSAndrew Rybchenko 	if (size > max_data_size) {
8893c838a9fSAndrew Rybchenko 		rc = EINVAL;
8903c838a9fSAndrew Rybchenko 		goto fail1;
8913c838a9fSAndrew Rybchenko 	}
8923c838a9fSAndrew Rybchenko 
8933c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8943c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
8953c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8963c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
8973c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8983c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
8993c838a9fSAndrew Rybchenko 
9003c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
9013c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
9023c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
9033c838a9fSAndrew Rybchenko 
9043c838a9fSAndrew Rybchenko 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
9053c838a9fSAndrew Rybchenko 	    data, size);
9063c838a9fSAndrew Rybchenko 
9073c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
9083c838a9fSAndrew Rybchenko 
9093c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
9103c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
9113c838a9fSAndrew Rybchenko 		goto fail2;
9123c838a9fSAndrew Rybchenko 	}
9133c838a9fSAndrew Rybchenko 
9143c838a9fSAndrew Rybchenko 	return (0);
9153c838a9fSAndrew Rybchenko 
9163c838a9fSAndrew Rybchenko fail2:
9173c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
9183c838a9fSAndrew Rybchenko fail1:
919460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9203c838a9fSAndrew Rybchenko 
9213c838a9fSAndrew Rybchenko 	return (rc);
9223c838a9fSAndrew Rybchenko }
9233c838a9fSAndrew Rybchenko 
924e9c123a5SAndrew Rybchenko 
925e9c123a5SAndrew Rybchenko /*
926e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
927e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
928e9c123a5SAndrew Rybchenko  */
929460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
9303c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_finish(
9313c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
9323c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
933e9c123a5SAndrew Rybchenko 	__in			boolean_t reboot,
934a21b2f20SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
9353c838a9fSAndrew Rybchenko {
936e9c123a5SAndrew Rybchenko 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
9373c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
938e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
939e9c123a5SAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
940a21b2f20SAndrew Rybchenko 	uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
941460cb568SAndrew Rybchenko 	efx_rc_t rc;
9423c838a9fSAndrew Rybchenko 
9433c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
9443c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
9453c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
946e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
9473c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
948e9c123a5SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
9493c838a9fSAndrew Rybchenko 
950e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
951e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
952e9c123a5SAndrew Rybchenko 
953e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
954e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
9553c838a9fSAndrew Rybchenko 
9563c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
9573c838a9fSAndrew Rybchenko 
9583c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
9593c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
9603c838a9fSAndrew Rybchenko 		goto fail1;
9613c838a9fSAndrew Rybchenko 	}
9623c838a9fSAndrew Rybchenko 
963f0d3455bSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
964a21b2f20SAndrew Rybchenko 		verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
965348d3529SAndrew Rybchenko 		if (encp->enc_nvram_update_verify_result_supported) {
966348d3529SAndrew Rybchenko 			/* Result of update verification is missing */
967e9c123a5SAndrew Rybchenko 			rc = EMSGSIZE;
968e9c123a5SAndrew Rybchenko 			goto fail2;
969e9c123a5SAndrew Rybchenko 		}
970f0d3455bSAndrew Rybchenko 	} else {
971a21b2f20SAndrew Rybchenko 		verify_result =
972e9c123a5SAndrew Rybchenko 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
973f0d3455bSAndrew Rybchenko 	}
974e9c123a5SAndrew Rybchenko 
975348d3529SAndrew Rybchenko 	if ((encp->enc_nvram_update_verify_result_supported) &&
976a21b2f20SAndrew Rybchenko 	    (verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)) {
977348d3529SAndrew Rybchenko 		/* Update verification failed */
978e9c123a5SAndrew Rybchenko 		rc = EINVAL;
979e9c123a5SAndrew Rybchenko 		goto fail3;
980e9c123a5SAndrew Rybchenko 	}
981e9c123a5SAndrew Rybchenko 
982a21b2f20SAndrew Rybchenko 	if (verify_resultp != NULL)
983a21b2f20SAndrew Rybchenko 		*verify_resultp = verify_result;
984e9c123a5SAndrew Rybchenko 
9853c838a9fSAndrew Rybchenko 	return (0);
9863c838a9fSAndrew Rybchenko 
987e9c123a5SAndrew Rybchenko fail3:
988e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail3);
989e9c123a5SAndrew Rybchenko fail2:
990e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
9913c838a9fSAndrew Rybchenko fail1:
992460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9933c838a9fSAndrew Rybchenko 
994e9c123a5SAndrew Rybchenko 	/* Always report verification result */
995a21b2f20SAndrew Rybchenko 	if (verify_resultp != NULL)
996a21b2f20SAndrew Rybchenko 		*verify_resultp = verify_result;
997e9c123a5SAndrew Rybchenko 
9983c838a9fSAndrew Rybchenko 	return (rc);
9993c838a9fSAndrew Rybchenko }
10003c838a9fSAndrew Rybchenko 
10013c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
10023c838a9fSAndrew Rybchenko 
1003460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
10043c838a9fSAndrew Rybchenko efx_mcdi_nvram_test(
10053c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
10063c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
10073c838a9fSAndrew Rybchenko {
10083c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
10093c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
10103c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
10113c838a9fSAndrew Rybchenko 	int result;
1012460cb568SAndrew Rybchenko 	efx_rc_t rc;
10133c838a9fSAndrew Rybchenko 
10143c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
10153c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_TEST;
10163c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
10173c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
10183c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
10193c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
10203c838a9fSAndrew Rybchenko 
10213c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
10223c838a9fSAndrew Rybchenko 
10233c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
10243c838a9fSAndrew Rybchenko 
10253c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
10263c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
10273c838a9fSAndrew Rybchenko 		goto fail1;
10283c838a9fSAndrew Rybchenko 	}
10293c838a9fSAndrew Rybchenko 
10303c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
10313c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
10323c838a9fSAndrew Rybchenko 		goto fail2;
10333c838a9fSAndrew Rybchenko 	}
10343c838a9fSAndrew Rybchenko 
10353c838a9fSAndrew Rybchenko 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
10363c838a9fSAndrew Rybchenko 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
10373c838a9fSAndrew Rybchenko 
10383c838a9fSAndrew Rybchenko 		EFSYS_PROBE1(nvram_test_failure, int, partn);
10393c838a9fSAndrew Rybchenko 
10403c838a9fSAndrew Rybchenko 		rc = (EINVAL);
10413c838a9fSAndrew Rybchenko 		goto fail3;
10423c838a9fSAndrew Rybchenko 	}
10433c838a9fSAndrew Rybchenko 
10443c838a9fSAndrew Rybchenko 	return (0);
10453c838a9fSAndrew Rybchenko 
10463c838a9fSAndrew Rybchenko fail3:
10473c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
10483c838a9fSAndrew Rybchenko fail2:
10493c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
10503c838a9fSAndrew Rybchenko fail1:
1051460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10523c838a9fSAndrew Rybchenko 
10533c838a9fSAndrew Rybchenko 	return (rc);
10543c838a9fSAndrew Rybchenko }
10553c838a9fSAndrew Rybchenko 
10563c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
10573c838a9fSAndrew Rybchenko 
10583c838a9fSAndrew Rybchenko 
10593c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1060