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