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