xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision e9c123a567874d52ed0ce675a3281f32a24c79d4)
1e948693eSPhilip Paeps /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2009-2016 Solarflare Communications Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
4e948693eSPhilip Paeps  *
5e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
63c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
7e948693eSPhilip Paeps  *
83c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
93c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
103c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
123c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
133c838a9fSAndrew Rybchenko  *
143c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
153c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
163c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
173c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
183c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
193c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
203c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
213c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
223c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
233c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
243c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253c838a9fSAndrew Rybchenko  *
263c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
273c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
283c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
29e948693eSPhilip Paeps  */
30e948693eSPhilip Paeps 
315dee87d7SPhilip Paeps #include <sys/cdefs.h>
325dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
335dee87d7SPhilip Paeps 
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps 
37e948693eSPhilip Paeps #if EFSYS_OPT_NVRAM
38e948693eSPhilip Paeps 
39e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
40e948693eSPhilip Paeps 
41ec831f7fSAndrew Rybchenko static const efx_nvram_ops_t	__efx_nvram_siena_ops = {
42e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
43e948693eSPhilip Paeps 	siena_nvram_test,		/* envo_test */
44e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
45bce88e31SAndrew Rybchenko 	siena_nvram_type_to_partn,	/* envo_type_to_partn */
4656bd83b0SAndrew Rybchenko 	siena_nvram_partn_size,		/* envo_partn_size */
475d846e87SAndrew Rybchenko 	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
480afdf29cSAndrew Rybchenko 	siena_nvram_partn_read,		/* envo_partn_read */
49b60ff840SAndrew Rybchenko 	siena_nvram_partn_erase,	/* envo_partn_erase */
50134c4c4aSAndrew Rybchenko 	siena_nvram_partn_write,	/* envo_partn_write */
51eb9703daSAndrew Rybchenko 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
5292187119SAndrew Rybchenko 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
536d0b856cSAndrew Rybchenko 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
545abce2b9SAndrew Rybchenko 	NULL,				/* envo_partn_validate */
55e948693eSPhilip Paeps };
56e948693eSPhilip Paeps 
57e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
58e948693eSPhilip Paeps 
59de9775adSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
603c838a9fSAndrew Rybchenko 
61ec831f7fSAndrew Rybchenko static const efx_nvram_ops_t	__efx_nvram_ef10_ops = {
623c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
63de9775adSAndrew Rybchenko 	ef10_nvram_test,		/* envo_test */
643c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
65bce88e31SAndrew Rybchenko 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
6656bd83b0SAndrew Rybchenko 	ef10_nvram_partn_size,		/* envo_partn_size */
675d846e87SAndrew Rybchenko 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
680afdf29cSAndrew Rybchenko 	ef10_nvram_partn_read,		/* envo_partn_read */
69b60ff840SAndrew Rybchenko 	ef10_nvram_partn_erase,		/* envo_partn_erase */
70134c4c4aSAndrew Rybchenko 	ef10_nvram_partn_write,		/* envo_partn_write */
71eb9703daSAndrew Rybchenko 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
7292187119SAndrew Rybchenko 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
736d0b856cSAndrew Rybchenko 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
745abce2b9SAndrew Rybchenko 	ef10_nvram_buffer_validate,	/* envo_buffer_validate */
753c838a9fSAndrew Rybchenko };
763c838a9fSAndrew Rybchenko 
77de9775adSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
783c838a9fSAndrew Rybchenko 
79460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
80e948693eSPhilip Paeps efx_nvram_init(
81e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
82e948693eSPhilip Paeps {
83ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop;
84460cb568SAndrew Rybchenko 	efx_rc_t rc;
85e948693eSPhilip Paeps 
86e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
87e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
88e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
89e948693eSPhilip Paeps 
90e948693eSPhilip Paeps 	switch (enp->en_family) {
91e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
92e948693eSPhilip Paeps 	case EFX_FAMILY_SIENA:
93ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_siena_ops;
94e948693eSPhilip Paeps 		break;
95e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
96e948693eSPhilip Paeps 
973c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
983c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
99ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
1003c838a9fSAndrew Rybchenko 		break;
1013c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
1023c838a9fSAndrew Rybchenko 
103de9775adSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
104de9775adSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
105ec831f7fSAndrew Rybchenko 		envop = &__efx_nvram_ef10_ops;
106de9775adSAndrew Rybchenko 		break;
107de9775adSAndrew Rybchenko #endif	/* EFSYS_OPT_MEDFORD */
108de9775adSAndrew Rybchenko 
109e948693eSPhilip Paeps 	default:
110e948693eSPhilip Paeps 		EFSYS_ASSERT(0);
111e948693eSPhilip Paeps 		rc = ENOTSUP;
112e948693eSPhilip Paeps 		goto fail1;
113e948693eSPhilip Paeps 	}
114e948693eSPhilip Paeps 
115e948693eSPhilip Paeps 	enp->en_envop = envop;
116e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_NVRAM;
117e948693eSPhilip Paeps 
118e948693eSPhilip Paeps 	return (0);
119e948693eSPhilip Paeps 
120e948693eSPhilip Paeps fail1:
121460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
122e948693eSPhilip Paeps 
123e948693eSPhilip Paeps 	return (rc);
124e948693eSPhilip Paeps }
125e948693eSPhilip Paeps 
126e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
127e948693eSPhilip Paeps 
128460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
129e948693eSPhilip Paeps efx_nvram_test(
130e948693eSPhilip Paeps 	__in			efx_nic_t *enp)
131e948693eSPhilip Paeps {
132ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
133460cb568SAndrew Rybchenko 	efx_rc_t rc;
134e948693eSPhilip Paeps 
135e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
136e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
137e948693eSPhilip Paeps 
138e948693eSPhilip Paeps 	if ((rc = envop->envo_test(enp)) != 0)
139e948693eSPhilip Paeps 		goto fail1;
140e948693eSPhilip Paeps 
141e948693eSPhilip Paeps 	return (0);
142e948693eSPhilip Paeps 
143e948693eSPhilip Paeps fail1:
144460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
145e948693eSPhilip Paeps 
146e948693eSPhilip Paeps 	return (rc);
147e948693eSPhilip Paeps }
148e948693eSPhilip Paeps 
149e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
150e948693eSPhilip Paeps 
151460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
152e948693eSPhilip Paeps efx_nvram_size(
153e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
154e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
155e948693eSPhilip Paeps 	__out			size_t *sizep)
156e948693eSPhilip Paeps {
157ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
15856bd83b0SAndrew Rybchenko 	uint32_t partn;
159460cb568SAndrew Rybchenko 	efx_rc_t rc;
160e948693eSPhilip Paeps 
161e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
162e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
163e948693eSPhilip Paeps 
164e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
165e948693eSPhilip Paeps 
16656bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
167e948693eSPhilip Paeps 		goto fail1;
168e948693eSPhilip Paeps 
16956bd83b0SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
17056bd83b0SAndrew Rybchenko 		goto fail2;
17156bd83b0SAndrew Rybchenko 
172e948693eSPhilip Paeps 	return (0);
173e948693eSPhilip Paeps 
17456bd83b0SAndrew Rybchenko fail2:
17556bd83b0SAndrew Rybchenko 	EFSYS_PROBE(fail2);
176e948693eSPhilip Paeps fail1:
177460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
17856bd83b0SAndrew Rybchenko 	*sizep = 0;
179e948693eSPhilip Paeps 
180e948693eSPhilip Paeps 	return (rc);
181e948693eSPhilip Paeps }
182e948693eSPhilip Paeps 
183460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
184e948693eSPhilip Paeps efx_nvram_get_version(
185e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
186e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
187e948693eSPhilip Paeps 	__out			uint32_t *subtypep,
188e948693eSPhilip Paeps 	__out_ecount(4)		uint16_t version[4])
189e948693eSPhilip Paeps {
190ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
19192187119SAndrew Rybchenko 	uint32_t partn;
192460cb568SAndrew Rybchenko 	efx_rc_t rc;
193e948693eSPhilip Paeps 
194e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
195e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
196e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
197e948693eSPhilip Paeps 
198e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
199e948693eSPhilip Paeps 
20092187119SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
201e948693eSPhilip Paeps 		goto fail1;
202e948693eSPhilip Paeps 
20392187119SAndrew Rybchenko 	if ((rc = envop->envo_partn_get_version(enp, partn,
20492187119SAndrew Rybchenko 		    subtypep, version)) != 0)
20592187119SAndrew Rybchenko 		goto fail2;
20692187119SAndrew Rybchenko 
207e948693eSPhilip Paeps 	return (0);
208e948693eSPhilip Paeps 
20992187119SAndrew Rybchenko fail2:
21092187119SAndrew Rybchenko 	EFSYS_PROBE(fail2);
211e948693eSPhilip Paeps fail1:
212460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
213e948693eSPhilip Paeps 
214e948693eSPhilip Paeps 	return (rc);
215e948693eSPhilip Paeps }
216e948693eSPhilip Paeps 
217460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
218e948693eSPhilip Paeps efx_nvram_rw_start(
219e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
220e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
221e948693eSPhilip Paeps 	__out_opt		size_t *chunk_sizep)
222e948693eSPhilip Paeps {
223ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2245d846e87SAndrew Rybchenko 	uint32_t partn;
225460cb568SAndrew Rybchenko 	efx_rc_t rc;
226e948693eSPhilip Paeps 
227e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
228e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
229e948693eSPhilip Paeps 
230e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
231e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
232e948693eSPhilip Paeps 
233e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
234e948693eSPhilip Paeps 
2355d846e87SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
236e948693eSPhilip Paeps 		goto fail1;
237e948693eSPhilip Paeps 
2385d846e87SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
2395d846e87SAndrew Rybchenko 		goto fail2;
2405d846e87SAndrew Rybchenko 
241e948693eSPhilip Paeps 	enp->en_nvram_locked = type;
242e948693eSPhilip Paeps 
243e948693eSPhilip Paeps 	return (0);
244e948693eSPhilip Paeps 
2455d846e87SAndrew Rybchenko fail2:
2465d846e87SAndrew Rybchenko 	EFSYS_PROBE(fail2);
247e948693eSPhilip Paeps fail1:
248460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
249e948693eSPhilip Paeps 
250e948693eSPhilip Paeps 	return (rc);
251e948693eSPhilip Paeps }
252e948693eSPhilip Paeps 
253460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
254e948693eSPhilip Paeps efx_nvram_read_chunk(
255e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
256e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
257e948693eSPhilip Paeps 	__in			unsigned int offset,
258e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
259e948693eSPhilip Paeps 	__in			size_t size)
260e948693eSPhilip Paeps {
261ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
2620afdf29cSAndrew Rybchenko 	uint32_t partn;
263460cb568SAndrew Rybchenko 	efx_rc_t rc;
264e948693eSPhilip Paeps 
265e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
266e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
267e948693eSPhilip Paeps 
268e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
269e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
270e948693eSPhilip Paeps 
271e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
272e948693eSPhilip Paeps 
2730afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
274e948693eSPhilip Paeps 		goto fail1;
275e948693eSPhilip Paeps 
2760afdf29cSAndrew Rybchenko 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
2770afdf29cSAndrew Rybchenko 		goto fail2;
2780afdf29cSAndrew Rybchenko 
279e948693eSPhilip Paeps 	return (0);
280e948693eSPhilip Paeps 
2810afdf29cSAndrew Rybchenko fail2:
2820afdf29cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
283e948693eSPhilip Paeps fail1:
284460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
285e948693eSPhilip Paeps 
286e948693eSPhilip Paeps 	return (rc);
287e948693eSPhilip Paeps }
288e948693eSPhilip Paeps 
289460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
290e948693eSPhilip Paeps efx_nvram_erase(
291e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
292e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
293e948693eSPhilip Paeps {
294ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
295b60ff840SAndrew Rybchenko 	unsigned int offset = 0;
296b60ff840SAndrew Rybchenko 	size_t size = 0;
297b60ff840SAndrew Rybchenko 	uint32_t partn;
298460cb568SAndrew Rybchenko 	efx_rc_t rc;
299e948693eSPhilip Paeps 
300e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
301e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
302e948693eSPhilip Paeps 
303e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
304e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
305e948693eSPhilip Paeps 
306e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
307e948693eSPhilip Paeps 
308b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
309e948693eSPhilip Paeps 		goto fail1;
310e948693eSPhilip Paeps 
311b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
312b60ff840SAndrew Rybchenko 		goto fail2;
313b60ff840SAndrew Rybchenko 
314b60ff840SAndrew Rybchenko 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
315b60ff840SAndrew Rybchenko 		goto fail3;
316b60ff840SAndrew Rybchenko 
317e948693eSPhilip Paeps 	return (0);
318e948693eSPhilip Paeps 
319b60ff840SAndrew Rybchenko fail3:
320b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail3);
321b60ff840SAndrew Rybchenko fail2:
322b60ff840SAndrew Rybchenko 	EFSYS_PROBE(fail2);
323e948693eSPhilip Paeps fail1:
324460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
325e948693eSPhilip Paeps 
326e948693eSPhilip Paeps 	return (rc);
327e948693eSPhilip Paeps }
328e948693eSPhilip Paeps 
329460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
330e948693eSPhilip Paeps efx_nvram_write_chunk(
331e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
332e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
333e948693eSPhilip Paeps 	__in			unsigned int offset,
334e948693eSPhilip Paeps 	__in_bcount(size)	caddr_t data,
335e948693eSPhilip Paeps 	__in			size_t size)
336e948693eSPhilip Paeps {
337ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
338134c4c4aSAndrew 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 
344e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
345e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
346e948693eSPhilip Paeps 
347e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
348e948693eSPhilip Paeps 
349134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
350e948693eSPhilip Paeps 		goto fail1;
351e948693eSPhilip Paeps 
352134c4c4aSAndrew Rybchenko 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
353134c4c4aSAndrew Rybchenko 		goto fail2;
354134c4c4aSAndrew Rybchenko 
355e948693eSPhilip Paeps 	return (0);
356e948693eSPhilip Paeps 
357134c4c4aSAndrew Rybchenko fail2:
358134c4c4aSAndrew Rybchenko 	EFSYS_PROBE(fail2);
359e948693eSPhilip Paeps fail1:
360460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
361e948693eSPhilip Paeps 
362e948693eSPhilip Paeps 	return (rc);
363e948693eSPhilip Paeps }
364e948693eSPhilip Paeps 
365*e9c123a5SAndrew Rybchenko 	__checkReturn		efx_rc_t
366e948693eSPhilip Paeps efx_nvram_rw_finish(
367e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
368e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
369e948693eSPhilip Paeps {
370ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
371eb9703daSAndrew Rybchenko 	uint32_t partn;
372*e9c123a5SAndrew Rybchenko 	efx_rc_t rc;
373e948693eSPhilip Paeps 
374e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
375e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
376e948693eSPhilip Paeps 
377e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
378e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
379e948693eSPhilip Paeps 
380e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
381e948693eSPhilip Paeps 
382*e9c123a5SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
383*e9c123a5SAndrew Rybchenko 		goto fail1;
384*e9c123a5SAndrew Rybchenko 
385*e9c123a5SAndrew Rybchenko 	if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
386*e9c123a5SAndrew Rybchenko 		goto fail2;
387e948693eSPhilip Paeps 
388e948693eSPhilip Paeps 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
389*e9c123a5SAndrew Rybchenko 
390*e9c123a5SAndrew Rybchenko 	return (0);
391*e9c123a5SAndrew Rybchenko 
392*e9c123a5SAndrew Rybchenko fail2:
393*e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
394*e9c123a5SAndrew Rybchenko 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
395*e9c123a5SAndrew Rybchenko 
396*e9c123a5SAndrew Rybchenko fail1:
397*e9c123a5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
398*e9c123a5SAndrew Rybchenko 
399*e9c123a5SAndrew Rybchenko 	return (rc);
400e948693eSPhilip Paeps }
401e948693eSPhilip Paeps 
402460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
403e948693eSPhilip Paeps efx_nvram_set_version(
404e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
405e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
4063c838a9fSAndrew Rybchenko 	__in_ecount(4)		uint16_t version[4])
407e948693eSPhilip Paeps {
408ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4096d0b856cSAndrew Rybchenko 	uint32_t partn;
410460cb568SAndrew Rybchenko 	efx_rc_t rc;
411e948693eSPhilip Paeps 
412e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
415e948693eSPhilip Paeps 
416e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
417e948693eSPhilip Paeps 
418e948693eSPhilip Paeps 	/*
419e948693eSPhilip Paeps 	 * The Siena implementation of envo_set_version() will attempt to
420e948693eSPhilip Paeps 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
421e948693eSPhilip Paeps 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
422e948693eSPhilip Paeps 	 */
423e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
424e948693eSPhilip Paeps 
4256d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
426e948693eSPhilip Paeps 		goto fail1;
427e948693eSPhilip Paeps 
4286d0b856cSAndrew Rybchenko 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
4296d0b856cSAndrew Rybchenko 		goto fail2;
4306d0b856cSAndrew Rybchenko 
431e948693eSPhilip Paeps 	return (0);
432e948693eSPhilip Paeps 
4336d0b856cSAndrew Rybchenko fail2:
4346d0b856cSAndrew Rybchenko 	EFSYS_PROBE(fail2);
435e948693eSPhilip Paeps fail1:
436460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
437e948693eSPhilip Paeps 
438e948693eSPhilip Paeps 	return (rc);
439e948693eSPhilip Paeps }
440e948693eSPhilip Paeps 
4415abce2b9SAndrew Rybchenko /* Validate buffer contents (before writing to flash) */
4425abce2b9SAndrew Rybchenko 	__checkReturn		efx_rc_t
4435abce2b9SAndrew Rybchenko efx_nvram_validate(
4445abce2b9SAndrew Rybchenko 	__in			efx_nic_t *enp,
4455abce2b9SAndrew Rybchenko 	__in			efx_nvram_type_t type,
4465abce2b9SAndrew Rybchenko 	__in_bcount(partn_size)	caddr_t partn_data,
4475abce2b9SAndrew Rybchenko 	__in			size_t partn_size)
4485abce2b9SAndrew Rybchenko {
449ec831f7fSAndrew Rybchenko 	const efx_nvram_ops_t *envop = enp->en_envop;
4505abce2b9SAndrew Rybchenko 	uint32_t partn;
4515abce2b9SAndrew Rybchenko 	efx_rc_t rc;
4525abce2b9SAndrew Rybchenko 
4535abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4545abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4555abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
4565abce2b9SAndrew Rybchenko 
4575abce2b9SAndrew Rybchenko 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
4585abce2b9SAndrew Rybchenko 
4595abce2b9SAndrew Rybchenko 
4605abce2b9SAndrew Rybchenko 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
4615abce2b9SAndrew Rybchenko 		goto fail1;
4625abce2b9SAndrew Rybchenko 
4635abce2b9SAndrew Rybchenko 	if (envop->envo_type_to_partn != NULL &&
4645abce2b9SAndrew Rybchenko 	    ((rc = envop->envo_buffer_validate(enp, partn,
4655abce2b9SAndrew Rybchenko 	    partn_data, partn_size)) != 0))
4665abce2b9SAndrew Rybchenko 		goto fail2;
4675abce2b9SAndrew Rybchenko 
4685abce2b9SAndrew Rybchenko 	return (0);
4695abce2b9SAndrew Rybchenko 
4705abce2b9SAndrew Rybchenko fail2:
4715abce2b9SAndrew Rybchenko 	EFSYS_PROBE(fail2);
4725abce2b9SAndrew Rybchenko fail1:
4735abce2b9SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4745abce2b9SAndrew Rybchenko 
4755abce2b9SAndrew Rybchenko 	return (rc);
4765abce2b9SAndrew Rybchenko }
4775abce2b9SAndrew Rybchenko 
4785abce2b9SAndrew Rybchenko 
479e948693eSPhilip Paeps void
480e948693eSPhilip Paeps efx_nvram_fini(
481e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
482e948693eSPhilip Paeps {
483e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
484e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
485e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
486e948693eSPhilip Paeps 
487e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
488e948693eSPhilip Paeps 
489e948693eSPhilip Paeps 	enp->en_envop = NULL;
490e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
491e948693eSPhilip Paeps }
492e948693eSPhilip Paeps 
493e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NVRAM */
4943c838a9fSAndrew Rybchenko 
4953c838a9fSAndrew Rybchenko #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
4963c838a9fSAndrew Rybchenko 
4973c838a9fSAndrew Rybchenko /*
4983c838a9fSAndrew Rybchenko  * Internal MCDI request handling
4993c838a9fSAndrew Rybchenko  */
5003c838a9fSAndrew Rybchenko 
501460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5023c838a9fSAndrew Rybchenko efx_mcdi_nvram_partitions(
5033c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5043c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
5053c838a9fSAndrew Rybchenko 	__in			size_t size,
5063c838a9fSAndrew Rybchenko 	__out			unsigned int *npartnp)
5073c838a9fSAndrew Rybchenko {
5083c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
5093c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
5103c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
5113c838a9fSAndrew Rybchenko 	unsigned int npartn;
512460cb568SAndrew Rybchenko 	efx_rc_t rc;
5133c838a9fSAndrew Rybchenko 
5143c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5153c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
5163c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5173c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
5183c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5193c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
5203c838a9fSAndrew Rybchenko 
5213c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
5223c838a9fSAndrew Rybchenko 
5233c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
5243c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5253c838a9fSAndrew Rybchenko 		goto fail1;
5263c838a9fSAndrew Rybchenko 	}
5273c838a9fSAndrew Rybchenko 
5283c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
5293c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5303c838a9fSAndrew Rybchenko 		goto fail2;
5313c838a9fSAndrew Rybchenko 	}
5323c838a9fSAndrew Rybchenko 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
5333c838a9fSAndrew Rybchenko 
5343c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
5353c838a9fSAndrew Rybchenko 		rc = ENOENT;
5363c838a9fSAndrew Rybchenko 		goto fail3;
5373c838a9fSAndrew Rybchenko 	}
5383c838a9fSAndrew Rybchenko 
5393c838a9fSAndrew Rybchenko 	if (size < npartn * sizeof (uint32_t)) {
5403c838a9fSAndrew Rybchenko 		rc = ENOSPC;
5413c838a9fSAndrew Rybchenko 		goto fail3;
5423c838a9fSAndrew Rybchenko 	}
5433c838a9fSAndrew Rybchenko 
5443c838a9fSAndrew Rybchenko 	*npartnp = npartn;
5453c838a9fSAndrew Rybchenko 
5463c838a9fSAndrew Rybchenko 	memcpy(data,
5473c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
5483c838a9fSAndrew Rybchenko 	    (npartn * sizeof (uint32_t)));
5493c838a9fSAndrew Rybchenko 
5503c838a9fSAndrew Rybchenko 	return (0);
5513c838a9fSAndrew Rybchenko 
5523c838a9fSAndrew Rybchenko fail3:
5533c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
5543c838a9fSAndrew Rybchenko fail2:
5553c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
5563c838a9fSAndrew Rybchenko fail1:
557460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5583c838a9fSAndrew Rybchenko 
5593c838a9fSAndrew Rybchenko 	return (rc);
5603c838a9fSAndrew Rybchenko }
5613c838a9fSAndrew Rybchenko 
562460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5633c838a9fSAndrew Rybchenko efx_mcdi_nvram_metadata(
5643c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5653c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
5663c838a9fSAndrew Rybchenko 	__out			uint32_t *subtypep,
5673c838a9fSAndrew Rybchenko 	__out_ecount(4)		uint16_t version[4],
5683c838a9fSAndrew Rybchenko 	__out_bcount_opt(size)	char *descp,
5693c838a9fSAndrew Rybchenko 	__in			size_t size)
5703c838a9fSAndrew Rybchenko {
5713c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
5723c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
5733c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
574460cb568SAndrew Rybchenko 	efx_rc_t rc;
5753c838a9fSAndrew Rybchenko 
5763c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5773c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
5783c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5793c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
5803c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5813c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
5823c838a9fSAndrew Rybchenko 
5833c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
5843c838a9fSAndrew Rybchenko 
5853c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
5863c838a9fSAndrew Rybchenko 
5873c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
5883c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5893c838a9fSAndrew Rybchenko 		goto fail1;
5903c838a9fSAndrew Rybchenko 	}
5913c838a9fSAndrew Rybchenko 
5923c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
5933c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5943c838a9fSAndrew Rybchenko 		goto fail2;
5953c838a9fSAndrew Rybchenko 	}
5963c838a9fSAndrew Rybchenko 
5973c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
5983c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
5993c838a9fSAndrew Rybchenko 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
6003c838a9fSAndrew Rybchenko 	} else {
6013c838a9fSAndrew Rybchenko 		*subtypep = 0;
6023c838a9fSAndrew Rybchenko 	}
6033c838a9fSAndrew Rybchenko 
6043c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6053c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_VERSION_VALID)) {
6063c838a9fSAndrew Rybchenko 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
6073c838a9fSAndrew Rybchenko 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
6083c838a9fSAndrew Rybchenko 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
6093c838a9fSAndrew Rybchenko 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
6103c838a9fSAndrew Rybchenko 	} else {
6113c838a9fSAndrew Rybchenko 		version[0] = version[1] = version[2] = version[3] = 0;
6123c838a9fSAndrew Rybchenko 	}
6133c838a9fSAndrew Rybchenko 
6143c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6153c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
6163c838a9fSAndrew Rybchenko 		/* Return optional descrition string */
6173c838a9fSAndrew Rybchenko 		if ((descp != NULL) && (size > 0)) {
6183c838a9fSAndrew Rybchenko 			size_t desclen;
6193c838a9fSAndrew Rybchenko 
6203c838a9fSAndrew Rybchenko 			descp[0] = '\0';
6213c838a9fSAndrew Rybchenko 			desclen = (req.emr_out_length_used
6223c838a9fSAndrew Rybchenko 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
6233c838a9fSAndrew Rybchenko 
6243c838a9fSAndrew Rybchenko 			EFSYS_ASSERT3U(desclen, <=,
6253c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
6263c838a9fSAndrew Rybchenko 
6273c838a9fSAndrew Rybchenko 			if (size < desclen) {
6283c838a9fSAndrew Rybchenko 				rc = ENOSPC;
6293c838a9fSAndrew Rybchenko 				goto fail3;
6303c838a9fSAndrew Rybchenko 			}
6313c838a9fSAndrew Rybchenko 
6323c838a9fSAndrew Rybchenko 			memcpy(descp, MCDI_OUT2(req, char,
6333c838a9fSAndrew Rybchenko 				NVRAM_METADATA_OUT_DESCRIPTION),
6343c838a9fSAndrew Rybchenko 			    desclen);
6353c838a9fSAndrew Rybchenko 
6363c838a9fSAndrew Rybchenko 			/* Ensure string is NUL terminated */
6373c838a9fSAndrew Rybchenko 			descp[desclen] = '\0';
6383c838a9fSAndrew Rybchenko 		}
6393c838a9fSAndrew Rybchenko 	}
6403c838a9fSAndrew Rybchenko 
6413c838a9fSAndrew Rybchenko 	return (0);
6423c838a9fSAndrew Rybchenko 
6433c838a9fSAndrew Rybchenko fail3:
6443c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
6453c838a9fSAndrew Rybchenko fail2:
6463c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
6473c838a9fSAndrew Rybchenko fail1:
648460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6493c838a9fSAndrew Rybchenko 
6503c838a9fSAndrew Rybchenko 	return (rc);
6513c838a9fSAndrew Rybchenko }
6523c838a9fSAndrew Rybchenko 
653460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6543c838a9fSAndrew Rybchenko efx_mcdi_nvram_info(
6553c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6563c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
6573c838a9fSAndrew Rybchenko 	__out_opt		size_t *sizep,
6583c838a9fSAndrew Rybchenko 	__out_opt		uint32_t *addressp,
6599cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *erase_sizep,
6609cb71b16SAndrew Rybchenko 	__out_opt		uint32_t *write_sizep)
6613c838a9fSAndrew Rybchenko {
6623c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
6639cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
6643c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
665460cb568SAndrew Rybchenko 	efx_rc_t rc;
6663c838a9fSAndrew Rybchenko 
6673c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
6683c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_INFO;
6693c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
6703c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
6713c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
6729cb71b16SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
6733c838a9fSAndrew Rybchenko 
6743c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
6753c838a9fSAndrew Rybchenko 
6763c838a9fSAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
6773c838a9fSAndrew Rybchenko 
6783c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6793c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6803c838a9fSAndrew Rybchenko 		goto fail1;
6813c838a9fSAndrew Rybchenko 	}
6823c838a9fSAndrew Rybchenko 
6833c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
6843c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
6853c838a9fSAndrew Rybchenko 		goto fail2;
6863c838a9fSAndrew Rybchenko 	}
6873c838a9fSAndrew Rybchenko 
6883c838a9fSAndrew Rybchenko 	if (sizep)
6893c838a9fSAndrew Rybchenko 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
6903c838a9fSAndrew Rybchenko 
6913c838a9fSAndrew Rybchenko 	if (addressp)
6923c838a9fSAndrew Rybchenko 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
6933c838a9fSAndrew Rybchenko 
6943c838a9fSAndrew Rybchenko 	if (erase_sizep)
6953c838a9fSAndrew Rybchenko 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
6963c838a9fSAndrew Rybchenko 
6979cb71b16SAndrew Rybchenko 	if (write_sizep) {
6989cb71b16SAndrew Rybchenko 		*write_sizep =
6999cb71b16SAndrew Rybchenko 			(req.emr_out_length_used <
7009cb71b16SAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
7019cb71b16SAndrew Rybchenko 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
7029cb71b16SAndrew Rybchenko 	}
7039cb71b16SAndrew Rybchenko 
7043c838a9fSAndrew Rybchenko 	return (0);
7053c838a9fSAndrew Rybchenko 
7063c838a9fSAndrew Rybchenko fail2:
7073c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
7083c838a9fSAndrew Rybchenko fail1:
709460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7103c838a9fSAndrew Rybchenko 
7113c838a9fSAndrew Rybchenko 	return (rc);
7123c838a9fSAndrew Rybchenko }
7133c838a9fSAndrew Rybchenko 
714*e9c123a5SAndrew Rybchenko /*
715*e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
716*e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
717*e9c123a5SAndrew Rybchenko  */
718460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7193c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_start(
7203c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7213c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
7223c838a9fSAndrew Rybchenko {
723*e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
7243c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
7253c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
726460cb568SAndrew Rybchenko 	efx_rc_t rc;
7273c838a9fSAndrew Rybchenko 
7283c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7293c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
7303c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
731*e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
7323c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7333c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
7343c838a9fSAndrew Rybchenko 
735*e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
736*e9c123a5SAndrew Rybchenko 
737*e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
738*e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
7393c838a9fSAndrew Rybchenko 
7403c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7413c838a9fSAndrew Rybchenko 
7423c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7433c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7443c838a9fSAndrew Rybchenko 		goto fail1;
7453c838a9fSAndrew Rybchenko 	}
7463c838a9fSAndrew Rybchenko 
7473c838a9fSAndrew Rybchenko 	return (0);
7483c838a9fSAndrew Rybchenko 
7493c838a9fSAndrew Rybchenko fail1:
750460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7513c838a9fSAndrew Rybchenko 
7523c838a9fSAndrew Rybchenko 	return (rc);
7533c838a9fSAndrew Rybchenko }
7543c838a9fSAndrew Rybchenko 
755460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7563c838a9fSAndrew Rybchenko efx_mcdi_nvram_read(
7573c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7583c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7593c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
7603c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
7619ad7e03fSAndrew Rybchenko 	__in			size_t size,
7629ad7e03fSAndrew Rybchenko 	__in			uint32_t mode)
7633c838a9fSAndrew Rybchenko {
7643c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
7659ad7e03fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
7663c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
767460cb568SAndrew Rybchenko 	efx_rc_t rc;
7683c838a9fSAndrew Rybchenko 
7693c838a9fSAndrew Rybchenko 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
7703c838a9fSAndrew Rybchenko 		rc = EINVAL;
7713c838a9fSAndrew Rybchenko 		goto fail1;
7723c838a9fSAndrew Rybchenko 	}
7733c838a9fSAndrew Rybchenko 
7743c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7753c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_READ;
7763c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
7779ad7e03fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
7783c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7793c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
7803c838a9fSAndrew Rybchenko 
7819ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
7829ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
7839ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
7849ad7e03fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
7853c838a9fSAndrew Rybchenko 
7863c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7873c838a9fSAndrew Rybchenko 
7883c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7893c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7903c838a9fSAndrew Rybchenko 		goto fail1;
7913c838a9fSAndrew Rybchenko 	}
7923c838a9fSAndrew Rybchenko 
7933c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
7943c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
7953c838a9fSAndrew Rybchenko 		goto fail2;
7963c838a9fSAndrew Rybchenko 	}
7973c838a9fSAndrew Rybchenko 
7983c838a9fSAndrew Rybchenko 	memcpy(data,
7993c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
8003c838a9fSAndrew Rybchenko 	    size);
8013c838a9fSAndrew Rybchenko 
8023c838a9fSAndrew Rybchenko 	return (0);
8033c838a9fSAndrew Rybchenko 
8043c838a9fSAndrew Rybchenko fail2:
8053c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
8063c838a9fSAndrew Rybchenko fail1:
807460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8083c838a9fSAndrew Rybchenko 
8093c838a9fSAndrew Rybchenko 	return (rc);
8103c838a9fSAndrew Rybchenko }
8113c838a9fSAndrew Rybchenko 
812460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8133c838a9fSAndrew Rybchenko efx_mcdi_nvram_erase(
8143c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8153c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8163c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
8173c838a9fSAndrew Rybchenko 	__in			size_t size)
8183c838a9fSAndrew Rybchenko {
8193c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8203c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
8213c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
822460cb568SAndrew Rybchenko 	efx_rc_t rc;
8233c838a9fSAndrew Rybchenko 
8243c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8253c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
8263c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8273c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
8283c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8293c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
8303c838a9fSAndrew Rybchenko 
8313c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
8323c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
8333c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
8343c838a9fSAndrew Rybchenko 
8353c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8363c838a9fSAndrew Rybchenko 
8373c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8383c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8393c838a9fSAndrew Rybchenko 		goto fail1;
8403c838a9fSAndrew Rybchenko 	}
8413c838a9fSAndrew Rybchenko 
8423c838a9fSAndrew Rybchenko 	return (0);
8433c838a9fSAndrew Rybchenko 
8443c838a9fSAndrew Rybchenko fail1:
845460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8463c838a9fSAndrew Rybchenko 
8473c838a9fSAndrew Rybchenko 	return (rc);
8483c838a9fSAndrew Rybchenko }
8493c838a9fSAndrew Rybchenko 
85057396b7aSAndrew Rybchenko /*
85157396b7aSAndrew Rybchenko  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
85257396b7aSAndrew Rybchenko  * Sienna and EF10 based boards.  However EF10 based boards support the use
85357396b7aSAndrew Rybchenko  * of this command with payloads up to the maximum MCDI V2 payload length.
85457396b7aSAndrew Rybchenko  */
855460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8563c838a9fSAndrew Rybchenko efx_mcdi_nvram_write(
8573c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8583c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
8593c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
8603c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
8613c838a9fSAndrew Rybchenko 	__in			size_t size)
8623c838a9fSAndrew Rybchenko {
8633c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
86457396b7aSAndrew Rybchenko 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
86557396b7aSAndrew Rybchenko 			    MCDI_CTL_SDU_LEN_MAX_V2)];
866460cb568SAndrew Rybchenko 	efx_rc_t rc;
86757396b7aSAndrew Rybchenko 	size_t max_data_size;
8683c838a9fSAndrew Rybchenko 
86957396b7aSAndrew Rybchenko 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
87057396b7aSAndrew Rybchenko 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
87157396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
87257396b7aSAndrew Rybchenko 	EFSYS_ASSERT3U(max_data_size, <,
87357396b7aSAndrew Rybchenko 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
87457396b7aSAndrew Rybchenko 
87557396b7aSAndrew Rybchenko 	if (size > max_data_size) {
8763c838a9fSAndrew Rybchenko 		rc = EINVAL;
8773c838a9fSAndrew Rybchenko 		goto fail1;
8783c838a9fSAndrew Rybchenko 	}
8793c838a9fSAndrew Rybchenko 
8803c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8813c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
8823c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8833c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
8843c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8853c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
8863c838a9fSAndrew Rybchenko 
8873c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
8883c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
8893c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
8903c838a9fSAndrew Rybchenko 
8913c838a9fSAndrew Rybchenko 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
8923c838a9fSAndrew Rybchenko 	    data, size);
8933c838a9fSAndrew Rybchenko 
8943c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8953c838a9fSAndrew Rybchenko 
8963c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8973c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8983c838a9fSAndrew Rybchenko 		goto fail2;
8993c838a9fSAndrew Rybchenko 	}
9003c838a9fSAndrew Rybchenko 
9013c838a9fSAndrew Rybchenko 	return (0);
9023c838a9fSAndrew Rybchenko 
9033c838a9fSAndrew Rybchenko fail2:
9043c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
9053c838a9fSAndrew Rybchenko fail1:
906460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9073c838a9fSAndrew Rybchenko 
9083c838a9fSAndrew Rybchenko 	return (rc);
9093c838a9fSAndrew Rybchenko }
9103c838a9fSAndrew Rybchenko 
911*e9c123a5SAndrew Rybchenko 
912*e9c123a5SAndrew Rybchenko /*
913*e9c123a5SAndrew Rybchenko  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
914*e9c123a5SAndrew Rybchenko  * NVRAM updates. Older firmware will ignore the flags field in the request.
915*e9c123a5SAndrew Rybchenko  */
916460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
9173c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_finish(
9183c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
9193c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
920*e9c123a5SAndrew Rybchenko 	__in			boolean_t reboot,
921*e9c123a5SAndrew Rybchenko 	__out_opt		uint32_t *resultp)
9223c838a9fSAndrew Rybchenko {
923*e9c123a5SAndrew Rybchenko 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
9243c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
925*e9c123a5SAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
926*e9c123a5SAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
927*e9c123a5SAndrew Rybchenko 	uint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */
928460cb568SAndrew Rybchenko 	efx_rc_t rc;
9293c838a9fSAndrew Rybchenko 
9303c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
9313c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
9323c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
933*e9c123a5SAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
9343c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
935*e9c123a5SAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
9363c838a9fSAndrew Rybchenko 
937*e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
938*e9c123a5SAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
939*e9c123a5SAndrew Rybchenko 
940*e9c123a5SAndrew Rybchenko 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
941*e9c123a5SAndrew Rybchenko 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
9423c838a9fSAndrew Rybchenko 
9433c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
9443c838a9fSAndrew Rybchenko 
9453c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
9463c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
9473c838a9fSAndrew Rybchenko 		goto fail1;
9483c838a9fSAndrew Rybchenko 	}
9493c838a9fSAndrew Rybchenko 
950*e9c123a5SAndrew Rybchenko 	if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
951*e9c123a5SAndrew Rybchenko 		/* Report success if verified updates are not supported. */
952*e9c123a5SAndrew Rybchenko 		result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
953*e9c123a5SAndrew Rybchenko 	} else {
954*e9c123a5SAndrew Rybchenko 		/* Firmware-verified NVRAM updates are required */
955*e9c123a5SAndrew Rybchenko 		if (req.emr_out_length_used <
956*e9c123a5SAndrew Rybchenko 		    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
957*e9c123a5SAndrew Rybchenko 			rc = EMSGSIZE;
958*e9c123a5SAndrew Rybchenko 			goto fail2;
959*e9c123a5SAndrew Rybchenko 		}
960*e9c123a5SAndrew Rybchenko 		result =
961*e9c123a5SAndrew Rybchenko 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
962*e9c123a5SAndrew Rybchenko 
963*e9c123a5SAndrew Rybchenko 		if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
964*e9c123a5SAndrew Rybchenko 			/* Mandatory verification failed */
965*e9c123a5SAndrew Rybchenko 			rc = EINVAL;
966*e9c123a5SAndrew Rybchenko 			goto fail3;
967*e9c123a5SAndrew Rybchenko 		}
968*e9c123a5SAndrew Rybchenko 	}
969*e9c123a5SAndrew Rybchenko 
970*e9c123a5SAndrew Rybchenko 	if (resultp != NULL)
971*e9c123a5SAndrew Rybchenko 		*resultp = result;
972*e9c123a5SAndrew Rybchenko 
9733c838a9fSAndrew Rybchenko 	return (0);
9743c838a9fSAndrew Rybchenko 
975*e9c123a5SAndrew Rybchenko fail3:
976*e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail3);
977*e9c123a5SAndrew Rybchenko fail2:
978*e9c123a5SAndrew Rybchenko 	EFSYS_PROBE(fail2);
9793c838a9fSAndrew Rybchenko fail1:
980460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9813c838a9fSAndrew Rybchenko 
982*e9c123a5SAndrew Rybchenko 	/* Always report verification result */
983*e9c123a5SAndrew Rybchenko 	if (resultp != NULL)
984*e9c123a5SAndrew Rybchenko 		*resultp = result;
985*e9c123a5SAndrew Rybchenko 
9863c838a9fSAndrew Rybchenko 	return (rc);
9873c838a9fSAndrew Rybchenko }
9883c838a9fSAndrew Rybchenko 
9893c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
9903c838a9fSAndrew Rybchenko 
991460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
9923c838a9fSAndrew Rybchenko efx_mcdi_nvram_test(
9933c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
9943c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
9953c838a9fSAndrew Rybchenko {
9963c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
9973c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
9983c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
9993c838a9fSAndrew Rybchenko 	int result;
1000460cb568SAndrew Rybchenko 	efx_rc_t rc;
10013c838a9fSAndrew Rybchenko 
10023c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
10033c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_TEST;
10043c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
10053c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
10063c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
10073c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
10083c838a9fSAndrew Rybchenko 
10093c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
10103c838a9fSAndrew Rybchenko 
10113c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
10123c838a9fSAndrew Rybchenko 
10133c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
10143c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
10153c838a9fSAndrew Rybchenko 		goto fail1;
10163c838a9fSAndrew Rybchenko 	}
10173c838a9fSAndrew Rybchenko 
10183c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
10193c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
10203c838a9fSAndrew Rybchenko 		goto fail2;
10213c838a9fSAndrew Rybchenko 	}
10223c838a9fSAndrew Rybchenko 
10233c838a9fSAndrew Rybchenko 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
10243c838a9fSAndrew Rybchenko 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
10253c838a9fSAndrew Rybchenko 
10263c838a9fSAndrew Rybchenko 		EFSYS_PROBE1(nvram_test_failure, int, partn);
10273c838a9fSAndrew Rybchenko 
10283c838a9fSAndrew Rybchenko 		rc = (EINVAL);
10293c838a9fSAndrew Rybchenko 		goto fail3;
10303c838a9fSAndrew Rybchenko 	}
10313c838a9fSAndrew Rybchenko 
10323c838a9fSAndrew Rybchenko 	return (0);
10333c838a9fSAndrew Rybchenko 
10343c838a9fSAndrew Rybchenko fail3:
10353c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
10363c838a9fSAndrew Rybchenko fail2:
10373c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
10383c838a9fSAndrew Rybchenko fail1:
1039460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10403c838a9fSAndrew Rybchenko 
10413c838a9fSAndrew Rybchenko 	return (rc);
10423c838a9fSAndrew Rybchenko }
10433c838a9fSAndrew Rybchenko 
10443c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
10453c838a9fSAndrew Rybchenko 
10463c838a9fSAndrew Rybchenko 
10473c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1048