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