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