xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision 93e779a26c651610ac6e7986d67ecc9ed2cadcbf)
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	int
97 efx_nvram_init(
98 	__in		efx_nic_t *enp)
99 {
100 	efx_nvram_ops_t *envop;
101 	int 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, int, rc);
139 
140 	return (rc);
141 }
142 
143 #if EFSYS_OPT_DIAG
144 
145 	__checkReturn		int
146 efx_nvram_test(
147 	__in			efx_nic_t *enp)
148 {
149 	efx_nvram_ops_t *envop = enp->en_envop;
150 	int 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, int, rc);
162 
163 	return (rc);
164 }
165 
166 #endif	/* EFSYS_OPT_DIAG */
167 
168 	__checkReturn		int
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 	int 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, int, rc);
189 
190 	return (rc);
191 }
192 
193 	__checkReturn		int
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 	int 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, int, rc);
216 
217 	return (rc);
218 }
219 
220 	__checkReturn		int
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 	int 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, int, rc);
246 
247 	return (rc);
248 }
249 
250 	__checkReturn		int
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 	int 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, int, rc);
276 
277 	return (rc);
278 }
279 
280 	__checkReturn		int
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 	int 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, int, rc);
303 
304 	return (rc);
305 }
306 
307 	__checkReturn		int
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 	int 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, int, 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		int
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 	int 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, int, 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		int
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 	int 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, int, rc);
469 
470 	return (rc);
471 }
472 
473 	__checkReturn		int
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 	int 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, int, rc);
560 
561 	return (rc);
562 }
563 
564 	__checkReturn		int
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 {
572 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
573 			    MC_CMD_NVRAM_INFO_OUT_LEN)];
574 	efx_mcdi_req_t req;
575 	int rc;
576 
577 	(void) memset(payload, 0, sizeof (payload));
578 	req.emr_cmd = MC_CMD_NVRAM_INFO;
579 	req.emr_in_buf = payload;
580 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
581 	req.emr_out_buf = payload;
582 	req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
583 
584 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
585 
586 	efx_mcdi_execute_quiet(enp, &req);
587 
588 	if (req.emr_rc != 0) {
589 		rc = req.emr_rc;
590 		goto fail1;
591 	}
592 
593 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
594 		rc = EMSGSIZE;
595 		goto fail2;
596 	}
597 
598 	if (sizep)
599 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
600 
601 	if (addressp)
602 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
603 
604 	if (erase_sizep)
605 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
606 
607 	return (0);
608 
609 fail2:
610 	EFSYS_PROBE(fail2);
611 fail1:
612 	EFSYS_PROBE1(fail1, int, rc);
613 
614 	return (rc);
615 }
616 
617 	__checkReturn		int
618 efx_mcdi_nvram_update_start(
619 	__in			efx_nic_t *enp,
620 	__in			uint32_t partn)
621 {
622 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
623 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
624 	efx_mcdi_req_t req;
625 	int rc;
626 
627 	(void) memset(payload, 0, sizeof (payload));
628 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
629 	req.emr_in_buf = payload;
630 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
631 	req.emr_out_buf = payload;
632 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
633 
634 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
635 
636 	efx_mcdi_execute(enp, &req);
637 
638 	if (req.emr_rc != 0) {
639 		rc = req.emr_rc;
640 		goto fail1;
641 	}
642 
643 	return (0);
644 
645 fail1:
646 	EFSYS_PROBE1(fail1, int, rc);
647 
648 	return (rc);
649 }
650 
651 	__checkReturn		int
652 efx_mcdi_nvram_read(
653 	__in			efx_nic_t *enp,
654 	__in			uint32_t partn,
655 	__in			uint32_t offset,
656 	__out_bcount(size)	caddr_t data,
657 	__in			size_t size)
658 {
659 	efx_mcdi_req_t req;
660 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
661 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
662 	int rc;
663 
664 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
665 		rc = EINVAL;
666 		goto fail1;
667 	}
668 
669 	(void) memset(payload, 0, sizeof (payload));
670 	req.emr_cmd = MC_CMD_NVRAM_READ;
671 	req.emr_in_buf = payload;
672 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
673 	req.emr_out_buf = payload;
674 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
675 
676 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
677 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
678 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
679 
680 	efx_mcdi_execute(enp, &req);
681 
682 	if (req.emr_rc != 0) {
683 		rc = req.emr_rc;
684 		goto fail1;
685 	}
686 
687 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
688 		rc = EMSGSIZE;
689 		goto fail2;
690 	}
691 
692 	memcpy(data,
693 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
694 	    size);
695 
696 	return (0);
697 
698 fail2:
699 	EFSYS_PROBE(fail2);
700 fail1:
701 	EFSYS_PROBE1(fail1, int, rc);
702 
703 	return (rc);
704 }
705 
706 	__checkReturn		int
707 efx_mcdi_nvram_erase(
708 	__in			efx_nic_t *enp,
709 	__in			uint32_t partn,
710 	__in			uint32_t offset,
711 	__in			size_t size)
712 {
713 	efx_mcdi_req_t req;
714 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
715 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
716 	int rc;
717 
718 	(void) memset(payload, 0, sizeof (payload));
719 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
720 	req.emr_in_buf = payload;
721 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
722 	req.emr_out_buf = payload;
723 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
724 
725 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
726 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
727 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
728 
729 	efx_mcdi_execute(enp, &req);
730 
731 	if (req.emr_rc != 0) {
732 		rc = req.emr_rc;
733 		goto fail1;
734 	}
735 
736 	return (0);
737 
738 fail1:
739 	EFSYS_PROBE1(fail1, int, rc);
740 
741 	return (rc);
742 }
743 
744 	__checkReturn		int
745 efx_mcdi_nvram_write(
746 	__in			efx_nic_t *enp,
747 	__in			uint32_t partn,
748 	__in			uint32_t offset,
749 	__out_bcount(size)	caddr_t data,
750 	__in			size_t size)
751 {
752 	efx_mcdi_req_t req;
753 	uint8_t payload[MAX(MC_CMD_NVRAM_WRITE_IN_LENMAX,
754 			    MC_CMD_NVRAM_WRITE_OUT_LEN)];
755 	int rc;
756 
757 	if (size > MC_CMD_NVRAM_WRITE_IN_LENMAX) {
758 		rc = EINVAL;
759 		goto fail1;
760 	}
761 
762 	(void) memset(payload, 0, sizeof (payload));
763 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
764 	req.emr_in_buf = payload;
765 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
766 	req.emr_out_buf = payload;
767 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
768 
769 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
770 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
771 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
772 
773 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
774 	    data, size);
775 
776 	efx_mcdi_execute(enp, &req);
777 
778 	if (req.emr_rc != 0) {
779 		rc = req.emr_rc;
780 		goto fail2;
781 	}
782 
783 	return (0);
784 
785 fail2:
786 	EFSYS_PROBE(fail2);
787 fail1:
788 	EFSYS_PROBE1(fail1, int, rc);
789 
790 	return (rc);
791 }
792 
793 	__checkReturn		int
794 efx_mcdi_nvram_update_finish(
795 	__in			efx_nic_t *enp,
796 	__in			uint32_t partn,
797 	__in			boolean_t reboot)
798 {
799 	efx_mcdi_req_t req;
800 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
801 			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
802 	int rc;
803 
804 	(void) memset(payload, 0, sizeof (payload));
805 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
806 	req.emr_in_buf = payload;
807 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
808 	req.emr_out_buf = payload;
809 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
810 
811 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
812 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
813 
814 	efx_mcdi_execute(enp, &req);
815 
816 	if (req.emr_rc != 0) {
817 		rc = req.emr_rc;
818 		goto fail1;
819 	}
820 
821 	return (0);
822 
823 fail1:
824 	EFSYS_PROBE1(fail1, int, rc);
825 
826 	return (rc);
827 }
828 
829 #if EFSYS_OPT_DIAG
830 
831 	__checkReturn		int
832 efx_mcdi_nvram_test(
833 	__in			efx_nic_t *enp,
834 	__in			uint32_t partn)
835 {
836 	efx_mcdi_req_t req;
837 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
838 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
839 	int result;
840 	int rc;
841 
842 	(void) memset(payload, 0, sizeof (payload));
843 	req.emr_cmd = MC_CMD_NVRAM_TEST;
844 	req.emr_in_buf = payload;
845 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
846 	req.emr_out_buf = payload;
847 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
848 
849 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
850 
851 	efx_mcdi_execute(enp, &req);
852 
853 	if (req.emr_rc != 0) {
854 		rc = req.emr_rc;
855 		goto fail1;
856 	}
857 
858 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
859 		rc = EMSGSIZE;
860 		goto fail2;
861 	}
862 
863 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
864 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
865 
866 		EFSYS_PROBE1(nvram_test_failure, int, partn);
867 
868 		rc = (EINVAL);
869 		goto fail3;
870 	}
871 
872 	return (0);
873 
874 fail3:
875 	EFSYS_PROBE(fail3);
876 fail2:
877 	EFSYS_PROBE(fail2);
878 fail1:
879 	EFSYS_PROBE1(fail1, int, rc);
880 
881 	return (rc);
882 }
883 
884 #endif	/* EFSYS_OPT_DIAG */
885 
886 
887 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
888