xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision fc7284da06408923f7850a0e4e954a903b8ee038)
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 "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_impl.h"
39 
40 #if EFSYS_OPT_NVRAM
41 
42 #if EFSYS_OPT_FALCON
43 
44 static efx_nvram_ops_t	__efx_nvram_falcon_ops = {
45 #if EFSYS_OPT_DIAG
46 	falcon_nvram_test,		/* envo_test */
47 #endif	/* EFSYS_OPT_DIAG */
48 	falcon_nvram_size,		/* envo_size */
49 	falcon_nvram_get_version,	/* envo_get_version */
50 	falcon_nvram_rw_start,		/* envo_rw_start */
51 	falcon_nvram_read_chunk,	/* envo_read_chunk */
52 	falcon_nvram_erase,		/* envo_erase */
53 	falcon_nvram_write_chunk,	/* envo_write_chunk */
54 	falcon_nvram_rw_finish,		/* envo_rw_finish */
55 	falcon_nvram_set_version,	/* envo_set_version */
56 };
57 
58 #endif	/* EFSYS_OPT_FALCON */
59 
60 #if EFSYS_OPT_SIENA
61 
62 static efx_nvram_ops_t	__efx_nvram_siena_ops = {
63 #if EFSYS_OPT_DIAG
64 	siena_nvram_test,		/* envo_test */
65 #endif	/* EFSYS_OPT_DIAG */
66 	siena_nvram_size,		/* envo_size */
67 	siena_nvram_get_version,	/* envo_get_version */
68 	siena_nvram_rw_start,		/* envo_rw_start */
69 	siena_nvram_read_chunk,		/* envo_read_chunk */
70 	siena_nvram_erase,		/* envo_erase */
71 	siena_nvram_write_chunk,	/* envo_write_chunk */
72 	siena_nvram_rw_finish,		/* envo_rw_finish */
73 	siena_nvram_set_version,	/* envo_set_version */
74 };
75 
76 #endif	/* EFSYS_OPT_SIENA */
77 
78 #if EFSYS_OPT_HUNTINGTON
79 
80 static efx_nvram_ops_t	__efx_nvram_hunt_ops = {
81 #if EFSYS_OPT_DIAG
82 	hunt_nvram_test,		/* envo_test */
83 #endif	/* EFSYS_OPT_DIAG */
84 	hunt_nvram_size,		/* envo_size */
85 	hunt_nvram_get_version,		/* envo_get_version */
86 	hunt_nvram_rw_start,		/* envo_rw_start */
87 	hunt_nvram_read_chunk,		/* envo_read_chunk */
88 	hunt_nvram_erase,		/* envo_erase */
89 	hunt_nvram_write_chunk,		/* envo_write_chunk */
90 	hunt_nvram_rw_finish,		/* envo_rw_finish */
91 	hunt_nvram_set_version,		/* envo_set_version */
92 };
93 
94 #endif	/* EFSYS_OPT_HUNTINGTON */
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_hunt_ops;
123 		break;
124 #endif	/* EFSYS_OPT_HUNTINGTON */
125 
126 	default:
127 		EFSYS_ASSERT(0);
128 		rc = ENOTSUP;
129 		goto fail1;
130 	}
131 
132 	enp->en_envop = envop;
133 	enp->en_mod_flags |= EFX_MOD_NVRAM;
134 
135 	return (0);
136 
137 fail1:
138 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
139 
140 	return (rc);
141 }
142 
143 #if EFSYS_OPT_DIAG
144 
145 	__checkReturn		efx_rc_t
146 efx_nvram_test(
147 	__in			efx_nic_t *enp)
148 {
149 	efx_nvram_ops_t *envop = enp->en_envop;
150 	efx_rc_t rc;
151 
152 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
153 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
154 
155 	if ((rc = envop->envo_test(enp)) != 0)
156 		goto fail1;
157 
158 	return (0);
159 
160 fail1:
161 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
162 
163 	return (rc);
164 }
165 
166 #endif	/* EFSYS_OPT_DIAG */
167 
168 	__checkReturn		efx_rc_t
169 efx_nvram_size(
170 	__in			efx_nic_t *enp,
171 	__in			efx_nvram_type_t type,
172 	__out			size_t *sizep)
173 {
174 	efx_nvram_ops_t *envop = enp->en_envop;
175 	efx_rc_t rc;
176 
177 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
178 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
179 
180 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
181 
182 	if ((rc = envop->envo_size(enp, type, sizep)) != 0)
183 		goto fail1;
184 
185 	return (0);
186 
187 fail1:
188 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
189 
190 	return (rc);
191 }
192 
193 	__checkReturn		efx_rc_t
194 efx_nvram_get_version(
195 	__in			efx_nic_t *enp,
196 	__in			efx_nvram_type_t type,
197 	__out			uint32_t *subtypep,
198 	__out_ecount(4)		uint16_t version[4])
199 {
200 	efx_nvram_ops_t *envop = enp->en_envop;
201 	efx_rc_t rc;
202 
203 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
206 
207 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
208 
209 	if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0)
210 		goto fail1;
211 
212 	return (0);
213 
214 fail1:
215 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
216 
217 	return (rc);
218 }
219 
220 	__checkReturn		efx_rc_t
221 efx_nvram_rw_start(
222 	__in			efx_nic_t *enp,
223 	__in			efx_nvram_type_t type,
224 	__out_opt		size_t *chunk_sizep)
225 {
226 	efx_nvram_ops_t *envop = enp->en_envop;
227 	efx_rc_t rc;
228 
229 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
230 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
231 
232 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
233 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
234 
235 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
236 
237 	if ((rc = envop->envo_rw_start(enp, type, chunk_sizep)) != 0)
238 		goto fail1;
239 
240 	enp->en_nvram_locked = type;
241 
242 	return (0);
243 
244 fail1:
245 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
246 
247 	return (rc);
248 }
249 
250 	__checkReturn		efx_rc_t
251 efx_nvram_read_chunk(
252 	__in			efx_nic_t *enp,
253 	__in			efx_nvram_type_t type,
254 	__in			unsigned int offset,
255 	__out_bcount(size)	caddr_t data,
256 	__in			size_t size)
257 {
258 	efx_nvram_ops_t *envop = enp->en_envop;
259 	efx_rc_t rc;
260 
261 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
263 
264 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
265 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
266 
267 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
268 
269 	if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0)
270 		goto fail1;
271 
272 	return (0);
273 
274 fail1:
275 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
276 
277 	return (rc);
278 }
279 
280 	__checkReturn		efx_rc_t
281 efx_nvram_erase(
282 	__in			efx_nic_t *enp,
283 	__in			efx_nvram_type_t type)
284 {
285 	efx_nvram_ops_t *envop = enp->en_envop;
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_erase(enp, type)) != 0)
297 		goto fail1;
298 
299 	return (0);
300 
301 fail1:
302 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
303 
304 	return (rc);
305 }
306 
307 	__checkReturn		efx_rc_t
308 efx_nvram_write_chunk(
309 	__in			efx_nic_t *enp,
310 	__in			efx_nvram_type_t type,
311 	__in			unsigned int offset,
312 	__in_bcount(size)	caddr_t data,
313 	__in			size_t size)
314 {
315 	efx_nvram_ops_t *envop = enp->en_envop;
316 	efx_rc_t rc;
317 
318 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
319 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
320 
321 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
322 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
323 
324 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
325 
326 	if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
327 		goto fail1;
328 
329 	return (0);
330 
331 fail1:
332 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
333 
334 	return (rc);
335 }
336 
337 				void
338 efx_nvram_rw_finish(
339 	__in			efx_nic_t *enp,
340 	__in			efx_nvram_type_t type)
341 {
342 	efx_nvram_ops_t *envop = enp->en_envop;
343 
344 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
345 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
346 
347 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
348 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
349 
350 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
351 
352 	envop->envo_rw_finish(enp, type);
353 
354 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
355 }
356 
357 	__checkReturn		efx_rc_t
358 efx_nvram_set_version(
359 	__in			efx_nic_t *enp,
360 	__in			efx_nvram_type_t type,
361 	__in_ecount(4)		uint16_t version[4])
362 {
363 	efx_nvram_ops_t *envop = enp->en_envop;
364 	efx_rc_t rc;
365 
366 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
367 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
368 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
369 
370 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
371 
372 	/*
373 	 * The Siena implementation of envo_set_version() will attempt to
374 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
375 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
376 	 */
377 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
378 
379 	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
380 		goto fail1;
381 
382 	return (0);
383 
384 fail1:
385 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
386 
387 	return (rc);
388 }
389 
390 void
391 efx_nvram_fini(
392 	__in		efx_nic_t *enp)
393 {
394 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
395 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
396 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
397 
398 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
399 
400 	enp->en_envop = NULL;
401 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
402 }
403 
404 #endif	/* EFSYS_OPT_NVRAM */
405 
406 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
407 
408 /*
409  * Internal MCDI request handling
410  */
411 
412 	__checkReturn		efx_rc_t
413 efx_mcdi_nvram_partitions(
414 	__in			efx_nic_t *enp,
415 	__out_bcount(size)	caddr_t data,
416 	__in			size_t size,
417 	__out			unsigned int *npartnp)
418 {
419 	efx_mcdi_req_t req;
420 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
421 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
422 	unsigned int npartn;
423 	efx_rc_t rc;
424 
425 	(void) memset(payload, 0, sizeof (payload));
426 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
427 	req.emr_in_buf = payload;
428 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
429 	req.emr_out_buf = payload;
430 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
431 
432 	efx_mcdi_execute(enp, &req);
433 
434 	if (req.emr_rc != 0) {
435 		rc = req.emr_rc;
436 		goto fail1;
437 	}
438 
439 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
440 		rc = EMSGSIZE;
441 		goto fail2;
442 	}
443 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
444 
445 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
446 		rc = ENOENT;
447 		goto fail3;
448 	}
449 
450 	if (size < npartn * sizeof (uint32_t)) {
451 		rc = ENOSPC;
452 		goto fail3;
453 	}
454 
455 	*npartnp = npartn;
456 
457 	memcpy(data,
458 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
459 	    (npartn * sizeof (uint32_t)));
460 
461 	return (0);
462 
463 fail3:
464 	EFSYS_PROBE(fail3);
465 fail2:
466 	EFSYS_PROBE(fail2);
467 fail1:
468 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
469 
470 	return (rc);
471 }
472 
473 	__checkReturn		efx_rc_t
474 efx_mcdi_nvram_metadata(
475 	__in			efx_nic_t *enp,
476 	__in			uint32_t partn,
477 	__out			uint32_t *subtypep,
478 	__out_ecount(4)		uint16_t version[4],
479 	__out_bcount_opt(size)	char *descp,
480 	__in			size_t size)
481 {
482 	efx_mcdi_req_t req;
483 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
484 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
485 	efx_rc_t rc;
486 
487 	(void) memset(payload, 0, sizeof (payload));
488 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
489 	req.emr_in_buf = payload;
490 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
491 	req.emr_out_buf = payload;
492 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
493 
494 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
495 
496 	efx_mcdi_execute(enp, &req);
497 
498 	if (req.emr_rc != 0) {
499 		rc = req.emr_rc;
500 		goto fail1;
501 	}
502 
503 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
504 		rc = EMSGSIZE;
505 		goto fail2;
506 	}
507 
508 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
509 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
510 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
511 	} else {
512 		*subtypep = 0;
513 	}
514 
515 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
516 		NVRAM_METADATA_OUT_VERSION_VALID)) {
517 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
518 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
519 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
520 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
521 	} else {
522 		version[0] = version[1] = version[2] = version[3] = 0;
523 	}
524 
525 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
526 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
527 		/* Return optional descrition string */
528 		if ((descp != NULL) && (size > 0)) {
529 			size_t desclen;
530 
531 			descp[0] = '\0';
532 			desclen = (req.emr_out_length_used
533 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
534 
535 			EFSYS_ASSERT3U(desclen, <=,
536 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
537 
538 			if (size < desclen) {
539 				rc = ENOSPC;
540 				goto fail3;
541 			}
542 
543 			memcpy(descp, MCDI_OUT2(req, char,
544 				NVRAM_METADATA_OUT_DESCRIPTION),
545 			    desclen);
546 
547 			/* Ensure string is NUL terminated */
548 			descp[desclen] = '\0';
549 		}
550 	}
551 
552 	return (0);
553 
554 fail3:
555 	EFSYS_PROBE(fail3);
556 fail2:
557 	EFSYS_PROBE(fail2);
558 fail1:
559 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
560 
561 	return (rc);
562 }
563 
564 	__checkReturn		efx_rc_t
565 efx_mcdi_nvram_info(
566 	__in			efx_nic_t *enp,
567 	__in			uint32_t partn,
568 	__out_opt		size_t *sizep,
569 	__out_opt		uint32_t *addressp,
570 	__out_opt		uint32_t *erase_sizep,
571 	__out_opt		uint32_t *write_sizep)
572 {
573 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
574 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
575 	efx_mcdi_req_t req;
576 	efx_rc_t rc;
577 
578 	(void) memset(payload, 0, sizeof (payload));
579 	req.emr_cmd = MC_CMD_NVRAM_INFO;
580 	req.emr_in_buf = payload;
581 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
582 	req.emr_out_buf = payload;
583 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
584 
585 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
586 
587 	efx_mcdi_execute_quiet(enp, &req);
588 
589 	if (req.emr_rc != 0) {
590 		rc = req.emr_rc;
591 		goto fail1;
592 	}
593 
594 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
595 		rc = EMSGSIZE;
596 		goto fail2;
597 	}
598 
599 	if (sizep)
600 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
601 
602 	if (addressp)
603 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
604 
605 	if (erase_sizep)
606 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
607 
608 	if (write_sizep) {
609 		*write_sizep =
610 			(req.emr_out_length_used <
611 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
612 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
613 	}
614 
615 	return (0);
616 
617 fail2:
618 	EFSYS_PROBE(fail2);
619 fail1:
620 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
621 
622 	return (rc);
623 }
624 
625 	__checkReturn		efx_rc_t
626 efx_mcdi_nvram_update_start(
627 	__in			efx_nic_t *enp,
628 	__in			uint32_t partn)
629 {
630 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
631 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
632 	efx_mcdi_req_t req;
633 	efx_rc_t rc;
634 
635 	(void) memset(payload, 0, sizeof (payload));
636 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
637 	req.emr_in_buf = payload;
638 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
639 	req.emr_out_buf = payload;
640 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
641 
642 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
643 
644 	efx_mcdi_execute(enp, &req);
645 
646 	if (req.emr_rc != 0) {
647 		rc = req.emr_rc;
648 		goto fail1;
649 	}
650 
651 	return (0);
652 
653 fail1:
654 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
655 
656 	return (rc);
657 }
658 
659 	__checkReturn		efx_rc_t
660 efx_mcdi_nvram_read(
661 	__in			efx_nic_t *enp,
662 	__in			uint32_t partn,
663 	__in			uint32_t offset,
664 	__out_bcount(size)	caddr_t data,
665 	__in			size_t size)
666 {
667 	efx_mcdi_req_t req;
668 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
669 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
670 	efx_rc_t rc;
671 
672 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
673 		rc = EINVAL;
674 		goto fail1;
675 	}
676 
677 	(void) memset(payload, 0, sizeof (payload));
678 	req.emr_cmd = MC_CMD_NVRAM_READ;
679 	req.emr_in_buf = payload;
680 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
681 	req.emr_out_buf = payload;
682 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
683 
684 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
685 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
686 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
687 
688 	efx_mcdi_execute(enp, &req);
689 
690 	if (req.emr_rc != 0) {
691 		rc = req.emr_rc;
692 		goto fail1;
693 	}
694 
695 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
696 		rc = EMSGSIZE;
697 		goto fail2;
698 	}
699 
700 	memcpy(data,
701 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
702 	    size);
703 
704 	return (0);
705 
706 fail2:
707 	EFSYS_PROBE(fail2);
708 fail1:
709 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
710 
711 	return (rc);
712 }
713 
714 	__checkReturn		efx_rc_t
715 efx_mcdi_nvram_erase(
716 	__in			efx_nic_t *enp,
717 	__in			uint32_t partn,
718 	__in			uint32_t offset,
719 	__in			size_t size)
720 {
721 	efx_mcdi_req_t req;
722 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
723 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
724 	efx_rc_t rc;
725 
726 	(void) memset(payload, 0, sizeof (payload));
727 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
728 	req.emr_in_buf = payload;
729 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
730 	req.emr_out_buf = payload;
731 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
732 
733 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
734 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
735 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
736 
737 	efx_mcdi_execute(enp, &req);
738 
739 	if (req.emr_rc != 0) {
740 		rc = req.emr_rc;
741 		goto fail1;
742 	}
743 
744 	return (0);
745 
746 fail1:
747 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
748 
749 	return (rc);
750 }
751 
752 /*
753  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
754  * Sienna and EF10 based boards.  However EF10 based boards support the use
755  * of this command with payloads up to the maximum MCDI V2 payload length.
756  */
757 	__checkReturn		efx_rc_t
758 efx_mcdi_nvram_write(
759 	__in			efx_nic_t *enp,
760 	__in			uint32_t partn,
761 	__in			uint32_t offset,
762 	__out_bcount(size)	caddr_t data,
763 	__in			size_t size)
764 {
765 	efx_mcdi_req_t req;
766 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
767 			    MCDI_CTL_SDU_LEN_MAX_V2)];
768 	efx_rc_t rc;
769 	size_t max_data_size;
770 
771 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
772 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
773 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
774 	EFSYS_ASSERT3U(max_data_size, <,
775 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
776 
777 	if (size > max_data_size) {
778 		rc = EINVAL;
779 		goto fail1;
780 	}
781 
782 	(void) memset(payload, 0, sizeof (payload));
783 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
784 	req.emr_in_buf = payload;
785 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
786 	req.emr_out_buf = payload;
787 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
788 
789 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
790 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
791 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
792 
793 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
794 	    data, size);
795 
796 	efx_mcdi_execute(enp, &req);
797 
798 	if (req.emr_rc != 0) {
799 		rc = req.emr_rc;
800 		goto fail2;
801 	}
802 
803 	return (0);
804 
805 fail2:
806 	EFSYS_PROBE(fail2);
807 fail1:
808 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
809 
810 	return (rc);
811 }
812 
813 	__checkReturn		efx_rc_t
814 efx_mcdi_nvram_update_finish(
815 	__in			efx_nic_t *enp,
816 	__in			uint32_t partn,
817 	__in			boolean_t reboot)
818 {
819 	efx_mcdi_req_t req;
820 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
821 			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
822 	efx_rc_t rc;
823 
824 	(void) memset(payload, 0, sizeof (payload));
825 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
826 	req.emr_in_buf = payload;
827 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
828 	req.emr_out_buf = payload;
829 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
830 
831 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
832 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
833 
834 	efx_mcdi_execute(enp, &req);
835 
836 	if (req.emr_rc != 0) {
837 		rc = req.emr_rc;
838 		goto fail1;
839 	}
840 
841 	return (0);
842 
843 fail1:
844 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
845 
846 	return (rc);
847 }
848 
849 #if EFSYS_OPT_DIAG
850 
851 	__checkReturn		efx_rc_t
852 efx_mcdi_nvram_test(
853 	__in			efx_nic_t *enp,
854 	__in			uint32_t partn)
855 {
856 	efx_mcdi_req_t req;
857 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
858 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
859 	int result;
860 	efx_rc_t rc;
861 
862 	(void) memset(payload, 0, sizeof (payload));
863 	req.emr_cmd = MC_CMD_NVRAM_TEST;
864 	req.emr_in_buf = payload;
865 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
866 	req.emr_out_buf = payload;
867 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
868 
869 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
870 
871 	efx_mcdi_execute(enp, &req);
872 
873 	if (req.emr_rc != 0) {
874 		rc = req.emr_rc;
875 		goto fail1;
876 	}
877 
878 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
879 		rc = EMSGSIZE;
880 		goto fail2;
881 	}
882 
883 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
884 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
885 
886 		EFSYS_PROBE1(nvram_test_failure, int, partn);
887 
888 		rc = (EINVAL);
889 		goto fail3;
890 	}
891 
892 	return (0);
893 
894 fail3:
895 	EFSYS_PROBE(fail3);
896 fail2:
897 	EFSYS_PROBE(fail2);
898 fail1:
899 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
900 
901 	return (rc);
902 }
903 
904 #endif	/* EFSYS_OPT_DIAG */
905 
906 
907 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
908