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