xref: /freebsd/sys/dev/sfxge/common/efx_nvram.c (revision b0b1dbdd)
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 	__checkReturn		efx_rc_t
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 	efx_rc_t rc;
373 
374 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
375 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
376 
377 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
378 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
379 
380 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
381 
382 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
383 		goto fail1;
384 
385 	if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
386 		goto fail2;
387 
388 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
389 
390 	return (0);
391 
392 fail2:
393 	EFSYS_PROBE(fail2);
394 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
395 
396 fail1:
397 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
398 
399 	return (rc);
400 }
401 
402 	__checkReturn		efx_rc_t
403 efx_nvram_set_version(
404 	__in			efx_nic_t *enp,
405 	__in			efx_nvram_type_t type,
406 	__in_ecount(4)		uint16_t version[4])
407 {
408 	const efx_nvram_ops_t *envop = enp->en_envop;
409 	uint32_t partn;
410 	efx_rc_t rc;
411 
412 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
415 
416 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
417 
418 	/*
419 	 * The Siena implementation of envo_set_version() will attempt to
420 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
421 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
422 	 */
423 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
424 
425 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
426 		goto fail1;
427 
428 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
429 		goto fail2;
430 
431 	return (0);
432 
433 fail2:
434 	EFSYS_PROBE(fail2);
435 fail1:
436 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
437 
438 	return (rc);
439 }
440 
441 /* Validate buffer contents (before writing to flash) */
442 	__checkReturn		efx_rc_t
443 efx_nvram_validate(
444 	__in			efx_nic_t *enp,
445 	__in			efx_nvram_type_t type,
446 	__in_bcount(partn_size)	caddr_t partn_data,
447 	__in			size_t partn_size)
448 {
449 	const efx_nvram_ops_t *envop = enp->en_envop;
450 	uint32_t partn;
451 	efx_rc_t rc;
452 
453 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
455 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
456 
457 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
458 
459 
460 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
461 		goto fail1;
462 
463 	if (envop->envo_type_to_partn != NULL &&
464 	    ((rc = envop->envo_buffer_validate(enp, partn,
465 	    partn_data, partn_size)) != 0))
466 		goto fail2;
467 
468 	return (0);
469 
470 fail2:
471 	EFSYS_PROBE(fail2);
472 fail1:
473 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
474 
475 	return (rc);
476 }
477 
478 
479 void
480 efx_nvram_fini(
481 	__in		efx_nic_t *enp)
482 {
483 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
484 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
485 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
486 
487 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
488 
489 	enp->en_envop = NULL;
490 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
491 }
492 
493 #endif	/* EFSYS_OPT_NVRAM */
494 
495 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
496 
497 /*
498  * Internal MCDI request handling
499  */
500 
501 	__checkReturn		efx_rc_t
502 efx_mcdi_nvram_partitions(
503 	__in			efx_nic_t *enp,
504 	__out_bcount(size)	caddr_t data,
505 	__in			size_t size,
506 	__out			unsigned int *npartnp)
507 {
508 	efx_mcdi_req_t req;
509 	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
510 			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
511 	unsigned int npartn;
512 	efx_rc_t rc;
513 
514 	(void) memset(payload, 0, sizeof (payload));
515 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
516 	req.emr_in_buf = payload;
517 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
518 	req.emr_out_buf = payload;
519 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
520 
521 	efx_mcdi_execute(enp, &req);
522 
523 	if (req.emr_rc != 0) {
524 		rc = req.emr_rc;
525 		goto fail1;
526 	}
527 
528 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
529 		rc = EMSGSIZE;
530 		goto fail2;
531 	}
532 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
533 
534 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
535 		rc = ENOENT;
536 		goto fail3;
537 	}
538 
539 	if (size < npartn * sizeof (uint32_t)) {
540 		rc = ENOSPC;
541 		goto fail3;
542 	}
543 
544 	*npartnp = npartn;
545 
546 	memcpy(data,
547 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
548 	    (npartn * sizeof (uint32_t)));
549 
550 	return (0);
551 
552 fail3:
553 	EFSYS_PROBE(fail3);
554 fail2:
555 	EFSYS_PROBE(fail2);
556 fail1:
557 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
558 
559 	return (rc);
560 }
561 
562 	__checkReturn		efx_rc_t
563 efx_mcdi_nvram_metadata(
564 	__in			efx_nic_t *enp,
565 	__in			uint32_t partn,
566 	__out			uint32_t *subtypep,
567 	__out_ecount(4)		uint16_t version[4],
568 	__out_bcount_opt(size)	char *descp,
569 	__in			size_t size)
570 {
571 	efx_mcdi_req_t req;
572 	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
573 			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
574 	efx_rc_t rc;
575 
576 	(void) memset(payload, 0, sizeof (payload));
577 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
578 	req.emr_in_buf = payload;
579 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
580 	req.emr_out_buf = payload;
581 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
582 
583 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
584 
585 	efx_mcdi_execute(enp, &req);
586 
587 	if (req.emr_rc != 0) {
588 		rc = req.emr_rc;
589 		goto fail1;
590 	}
591 
592 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
593 		rc = EMSGSIZE;
594 		goto fail2;
595 	}
596 
597 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
598 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
599 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
600 	} else {
601 		*subtypep = 0;
602 	}
603 
604 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
605 		NVRAM_METADATA_OUT_VERSION_VALID)) {
606 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
607 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
608 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
609 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
610 	} else {
611 		version[0] = version[1] = version[2] = version[3] = 0;
612 	}
613 
614 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
615 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
616 		/* Return optional descrition string */
617 		if ((descp != NULL) && (size > 0)) {
618 			size_t desclen;
619 
620 			descp[0] = '\0';
621 			desclen = (req.emr_out_length_used
622 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
623 
624 			EFSYS_ASSERT3U(desclen, <=,
625 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
626 
627 			if (size < desclen) {
628 				rc = ENOSPC;
629 				goto fail3;
630 			}
631 
632 			memcpy(descp, MCDI_OUT2(req, char,
633 				NVRAM_METADATA_OUT_DESCRIPTION),
634 			    desclen);
635 
636 			/* Ensure string is NUL terminated */
637 			descp[desclen] = '\0';
638 		}
639 	}
640 
641 	return (0);
642 
643 fail3:
644 	EFSYS_PROBE(fail3);
645 fail2:
646 	EFSYS_PROBE(fail2);
647 fail1:
648 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
649 
650 	return (rc);
651 }
652 
653 	__checkReturn		efx_rc_t
654 efx_mcdi_nvram_info(
655 	__in			efx_nic_t *enp,
656 	__in			uint32_t partn,
657 	__out_opt		size_t *sizep,
658 	__out_opt		uint32_t *addressp,
659 	__out_opt		uint32_t *erase_sizep,
660 	__out_opt		uint32_t *write_sizep)
661 {
662 	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
663 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
664 	efx_mcdi_req_t req;
665 	efx_rc_t rc;
666 
667 	(void) memset(payload, 0, sizeof (payload));
668 	req.emr_cmd = MC_CMD_NVRAM_INFO;
669 	req.emr_in_buf = payload;
670 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
671 	req.emr_out_buf = payload;
672 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
673 
674 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
675 
676 	efx_mcdi_execute_quiet(enp, &req);
677 
678 	if (req.emr_rc != 0) {
679 		rc = req.emr_rc;
680 		goto fail1;
681 	}
682 
683 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
684 		rc = EMSGSIZE;
685 		goto fail2;
686 	}
687 
688 	if (sizep)
689 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
690 
691 	if (addressp)
692 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
693 
694 	if (erase_sizep)
695 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
696 
697 	if (write_sizep) {
698 		*write_sizep =
699 			(req.emr_out_length_used <
700 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
701 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
702 	}
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 /*
715  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
716  * NVRAM updates. Older firmware will ignore the flags field in the request.
717  */
718 	__checkReturn		efx_rc_t
719 efx_mcdi_nvram_update_start(
720 	__in			efx_nic_t *enp,
721 	__in			uint32_t partn)
722 {
723 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
724 			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
725 	efx_mcdi_req_t req;
726 	efx_rc_t rc;
727 
728 	(void) memset(payload, 0, sizeof (payload));
729 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
730 	req.emr_in_buf = payload;
731 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
732 	req.emr_out_buf = payload;
733 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
734 
735 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
736 
737 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
738 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
739 
740 	efx_mcdi_execute(enp, &req);
741 
742 	if (req.emr_rc != 0) {
743 		rc = req.emr_rc;
744 		goto fail1;
745 	}
746 
747 	return (0);
748 
749 fail1:
750 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
751 
752 	return (rc);
753 }
754 
755 	__checkReturn		efx_rc_t
756 efx_mcdi_nvram_read(
757 	__in			efx_nic_t *enp,
758 	__in			uint32_t partn,
759 	__in			uint32_t offset,
760 	__out_bcount(size)	caddr_t data,
761 	__in			size_t size,
762 	__in			uint32_t mode)
763 {
764 	efx_mcdi_req_t req;
765 	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
766 			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
767 	efx_rc_t rc;
768 
769 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
770 		rc = EINVAL;
771 		goto fail1;
772 	}
773 
774 	(void) memset(payload, 0, sizeof (payload));
775 	req.emr_cmd = MC_CMD_NVRAM_READ;
776 	req.emr_in_buf = payload;
777 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
778 	req.emr_out_buf = payload;
779 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
780 
781 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
782 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
783 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
784 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
785 
786 	efx_mcdi_execute(enp, &req);
787 
788 	if (req.emr_rc != 0) {
789 		rc = req.emr_rc;
790 		goto fail1;
791 	}
792 
793 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
794 		rc = EMSGSIZE;
795 		goto fail2;
796 	}
797 
798 	memcpy(data,
799 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
800 	    size);
801 
802 	return (0);
803 
804 fail2:
805 	EFSYS_PROBE(fail2);
806 fail1:
807 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
808 
809 	return (rc);
810 }
811 
812 	__checkReturn		efx_rc_t
813 efx_mcdi_nvram_erase(
814 	__in			efx_nic_t *enp,
815 	__in			uint32_t partn,
816 	__in			uint32_t offset,
817 	__in			size_t size)
818 {
819 	efx_mcdi_req_t req;
820 	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
821 			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
822 	efx_rc_t rc;
823 
824 	(void) memset(payload, 0, sizeof (payload));
825 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
826 	req.emr_in_buf = payload;
827 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
828 	req.emr_out_buf = payload;
829 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
830 
831 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
832 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
833 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
834 
835 	efx_mcdi_execute(enp, &req);
836 
837 	if (req.emr_rc != 0) {
838 		rc = req.emr_rc;
839 		goto fail1;
840 	}
841 
842 	return (0);
843 
844 fail1:
845 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
846 
847 	return (rc);
848 }
849 
850 /*
851  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
852  * Sienna and EF10 based boards.  However EF10 based boards support the use
853  * of this command with payloads up to the maximum MCDI V2 payload length.
854  */
855 	__checkReturn		efx_rc_t
856 efx_mcdi_nvram_write(
857 	__in			efx_nic_t *enp,
858 	__in			uint32_t partn,
859 	__in			uint32_t offset,
860 	__out_bcount(size)	caddr_t data,
861 	__in			size_t size)
862 {
863 	efx_mcdi_req_t req;
864 	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
865 			    MCDI_CTL_SDU_LEN_MAX_V2)];
866 	efx_rc_t rc;
867 	size_t max_data_size;
868 
869 	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
870 	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
871 	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
872 	EFSYS_ASSERT3U(max_data_size, <,
873 		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
874 
875 	if (size > max_data_size) {
876 		rc = EINVAL;
877 		goto fail1;
878 	}
879 
880 	(void) memset(payload, 0, sizeof (payload));
881 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
882 	req.emr_in_buf = payload;
883 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
884 	req.emr_out_buf = payload;
885 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
886 
887 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
888 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
889 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
890 
891 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
892 	    data, size);
893 
894 	efx_mcdi_execute(enp, &req);
895 
896 	if (req.emr_rc != 0) {
897 		rc = req.emr_rc;
898 		goto fail2;
899 	}
900 
901 	return (0);
902 
903 fail2:
904 	EFSYS_PROBE(fail2);
905 fail1:
906 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
907 
908 	return (rc);
909 }
910 
911 
912 /*
913  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
914  * NVRAM updates. Older firmware will ignore the flags field in the request.
915  */
916 	__checkReturn		efx_rc_t
917 efx_mcdi_nvram_update_finish(
918 	__in			efx_nic_t *enp,
919 	__in			uint32_t partn,
920 	__in			boolean_t reboot,
921 	__out_opt		uint32_t *resultp)
922 {
923 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
924 	efx_mcdi_req_t req;
925 	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
926 			    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
927 	uint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */
928 	efx_rc_t rc;
929 
930 	(void) memset(payload, 0, sizeof (payload));
931 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
932 	req.emr_in_buf = payload;
933 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
934 	req.emr_out_buf = payload;
935 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
936 
937 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
938 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
939 
940 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
941 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
942 
943 	efx_mcdi_execute(enp, &req);
944 
945 	if (req.emr_rc != 0) {
946 		rc = req.emr_rc;
947 		goto fail1;
948 	}
949 
950 	if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
951 		/* Report success if verified updates are not supported. */
952 		result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
953 	} else {
954 		/* Firmware-verified NVRAM updates are required */
955 		if (req.emr_out_length_used <
956 		    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
957 			rc = EMSGSIZE;
958 			goto fail2;
959 		}
960 		result =
961 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
962 
963 		if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
964 			/* Mandatory verification failed */
965 			rc = EINVAL;
966 			goto fail3;
967 		}
968 	}
969 
970 	if (resultp != NULL)
971 		*resultp = result;
972 
973 	return (0);
974 
975 fail3:
976 	EFSYS_PROBE(fail3);
977 fail2:
978 	EFSYS_PROBE(fail2);
979 fail1:
980 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
981 
982 	/* Always report verification result */
983 	if (resultp != NULL)
984 		*resultp = result;
985 
986 	return (rc);
987 }
988 
989 #if EFSYS_OPT_DIAG
990 
991 	__checkReturn		efx_rc_t
992 efx_mcdi_nvram_test(
993 	__in			efx_nic_t *enp,
994 	__in			uint32_t partn)
995 {
996 	efx_mcdi_req_t req;
997 	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
998 			    MC_CMD_NVRAM_TEST_OUT_LEN)];
999 	int result;
1000 	efx_rc_t rc;
1001 
1002 	(void) memset(payload, 0, sizeof (payload));
1003 	req.emr_cmd = MC_CMD_NVRAM_TEST;
1004 	req.emr_in_buf = payload;
1005 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
1006 	req.emr_out_buf = payload;
1007 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
1008 
1009 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
1010 
1011 	efx_mcdi_execute(enp, &req);
1012 
1013 	if (req.emr_rc != 0) {
1014 		rc = req.emr_rc;
1015 		goto fail1;
1016 	}
1017 
1018 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
1019 		rc = EMSGSIZE;
1020 		goto fail2;
1021 	}
1022 
1023 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
1024 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
1025 
1026 		EFSYS_PROBE1(nvram_test_failure, int, partn);
1027 
1028 		rc = (EINVAL);
1029 		goto fail3;
1030 	}
1031 
1032 	return (0);
1033 
1034 fail3:
1035 	EFSYS_PROBE(fail3);
1036 fail2:
1037 	EFSYS_PROBE(fail2);
1038 fail1:
1039 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1040 
1041 	return (rc);
1042 }
1043 
1044 #endif	/* EFSYS_OPT_DIAG */
1045 
1046 
1047 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1048