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