efx_nvram.c revision 294201
1273562Smarcel/*-
2287111Smarcel * Copyright (c) 2009-2015 Solarflare Communications Inc.
3287111Smarcel * All rights reserved.
4298083Sphil *
5298083Sphil * Redistribution and use in source and binary forms, with or without
6298083Sphil * modification, are permitted provided that the following conditions are met:
7298083Sphil *
8298083Sphil * 1. Redistributions of source code must retain the above copyright notice,
9298083Sphil *    this list of conditions and the following disclaimer.
10298083Sphil * 2. Redistributions in binary form must reproduce the above copyright notice,
11298083Sphil *    this list of conditions and the following disclaimer in the documentation
12277353Smarcel *    and/or other materials provided with the distribution.
13277353Smarcel *
14277353Smarcel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15273562Smarcel * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16273562Smarcel * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17273562Smarcel * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18273562Smarcel * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19273562Smarcel * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20273562Smarcel * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21277353Smarcel * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22273562Smarcel * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23273562Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24273562Smarcel * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25273562Smarcel *
26273562Smarcel * The views and conclusions contained in the software and documentation are
27273562Smarcel * those of the authors and should not be interpreted as representing official
28277353Smarcel * policies, either expressed or implied, of the FreeBSD Project.
29273562Smarcel */
30273562Smarcel
31273562Smarcel#include <sys/cdefs.h>
32273562Smarcel__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_nvram.c 294201 2016-01-17 05:12:37Z arybchik $");
33273562Smarcel
34273562Smarcel#include "efx.h"
35277353Smarcel#include "efx_impl.h"
36273562Smarcel
37273562Smarcel#if EFSYS_OPT_NVRAM
38273562Smarcel
39273562Smarcel#if EFSYS_OPT_FALCON
40273562Smarcel
41273562Smarcelstatic efx_nvram_ops_t	__efx_nvram_falcon_ops = {
42277353Smarcel#if EFSYS_OPT_DIAG
43273562Smarcel	falcon_nvram_test,		/* envo_test */
44273562Smarcel#endif	/* EFSYS_OPT_DIAG */
45273562Smarcel	falcon_nvram_get_version,	/* envo_get_version */
46273562Smarcel	falcon_nvram_write_chunk,	/* envo_write_chunk */
47273562Smarcel	falcon_nvram_rw_finish,		/* envo_rw_finish */
48273562Smarcel	falcon_nvram_set_version,	/* envo_set_version */
49287111Smarcel	falcon_nvram_type_to_partn,	/* envo_type_to_partn */
50273562Smarcel	falcon_nvram_partn_size,	/* envo_partn_size */
51273562Smarcel	falcon_nvram_partn_rw_start,	/* envo_partn_rw_start */
52273562Smarcel	falcon_nvram_partn_read,	/* envo_partn_read */
53273562Smarcel	falcon_nvram_partn_erase,	/* envo_partn_erase */
54273562Smarcel};
55273562Smarcel
56273562Smarcel#endif	/* EFSYS_OPT_FALCON */
57273562Smarcel
58273562Smarcel#if EFSYS_OPT_SIENA
59273562Smarcel
60273562Smarcelstatic efx_nvram_ops_t	__efx_nvram_siena_ops = {
61273562Smarcel#if EFSYS_OPT_DIAG
62273562Smarcel	siena_nvram_test,		/* envo_test */
63273562Smarcel#endif	/* EFSYS_OPT_DIAG */
64273562Smarcel	siena_nvram_get_version,	/* envo_get_version */
65273562Smarcel	siena_nvram_write_chunk,	/* envo_write_chunk */
66273562Smarcel	siena_nvram_rw_finish,		/* envo_rw_finish */
67273562Smarcel	siena_nvram_set_version,	/* envo_set_version */
68273562Smarcel	siena_nvram_type_to_partn,	/* envo_type_to_partn */
69273562Smarcel	siena_nvram_partn_size,		/* envo_partn_size */
70273562Smarcel	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
71273562Smarcel	siena_nvram_partn_read,		/* envo_partn_read */
72273562Smarcel	siena_nvram_partn_erase,	/* envo_partn_erase */
73273562Smarcel};
74273562Smarcel
75273562Smarcel#endif	/* EFSYS_OPT_SIENA */
76273562Smarcel
77273562Smarcel#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
78273562Smarcel
79273562Smarcelstatic efx_nvram_ops_t	__efx_nvram_ef10_ops = {
80273562Smarcel#if EFSYS_OPT_DIAG
81273562Smarcel	ef10_nvram_test,		/* envo_test */
82273562Smarcel#endif	/* EFSYS_OPT_DIAG */
83273562Smarcel	ef10_nvram_get_version,		/* envo_get_version */
84273562Smarcel	ef10_nvram_write_chunk,		/* envo_write_chunk */
85287111Smarcel	ef10_nvram_rw_finish,		/* envo_rw_finish */
86287111Smarcel	ef10_nvram_set_version,		/* envo_set_version */
87273562Smarcel	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
88273562Smarcel	ef10_nvram_partn_size,		/* envo_partn_size */
89273562Smarcel	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
90273562Smarcel	ef10_nvram_partn_read,		/* envo_partn_read */
91273562Smarcel	ef10_nvram_partn_erase,		/* envo_partn_erase */
92273562Smarcel};
93273562Smarcel
94287111Smarcel#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
95287111Smarcel
96277353Smarcel	__checkReturn	efx_rc_t
97277353Smarcelefx_nvram_init(
98277353Smarcel	__in		efx_nic_t *enp)
99277353Smarcel{
100277353Smarcel	efx_nvram_ops_t *envop;
101287111Smarcel	efx_rc_t rc;
102277353Smarcel
103277353Smarcel	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
104298067Sphil	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
105298067Sphil	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
106298067Sphil
107298067Sphil	switch (enp->en_family) {
108298067Sphil#if EFSYS_OPT_FALCON
109298067Sphil	case EFX_FAMILY_FALCON:
110298067Sphil		envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops;
111298067Sphil		break;
112298067Sphil#endif	/* EFSYS_OPT_FALCON */
113298067Sphil
114273562Smarcel#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	efx_rc_t rc;
355
356	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
357	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
358
359	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
360	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
361
362	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
363
364	if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
365		goto fail1;
366
367	return (0);
368
369fail1:
370	EFSYS_PROBE1(fail1, efx_rc_t, rc);
371
372	return (rc);
373}
374
375				void
376efx_nvram_rw_finish(
377	__in			efx_nic_t *enp,
378	__in			efx_nvram_type_t type)
379{
380	efx_nvram_ops_t *envop = enp->en_envop;
381
382	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
383	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
384
385	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
386	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
387
388	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
389
390	envop->envo_rw_finish(enp, type);
391
392	enp->en_nvram_locked = EFX_NVRAM_INVALID;
393}
394
395	__checkReturn		efx_rc_t
396efx_nvram_set_version(
397	__in			efx_nic_t *enp,
398	__in			efx_nvram_type_t type,
399	__in_ecount(4)		uint16_t version[4])
400{
401	efx_nvram_ops_t *envop = enp->en_envop;
402	efx_rc_t rc;
403
404	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
405	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
406	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
407
408	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
409
410	/*
411	 * The Siena implementation of envo_set_version() will attempt to
412	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
413	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
414	 */
415	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
416
417	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
418		goto fail1;
419
420	return (0);
421
422fail1:
423	EFSYS_PROBE1(fail1, efx_rc_t, rc);
424
425	return (rc);
426}
427
428void
429efx_nvram_fini(
430	__in		efx_nic_t *enp)
431{
432	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
433	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
434	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
435
436	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
437
438	enp->en_envop = NULL;
439	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
440}
441
442#endif	/* EFSYS_OPT_NVRAM */
443
444#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
445
446/*
447 * Internal MCDI request handling
448 */
449
450	__checkReturn		efx_rc_t
451efx_mcdi_nvram_partitions(
452	__in			efx_nic_t *enp,
453	__out_bcount(size)	caddr_t data,
454	__in			size_t size,
455	__out			unsigned int *npartnp)
456{
457	efx_mcdi_req_t req;
458	uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
459			    MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
460	unsigned int npartn;
461	efx_rc_t rc;
462
463	(void) memset(payload, 0, sizeof (payload));
464	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
465	req.emr_in_buf = payload;
466	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
467	req.emr_out_buf = payload;
468	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
469
470	efx_mcdi_execute(enp, &req);
471
472	if (req.emr_rc != 0) {
473		rc = req.emr_rc;
474		goto fail1;
475	}
476
477	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
478		rc = EMSGSIZE;
479		goto fail2;
480	}
481	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
482
483	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
484		rc = ENOENT;
485		goto fail3;
486	}
487
488	if (size < npartn * sizeof (uint32_t)) {
489		rc = ENOSPC;
490		goto fail3;
491	}
492
493	*npartnp = npartn;
494
495	memcpy(data,
496	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
497	    (npartn * sizeof (uint32_t)));
498
499	return (0);
500
501fail3:
502	EFSYS_PROBE(fail3);
503fail2:
504	EFSYS_PROBE(fail2);
505fail1:
506	EFSYS_PROBE1(fail1, efx_rc_t, rc);
507
508	return (rc);
509}
510
511	__checkReturn		efx_rc_t
512efx_mcdi_nvram_metadata(
513	__in			efx_nic_t *enp,
514	__in			uint32_t partn,
515	__out			uint32_t *subtypep,
516	__out_ecount(4)		uint16_t version[4],
517	__out_bcount_opt(size)	char *descp,
518	__in			size_t size)
519{
520	efx_mcdi_req_t req;
521	uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
522			    MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
523	efx_rc_t rc;
524
525	(void) memset(payload, 0, sizeof (payload));
526	req.emr_cmd = MC_CMD_NVRAM_METADATA;
527	req.emr_in_buf = payload;
528	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
529	req.emr_out_buf = payload;
530	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
531
532	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
533
534	efx_mcdi_execute(enp, &req);
535
536	if (req.emr_rc != 0) {
537		rc = req.emr_rc;
538		goto fail1;
539	}
540
541	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
542		rc = EMSGSIZE;
543		goto fail2;
544	}
545
546	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
547		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
548		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
549	} else {
550		*subtypep = 0;
551	}
552
553	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
554		NVRAM_METADATA_OUT_VERSION_VALID)) {
555		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
556		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
557		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
558		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
559	} else {
560		version[0] = version[1] = version[2] = version[3] = 0;
561	}
562
563	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
564		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
565		/* Return optional descrition string */
566		if ((descp != NULL) && (size > 0)) {
567			size_t desclen;
568
569			descp[0] = '\0';
570			desclen = (req.emr_out_length_used
571			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
572
573			EFSYS_ASSERT3U(desclen, <=,
574			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
575
576			if (size < desclen) {
577				rc = ENOSPC;
578				goto fail3;
579			}
580
581			memcpy(descp, MCDI_OUT2(req, char,
582				NVRAM_METADATA_OUT_DESCRIPTION),
583			    desclen);
584
585			/* Ensure string is NUL terminated */
586			descp[desclen] = '\0';
587		}
588	}
589
590	return (0);
591
592fail3:
593	EFSYS_PROBE(fail3);
594fail2:
595	EFSYS_PROBE(fail2);
596fail1:
597	EFSYS_PROBE1(fail1, efx_rc_t, rc);
598
599	return (rc);
600}
601
602	__checkReturn		efx_rc_t
603efx_mcdi_nvram_info(
604	__in			efx_nic_t *enp,
605	__in			uint32_t partn,
606	__out_opt		size_t *sizep,
607	__out_opt		uint32_t *addressp,
608	__out_opt		uint32_t *erase_sizep,
609	__out_opt		uint32_t *write_sizep)
610{
611	uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
612			    MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
613	efx_mcdi_req_t req;
614	efx_rc_t rc;
615
616	(void) memset(payload, 0, sizeof (payload));
617	req.emr_cmd = MC_CMD_NVRAM_INFO;
618	req.emr_in_buf = payload;
619	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
620	req.emr_out_buf = payload;
621	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
622
623	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
624
625	efx_mcdi_execute_quiet(enp, &req);
626
627	if (req.emr_rc != 0) {
628		rc = req.emr_rc;
629		goto fail1;
630	}
631
632	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
633		rc = EMSGSIZE;
634		goto fail2;
635	}
636
637	if (sizep)
638		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
639
640	if (addressp)
641		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
642
643	if (erase_sizep)
644		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
645
646	if (write_sizep) {
647		*write_sizep =
648			(req.emr_out_length_used <
649			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
650			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
651	}
652
653	return (0);
654
655fail2:
656	EFSYS_PROBE(fail2);
657fail1:
658	EFSYS_PROBE1(fail1, efx_rc_t, rc);
659
660	return (rc);
661}
662
663	__checkReturn		efx_rc_t
664efx_mcdi_nvram_update_start(
665	__in			efx_nic_t *enp,
666	__in			uint32_t partn)
667{
668	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
669			    MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
670	efx_mcdi_req_t req;
671	efx_rc_t rc;
672
673	(void) memset(payload, 0, sizeof (payload));
674	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
675	req.emr_in_buf = payload;
676	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
677	req.emr_out_buf = payload;
678	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
679
680	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
681
682	efx_mcdi_execute(enp, &req);
683
684	if (req.emr_rc != 0) {
685		rc = req.emr_rc;
686		goto fail1;
687	}
688
689	return (0);
690
691fail1:
692	EFSYS_PROBE1(fail1, efx_rc_t, rc);
693
694	return (rc);
695}
696
697	__checkReturn		efx_rc_t
698efx_mcdi_nvram_read(
699	__in			efx_nic_t *enp,
700	__in			uint32_t partn,
701	__in			uint32_t offset,
702	__out_bcount(size)	caddr_t data,
703	__in			size_t size)
704{
705	efx_mcdi_req_t req;
706	uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
707			    MC_CMD_NVRAM_READ_OUT_LENMAX)];
708	efx_rc_t rc;
709
710	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
711		rc = EINVAL;
712		goto fail1;
713	}
714
715	(void) memset(payload, 0, sizeof (payload));
716	req.emr_cmd = MC_CMD_NVRAM_READ;
717	req.emr_in_buf = payload;
718	req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
719	req.emr_out_buf = payload;
720	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
721
722	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
723	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
724	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
725
726	efx_mcdi_execute(enp, &req);
727
728	if (req.emr_rc != 0) {
729		rc = req.emr_rc;
730		goto fail1;
731	}
732
733	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
734		rc = EMSGSIZE;
735		goto fail2;
736	}
737
738	memcpy(data,
739	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
740	    size);
741
742	return (0);
743
744fail2:
745	EFSYS_PROBE(fail2);
746fail1:
747	EFSYS_PROBE1(fail1, efx_rc_t, rc);
748
749	return (rc);
750}
751
752	__checkReturn		efx_rc_t
753efx_mcdi_nvram_erase(
754	__in			efx_nic_t *enp,
755	__in			uint32_t partn,
756	__in			uint32_t offset,
757	__in			size_t size)
758{
759	efx_mcdi_req_t req;
760	uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
761			    MC_CMD_NVRAM_ERASE_OUT_LEN)];
762	efx_rc_t rc;
763
764	(void) memset(payload, 0, sizeof (payload));
765	req.emr_cmd = MC_CMD_NVRAM_ERASE;
766	req.emr_in_buf = payload;
767	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
768	req.emr_out_buf = payload;
769	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
770
771	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
772	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
773	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
774
775	efx_mcdi_execute(enp, &req);
776
777	if (req.emr_rc != 0) {
778		rc = req.emr_rc;
779		goto fail1;
780	}
781
782	return (0);
783
784fail1:
785	EFSYS_PROBE1(fail1, efx_rc_t, rc);
786
787	return (rc);
788}
789
790/*
791 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
792 * Sienna and EF10 based boards.  However EF10 based boards support the use
793 * of this command with payloads up to the maximum MCDI V2 payload length.
794 */
795	__checkReturn		efx_rc_t
796efx_mcdi_nvram_write(
797	__in			efx_nic_t *enp,
798	__in			uint32_t partn,
799	__in			uint32_t offset,
800	__out_bcount(size)	caddr_t data,
801	__in			size_t size)
802{
803	efx_mcdi_req_t req;
804	uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
805			    MCDI_CTL_SDU_LEN_MAX_V2)];
806	efx_rc_t rc;
807	size_t max_data_size;
808
809	max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
810	    - MC_CMD_NVRAM_WRITE_IN_LEN(0);
811	EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
812	EFSYS_ASSERT3U(max_data_size, <,
813		    enp->en_nic_cfg.enc_mcdi_max_payload_length);
814
815	if (size > max_data_size) {
816		rc = EINVAL;
817		goto fail1;
818	}
819
820	(void) memset(payload, 0, sizeof (payload));
821	req.emr_cmd = MC_CMD_NVRAM_WRITE;
822	req.emr_in_buf = payload;
823	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
824	req.emr_out_buf = payload;
825	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
826
827	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
828	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
829	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
830
831	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
832	    data, size);
833
834	efx_mcdi_execute(enp, &req);
835
836	if (req.emr_rc != 0) {
837		rc = req.emr_rc;
838		goto fail2;
839	}
840
841	return (0);
842
843fail2:
844	EFSYS_PROBE(fail2);
845fail1:
846	EFSYS_PROBE1(fail1, efx_rc_t, rc);
847
848	return (rc);
849}
850
851	__checkReturn		efx_rc_t
852efx_mcdi_nvram_update_finish(
853	__in			efx_nic_t *enp,
854	__in			uint32_t partn,
855	__in			boolean_t reboot)
856{
857	efx_mcdi_req_t req;
858	uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
859			    MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
860	efx_rc_t rc;
861
862	(void) memset(payload, 0, sizeof (payload));
863	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
864	req.emr_in_buf = payload;
865	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
866	req.emr_out_buf = payload;
867	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
868
869	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
870	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
871
872	efx_mcdi_execute(enp, &req);
873
874	if (req.emr_rc != 0) {
875		rc = req.emr_rc;
876		goto fail1;
877	}
878
879	return (0);
880
881fail1:
882	EFSYS_PROBE1(fail1, efx_rc_t, rc);
883
884	return (rc);
885}
886
887#if EFSYS_OPT_DIAG
888
889	__checkReturn		efx_rc_t
890efx_mcdi_nvram_test(
891	__in			efx_nic_t *enp,
892	__in			uint32_t partn)
893{
894	efx_mcdi_req_t req;
895	uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
896			    MC_CMD_NVRAM_TEST_OUT_LEN)];
897	int result;
898	efx_rc_t rc;
899
900	(void) memset(payload, 0, sizeof (payload));
901	req.emr_cmd = MC_CMD_NVRAM_TEST;
902	req.emr_in_buf = payload;
903	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
904	req.emr_out_buf = payload;
905	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
906
907	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
908
909	efx_mcdi_execute(enp, &req);
910
911	if (req.emr_rc != 0) {
912		rc = req.emr_rc;
913		goto fail1;
914	}
915
916	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
917		rc = EMSGSIZE;
918		goto fail2;
919	}
920
921	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
922	if (result == MC_CMD_NVRAM_TEST_FAIL) {
923
924		EFSYS_PROBE1(nvram_test_failure, int, partn);
925
926		rc = (EINVAL);
927		goto fail3;
928	}
929
930	return (0);
931
932fail3:
933	EFSYS_PROBE(fail3);
934fail2:
935	EFSYS_PROBE(fail2);
936fail1:
937	EFSYS_PROBE1(fail1, efx_rc_t, rc);
938
939	return (rc);
940}
941
942#endif	/* EFSYS_OPT_DIAG */
943
944
945#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
946