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