efx_nvram.c revision 294250
1217309Snwhitehorn/*-
2217309Snwhitehorn * Copyright (c) 2009-2015 Solarflare Communications Inc.
3217309Snwhitehorn * All rights reserved.
4217309Snwhitehorn *
5217309Snwhitehorn * Redistribution and use in source and binary forms, with or without
6217309Snwhitehorn * modification, are permitted provided that the following conditions are met:
7217309Snwhitehorn *
8217309Snwhitehorn * 1. Redistributions of source code must retain the above copyright notice,
9217309Snwhitehorn *    this list of conditions and the following disclaimer.
10217309Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright notice,
11217309Snwhitehorn *    this list of conditions and the following disclaimer in the documentation
12217309Snwhitehorn *    and/or other materials provided with the distribution.
13217309Snwhitehorn *
14217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15217309Snwhitehorn * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16217309Snwhitehorn * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17217309Snwhitehorn * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18217309Snwhitehorn * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19217309Snwhitehorn * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20217309Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21217309Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22217309Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23217309Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24217309Snwhitehorn * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25217309Snwhitehorn *
26217309Snwhitehorn * The views and conclusions contained in the software and documentation are
27217309Snwhitehorn * those of the authors and should not be interpreted as representing official
28217309Snwhitehorn * policies, either expressed or implied, of the FreeBSD Project.
29217309Snwhitehorn */
30217309Snwhitehorn
31217309Snwhitehorn#include <sys/cdefs.h>
32217309Snwhitehorn__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_nvram.c 294250 2016-01-18 06:14:43Z arybchik $");
33217309Snwhitehorn
34217309Snwhitehorn#include "efx.h"
35217309Snwhitehorn#include "efx_impl.h"
36217309Snwhitehorn
37217309Snwhitehorn#if EFSYS_OPT_NVRAM
38217309Snwhitehorn
39217309Snwhitehorn#if EFSYS_OPT_FALCON
40217309Snwhitehorn
41217309Snwhitehornstatic efx_nvram_ops_t	__efx_nvram_falcon_ops = {
42217309Snwhitehorn#if EFSYS_OPT_DIAG
43217309Snwhitehorn	falcon_nvram_test,		/* envo_test */
44217309Snwhitehorn#endif	/* EFSYS_OPT_DIAG */
45217309Snwhitehorn	falcon_nvram_get_version,	/* envo_get_version */
46217309Snwhitehorn	falcon_nvram_set_version,	/* envo_set_version */
47217309Snwhitehorn	falcon_nvram_type_to_partn,	/* envo_type_to_partn */
48217309Snwhitehorn	falcon_nvram_partn_size,	/* envo_partn_size */
49217309Snwhitehorn	falcon_nvram_partn_rw_start,	/* envo_partn_rw_start */
50217309Snwhitehorn	falcon_nvram_partn_read,	/* envo_partn_read */
51217309Snwhitehorn	falcon_nvram_partn_erase,	/* envo_partn_erase */
52217309Snwhitehorn	falcon_nvram_partn_write,	/* envo_partn_write */
53217309Snwhitehorn	falcon_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
54217309Snwhitehorn};
55217309Snwhitehorn
56217309Snwhitehorn#endif	/* EFSYS_OPT_FALCON */
57217309Snwhitehorn
58217309Snwhitehorn#if EFSYS_OPT_SIENA
59217309Snwhitehorn
60217309Snwhitehornstatic efx_nvram_ops_t	__efx_nvram_siena_ops = {
61217309Snwhitehorn#if EFSYS_OPT_DIAG
62217309Snwhitehorn	siena_nvram_test,		/* envo_test */
63217309Snwhitehorn#endif	/* EFSYS_OPT_DIAG */
64217309Snwhitehorn	siena_nvram_get_version,	/* envo_get_version */
65217309Snwhitehorn	siena_nvram_set_version,	/* envo_set_version */
66217309Snwhitehorn	siena_nvram_type_to_partn,	/* envo_type_to_partn */
67217309Snwhitehorn	siena_nvram_partn_size,		/* envo_partn_size */
68217309Snwhitehorn	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
69217309Snwhitehorn	siena_nvram_partn_read,		/* envo_partn_read */
70217309Snwhitehorn	siena_nvram_partn_erase,	/* envo_partn_erase */
71217309Snwhitehorn	siena_nvram_partn_write,	/* envo_partn_write */
72217309Snwhitehorn	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
73217309Snwhitehorn};
74217309Snwhitehorn
75217309Snwhitehorn#endif	/* EFSYS_OPT_SIENA */
76217309Snwhitehorn
77217309Snwhitehorn#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
78217309Snwhitehorn
79217309Snwhitehornstatic efx_nvram_ops_t	__efx_nvram_ef10_ops = {
80217309Snwhitehorn#if EFSYS_OPT_DIAG
81217309Snwhitehorn	ef10_nvram_test,		/* envo_test */
82217309Snwhitehorn#endif	/* EFSYS_OPT_DIAG */
83217309Snwhitehorn	ef10_nvram_get_version,		/* envo_get_version */
84217309Snwhitehorn	ef10_nvram_set_version,		/* envo_set_version */
85217309Snwhitehorn	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
86217309Snwhitehorn	ef10_nvram_partn_size,		/* envo_partn_size */
87217309Snwhitehorn	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
88217309Snwhitehorn	ef10_nvram_partn_read,		/* envo_partn_read */
89217309Snwhitehorn	ef10_nvram_partn_erase,		/* envo_partn_erase */
90217309Snwhitehorn	ef10_nvram_partn_write,		/* envo_partn_write */
91217309Snwhitehorn	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
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	uint32_t partn;
388
389	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
390	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
391
392	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
393	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
394
395	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
396
397	if (envop->envo_type_to_partn(enp, type, &partn) == 0)
398		envop->envo_partn_rw_finish(enp, partn);
399
400	enp->en_nvram_locked = EFX_NVRAM_INVALID;
401}
402
403	__checkReturn		efx_rc_t
404efx_nvram_set_version(
405	__in			efx_nic_t *enp,
406	__in			efx_nvram_type_t type,
407	__in_ecount(4)		uint16_t version[4])
408{
409	efx_nvram_ops_t *envop = enp->en_envop;
410	efx_rc_t rc;
411
412	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
415
416	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
417
418	/*
419	 * The Siena implementation of envo_set_version() will attempt to
420	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
421	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
422	 */
423	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
424
425	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
426		goto fail1;
427
428	return (0);
429
430fail1:
431	EFSYS_PROBE1(fail1, efx_rc_t, rc);
432
433	return (rc);
434}
435
436void
437efx_nvram_fini(
438	__in		efx_nic_t *enp)
439{
440	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
441	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
442	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
443
444	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
445
446	enp->en_envop = NULL;
447	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
448}
449
450#endif	/* EFSYS_OPT_NVRAM */
451
452#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
453
454/*
455 * Internal MCDI request handling
456 */
457
458	__checkReturn		efx_rc_t
459efx_mcdi_nvram_partitions(
460	__in			efx_nic_t *enp,
461	__out_bcount(size)	caddr_t data,
462	__in			size_t size,
463	__out			unsigned int *npartnp)
464{
465	efx_mcdi_req_t req;
466	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
467			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
468	unsigned int npartn;
469	efx_rc_t rc;
470
471	(void) memset(payload, 0, sizeof (payload));
472	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
473	req.emr_in_buf = payload;
474	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
475	req.emr_out_buf = payload;
476	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
477
478	efx_mcdi_execute(enp, &req);
479
480	if (req.emr_rc != 0) {
481		rc = req.emr_rc;
482		goto fail1;
483	}
484
485	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
486		rc = EMSGSIZE;
487		goto fail2;
488	}
489	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
490
491	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
492		rc = ENOENT;
493		goto fail3;
494	}
495
496	if (size < npartn * sizeof (uint32_t)) {
497		rc = ENOSPC;
498		goto fail3;
499	}
500
501	*npartnp = npartn;
502
503	memcpy(data,
504	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
505	    (npartn * sizeof (uint32_t)));
506
507	return (0);
508
509fail3:
510	EFSYS_PROBE(fail3);
511fail2:
512	EFSYS_PROBE(fail2);
513fail1:
514	EFSYS_PROBE1(fail1, efx_rc_t, rc);
515
516	return (rc);
517}
518
519	__checkReturn		efx_rc_t
520efx_mcdi_nvram_metadata(
521	__in			efx_nic_t *enp,
522	__in			uint32_t partn,
523	__out			uint32_t *subtypep,
524	__out_ecount(4)		uint16_t version[4],
525	__out_bcount_opt(size)	char *descp,
526	__in			size_t size)
527{
528	efx_mcdi_req_t req;
529	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
530			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
531	efx_rc_t rc;
532
533	(void) memset(payload, 0, sizeof (payload));
534	req.emr_cmd = MC_CMD_NVRAM_METADATA;
535	req.emr_in_buf = payload;
536	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
537	req.emr_out_buf = payload;
538	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
539
540	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
541
542	efx_mcdi_execute(enp, &req);
543
544	if (req.emr_rc != 0) {
545		rc = req.emr_rc;
546		goto fail1;
547	}
548
549	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
550		rc = EMSGSIZE;
551		goto fail2;
552	}
553
554	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
555		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
556		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
557	} else {
558		*subtypep = 0;
559	}
560
561	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
562		NVRAM_METADATA_OUT_VERSION_VALID)) {
563		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
564		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
565		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
566		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
567	} else {
568		version[0] = version[1] = version[2] = version[3] = 0;
569	}
570
571	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
572		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
573		/* Return optional descrition string */
574		if ((descp != NULL) && (size > 0)) {
575			size_t desclen;
576
577			descp[0] = '\0';
578			desclen = (req.emr_out_length_used
579			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
580
581			EFSYS_ASSERT3U(desclen, <=,
582			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
583
584			if (size < desclen) {
585				rc = ENOSPC;
586				goto fail3;
587			}
588
589			memcpy(descp, MCDI_OUT2(req, char,
590				NVRAM_METADATA_OUT_DESCRIPTION),
591			    desclen);
592
593			/* Ensure string is NUL terminated */
594			descp[desclen] = '\0';
595		}
596	}
597
598	return (0);
599
600fail3:
601	EFSYS_PROBE(fail3);
602fail2:
603	EFSYS_PROBE(fail2);
604fail1:
605	EFSYS_PROBE1(fail1, efx_rc_t, rc);
606
607	return (rc);
608}
609
610	__checkReturn		efx_rc_t
611efx_mcdi_nvram_info(
612	__in			efx_nic_t *enp,
613	__in			uint32_t partn,
614	__out_opt		size_t *sizep,
615	__out_opt		uint32_t *addressp,
616	__out_opt		uint32_t *erase_sizep,
617	__out_opt		uint32_t *write_sizep)
618{
619	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
620			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
621	efx_mcdi_req_t req;
622	efx_rc_t rc;
623
624	(void) memset(payload, 0, sizeof (payload));
625	req.emr_cmd = MC_CMD_NVRAM_INFO;
626	req.emr_in_buf = payload;
627	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
628	req.emr_out_buf = payload;
629	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
630
631	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
632
633	efx_mcdi_execute_quiet(enp, &req);
634
635	if (req.emr_rc != 0) {
636		rc = req.emr_rc;
637		goto fail1;
638	}
639
640	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
641		rc = EMSGSIZE;
642		goto fail2;
643	}
644
645	if (sizep)
646		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
647
648	if (addressp)
649		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
650
651	if (erase_sizep)
652		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
653
654	if (write_sizep) {
655		*write_sizep =
656			(req.emr_out_length_used <
657			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
658			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
659	}
660
661	return (0);
662
663fail2:
664	EFSYS_PROBE(fail2);
665fail1:
666	EFSYS_PROBE1(fail1, efx_rc_t, rc);
667
668	return (rc);
669}
670
671	__checkReturn		efx_rc_t
672efx_mcdi_nvram_update_start(
673	__in			efx_nic_t *enp,
674	__in			uint32_t partn)
675{
676	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
677			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
678	efx_mcdi_req_t req;
679	efx_rc_t rc;
680
681	(void) memset(payload, 0, sizeof (payload));
682	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
683	req.emr_in_buf = payload;
684	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
685	req.emr_out_buf = payload;
686	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
687
688	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
689
690	efx_mcdi_execute(enp, &req);
691
692	if (req.emr_rc != 0) {
693		rc = req.emr_rc;
694		goto fail1;
695	}
696
697	return (0);
698
699fail1:
700	EFSYS_PROBE1(fail1, efx_rc_t, rc);
701
702	return (rc);
703}
704
705	__checkReturn		efx_rc_t
706efx_mcdi_nvram_read(
707	__in			efx_nic_t *enp,
708	__in			uint32_t partn,
709	__in			uint32_t offset,
710	__out_bcount(size)	caddr_t data,
711	__in			size_t size)
712{
713	efx_mcdi_req_t req;
714	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
715			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
716	efx_rc_t rc;
717
718	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
719		rc = EINVAL;
720		goto fail1;
721	}
722
723	(void) memset(payload, 0, sizeof (payload));
724	req.emr_cmd = MC_CMD_NVRAM_READ;
725	req.emr_in_buf = payload;
726	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
727	req.emr_out_buf = payload;
728	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
729
730	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
731	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
732	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
733
734	efx_mcdi_execute(enp, &req);
735
736	if (req.emr_rc != 0) {
737		rc = req.emr_rc;
738		goto fail1;
739	}
740
741	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
742		rc = EMSGSIZE;
743		goto fail2;
744	}
745
746	memcpy(data,
747	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
748	    size);
749
750	return (0);
751
752fail2:
753	EFSYS_PROBE(fail2);
754fail1:
755	EFSYS_PROBE1(fail1, efx_rc_t, rc);
756
757	return (rc);
758}
759
760	__checkReturn		efx_rc_t
761efx_mcdi_nvram_erase(
762	__in			efx_nic_t *enp,
763	__in			uint32_t partn,
764	__in			uint32_t offset,
765	__in			size_t size)
766{
767	efx_mcdi_req_t req;
768	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
769			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
770	efx_rc_t rc;
771
772	(void) memset(payload, 0, sizeof (payload));
773	req.emr_cmd = MC_CMD_NVRAM_ERASE;
774	req.emr_in_buf = payload;
775	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
776	req.emr_out_buf = payload;
777	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
778
779	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
780	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
781	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
782
783	efx_mcdi_execute(enp, &req);
784
785	if (req.emr_rc != 0) {
786		rc = req.emr_rc;
787		goto fail1;
788	}
789
790	return (0);
791
792fail1:
793	EFSYS_PROBE1(fail1, efx_rc_t, rc);
794
795	return (rc);
796}
797
798/*
799 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
800 * Sienna and EF10 based boards.  However EF10 based boards support the use
801 * of this command with payloads up to the maximum MCDI V2 payload length.
802 */
803	__checkReturn		efx_rc_t
804efx_mcdi_nvram_write(
805	__in			efx_nic_t *enp,
806	__in			uint32_t partn,
807	__in			uint32_t offset,
808	__out_bcount(size)	caddr_t data,
809	__in			size_t size)
810{
811	efx_mcdi_req_t req;
812	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
813			    MCDI_CTL_SDU_LEN_MAX_V2)];
814	efx_rc_t rc;
815	size_t max_data_size;
816
817	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
818	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
819	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
820	EFSYS_ASSERT3U(max_data_size, <,
821		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
822
823	if (size > max_data_size) {
824		rc = EINVAL;
825		goto fail1;
826	}
827
828	(void) memset(payload, 0, sizeof (payload));
829	req.emr_cmd = MC_CMD_NVRAM_WRITE;
830	req.emr_in_buf = payload;
831	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
832	req.emr_out_buf = payload;
833	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
834
835	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
836	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
837	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
838
839	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
840	    data, size);
841
842	efx_mcdi_execute(enp, &req);
843
844	if (req.emr_rc != 0) {
845		rc = req.emr_rc;
846		goto fail2;
847	}
848
849	return (0);
850
851fail2:
852	EFSYS_PROBE(fail2);
853fail1:
854	EFSYS_PROBE1(fail1, efx_rc_t, rc);
855
856	return (rc);
857}
858
859	__checkReturn		efx_rc_t
860efx_mcdi_nvram_update_finish(
861	__in			efx_nic_t *enp,
862	__in			uint32_t partn,
863	__in			boolean_t reboot)
864{
865	efx_mcdi_req_t req;
866	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
867			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
868	efx_rc_t rc;
869
870	(void) memset(payload, 0, sizeof (payload));
871	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
872	req.emr_in_buf = payload;
873	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
874	req.emr_out_buf = payload;
875	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
876
877	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
878	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
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	return (0);
888
889fail1:
890	EFSYS_PROBE1(fail1, efx_rc_t, rc);
891
892	return (rc);
893}
894
895#if EFSYS_OPT_DIAG
896
897	__checkReturn		efx_rc_t
898efx_mcdi_nvram_test(
899	__in			efx_nic_t *enp,
900	__in			uint32_t partn)
901{
902	efx_mcdi_req_t req;
903	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
904			    MC_CMD_NVRAM_TEST_OUT_LEN)];
905	int result;
906	efx_rc_t rc;
907
908	(void) memset(payload, 0, sizeof (payload));
909	req.emr_cmd = MC_CMD_NVRAM_TEST;
910	req.emr_in_buf = payload;
911	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
912	req.emr_out_buf = payload;
913	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
914
915	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
916
917	efx_mcdi_execute(enp, &req);
918
919	if (req.emr_rc != 0) {
920		rc = req.emr_rc;
921		goto fail1;
922	}
923
924	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
925		rc = EMSGSIZE;
926		goto fail2;
927	}
928
929	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
930	if (result == MC_CMD_NVRAM_TEST_FAIL) {
931
932		EFSYS_PROBE1(nvram_test_failure, int, partn);
933
934		rc = (EINVAL);
935		goto fail3;
936	}
937
938	return (0);
939
940fail3:
941	EFSYS_PROBE(fail3);
942fail2:
943	EFSYS_PROBE(fail2);
944fail1:
945	EFSYS_PROBE1(fail1, efx_rc_t, rc);
946
947	return (rc);
948}
949
950#endif	/* EFSYS_OPT_DIAG */
951
952
953#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
954