efx_nvram.c revision 291923
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 291923 2015-12-07 06:01:14Z arybchik $");
33
34#include "efsys.h"
35#include "efx.h"
36#include "efx_types.h"
37#include "efx_regs.h"
38#include "efx_impl.h"
39
40#if EFSYS_OPT_NVRAM
41
42#if EFSYS_OPT_FALCON
43
44static efx_nvram_ops_t	__efx_nvram_falcon_ops = {
45#if EFSYS_OPT_DIAG
46	falcon_nvram_test,		/* envo_test */
47#endif	/* EFSYS_OPT_DIAG */
48	falcon_nvram_size,		/* envo_size */
49	falcon_nvram_get_version,	/* envo_get_version */
50	falcon_nvram_rw_start,		/* envo_rw_start */
51	falcon_nvram_read_chunk,	/* envo_read_chunk */
52	falcon_nvram_erase,		/* envo_erase */
53	falcon_nvram_write_chunk,	/* envo_write_chunk */
54	falcon_nvram_rw_finish,		/* envo_rw_finish */
55	falcon_nvram_set_version,	/* envo_set_version */
56};
57
58#endif	/* EFSYS_OPT_FALCON */
59
60#if EFSYS_OPT_SIENA
61
62static efx_nvram_ops_t	__efx_nvram_siena_ops = {
63#if EFSYS_OPT_DIAG
64	siena_nvram_test,		/* envo_test */
65#endif	/* EFSYS_OPT_DIAG */
66	siena_nvram_size,		/* envo_size */
67	siena_nvram_get_version,	/* envo_get_version */
68	siena_nvram_rw_start,		/* envo_rw_start */
69	siena_nvram_read_chunk,		/* envo_read_chunk */
70	siena_nvram_erase,		/* envo_erase */
71	siena_nvram_write_chunk,	/* envo_write_chunk */
72	siena_nvram_rw_finish,		/* envo_rw_finish */
73	siena_nvram_set_version,	/* envo_set_version */
74};
75
76#endif	/* EFSYS_OPT_SIENA */
77
78#if EFSYS_OPT_HUNTINGTON
79
80static efx_nvram_ops_t	__efx_nvram_hunt_ops = {
81#if EFSYS_OPT_DIAG
82	hunt_nvram_test,		/* envo_test */
83#endif	/* EFSYS_OPT_DIAG */
84	hunt_nvram_size,		/* envo_size */
85	hunt_nvram_get_version,		/* envo_get_version */
86	hunt_nvram_rw_start,		/* envo_rw_start */
87	hunt_nvram_read_chunk,		/* envo_read_chunk */
88	hunt_nvram_erase,		/* envo_erase */
89	hunt_nvram_write_chunk,		/* envo_write_chunk */
90	hunt_nvram_rw_finish,		/* envo_rw_finish */
91	hunt_nvram_set_version,		/* envo_set_version */
92};
93
94#endif	/* EFSYS_OPT_HUNTINGTON */
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_hunt_ops;
123		break;
124#endif	/* EFSYS_OPT_HUNTINGTON */
125
126	default:
127		EFSYS_ASSERT(0);
128		rc = ENOTSUP;
129		goto fail1;
130	}
131
132	enp->en_envop = envop;
133	enp->en_mod_flags |= EFX_MOD_NVRAM;
134
135	return (0);
136
137fail1:
138	EFSYS_PROBE1(fail1, efx_rc_t, rc);
139
140	return (rc);
141}
142
143#if EFSYS_OPT_DIAG
144
145	__checkReturn		efx_rc_t
146efx_nvram_test(
147	__in			efx_nic_t *enp)
148{
149	efx_nvram_ops_t *envop = enp->en_envop;
150	efx_rc_t rc;
151
152	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
153	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
154
155	if ((rc = envop->envo_test(enp)) != 0)
156		goto fail1;
157
158	return (0);
159
160fail1:
161	EFSYS_PROBE1(fail1, efx_rc_t, rc);
162
163	return (rc);
164}
165
166#endif	/* EFSYS_OPT_DIAG */
167
168	__checkReturn		efx_rc_t
169efx_nvram_size(
170	__in			efx_nic_t *enp,
171	__in			efx_nvram_type_t type,
172	__out			size_t *sizep)
173{
174	efx_nvram_ops_t *envop = enp->en_envop;
175	efx_rc_t rc;
176
177	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
178	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
179
180	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
181
182	if ((rc = envop->envo_size(enp, type, sizep)) != 0)
183		goto fail1;
184
185	return (0);
186
187fail1:
188	EFSYS_PROBE1(fail1, efx_rc_t, rc);
189
190	return (rc);
191}
192
193	__checkReturn		efx_rc_t
194efx_nvram_get_version(
195	__in			efx_nic_t *enp,
196	__in			efx_nvram_type_t type,
197	__out			uint32_t *subtypep,
198	__out_ecount(4)		uint16_t version[4])
199{
200	efx_nvram_ops_t *envop = enp->en_envop;
201	efx_rc_t rc;
202
203	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
206
207	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
208
209	if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0)
210		goto fail1;
211
212	return (0);
213
214fail1:
215	EFSYS_PROBE1(fail1, efx_rc_t, rc);
216
217	return (rc);
218}
219
220	__checkReturn		efx_rc_t
221efx_nvram_rw_start(
222	__in			efx_nic_t *enp,
223	__in			efx_nvram_type_t type,
224	__out_opt		size_t *chunk_sizep)
225{
226	efx_nvram_ops_t *envop = enp->en_envop;
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_rw_start(enp, type, chunk_sizep)) != 0)
238		goto fail1;
239
240	enp->en_nvram_locked = type;
241
242	return (0);
243
244fail1:
245	EFSYS_PROBE1(fail1, efx_rc_t, rc);
246
247	return (rc);
248}
249
250	__checkReturn		efx_rc_t
251efx_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	efx_nvram_ops_t *envop = enp->en_envop;
259	efx_rc_t rc;
260
261	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
263
264	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
265	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
266
267	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
268
269	if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0)
270		goto fail1;
271
272	return (0);
273
274fail1:
275	EFSYS_PROBE1(fail1, efx_rc_t, rc);
276
277	return (rc);
278}
279
280	__checkReturn		efx_rc_t
281efx_nvram_erase(
282	__in			efx_nic_t *enp,
283	__in			efx_nvram_type_t type)
284{
285	efx_nvram_ops_t *envop = enp->en_envop;
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_erase(enp, type)) != 0)
297		goto fail1;
298
299	return (0);
300
301fail1:
302	EFSYS_PROBE1(fail1, efx_rc_t, rc);
303
304	return (rc);
305}
306
307	__checkReturn		efx_rc_t
308efx_nvram_write_chunk(
309	__in			efx_nic_t *enp,
310	__in			efx_nvram_type_t type,
311	__in			unsigned int offset,
312	__in_bcount(size)	caddr_t data,
313	__in			size_t size)
314{
315	efx_nvram_ops_t *envop = enp->en_envop;
316	efx_rc_t rc;
317
318	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
319	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
320
321	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
322	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
323
324	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
325
326	if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
327		goto fail1;
328
329	return (0);
330
331fail1:
332	EFSYS_PROBE1(fail1, efx_rc_t, rc);
333
334	return (rc);
335}
336
337				void
338efx_nvram_rw_finish(
339	__in			efx_nic_t *enp,
340	__in			efx_nvram_type_t type)
341{
342	efx_nvram_ops_t *envop = enp->en_envop;
343
344	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
345	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
346
347	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
348	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
349
350	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
351
352	envop->envo_rw_finish(enp, type);
353
354	enp->en_nvram_locked = EFX_NVRAM_INVALID;
355}
356
357	__checkReturn		efx_rc_t
358efx_nvram_set_version(
359	__in			efx_nic_t *enp,
360	__in			efx_nvram_type_t type,
361	__in_ecount(4)		uint16_t version[4])
362{
363	efx_nvram_ops_t *envop = enp->en_envop;
364	efx_rc_t rc;
365
366	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
367	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
368	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
369
370	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
371
372	/*
373	 * The Siena implementation of envo_set_version() will attempt to
374	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
375	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
376	 */
377	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
378
379	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
380		goto fail1;
381
382	return (0);
383
384fail1:
385	EFSYS_PROBE1(fail1, efx_rc_t, rc);
386
387	return (rc);
388}
389
390void
391efx_nvram_fini(
392	__in		efx_nic_t *enp)
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(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
399
400	enp->en_envop = NULL;
401	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
402}
403
404#endif	/* EFSYS_OPT_NVRAM */
405
406#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
407
408/*
409 * Internal MCDI request handling
410 */
411
412	__checkReturn		efx_rc_t
413efx_mcdi_nvram_partitions(
414	__in			efx_nic_t *enp,
415	__out_bcount(size)	caddr_t data,
416	__in			size_t size,
417	__out			unsigned int *npartnp)
418{
419	efx_mcdi_req_t req;
420	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
421			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
422	unsigned int npartn;
423	efx_rc_t rc;
424
425	(void) memset(payload, 0, sizeof (payload));
426	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
427	req.emr_in_buf = payload;
428	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
429	req.emr_out_buf = payload;
430	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
431
432	efx_mcdi_execute(enp, &req);
433
434	if (req.emr_rc != 0) {
435		rc = req.emr_rc;
436		goto fail1;
437	}
438
439	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
440		rc = EMSGSIZE;
441		goto fail2;
442	}
443	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
444
445	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
446		rc = ENOENT;
447		goto fail3;
448	}
449
450	if (size < npartn * sizeof (uint32_t)) {
451		rc = ENOSPC;
452		goto fail3;
453	}
454
455	*npartnp = npartn;
456
457	memcpy(data,
458	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
459	    (npartn * sizeof (uint32_t)));
460
461	return (0);
462
463fail3:
464	EFSYS_PROBE(fail3);
465fail2:
466	EFSYS_PROBE(fail2);
467fail1:
468	EFSYS_PROBE1(fail1, efx_rc_t, rc);
469
470	return (rc);
471}
472
473	__checkReturn		efx_rc_t
474efx_mcdi_nvram_metadata(
475	__in			efx_nic_t *enp,
476	__in			uint32_t partn,
477	__out			uint32_t *subtypep,
478	__out_ecount(4)		uint16_t version[4],
479	__out_bcount_opt(size)	char *descp,
480	__in			size_t size)
481{
482	efx_mcdi_req_t req;
483	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
484			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
485	efx_rc_t rc;
486
487	(void) memset(payload, 0, sizeof (payload));
488	req.emr_cmd = MC_CMD_NVRAM_METADATA;
489	req.emr_in_buf = payload;
490	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
491	req.emr_out_buf = payload;
492	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
493
494	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
495
496	efx_mcdi_execute(enp, &req);
497
498	if (req.emr_rc != 0) {
499		rc = req.emr_rc;
500		goto fail1;
501	}
502
503	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
504		rc = EMSGSIZE;
505		goto fail2;
506	}
507
508	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
509		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
510		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
511	} else {
512		*subtypep = 0;
513	}
514
515	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
516		NVRAM_METADATA_OUT_VERSION_VALID)) {
517		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
518		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
519		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
520		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
521	} else {
522		version[0] = version[1] = version[2] = version[3] = 0;
523	}
524
525	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
526		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
527		/* Return optional descrition string */
528		if ((descp != NULL) && (size > 0)) {
529			size_t desclen;
530
531			descp[0] = '\0';
532			desclen = (req.emr_out_length_used
533			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
534
535			EFSYS_ASSERT3U(desclen, <=,
536			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
537
538			if (size < desclen) {
539				rc = ENOSPC;
540				goto fail3;
541			}
542
543			memcpy(descp, MCDI_OUT2(req, char,
544				NVRAM_METADATA_OUT_DESCRIPTION),
545			    desclen);
546
547			/* Ensure string is NUL terminated */
548			descp[desclen] = '\0';
549		}
550	}
551
552	return (0);
553
554fail3:
555	EFSYS_PROBE(fail3);
556fail2:
557	EFSYS_PROBE(fail2);
558fail1:
559	EFSYS_PROBE1(fail1, efx_rc_t, rc);
560
561	return (rc);
562}
563
564	__checkReturn		efx_rc_t
565efx_mcdi_nvram_info(
566	__in			efx_nic_t *enp,
567	__in			uint32_t partn,
568	__out_opt		size_t *sizep,
569	__out_opt		uint32_t *addressp,
570	__out_opt		uint32_t *erase_sizep,
571	__out_opt		uint32_t *write_sizep)
572{
573	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
574			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
575	efx_mcdi_req_t req;
576	efx_rc_t rc;
577
578	(void) memset(payload, 0, sizeof (payload));
579	req.emr_cmd = MC_CMD_NVRAM_INFO;
580	req.emr_in_buf = payload;
581	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
582	req.emr_out_buf = payload;
583	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
584
585	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
586
587	efx_mcdi_execute_quiet(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_INFO_OUT_LEN) {
595		rc = EMSGSIZE;
596		goto fail2;
597	}
598
599	if (sizep)
600		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
601
602	if (addressp)
603		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
604
605	if (erase_sizep)
606		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
607
608	if (write_sizep) {
609		*write_sizep =
610			(req.emr_out_length_used <
611			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
612			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
613	}
614
615	return (0);
616
617fail2:
618	EFSYS_PROBE(fail2);
619fail1:
620	EFSYS_PROBE1(fail1, efx_rc_t, rc);
621
622	return (rc);
623}
624
625	__checkReturn		efx_rc_t
626efx_mcdi_nvram_update_start(
627	__in			efx_nic_t *enp,
628	__in			uint32_t partn)
629{
630	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
631			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
632	efx_mcdi_req_t req;
633	efx_rc_t rc;
634
635	(void) memset(payload, 0, sizeof (payload));
636	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
637	req.emr_in_buf = payload;
638	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
639	req.emr_out_buf = payload;
640	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
641
642	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
643
644	efx_mcdi_execute(enp, &req);
645
646	if (req.emr_rc != 0) {
647		rc = req.emr_rc;
648		goto fail1;
649	}
650
651	return (0);
652
653fail1:
654	EFSYS_PROBE1(fail1, efx_rc_t, rc);
655
656	return (rc);
657}
658
659	__checkReturn		efx_rc_t
660efx_mcdi_nvram_read(
661	__in			efx_nic_t *enp,
662	__in			uint32_t partn,
663	__in			uint32_t offset,
664	__out_bcount(size)	caddr_t data,
665	__in			size_t size)
666{
667	efx_mcdi_req_t req;
668	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
669			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
670	efx_rc_t rc;
671
672	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
673		rc = EINVAL;
674		goto fail1;
675	}
676
677	(void) memset(payload, 0, sizeof (payload));
678	req.emr_cmd = MC_CMD_NVRAM_READ;
679	req.emr_in_buf = payload;
680	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
681	req.emr_out_buf = payload;
682	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
683
684	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
685	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
686	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
687
688	efx_mcdi_execute(enp, &req);
689
690	if (req.emr_rc != 0) {
691		rc = req.emr_rc;
692		goto fail1;
693	}
694
695	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
696		rc = EMSGSIZE;
697		goto fail2;
698	}
699
700	memcpy(data,
701	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
702	    size);
703
704	return (0);
705
706fail2:
707	EFSYS_PROBE(fail2);
708fail1:
709	EFSYS_PROBE1(fail1, efx_rc_t, rc);
710
711	return (rc);
712}
713
714	__checkReturn		efx_rc_t
715efx_mcdi_nvram_erase(
716	__in			efx_nic_t *enp,
717	__in			uint32_t partn,
718	__in			uint32_t offset,
719	__in			size_t size)
720{
721	efx_mcdi_req_t req;
722	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
723			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
724	efx_rc_t rc;
725
726	(void) memset(payload, 0, sizeof (payload));
727	req.emr_cmd = MC_CMD_NVRAM_ERASE;
728	req.emr_in_buf = payload;
729	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
730	req.emr_out_buf = payload;
731	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
732
733	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
734	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
735	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
736
737	efx_mcdi_execute(enp, &req);
738
739	if (req.emr_rc != 0) {
740		rc = req.emr_rc;
741		goto fail1;
742	}
743
744	return (0);
745
746fail1:
747	EFSYS_PROBE1(fail1, efx_rc_t, rc);
748
749	return (rc);
750}
751
752/*
753 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
754 * Sienna and EF10 based boards.  However EF10 based boards support the use
755 * of this command with payloads up to the maximum MCDI V2 payload length.
756 */
757	__checkReturn		efx_rc_t
758efx_mcdi_nvram_write(
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{
765	efx_mcdi_req_t req;
766	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
767			    MCDI_CTL_SDU_LEN_MAX_V2)];
768	efx_rc_t rc;
769	size_t max_data_size;
770
771	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
772	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
773	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
774	EFSYS_ASSERT3U(max_data_size, <,
775		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
776
777	if (size > max_data_size) {
778		rc = EINVAL;
779		goto fail1;
780	}
781
782	(void) memset(payload, 0, sizeof (payload));
783	req.emr_cmd = MC_CMD_NVRAM_WRITE;
784	req.emr_in_buf = payload;
785	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
786	req.emr_out_buf = payload;
787	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
788
789	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
790	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
791	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
792
793	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
794	    data, size);
795
796	efx_mcdi_execute(enp, &req);
797
798	if (req.emr_rc != 0) {
799		rc = req.emr_rc;
800		goto fail2;
801	}
802
803	return (0);
804
805fail2:
806	EFSYS_PROBE(fail2);
807fail1:
808	EFSYS_PROBE1(fail1, efx_rc_t, rc);
809
810	return (rc);
811}
812
813	__checkReturn		efx_rc_t
814efx_mcdi_nvram_update_finish(
815	__in			efx_nic_t *enp,
816	__in			uint32_t partn,
817	__in			boolean_t reboot)
818{
819	efx_mcdi_req_t req;
820	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
821			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
822	efx_rc_t rc;
823
824	(void) memset(payload, 0, sizeof (payload));
825	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
826	req.emr_in_buf = payload;
827	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
828	req.emr_out_buf = payload;
829	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
830
831	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
832	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
833
834	efx_mcdi_execute(enp, &req);
835
836	if (req.emr_rc != 0) {
837		rc = req.emr_rc;
838		goto fail1;
839	}
840
841	return (0);
842
843fail1:
844	EFSYS_PROBE1(fail1, efx_rc_t, rc);
845
846	return (rc);
847}
848
849#if EFSYS_OPT_DIAG
850
851	__checkReturn		efx_rc_t
852efx_mcdi_nvram_test(
853	__in			efx_nic_t *enp,
854	__in			uint32_t partn)
855{
856	efx_mcdi_req_t req;
857	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
858			    MC_CMD_NVRAM_TEST_OUT_LEN)];
859	int result;
860	efx_rc_t rc;
861
862	(void) memset(payload, 0, sizeof (payload));
863	req.emr_cmd = MC_CMD_NVRAM_TEST;
864	req.emr_in_buf = payload;
865	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
866	req.emr_out_buf = payload;
867	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
868
869	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
870
871	efx_mcdi_execute(enp, &req);
872
873	if (req.emr_rc != 0) {
874		rc = req.emr_rc;
875		goto fail1;
876	}
877
878	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
879		rc = EMSGSIZE;
880		goto fail2;
881	}
882
883	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
884	if (result == MC_CMD_NVRAM_TEST_FAIL) {
885
886		EFSYS_PROBE1(nvram_test_failure, int, partn);
887
888		rc = (EINVAL);
889		goto fail3;
890	}
891
892	return (0);
893
894fail3:
895	EFSYS_PROBE(fail3);
896fail2:
897	EFSYS_PROBE(fail2);
898fail1:
899	EFSYS_PROBE1(fail1, efx_rc_t, rc);
900
901	return (rc);
902}
903
904#endif	/* EFSYS_OPT_DIAG */
905
906
907#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
908