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