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