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