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