xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision d9f0ce31900a48d1a2bfc1c8c86f79d1e831451a)
1 /*-
2  * Copyright (c) 2009-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include "efx.h"
35 #include "efx_impl.h"
36 
37 #if EFSYS_OPT_NVRAM
38 
39 #if EFSYS_OPT_FALCON
40 
41 static efx_nvram_ops_t	__efx_nvram_falcon_ops = {
42 #if EFSYS_OPT_DIAG
43 	falcon_nvram_test,		/* envo_test */
44 #endif	/* EFSYS_OPT_DIAG */
45 	falcon_nvram_type_to_partn,	/* envo_type_to_partn */
46 	falcon_nvram_partn_size,	/* envo_partn_size */
47 	falcon_nvram_partn_rw_start,	/* envo_partn_rw_start */
48 	falcon_nvram_partn_read,	/* envo_partn_read */
49 	falcon_nvram_partn_erase,	/* envo_partn_erase */
50 	falcon_nvram_partn_write,	/* envo_partn_write */
51 	falcon_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
52 	falcon_nvram_partn_get_version,	/* envo_partn_get_version */
53 	falcon_nvram_partn_set_version,	/* envo_partn_set_version */
54 };
55 
56 #endif	/* EFSYS_OPT_FALCON */
57 
58 #if EFSYS_OPT_SIENA
59 
60 static efx_nvram_ops_t	__efx_nvram_siena_ops = {
61 #if EFSYS_OPT_DIAG
62 	siena_nvram_test,		/* envo_test */
63 #endif	/* EFSYS_OPT_DIAG */
64 	siena_nvram_type_to_partn,	/* envo_type_to_partn */
65 	siena_nvram_partn_size,		/* envo_partn_size */
66 	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
67 	siena_nvram_partn_read,		/* envo_partn_read */
68 	siena_nvram_partn_erase,	/* envo_partn_erase */
69 	siena_nvram_partn_write,	/* envo_partn_write */
70 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
71 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
72 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
73 };
74 
75 #endif	/* EFSYS_OPT_SIENA */
76 
77 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
78 
79 static efx_nvram_ops_t	__efx_nvram_ef10_ops = {
80 #if EFSYS_OPT_DIAG
81 	ef10_nvram_test,		/* envo_test */
82 #endif	/* EFSYS_OPT_DIAG */
83 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
84 	ef10_nvram_partn_size,		/* envo_partn_size */
85 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
86 	ef10_nvram_partn_read,		/* envo_partn_read */
87 	ef10_nvram_partn_erase,		/* envo_partn_erase */
88 	ef10_nvram_partn_write,		/* envo_partn_write */
89 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
90 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
91 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
92 };
93 
94 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
95 
96 	__checkReturn	efx_rc_t
97 efx_nvram_init(
98 	__in		efx_nic_t *enp)
99 {
100 	efx_nvram_ops_t *envop;
101 	efx_rc_t rc;
102 
103 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
104 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
105 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
106 
107 	switch (enp->en_family) {
108 #if EFSYS_OPT_FALCON
109 	case EFX_FAMILY_FALCON:
110 		envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops;
111 		break;
112 #endif	/* EFSYS_OPT_FALCON */
113 
114 #if EFSYS_OPT_SIENA
115 	case EFX_FAMILY_SIENA:
116 		envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops;
117 		break;
118 #endif	/* EFSYS_OPT_SIENA */
119 
120 #if EFSYS_OPT_HUNTINGTON
121 	case EFX_FAMILY_HUNTINGTON:
122 		envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops;
123 		break;
124 #endif	/* EFSYS_OPT_HUNTINGTON */
125 
126 #if EFSYS_OPT_MEDFORD
127 	case EFX_FAMILY_MEDFORD:
128 		envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops;
129 		break;
130 #endif	/* EFSYS_OPT_MEDFORD */
131 
132 	default:
133 		EFSYS_ASSERT(0);
134 		rc = ENOTSUP;
135 		goto fail1;
136 	}
137 
138 	enp->en_envop = envop;
139 	enp->en_mod_flags |= EFX_MOD_NVRAM;
140 
141 	return (0);
142 
143 fail1:
144 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
145 
146 	return (rc);
147 }
148 
149 #if EFSYS_OPT_DIAG
150 
151 	__checkReturn		efx_rc_t
152 efx_nvram_test(
153 	__in			efx_nic_t *enp)
154 {
155 	efx_nvram_ops_t *envop = enp->en_envop;
156 	efx_rc_t rc;
157 
158 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
159 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
160 
161 	if ((rc = envop->envo_test(enp)) != 0)
162 		goto fail1;
163 
164 	return (0);
165 
166 fail1:
167 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
168 
169 	return (rc);
170 }
171 
172 #endif	/* EFSYS_OPT_DIAG */
173 
174 	__checkReturn		efx_rc_t
175 efx_nvram_size(
176 	__in			efx_nic_t *enp,
177 	__in			efx_nvram_type_t type,
178 	__out			size_t *sizep)
179 {
180 	efx_nvram_ops_t *envop = enp->en_envop;
181 	uint32_t partn;
182 	efx_rc_t rc;
183 
184 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
185 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
186 
187 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
188 
189 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
190 		goto fail1;
191 
192 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
193 		goto fail2;
194 
195 	return (0);
196 
197 fail2:
198 	EFSYS_PROBE(fail2);
199 fail1:
200 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
201 	*sizep = 0;
202 
203 	return (rc);
204 }
205 
206 	__checkReturn		efx_rc_t
207 efx_nvram_get_version(
208 	__in			efx_nic_t *enp,
209 	__in			efx_nvram_type_t type,
210 	__out			uint32_t *subtypep,
211 	__out_ecount(4)		uint16_t version[4])
212 {
213 	efx_nvram_ops_t *envop = enp->en_envop;
214 	uint32_t partn;
215 	efx_rc_t rc;
216 
217 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
218 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
219 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
220 
221 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
222 
223 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
224 		goto fail1;
225 
226 	if ((rc = envop->envo_partn_get_version(enp, partn,
227 		    subtypep, version)) != 0)
228 		goto fail2;
229 
230 	return (0);
231 
232 fail2:
233 	EFSYS_PROBE(fail2);
234 fail1:
235 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
236 
237 	return (rc);
238 }
239 
240 	__checkReturn		efx_rc_t
241 efx_nvram_rw_start(
242 	__in			efx_nic_t *enp,
243 	__in			efx_nvram_type_t type,
244 	__out_opt		size_t *chunk_sizep)
245 {
246 	efx_nvram_ops_t *envop = enp->en_envop;
247 	uint32_t partn;
248 	efx_rc_t rc;
249 
250 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
251 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
252 
253 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
254 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
255 
256 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
257 
258 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
259 		goto fail1;
260 
261 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
262 		goto fail2;
263 
264 	enp->en_nvram_locked = type;
265 
266 	return (0);
267 
268 fail2:
269 	EFSYS_PROBE(fail2);
270 fail1:
271 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
272 
273 	return (rc);
274 }
275 
276 	__checkReturn		efx_rc_t
277 efx_nvram_read_chunk(
278 	__in			efx_nic_t *enp,
279 	__in			efx_nvram_type_t type,
280 	__in			unsigned int offset,
281 	__out_bcount(size)	caddr_t data,
282 	__in			size_t size)
283 {
284 	efx_nvram_ops_t *envop = enp->en_envop;
285 	uint32_t partn;
286 	efx_rc_t rc;
287 
288 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
289 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
290 
291 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
292 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
293 
294 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
295 
296 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
297 		goto fail1;
298 
299 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
300 		goto fail2;
301 
302 	return (0);
303 
304 fail2:
305 	EFSYS_PROBE(fail2);
306 fail1:
307 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
308 
309 	return (rc);
310 }
311 
312 	__checkReturn		efx_rc_t
313 efx_nvram_erase(
314 	__in			efx_nic_t *enp,
315 	__in			efx_nvram_type_t type)
316 {
317 	efx_nvram_ops_t *envop = enp->en_envop;
318 	unsigned int offset = 0;
319 	size_t size = 0;
320 	uint32_t partn;
321 	efx_rc_t rc;
322 
323 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
324 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
325 
326 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
327 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
328 
329 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
330 
331 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
332 		goto fail1;
333 
334 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
335 		goto fail2;
336 
337 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
338 		goto fail3;
339 
340 	return (0);
341 
342 fail3:
343 	EFSYS_PROBE(fail3);
344 fail2:
345 	EFSYS_PROBE(fail2);
346 fail1:
347 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
348 
349 	return (rc);
350 }
351 
352 	__checkReturn		efx_rc_t
353 efx_nvram_write_chunk(
354 	__in			efx_nic_t *enp,
355 	__in			efx_nvram_type_t type,
356 	__in			unsigned int offset,
357 	__in_bcount(size)	caddr_t data,
358 	__in			size_t size)
359 {
360 	efx_nvram_ops_t *envop = enp->en_envop;
361 	uint32_t partn;
362 	efx_rc_t rc;
363 
364 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
365 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
366 
367 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
368 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
369 
370 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
371 
372 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
373 		goto fail1;
374 
375 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
376 		goto fail2;
377 
378 	return (0);
379 
380 fail2:
381 	EFSYS_PROBE(fail2);
382 fail1:
383 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
384 
385 	return (rc);
386 }
387 
388 				void
389 efx_nvram_rw_finish(
390 	__in			efx_nic_t *enp,
391 	__in			efx_nvram_type_t type)
392 {
393 	efx_nvram_ops_t *envop = enp->en_envop;
394 	uint32_t partn;
395 
396 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
397 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
398 
399 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
400 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
401 
402 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
403 
404 	if (envop->envo_type_to_partn(enp, type, &partn) == 0)
405 		envop->envo_partn_rw_finish(enp, partn);
406 
407 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
408 }
409 
410 	__checkReturn		efx_rc_t
411 efx_nvram_set_version(
412 	__in			efx_nic_t *enp,
413 	__in			efx_nvram_type_t type,
414 	__in_ecount(4)		uint16_t version[4])
415 {
416 	efx_nvram_ops_t *envop = enp->en_envop;
417 	uint32_t partn;
418 	efx_rc_t rc;
419 
420 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
421 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
422 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
423 
424 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
425 
426 	/*
427 	 * The Siena implementation of envo_set_version() will attempt to
428 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
429 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
430 	 */
431 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
432 
433 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
434 		goto fail1;
435 
436 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
437 		goto fail2;
438 
439 	return (0);
440 
441 fail2:
442 	EFSYS_PROBE(fail2);
443 fail1:
444 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
445 
446 	return (rc);
447 }
448 
449 void
450 efx_nvram_fini(
451 	__in		efx_nic_t *enp)
452 {
453 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
455 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
456 
457 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
458 
459 	enp->en_envop = NULL;
460 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
461 }
462 
463 #endif	/* EFSYS_OPT_NVRAM */
464 
465 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
466 
467 /*
468  * Internal MCDI request handling
469  */
470 
471 	__checkReturn		efx_rc_t
472 efx_mcdi_nvram_partitions(
473 	__in			efx_nic_t *enp,
474 	__out_bcount(size)	caddr_t data,
475 	__in			size_t size,
476 	__out			unsigned int *npartnp)
477 {
478 	efx_mcdi_req_t req;
479 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
480 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
481 	unsigned int npartn;
482 	efx_rc_t rc;
483 
484 	(void) memset(payload, 0, sizeof (payload));
485 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
486 	req.emr_in_buf = payload;
487 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
488 	req.emr_out_buf = payload;
489 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
490 
491 	efx_mcdi_execute(enp, &req);
492 
493 	if (req.emr_rc != 0) {
494 		rc = req.emr_rc;
495 		goto fail1;
496 	}
497 
498 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
499 		rc = EMSGSIZE;
500 		goto fail2;
501 	}
502 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
503 
504 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
505 		rc = ENOENT;
506 		goto fail3;
507 	}
508 
509 	if (size < npartn * sizeof (uint32_t)) {
510 		rc = ENOSPC;
511 		goto fail3;
512 	}
513 
514 	*npartnp = npartn;
515 
516 	memcpy(data,
517 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
518 	    (npartn * sizeof (uint32_t)));
519 
520 	return (0);
521 
522 fail3:
523 	EFSYS_PROBE(fail3);
524 fail2:
525 	EFSYS_PROBE(fail2);
526 fail1:
527 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
528 
529 	return (rc);
530 }
531 
532 	__checkReturn		efx_rc_t
533 efx_mcdi_nvram_metadata(
534 	__in			efx_nic_t *enp,
535 	__in			uint32_t partn,
536 	__out			uint32_t *subtypep,
537 	__out_ecount(4)		uint16_t version[4],
538 	__out_bcount_opt(size)	char *descp,
539 	__in			size_t size)
540 {
541 	efx_mcdi_req_t req;
542 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
543 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
544 	efx_rc_t rc;
545 
546 	(void) memset(payload, 0, sizeof (payload));
547 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
548 	req.emr_in_buf = payload;
549 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
550 	req.emr_out_buf = payload;
551 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
552 
553 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
554 
555 	efx_mcdi_execute(enp, &req);
556 
557 	if (req.emr_rc != 0) {
558 		rc = req.emr_rc;
559 		goto fail1;
560 	}
561 
562 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
563 		rc = EMSGSIZE;
564 		goto fail2;
565 	}
566 
567 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
568 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
569 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
570 	} else {
571 		*subtypep = 0;
572 	}
573 
574 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
575 		NVRAM_METADATA_OUT_VERSION_VALID)) {
576 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
577 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
578 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
579 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
580 	} else {
581 		version[0] = version[1] = version[2] = version[3] = 0;
582 	}
583 
584 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
585 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
586 		/* Return optional descrition string */
587 		if ((descp != NULL) && (size > 0)) {
588 			size_t desclen;
589 
590 			descp[0] = '\0';
591 			desclen = (req.emr_out_length_used
592 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
593 
594 			EFSYS_ASSERT3U(desclen, <=,
595 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
596 
597 			if (size < desclen) {
598 				rc = ENOSPC;
599 				goto fail3;
600 			}
601 
602 			memcpy(descp, MCDI_OUT2(req, char,
603 				NVRAM_METADATA_OUT_DESCRIPTION),
604 			    desclen);
605 
606 			/* Ensure string is NUL terminated */
607 			descp[desclen] = '\0';
608 		}
609 	}
610 
611 	return (0);
612 
613 fail3:
614 	EFSYS_PROBE(fail3);
615 fail2:
616 	EFSYS_PROBE(fail2);
617 fail1:
618 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
619 
620 	return (rc);
621 }
622 
623 	__checkReturn		efx_rc_t
624 efx_mcdi_nvram_info(
625 	__in			efx_nic_t *enp,
626 	__in			uint32_t partn,
627 	__out_opt		size_t *sizep,
628 	__out_opt		uint32_t *addressp,
629 	__out_opt		uint32_t *erase_sizep,
630 	__out_opt		uint32_t *write_sizep)
631 {
632 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
633 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
634 	efx_mcdi_req_t req;
635 	efx_rc_t rc;
636 
637 	(void) memset(payload, 0, sizeof (payload));
638 	req.emr_cmd = MC_CMD_NVRAM_INFO;
639 	req.emr_in_buf = payload;
640 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
641 	req.emr_out_buf = payload;
642 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
643 
644 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
645 
646 	efx_mcdi_execute_quiet(enp, &req);
647 
648 	if (req.emr_rc != 0) {
649 		rc = req.emr_rc;
650 		goto fail1;
651 	}
652 
653 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
654 		rc = EMSGSIZE;
655 		goto fail2;
656 	}
657 
658 	if (sizep)
659 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
660 
661 	if (addressp)
662 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
663 
664 	if (erase_sizep)
665 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
666 
667 	if (write_sizep) {
668 		*write_sizep =
669 			(req.emr_out_length_used <
670 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
671 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
672 	}
673 
674 	return (0);
675 
676 fail2:
677 	EFSYS_PROBE(fail2);
678 fail1:
679 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
680 
681 	return (rc);
682 }
683 
684 	__checkReturn		efx_rc_t
685 efx_mcdi_nvram_update_start(
686 	__in			efx_nic_t *enp,
687 	__in			uint32_t partn)
688 {
689 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
690 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
691 	efx_mcdi_req_t req;
692 	efx_rc_t rc;
693 
694 	(void) memset(payload, 0, sizeof (payload));
695 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
696 	req.emr_in_buf = payload;
697 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
698 	req.emr_out_buf = payload;
699 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
700 
701 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
702 
703 	efx_mcdi_execute(enp, &req);
704 
705 	if (req.emr_rc != 0) {
706 		rc = req.emr_rc;
707 		goto fail1;
708 	}
709 
710 	return (0);
711 
712 fail1:
713 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
714 
715 	return (rc);
716 }
717 
718 	__checkReturn		efx_rc_t
719 efx_mcdi_nvram_read(
720 	__in			efx_nic_t *enp,
721 	__in			uint32_t partn,
722 	__in			uint32_t offset,
723 	__out_bcount(size)	caddr_t data,
724 	__in			size_t size,
725 	__in			uint32_t mode)
726 {
727 	efx_mcdi_req_t req;
728 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
729 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
730 	efx_rc_t rc;
731 
732 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
733 		rc = EINVAL;
734 		goto fail1;
735 	}
736 
737 	(void) memset(payload, 0, sizeof (payload));
738 	req.emr_cmd = MC_CMD_NVRAM_READ;
739 	req.emr_in_buf = payload;
740 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
741 	req.emr_out_buf = payload;
742 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
743 
744 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
745 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
746 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
747 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
748 
749 	efx_mcdi_execute(enp, &req);
750 
751 	if (req.emr_rc != 0) {
752 		rc = req.emr_rc;
753 		goto fail1;
754 	}
755 
756 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
757 		rc = EMSGSIZE;
758 		goto fail2;
759 	}
760 
761 	memcpy(data,
762 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
763 	    size);
764 
765 	return (0);
766 
767 fail2:
768 	EFSYS_PROBE(fail2);
769 fail1:
770 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
771 
772 	return (rc);
773 }
774 
775 	__checkReturn		efx_rc_t
776 efx_mcdi_nvram_erase(
777 	__in			efx_nic_t *enp,
778 	__in			uint32_t partn,
779 	__in			uint32_t offset,
780 	__in			size_t size)
781 {
782 	efx_mcdi_req_t req;
783 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
784 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
785 	efx_rc_t rc;
786 
787 	(void) memset(payload, 0, sizeof (payload));
788 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
789 	req.emr_in_buf = payload;
790 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
791 	req.emr_out_buf = payload;
792 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
793 
794 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
795 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
796 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
797 
798 	efx_mcdi_execute(enp, &req);
799 
800 	if (req.emr_rc != 0) {
801 		rc = req.emr_rc;
802 		goto fail1;
803 	}
804 
805 	return (0);
806 
807 fail1:
808 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
809 
810 	return (rc);
811 }
812 
813 /*
814  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
815  * Sienna and EF10 based boards.  However EF10 based boards support the use
816  * of this command with payloads up to the maximum MCDI V2 payload length.
817  */
818 	__checkReturn		efx_rc_t
819 efx_mcdi_nvram_write(
820 	__in			efx_nic_t *enp,
821 	__in			uint32_t partn,
822 	__in			uint32_t offset,
823 	__out_bcount(size)	caddr_t data,
824 	__in			size_t size)
825 {
826 	efx_mcdi_req_t req;
827 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
828 			    MCDI_CTL_SDU_LEN_MAX_V2)];
829 	efx_rc_t rc;
830 	size_t max_data_size;
831 
832 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
833 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
834 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
835 	EFSYS_ASSERT3U(max_data_size, <,
836 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
837 
838 	if (size > max_data_size) {
839 		rc = EINVAL;
840 		goto fail1;
841 	}
842 
843 	(void) memset(payload, 0, sizeof (payload));
844 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
845 	req.emr_in_buf = payload;
846 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
847 	req.emr_out_buf = payload;
848 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
849 
850 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
851 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
852 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
853 
854 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
855 	    data, size);
856 
857 	efx_mcdi_execute(enp, &req);
858 
859 	if (req.emr_rc != 0) {
860 		rc = req.emr_rc;
861 		goto fail2;
862 	}
863 
864 	return (0);
865 
866 fail2:
867 	EFSYS_PROBE(fail2);
868 fail1:
869 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
870 
871 	return (rc);
872 }
873 
874 	__checkReturn		efx_rc_t
875 efx_mcdi_nvram_update_finish(
876 	__in			efx_nic_t *enp,
877 	__in			uint32_t partn,
878 	__in			boolean_t reboot)
879 {
880 	efx_mcdi_req_t req;
881 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
882 			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
883 	efx_rc_t rc;
884 
885 	(void) memset(payload, 0, sizeof (payload));
886 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
887 	req.emr_in_buf = payload;
888 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
889 	req.emr_out_buf = payload;
890 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
891 
892 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
893 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
894 
895 	efx_mcdi_execute(enp, &req);
896 
897 	if (req.emr_rc != 0) {
898 		rc = req.emr_rc;
899 		goto fail1;
900 	}
901 
902 	return (0);
903 
904 fail1:
905 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
906 
907 	return (rc);
908 }
909 
910 #if EFSYS_OPT_DIAG
911 
912 	__checkReturn		efx_rc_t
913 efx_mcdi_nvram_test(
914 	__in			efx_nic_t *enp,
915 	__in			uint32_t partn)
916 {
917 	efx_mcdi_req_t req;
918 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
919 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
920 	int result;
921 	efx_rc_t rc;
922 
923 	(void) memset(payload, 0, sizeof (payload));
924 	req.emr_cmd = MC_CMD_NVRAM_TEST;
925 	req.emr_in_buf = payload;
926 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
927 	req.emr_out_buf = payload;
928 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
929 
930 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
931 
932 	efx_mcdi_execute(enp, &req);
933 
934 	if (req.emr_rc != 0) {
935 		rc = req.emr_rc;
936 		goto fail1;
937 	}
938 
939 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
940 		rc = EMSGSIZE;
941 		goto fail2;
942 	}
943 
944 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
945 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
946 
947 		EFSYS_PROBE1(nvram_test_failure, int, partn);
948 
949 		rc = (EINVAL);
950 		goto fail3;
951 	}
952 
953 	return (0);
954 
955 fail3:
956 	EFSYS_PROBE(fail3);
957 fail2:
958 	EFSYS_PROBE(fail2);
959 fail1:
960 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
961 
962 	return (rc);
963 }
964 
965 #endif	/* EFSYS_OPT_DIAG */
966 
967 
968 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
969