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