xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision 460cb5684c2e5be7cfa244dd4c970c56259edfaf)
1e948693eSPhilip Paeps /*-
23c838a9fSAndrew Rybchenko  * Copyright (c) 2009-2015 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 "efsys.h"
35e948693eSPhilip Paeps #include "efx.h"
36e948693eSPhilip Paeps #include "efx_types.h"
37e948693eSPhilip Paeps #include "efx_regs.h"
38e948693eSPhilip Paeps #include "efx_impl.h"
39e948693eSPhilip Paeps 
40e948693eSPhilip Paeps #if EFSYS_OPT_NVRAM
41e948693eSPhilip Paeps 
42e948693eSPhilip Paeps #if EFSYS_OPT_FALCON
43e948693eSPhilip Paeps 
443c838a9fSAndrew Rybchenko static efx_nvram_ops_t	__efx_nvram_falcon_ops = {
45e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
46e948693eSPhilip Paeps 	falcon_nvram_test,		/* envo_test */
47e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
48e948693eSPhilip Paeps 	falcon_nvram_size,		/* envo_size */
49e948693eSPhilip Paeps 	falcon_nvram_get_version,	/* envo_get_version */
50e948693eSPhilip Paeps 	falcon_nvram_rw_start,		/* envo_rw_start */
51e948693eSPhilip Paeps 	falcon_nvram_read_chunk,	/* envo_read_chunk */
52e948693eSPhilip Paeps 	falcon_nvram_erase,		/* envo_erase */
53e948693eSPhilip Paeps 	falcon_nvram_write_chunk,	/* envo_write_chunk */
54e948693eSPhilip Paeps 	falcon_nvram_rw_finish,		/* envo_rw_finish */
55e948693eSPhilip Paeps 	falcon_nvram_set_version,	/* envo_set_version */
56e948693eSPhilip Paeps };
57e948693eSPhilip Paeps 
58e948693eSPhilip Paeps #endif	/* EFSYS_OPT_FALCON */
59e948693eSPhilip Paeps 
60e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
61e948693eSPhilip Paeps 
623c838a9fSAndrew Rybchenko static efx_nvram_ops_t	__efx_nvram_siena_ops = {
63e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
64e948693eSPhilip Paeps 	siena_nvram_test,		/* envo_test */
65e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
66e948693eSPhilip Paeps 	siena_nvram_size,		/* envo_size */
67e948693eSPhilip Paeps 	siena_nvram_get_version,	/* envo_get_version */
68e948693eSPhilip Paeps 	siena_nvram_rw_start,		/* envo_rw_start */
69e948693eSPhilip Paeps 	siena_nvram_read_chunk,		/* envo_read_chunk */
70e948693eSPhilip Paeps 	siena_nvram_erase,		/* envo_erase */
71e948693eSPhilip Paeps 	siena_nvram_write_chunk,	/* envo_write_chunk */
72e948693eSPhilip Paeps 	siena_nvram_rw_finish,		/* envo_rw_finish */
73e948693eSPhilip Paeps 	siena_nvram_set_version,	/* envo_set_version */
74e948693eSPhilip Paeps };
75e948693eSPhilip Paeps 
76e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
77e948693eSPhilip Paeps 
783c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
793c838a9fSAndrew Rybchenko 
803c838a9fSAndrew Rybchenko static efx_nvram_ops_t	__efx_nvram_hunt_ops = {
813c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
823c838a9fSAndrew Rybchenko 	hunt_nvram_test,		/* envo_test */
833c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
843c838a9fSAndrew Rybchenko 	hunt_nvram_size,		/* envo_size */
853c838a9fSAndrew Rybchenko 	hunt_nvram_get_version,		/* envo_get_version */
863c838a9fSAndrew Rybchenko 	hunt_nvram_rw_start,		/* envo_rw_start */
873c838a9fSAndrew Rybchenko 	hunt_nvram_read_chunk,		/* envo_read_chunk */
883c838a9fSAndrew Rybchenko 	hunt_nvram_erase,		/* envo_erase */
893c838a9fSAndrew Rybchenko 	hunt_nvram_write_chunk,		/* envo_write_chunk */
903c838a9fSAndrew Rybchenko 	hunt_nvram_rw_finish,		/* envo_rw_finish */
913c838a9fSAndrew Rybchenko 	hunt_nvram_set_version,		/* envo_set_version */
923c838a9fSAndrew Rybchenko };
933c838a9fSAndrew Rybchenko 
943c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
953c838a9fSAndrew Rybchenko 
96*460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
97e948693eSPhilip Paeps efx_nvram_init(
98e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
99e948693eSPhilip Paeps {
100e948693eSPhilip Paeps 	efx_nvram_ops_t *envop;
101*460cb568SAndrew Rybchenko 	efx_rc_t rc;
102e948693eSPhilip Paeps 
103e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
104e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
105e948693eSPhilip Paeps 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
106e948693eSPhilip Paeps 
107e948693eSPhilip Paeps 	switch (enp->en_family) {
108e948693eSPhilip Paeps #if EFSYS_OPT_FALCON
109e948693eSPhilip Paeps 	case EFX_FAMILY_FALCON:
110e948693eSPhilip Paeps 		envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops;
111e948693eSPhilip Paeps 		break;
112e948693eSPhilip Paeps #endif	/* EFSYS_OPT_FALCON */
113e948693eSPhilip Paeps 
114e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
115e948693eSPhilip Paeps 	case EFX_FAMILY_SIENA:
116e948693eSPhilip Paeps 		envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops;
117e948693eSPhilip Paeps 		break;
118e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
119e948693eSPhilip Paeps 
1203c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1213c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
1223c838a9fSAndrew Rybchenko 		envop = (efx_nvram_ops_t *)&__efx_nvram_hunt_ops;
1233c838a9fSAndrew Rybchenko 		break;
1243c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_HUNTINGTON */
1253c838a9fSAndrew Rybchenko 
126e948693eSPhilip Paeps 	default:
127e948693eSPhilip Paeps 		EFSYS_ASSERT(0);
128e948693eSPhilip Paeps 		rc = ENOTSUP;
129e948693eSPhilip Paeps 		goto fail1;
130e948693eSPhilip Paeps 	}
131e948693eSPhilip Paeps 
132e948693eSPhilip Paeps 	enp->en_envop = envop;
133e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_NVRAM;
134e948693eSPhilip Paeps 
135e948693eSPhilip Paeps 	return (0);
136e948693eSPhilip Paeps 
137e948693eSPhilip Paeps fail1:
138*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
139e948693eSPhilip Paeps 
140e948693eSPhilip Paeps 	return (rc);
141e948693eSPhilip Paeps }
142e948693eSPhilip Paeps 
143e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
144e948693eSPhilip Paeps 
145*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
146e948693eSPhilip Paeps efx_nvram_test(
147e948693eSPhilip Paeps 	__in			efx_nic_t *enp)
148e948693eSPhilip Paeps {
149e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
150*460cb568SAndrew Rybchenko 	efx_rc_t rc;
151e948693eSPhilip Paeps 
152e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
153e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
154e948693eSPhilip Paeps 
155e948693eSPhilip Paeps 	if ((rc = envop->envo_test(enp)) != 0)
156e948693eSPhilip Paeps 		goto fail1;
157e948693eSPhilip Paeps 
158e948693eSPhilip Paeps 	return (0);
159e948693eSPhilip Paeps 
160e948693eSPhilip Paeps fail1:
161*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
162e948693eSPhilip Paeps 
163e948693eSPhilip Paeps 	return (rc);
164e948693eSPhilip Paeps }
165e948693eSPhilip Paeps 
166e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
167e948693eSPhilip Paeps 
168*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
169e948693eSPhilip Paeps efx_nvram_size(
170e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
171e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
172e948693eSPhilip Paeps 	__out			size_t *sizep)
173e948693eSPhilip Paeps {
174e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
175*460cb568SAndrew Rybchenko 	efx_rc_t rc;
176e948693eSPhilip Paeps 
177e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
178e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
179e948693eSPhilip Paeps 
180e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
181e948693eSPhilip Paeps 
182e948693eSPhilip Paeps 	if ((rc = envop->envo_size(enp, type, sizep)) != 0)
183e948693eSPhilip Paeps 		goto fail1;
184e948693eSPhilip Paeps 
185e948693eSPhilip Paeps 	return (0);
186e948693eSPhilip Paeps 
187e948693eSPhilip Paeps fail1:
188*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
189e948693eSPhilip Paeps 
190e948693eSPhilip Paeps 	return (rc);
191e948693eSPhilip Paeps }
192e948693eSPhilip Paeps 
193*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
194e948693eSPhilip Paeps efx_nvram_get_version(
195e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
196e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
197e948693eSPhilip Paeps 	__out			uint32_t *subtypep,
198e948693eSPhilip Paeps 	__out_ecount(4)		uint16_t version[4])
199e948693eSPhilip Paeps {
200e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
201*460cb568SAndrew Rybchenko 	efx_rc_t rc;
202e948693eSPhilip Paeps 
203e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
206e948693eSPhilip Paeps 
207e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
208e948693eSPhilip Paeps 
209e948693eSPhilip Paeps 	if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0)
210e948693eSPhilip Paeps 		goto fail1;
211e948693eSPhilip Paeps 
212e948693eSPhilip Paeps 	return (0);
213e948693eSPhilip Paeps 
214e948693eSPhilip Paeps fail1:
215*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
216e948693eSPhilip Paeps 
217e948693eSPhilip Paeps 	return (rc);
218e948693eSPhilip Paeps }
219e948693eSPhilip Paeps 
220*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
221e948693eSPhilip Paeps efx_nvram_rw_start(
222e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
223e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
224e948693eSPhilip Paeps 	__out_opt		size_t *chunk_sizep)
225e948693eSPhilip Paeps {
226e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
227*460cb568SAndrew Rybchenko 	efx_rc_t rc;
228e948693eSPhilip Paeps 
229e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
230e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
231e948693eSPhilip Paeps 
232e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
233e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
234e948693eSPhilip Paeps 
235e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
236e948693eSPhilip Paeps 
237e948693eSPhilip Paeps 	if ((rc = envop->envo_rw_start(enp, type, chunk_sizep)) != 0)
238e948693eSPhilip Paeps 		goto fail1;
239e948693eSPhilip Paeps 
240e948693eSPhilip Paeps 	enp->en_nvram_locked = type;
241e948693eSPhilip Paeps 
242e948693eSPhilip Paeps 	return (0);
243e948693eSPhilip Paeps 
244e948693eSPhilip Paeps fail1:
245*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
246e948693eSPhilip Paeps 
247e948693eSPhilip Paeps 	return (rc);
248e948693eSPhilip Paeps }
249e948693eSPhilip Paeps 
250*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
251e948693eSPhilip Paeps efx_nvram_read_chunk(
252e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
253e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
254e948693eSPhilip Paeps 	__in			unsigned int offset,
255e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
256e948693eSPhilip Paeps 	__in			size_t size)
257e948693eSPhilip Paeps {
258e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
259*460cb568SAndrew Rybchenko 	efx_rc_t rc;
260e948693eSPhilip Paeps 
261e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
263e948693eSPhilip Paeps 
264e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
265e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
266e948693eSPhilip Paeps 
267e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
268e948693eSPhilip Paeps 
269e948693eSPhilip Paeps 	if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0)
270e948693eSPhilip Paeps 		goto fail1;
271e948693eSPhilip Paeps 
272e948693eSPhilip Paeps 	return (0);
273e948693eSPhilip Paeps 
274e948693eSPhilip Paeps fail1:
275*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
276e948693eSPhilip Paeps 
277e948693eSPhilip Paeps 	return (rc);
278e948693eSPhilip Paeps }
279e948693eSPhilip Paeps 
280*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
281e948693eSPhilip Paeps efx_nvram_erase(
282e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
283e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
284e948693eSPhilip Paeps {
285e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
286*460cb568SAndrew Rybchenko 	efx_rc_t rc;
287e948693eSPhilip Paeps 
288e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
289e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
290e948693eSPhilip Paeps 
291e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
292e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
293e948693eSPhilip Paeps 
294e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
295e948693eSPhilip Paeps 
296e948693eSPhilip Paeps 	if ((rc = envop->envo_erase(enp, type)) != 0)
297e948693eSPhilip Paeps 		goto fail1;
298e948693eSPhilip Paeps 
299e948693eSPhilip Paeps 	return (0);
300e948693eSPhilip Paeps 
301e948693eSPhilip Paeps fail1:
302*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
303e948693eSPhilip Paeps 
304e948693eSPhilip Paeps 	return (rc);
305e948693eSPhilip Paeps }
306e948693eSPhilip Paeps 
307*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
308e948693eSPhilip Paeps efx_nvram_write_chunk(
309e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
310e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
311e948693eSPhilip Paeps 	__in			unsigned int offset,
312e948693eSPhilip Paeps 	__in_bcount(size)	caddr_t data,
313e948693eSPhilip Paeps 	__in			size_t size)
314e948693eSPhilip Paeps {
315e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
316*460cb568SAndrew Rybchenko 	efx_rc_t rc;
317e948693eSPhilip Paeps 
318e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
319e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
320e948693eSPhilip Paeps 
321e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
322e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
323e948693eSPhilip Paeps 
324e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
325e948693eSPhilip Paeps 
326e948693eSPhilip Paeps 	if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
327e948693eSPhilip Paeps 		goto fail1;
328e948693eSPhilip Paeps 
329e948693eSPhilip Paeps 	return (0);
330e948693eSPhilip Paeps 
331e948693eSPhilip Paeps fail1:
332*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
333e948693eSPhilip Paeps 
334e948693eSPhilip Paeps 	return (rc);
335e948693eSPhilip Paeps }
336e948693eSPhilip Paeps 
337e948693eSPhilip Paeps 				void
338e948693eSPhilip Paeps efx_nvram_rw_finish(
339e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
340e948693eSPhilip Paeps 	__in			efx_nvram_type_t type)
341e948693eSPhilip Paeps {
342e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
343e948693eSPhilip Paeps 
344e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
345e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
346e948693eSPhilip Paeps 
347e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
348e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
349e948693eSPhilip Paeps 
350e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
351e948693eSPhilip Paeps 
352e948693eSPhilip Paeps 	envop->envo_rw_finish(enp, type);
353e948693eSPhilip Paeps 
354e948693eSPhilip Paeps 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
355e948693eSPhilip Paeps }
356e948693eSPhilip Paeps 
357*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
358e948693eSPhilip Paeps efx_nvram_set_version(
359e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
360e948693eSPhilip Paeps 	__in			efx_nvram_type_t type,
3613c838a9fSAndrew Rybchenko 	__in_ecount(4)		uint16_t version[4])
362e948693eSPhilip Paeps {
363e948693eSPhilip Paeps 	efx_nvram_ops_t *envop = enp->en_envop;
364*460cb568SAndrew Rybchenko 	efx_rc_t rc;
365e948693eSPhilip Paeps 
366e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
367e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
368e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
369e948693eSPhilip Paeps 
370e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
371e948693eSPhilip Paeps 
372e948693eSPhilip Paeps 	/*
373e948693eSPhilip Paeps 	 * The Siena implementation of envo_set_version() will attempt to
374e948693eSPhilip Paeps 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
375e948693eSPhilip Paeps 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
376e948693eSPhilip Paeps 	 */
377e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
378e948693eSPhilip Paeps 
379e948693eSPhilip Paeps 	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
380e948693eSPhilip Paeps 		goto fail1;
381e948693eSPhilip Paeps 
382e948693eSPhilip Paeps 	return (0);
383e948693eSPhilip Paeps 
384e948693eSPhilip Paeps fail1:
385*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
386e948693eSPhilip Paeps 
387e948693eSPhilip Paeps 	return (rc);
388e948693eSPhilip Paeps }
389e948693eSPhilip Paeps 
390e948693eSPhilip Paeps void
391e948693eSPhilip Paeps efx_nvram_fini(
392e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
393e948693eSPhilip Paeps {
394e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
395e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
396e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
397e948693eSPhilip Paeps 
398e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
399e948693eSPhilip Paeps 
400e948693eSPhilip Paeps 	enp->en_envop = NULL;
401e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
402e948693eSPhilip Paeps }
403e948693eSPhilip Paeps 
404e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NVRAM */
4053c838a9fSAndrew Rybchenko 
4063c838a9fSAndrew Rybchenko #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
4073c838a9fSAndrew Rybchenko 
4083c838a9fSAndrew Rybchenko /*
4093c838a9fSAndrew Rybchenko  * Internal MCDI request handling
4103c838a9fSAndrew Rybchenko  */
4113c838a9fSAndrew Rybchenko 
412*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
4133c838a9fSAndrew Rybchenko efx_mcdi_nvram_partitions(
4143c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
4153c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
4163c838a9fSAndrew Rybchenko 	__in			size_t size,
4173c838a9fSAndrew Rybchenko 	__out			unsigned int *npartnp)
4183c838a9fSAndrew Rybchenko {
4193c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
4203c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
4213c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
4223c838a9fSAndrew Rybchenko 	unsigned int npartn;
423*460cb568SAndrew Rybchenko 	efx_rc_t rc;
4243c838a9fSAndrew Rybchenko 
4253c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
4263c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
4273c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
4283c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
4293c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
4303c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
4313c838a9fSAndrew Rybchenko 
4323c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
4333c838a9fSAndrew Rybchenko 
4343c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
4353c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
4363c838a9fSAndrew Rybchenko 		goto fail1;
4373c838a9fSAndrew Rybchenko 	}
4383c838a9fSAndrew Rybchenko 
4393c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
4403c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
4413c838a9fSAndrew Rybchenko 		goto fail2;
4423c838a9fSAndrew Rybchenko 	}
4433c838a9fSAndrew Rybchenko 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
4443c838a9fSAndrew Rybchenko 
4453c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
4463c838a9fSAndrew Rybchenko 		rc = ENOENT;
4473c838a9fSAndrew Rybchenko 		goto fail3;
4483c838a9fSAndrew Rybchenko 	}
4493c838a9fSAndrew Rybchenko 
4503c838a9fSAndrew Rybchenko 	if (size < npartn * sizeof (uint32_t)) {
4513c838a9fSAndrew Rybchenko 		rc = ENOSPC;
4523c838a9fSAndrew Rybchenko 		goto fail3;
4533c838a9fSAndrew Rybchenko 	}
4543c838a9fSAndrew Rybchenko 
4553c838a9fSAndrew Rybchenko 	*npartnp = npartn;
4563c838a9fSAndrew Rybchenko 
4573c838a9fSAndrew Rybchenko 	memcpy(data,
4583c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
4593c838a9fSAndrew Rybchenko 	    (npartn * sizeof (uint32_t)));
4603c838a9fSAndrew Rybchenko 
4613c838a9fSAndrew Rybchenko 	return (0);
4623c838a9fSAndrew Rybchenko 
4633c838a9fSAndrew Rybchenko fail3:
4643c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
4653c838a9fSAndrew Rybchenko fail2:
4663c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
4673c838a9fSAndrew Rybchenko fail1:
468*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4693c838a9fSAndrew Rybchenko 
4703c838a9fSAndrew Rybchenko 	return (rc);
4713c838a9fSAndrew Rybchenko }
4723c838a9fSAndrew Rybchenko 
473*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
4743c838a9fSAndrew Rybchenko efx_mcdi_nvram_metadata(
4753c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
4763c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
4773c838a9fSAndrew Rybchenko 	__out			uint32_t *subtypep,
4783c838a9fSAndrew Rybchenko 	__out_ecount(4)		uint16_t version[4],
4793c838a9fSAndrew Rybchenko 	__out_bcount_opt(size)	char *descp,
4803c838a9fSAndrew Rybchenko 	__in			size_t size)
4813c838a9fSAndrew Rybchenko {
4823c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
4833c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
4843c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
485*460cb568SAndrew Rybchenko 	efx_rc_t rc;
4863c838a9fSAndrew Rybchenko 
4873c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
4883c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
4893c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
4903c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
4913c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
4923c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
4933c838a9fSAndrew Rybchenko 
4943c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
4953c838a9fSAndrew Rybchenko 
4963c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
4973c838a9fSAndrew Rybchenko 
4983c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
4993c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5003c838a9fSAndrew Rybchenko 		goto fail1;
5013c838a9fSAndrew Rybchenko 	}
5023c838a9fSAndrew Rybchenko 
5033c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
5043c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5053c838a9fSAndrew Rybchenko 		goto fail2;
5063c838a9fSAndrew Rybchenko 	}
5073c838a9fSAndrew Rybchenko 
5083c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
5093c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
5103c838a9fSAndrew Rybchenko 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
5113c838a9fSAndrew Rybchenko 	} else {
5123c838a9fSAndrew Rybchenko 		*subtypep = 0;
5133c838a9fSAndrew Rybchenko 	}
5143c838a9fSAndrew Rybchenko 
5153c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
5163c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_VERSION_VALID)) {
5173c838a9fSAndrew Rybchenko 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
5183c838a9fSAndrew Rybchenko 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
5193c838a9fSAndrew Rybchenko 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
5203c838a9fSAndrew Rybchenko 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
5213c838a9fSAndrew Rybchenko 	} else {
5223c838a9fSAndrew Rybchenko 		version[0] = version[1] = version[2] = version[3] = 0;
5233c838a9fSAndrew Rybchenko 	}
5243c838a9fSAndrew Rybchenko 
5253c838a9fSAndrew Rybchenko 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
5263c838a9fSAndrew Rybchenko 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
5273c838a9fSAndrew Rybchenko 		/* Return optional descrition string */
5283c838a9fSAndrew Rybchenko 		if ((descp != NULL) && (size > 0)) {
5293c838a9fSAndrew Rybchenko 			size_t desclen;
5303c838a9fSAndrew Rybchenko 
5313c838a9fSAndrew Rybchenko 			descp[0] = '\0';
5323c838a9fSAndrew Rybchenko 			desclen = (req.emr_out_length_used
5333c838a9fSAndrew Rybchenko 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
5343c838a9fSAndrew Rybchenko 
5353c838a9fSAndrew Rybchenko 			EFSYS_ASSERT3U(desclen, <=,
5363c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
5373c838a9fSAndrew Rybchenko 
5383c838a9fSAndrew Rybchenko 			if (size < desclen) {
5393c838a9fSAndrew Rybchenko 				rc = ENOSPC;
5403c838a9fSAndrew Rybchenko 				goto fail3;
5413c838a9fSAndrew Rybchenko 			}
5423c838a9fSAndrew Rybchenko 
5433c838a9fSAndrew Rybchenko 			memcpy(descp, MCDI_OUT2(req, char,
5443c838a9fSAndrew Rybchenko 				NVRAM_METADATA_OUT_DESCRIPTION),
5453c838a9fSAndrew Rybchenko 			    desclen);
5463c838a9fSAndrew Rybchenko 
5473c838a9fSAndrew Rybchenko 			/* Ensure string is NUL terminated */
5483c838a9fSAndrew Rybchenko 			descp[desclen] = '\0';
5493c838a9fSAndrew Rybchenko 		}
5503c838a9fSAndrew Rybchenko 	}
5513c838a9fSAndrew Rybchenko 
5523c838a9fSAndrew Rybchenko 	return (0);
5533c838a9fSAndrew Rybchenko 
5543c838a9fSAndrew Rybchenko fail3:
5553c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
5563c838a9fSAndrew Rybchenko fail2:
5573c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
5583c838a9fSAndrew Rybchenko fail1:
559*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5603c838a9fSAndrew Rybchenko 
5613c838a9fSAndrew Rybchenko 	return (rc);
5623c838a9fSAndrew Rybchenko }
5633c838a9fSAndrew Rybchenko 
564*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5653c838a9fSAndrew Rybchenko efx_mcdi_nvram_info(
5663c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
5673c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
5683c838a9fSAndrew Rybchenko 	__out_opt		size_t *sizep,
5693c838a9fSAndrew Rybchenko 	__out_opt		uint32_t *addressp,
5703c838a9fSAndrew Rybchenko 	__out_opt		uint32_t *erase_sizep)
5713c838a9fSAndrew Rybchenko {
5723c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
5733c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_INFO_OUT_LEN)];
5743c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
575*460cb568SAndrew Rybchenko 	efx_rc_t rc;
5763c838a9fSAndrew Rybchenko 
5773c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
5783c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_INFO;
5793c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
5803c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
5813c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
5823c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
5833c838a9fSAndrew Rybchenko 
5843c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
5853c838a9fSAndrew Rybchenko 
5863c838a9fSAndrew Rybchenko 	efx_mcdi_execute_quiet(enp, &req);
5873c838a9fSAndrew Rybchenko 
5883c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
5893c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
5903c838a9fSAndrew Rybchenko 		goto fail1;
5913c838a9fSAndrew Rybchenko 	}
5923c838a9fSAndrew Rybchenko 
5933c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
5943c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
5953c838a9fSAndrew Rybchenko 		goto fail2;
5963c838a9fSAndrew Rybchenko 	}
5973c838a9fSAndrew Rybchenko 
5983c838a9fSAndrew Rybchenko 	if (sizep)
5993c838a9fSAndrew Rybchenko 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
6003c838a9fSAndrew Rybchenko 
6013c838a9fSAndrew Rybchenko 	if (addressp)
6023c838a9fSAndrew Rybchenko 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
6033c838a9fSAndrew Rybchenko 
6043c838a9fSAndrew Rybchenko 	if (erase_sizep)
6053c838a9fSAndrew Rybchenko 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
6063c838a9fSAndrew Rybchenko 
6073c838a9fSAndrew Rybchenko 	return (0);
6083c838a9fSAndrew Rybchenko 
6093c838a9fSAndrew Rybchenko fail2:
6103c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
6113c838a9fSAndrew Rybchenko fail1:
612*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6133c838a9fSAndrew Rybchenko 
6143c838a9fSAndrew Rybchenko 	return (rc);
6153c838a9fSAndrew Rybchenko }
6163c838a9fSAndrew Rybchenko 
617*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6183c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_start(
6193c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6203c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
6213c838a9fSAndrew Rybchenko {
6223c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
6233c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
6243c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
625*460cb568SAndrew Rybchenko 	efx_rc_t rc;
6263c838a9fSAndrew Rybchenko 
6273c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
6283c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
6293c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
6303c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
6313c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
6323c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
6333c838a9fSAndrew Rybchenko 
6343c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
6353c838a9fSAndrew Rybchenko 
6363c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
6373c838a9fSAndrew Rybchenko 
6383c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6393c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6403c838a9fSAndrew Rybchenko 		goto fail1;
6413c838a9fSAndrew Rybchenko 	}
6423c838a9fSAndrew Rybchenko 
6433c838a9fSAndrew Rybchenko 	return (0);
6443c838a9fSAndrew Rybchenko 
6453c838a9fSAndrew Rybchenko fail1:
646*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6473c838a9fSAndrew Rybchenko 
6483c838a9fSAndrew Rybchenko 	return (rc);
6493c838a9fSAndrew Rybchenko }
6503c838a9fSAndrew Rybchenko 
651*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6523c838a9fSAndrew Rybchenko efx_mcdi_nvram_read(
6533c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
6543c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
6553c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
6563c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
6573c838a9fSAndrew Rybchenko 	__in			size_t size)
6583c838a9fSAndrew Rybchenko {
6593c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
6603c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
6613c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
662*460cb568SAndrew Rybchenko 	efx_rc_t rc;
6633c838a9fSAndrew Rybchenko 
6643c838a9fSAndrew Rybchenko 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
6653c838a9fSAndrew Rybchenko 		rc = EINVAL;
6663c838a9fSAndrew Rybchenko 		goto fail1;
6673c838a9fSAndrew Rybchenko 	}
6683c838a9fSAndrew Rybchenko 
6693c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
6703c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_READ;
6713c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
6723c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
6733c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
6743c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
6753c838a9fSAndrew Rybchenko 
6763c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
6773c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
6783c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
6793c838a9fSAndrew Rybchenko 
6803c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
6813c838a9fSAndrew Rybchenko 
6823c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
6833c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
6843c838a9fSAndrew Rybchenko 		goto fail1;
6853c838a9fSAndrew Rybchenko 	}
6863c838a9fSAndrew Rybchenko 
6873c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
6883c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
6893c838a9fSAndrew Rybchenko 		goto fail2;
6903c838a9fSAndrew Rybchenko 	}
6913c838a9fSAndrew Rybchenko 
6923c838a9fSAndrew Rybchenko 	memcpy(data,
6933c838a9fSAndrew Rybchenko 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
6943c838a9fSAndrew Rybchenko 	    size);
6953c838a9fSAndrew Rybchenko 
6963c838a9fSAndrew Rybchenko 	return (0);
6973c838a9fSAndrew Rybchenko 
6983c838a9fSAndrew Rybchenko fail2:
6993c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
7003c838a9fSAndrew Rybchenko fail1:
701*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7023c838a9fSAndrew Rybchenko 
7033c838a9fSAndrew Rybchenko 	return (rc);
7043c838a9fSAndrew Rybchenko }
7053c838a9fSAndrew Rybchenko 
706*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7073c838a9fSAndrew Rybchenko efx_mcdi_nvram_erase(
7083c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7093c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7103c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
7113c838a9fSAndrew Rybchenko 	__in			size_t size)
7123c838a9fSAndrew Rybchenko {
7133c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
7143c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
7153c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
716*460cb568SAndrew Rybchenko 	efx_rc_t rc;
7173c838a9fSAndrew Rybchenko 
7183c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7193c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
7203c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
7213c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
7223c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7233c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
7243c838a9fSAndrew Rybchenko 
7253c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
7263c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
7273c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
7283c838a9fSAndrew Rybchenko 
7293c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7303c838a9fSAndrew Rybchenko 
7313c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7323c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7333c838a9fSAndrew Rybchenko 		goto fail1;
7343c838a9fSAndrew Rybchenko 	}
7353c838a9fSAndrew Rybchenko 
7363c838a9fSAndrew Rybchenko 	return (0);
7373c838a9fSAndrew Rybchenko 
7383c838a9fSAndrew Rybchenko fail1:
739*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7403c838a9fSAndrew Rybchenko 
7413c838a9fSAndrew Rybchenko 	return (rc);
7423c838a9fSAndrew Rybchenko }
7433c838a9fSAndrew Rybchenko 
744*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7453c838a9fSAndrew Rybchenko efx_mcdi_nvram_write(
7463c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7473c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7483c838a9fSAndrew Rybchenko 	__in			uint32_t offset,
7493c838a9fSAndrew Rybchenko 	__out_bcount(size)	caddr_t data,
7503c838a9fSAndrew Rybchenko 	__in			size_t size)
7513c838a9fSAndrew Rybchenko {
7523c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
7533c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_WRITE_IN_LENMAX,
7543c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_WRITE_OUT_LEN)];
755*460cb568SAndrew Rybchenko 	efx_rc_t rc;
7563c838a9fSAndrew Rybchenko 
7573c838a9fSAndrew Rybchenko 	if (size > MC_CMD_NVRAM_WRITE_IN_LENMAX) {
7583c838a9fSAndrew Rybchenko 		rc = EINVAL;
7593c838a9fSAndrew Rybchenko 		goto fail1;
7603c838a9fSAndrew Rybchenko 	}
7613c838a9fSAndrew Rybchenko 
7623c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
7633c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
7643c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
7653c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
7663c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
7673c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
7683c838a9fSAndrew Rybchenko 
7693c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
7703c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
7713c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
7723c838a9fSAndrew Rybchenko 
7733c838a9fSAndrew Rybchenko 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
7743c838a9fSAndrew Rybchenko 	    data, size);
7753c838a9fSAndrew Rybchenko 
7763c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
7773c838a9fSAndrew Rybchenko 
7783c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
7793c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
7803c838a9fSAndrew Rybchenko 		goto fail2;
7813c838a9fSAndrew Rybchenko 	}
7823c838a9fSAndrew Rybchenko 
7833c838a9fSAndrew Rybchenko 	return (0);
7843c838a9fSAndrew Rybchenko 
7853c838a9fSAndrew Rybchenko fail2:
7863c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
7873c838a9fSAndrew Rybchenko fail1:
788*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7893c838a9fSAndrew Rybchenko 
7903c838a9fSAndrew Rybchenko 	return (rc);
7913c838a9fSAndrew Rybchenko }
7923c838a9fSAndrew Rybchenko 
793*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
7943c838a9fSAndrew Rybchenko efx_mcdi_nvram_update_finish(
7953c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
7963c838a9fSAndrew Rybchenko 	__in			uint32_t partn,
7973c838a9fSAndrew Rybchenko 	__in			boolean_t reboot)
7983c838a9fSAndrew Rybchenko {
7993c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8003c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
8013c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
802*460cb568SAndrew Rybchenko 	efx_rc_t rc;
8033c838a9fSAndrew Rybchenko 
8043c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8053c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
8063c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8073c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
8083c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8093c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
8103c838a9fSAndrew Rybchenko 
8113c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
8123c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
8133c838a9fSAndrew Rybchenko 
8143c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8153c838a9fSAndrew Rybchenko 
8163c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8173c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8183c838a9fSAndrew Rybchenko 		goto fail1;
8193c838a9fSAndrew Rybchenko 	}
8203c838a9fSAndrew Rybchenko 
8213c838a9fSAndrew Rybchenko 	return (0);
8223c838a9fSAndrew Rybchenko 
8233c838a9fSAndrew Rybchenko fail1:
824*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8253c838a9fSAndrew Rybchenko 
8263c838a9fSAndrew Rybchenko 	return (rc);
8273c838a9fSAndrew Rybchenko }
8283c838a9fSAndrew Rybchenko 
8293c838a9fSAndrew Rybchenko #if EFSYS_OPT_DIAG
8303c838a9fSAndrew Rybchenko 
831*460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
8323c838a9fSAndrew Rybchenko efx_mcdi_nvram_test(
8333c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
8343c838a9fSAndrew Rybchenko 	__in			uint32_t partn)
8353c838a9fSAndrew Rybchenko {
8363c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
8373c838a9fSAndrew Rybchenko 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
8383c838a9fSAndrew Rybchenko 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
8393c838a9fSAndrew Rybchenko 	int result;
840*460cb568SAndrew Rybchenko 	efx_rc_t rc;
8413c838a9fSAndrew Rybchenko 
8423c838a9fSAndrew Rybchenko 	(void) memset(payload, 0, sizeof (payload));
8433c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_NVRAM_TEST;
8443c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
8453c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
8463c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
8473c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
8483c838a9fSAndrew Rybchenko 
8493c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
8503c838a9fSAndrew Rybchenko 
8513c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
8523c838a9fSAndrew Rybchenko 
8533c838a9fSAndrew Rybchenko 	if (req.emr_rc != 0) {
8543c838a9fSAndrew Rybchenko 		rc = req.emr_rc;
8553c838a9fSAndrew Rybchenko 		goto fail1;
8563c838a9fSAndrew Rybchenko 	}
8573c838a9fSAndrew Rybchenko 
8583c838a9fSAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
8593c838a9fSAndrew Rybchenko 		rc = EMSGSIZE;
8603c838a9fSAndrew Rybchenko 		goto fail2;
8613c838a9fSAndrew Rybchenko 	}
8623c838a9fSAndrew Rybchenko 
8633c838a9fSAndrew Rybchenko 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
8643c838a9fSAndrew Rybchenko 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
8653c838a9fSAndrew Rybchenko 
8663c838a9fSAndrew Rybchenko 		EFSYS_PROBE1(nvram_test_failure, int, partn);
8673c838a9fSAndrew Rybchenko 
8683c838a9fSAndrew Rybchenko 		rc = (EINVAL);
8693c838a9fSAndrew Rybchenko 		goto fail3;
8703c838a9fSAndrew Rybchenko 	}
8713c838a9fSAndrew Rybchenko 
8723c838a9fSAndrew Rybchenko 	return (0);
8733c838a9fSAndrew Rybchenko 
8743c838a9fSAndrew Rybchenko fail3:
8753c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
8763c838a9fSAndrew Rybchenko fail2:
8773c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
8783c838a9fSAndrew Rybchenko fail1:
879*460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8803c838a9fSAndrew Rybchenko 
8813c838a9fSAndrew Rybchenko 	return (rc);
8823c838a9fSAndrew Rybchenko }
8833c838a9fSAndrew Rybchenko 
8843c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_DIAG */
8853c838a9fSAndrew Rybchenko 
8863c838a9fSAndrew Rybchenko 
8873c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
888