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