]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/dev/sfxge/common/efx_nvram.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / dev / sfxge / common / efx_nvram.c
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$");
33
34 #include "efx.h"
35 #include "efx_impl.h"
36
37 #if EFSYS_OPT_NVRAM
38
39 #if EFSYS_OPT_FALCON
40
41 static 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 };
55
56 #endif  /* EFSYS_OPT_FALCON */
57
58 #if EFSYS_OPT_SIENA
59
60 static 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_type_to_partn,      /* envo_type_to_partn */
65         siena_nvram_partn_size,         /* envo_partn_size */
66         siena_nvram_partn_rw_start,     /* envo_partn_rw_start */
67         siena_nvram_partn_read,         /* envo_partn_read */
68         siena_nvram_partn_erase,        /* envo_partn_erase */
69         siena_nvram_partn_write,        /* envo_partn_write */
70         siena_nvram_partn_rw_finish,    /* envo_partn_rw_finish */
71         siena_nvram_partn_get_version,  /* envo_partn_get_version */
72         siena_nvram_partn_set_version,  /* envo_partn_set_version */
73 };
74
75 #endif  /* EFSYS_OPT_SIENA */
76
77 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
78
79 static 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_type_to_partn,       /* envo_type_to_partn */
84         ef10_nvram_partn_size,          /* envo_partn_size */
85         ef10_nvram_partn_rw_start,      /* envo_partn_rw_start */
86         ef10_nvram_partn_read,          /* envo_partn_read */
87         ef10_nvram_partn_erase,         /* envo_partn_erase */
88         ef10_nvram_partn_write,         /* envo_partn_write */
89         ef10_nvram_partn_rw_finish,     /* envo_partn_rw_finish */
90         ef10_nvram_partn_get_version,   /* envo_partn_get_version */
91         ef10_nvram_partn_set_version,   /* envo_partn_set_version */
92 };
93
94 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
95
96         __checkReturn   efx_rc_t
97 efx_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
143 fail1:
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
152 efx_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
166 fail1:
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
175 efx_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
197 fail2:
198         EFSYS_PROBE(fail2);
199 fail1:
200         EFSYS_PROBE1(fail1, efx_rc_t, rc);
201         *sizep = 0;
202
203         return (rc);
204 }
205
206         __checkReturn           efx_rc_t
207 efx_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
232 fail2:
233         EFSYS_PROBE(fail2);
234 fail1:
235         EFSYS_PROBE1(fail1, efx_rc_t, rc);
236
237         return (rc);
238 }
239
240         __checkReturn           efx_rc_t
241 efx_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
268 fail2:
269         EFSYS_PROBE(fail2);
270 fail1:
271         EFSYS_PROBE1(fail1, efx_rc_t, rc);
272
273         return (rc);
274 }
275
276         __checkReturn           efx_rc_t
277 efx_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
304 fail2:
305         EFSYS_PROBE(fail2);
306 fail1:
307         EFSYS_PROBE1(fail1, efx_rc_t, rc);
308
309         return (rc);
310 }
311
312         __checkReturn           efx_rc_t
313 efx_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
342 fail3:
343         EFSYS_PROBE(fail3);
344 fail2:
345         EFSYS_PROBE(fail2);
346 fail1:
347         EFSYS_PROBE1(fail1, efx_rc_t, rc);
348
349         return (rc);
350 }
351
352         __checkReturn           efx_rc_t
353 efx_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
380 fail2:
381         EFSYS_PROBE(fail2);
382 fail1:
383         EFSYS_PROBE1(fail1, efx_rc_t, rc);
384
385         return (rc);
386 }
387
388                                 void
389 efx_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
411 efx_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         uint32_t partn;
418         efx_rc_t rc;
419
420         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
421         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
422         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
423
424         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
425
426         /*
427          * The Siena implementation of envo_set_version() will attempt to
428          * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
429          * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
430          */
431         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
432
433         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
434                 goto fail1;
435
436         if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
437                 goto fail2;
438
439         return (0);
440
441 fail2:
442         EFSYS_PROBE(fail2);
443 fail1:
444         EFSYS_PROBE1(fail1, efx_rc_t, rc);
445
446         return (rc);
447 }
448
449 void
450 efx_nvram_fini(
451         __in            efx_nic_t *enp)
452 {
453         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
455         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
456
457         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
458
459         enp->en_envop = NULL;
460         enp->en_mod_flags &= ~EFX_MOD_NVRAM;
461 }
462
463 #endif  /* EFSYS_OPT_NVRAM */
464
465 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
466
467 /*
468  * Internal MCDI request handling
469  */
470
471         __checkReturn           efx_rc_t
472 efx_mcdi_nvram_partitions(
473         __in                    efx_nic_t *enp,
474         __out_bcount(size)      caddr_t data,
475         __in                    size_t size,
476         __out                   unsigned int *npartnp)
477 {
478         efx_mcdi_req_t req;
479         uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
480                             MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
481         unsigned int npartn;
482         efx_rc_t rc;
483
484         (void) memset(payload, 0, sizeof (payload));
485         req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
486         req.emr_in_buf = payload;
487         req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
488         req.emr_out_buf = payload;
489         req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
490
491         efx_mcdi_execute(enp, &req);
492
493         if (req.emr_rc != 0) {
494                 rc = req.emr_rc;
495                 goto fail1;
496         }
497
498         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
499                 rc = EMSGSIZE;
500                 goto fail2;
501         }
502         npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
503
504         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
505                 rc = ENOENT;
506                 goto fail3;
507         }
508
509         if (size < npartn * sizeof (uint32_t)) {
510                 rc = ENOSPC;
511                 goto fail3;
512         }
513
514         *npartnp = npartn;
515
516         memcpy(data,
517             MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
518             (npartn * sizeof (uint32_t)));
519
520         return (0);
521
522 fail3:
523         EFSYS_PROBE(fail3);
524 fail2:
525         EFSYS_PROBE(fail2);
526 fail1:
527         EFSYS_PROBE1(fail1, efx_rc_t, rc);
528
529         return (rc);
530 }
531
532         __checkReturn           efx_rc_t
533 efx_mcdi_nvram_metadata(
534         __in                    efx_nic_t *enp,
535         __in                    uint32_t partn,
536         __out                   uint32_t *subtypep,
537         __out_ecount(4)         uint16_t version[4],
538         __out_bcount_opt(size)  char *descp,
539         __in                    size_t size)
540 {
541         efx_mcdi_req_t req;
542         uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
543                             MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
544         efx_rc_t rc;
545
546         (void) memset(payload, 0, sizeof (payload));
547         req.emr_cmd = MC_CMD_NVRAM_METADATA;
548         req.emr_in_buf = payload;
549         req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
550         req.emr_out_buf = payload;
551         req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
552
553         MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
554
555         efx_mcdi_execute(enp, &req);
556
557         if (req.emr_rc != 0) {
558                 rc = req.emr_rc;
559                 goto fail1;
560         }
561
562         if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
563                 rc = EMSGSIZE;
564                 goto fail2;
565         }
566
567         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
568                 NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
569                 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
570         } else {
571                 *subtypep = 0;
572         }
573
574         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
575                 NVRAM_METADATA_OUT_VERSION_VALID)) {
576                 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
577                 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
578                 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
579                 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
580         } else {
581                 version[0] = version[1] = version[2] = version[3] = 0;
582         }
583
584         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
585                 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
586                 /* Return optional descrition string */
587                 if ((descp != NULL) && (size > 0)) {
588                         size_t desclen;
589
590                         descp[0] = '\0';
591                         desclen = (req.emr_out_length_used
592                             - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
593
594                         EFSYS_ASSERT3U(desclen, <=,
595                             MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
596
597                         if (size < desclen) {
598                                 rc = ENOSPC;
599                                 goto fail3;
600                         }
601
602                         memcpy(descp, MCDI_OUT2(req, char,
603                                 NVRAM_METADATA_OUT_DESCRIPTION),
604                             desclen);
605
606                         /* Ensure string is NUL terminated */
607                         descp[desclen] = '\0';
608                 }
609         }
610
611         return (0);
612
613 fail3:
614         EFSYS_PROBE(fail3);
615 fail2:
616         EFSYS_PROBE(fail2);
617 fail1:
618         EFSYS_PROBE1(fail1, efx_rc_t, rc);
619
620         return (rc);
621 }
622
623         __checkReturn           efx_rc_t
624 efx_mcdi_nvram_info(
625         __in                    efx_nic_t *enp,
626         __in                    uint32_t partn,
627         __out_opt               size_t *sizep,
628         __out_opt               uint32_t *addressp,
629         __out_opt               uint32_t *erase_sizep,
630         __out_opt               uint32_t *write_sizep)
631 {
632         uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
633                             MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
634         efx_mcdi_req_t req;
635         efx_rc_t rc;
636
637         (void) memset(payload, 0, sizeof (payload));
638         req.emr_cmd = MC_CMD_NVRAM_INFO;
639         req.emr_in_buf = payload;
640         req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
641         req.emr_out_buf = payload;
642         req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
643
644         MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
645
646         efx_mcdi_execute_quiet(enp, &req);
647
648         if (req.emr_rc != 0) {
649                 rc = req.emr_rc;
650                 goto fail1;
651         }
652
653         if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
654                 rc = EMSGSIZE;
655                 goto fail2;
656         }
657
658         if (sizep)
659                 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
660
661         if (addressp)
662                 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
663
664         if (erase_sizep)
665                 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
666
667         if (write_sizep) {
668                 *write_sizep =
669                         (req.emr_out_length_used <
670                             MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
671                         0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
672         }
673
674         return (0);
675
676 fail2:
677         EFSYS_PROBE(fail2);
678 fail1:
679         EFSYS_PROBE1(fail1, efx_rc_t, rc);
680
681         return (rc);
682 }
683
684         __checkReturn           efx_rc_t
685 efx_mcdi_nvram_update_start(
686         __in                    efx_nic_t *enp,
687         __in                    uint32_t partn)
688 {
689         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
690                             MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
691         efx_mcdi_req_t req;
692         efx_rc_t rc;
693
694         (void) memset(payload, 0, sizeof (payload));
695         req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
696         req.emr_in_buf = payload;
697         req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
698         req.emr_out_buf = payload;
699         req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
700
701         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
702
703         efx_mcdi_execute(enp, &req);
704
705         if (req.emr_rc != 0) {
706                 rc = req.emr_rc;
707                 goto fail1;
708         }
709
710         return (0);
711
712 fail1:
713         EFSYS_PROBE1(fail1, efx_rc_t, rc);
714
715         return (rc);
716 }
717
718         __checkReturn           efx_rc_t
719 efx_mcdi_nvram_read(
720         __in                    efx_nic_t *enp,
721         __in                    uint32_t partn,
722         __in                    uint32_t offset,
723         __out_bcount(size)      caddr_t data,
724         __in                    size_t size,
725         __in                    uint32_t mode)
726 {
727         efx_mcdi_req_t req;
728         uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
729                             MC_CMD_NVRAM_READ_OUT_LENMAX)];
730         efx_rc_t rc;
731
732         if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
733                 rc = EINVAL;
734                 goto fail1;
735         }
736
737         (void) memset(payload, 0, sizeof (payload));
738         req.emr_cmd = MC_CMD_NVRAM_READ;
739         req.emr_in_buf = payload;
740         req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
741         req.emr_out_buf = payload;
742         req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
743
744         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
745         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
746         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
747         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
748
749         efx_mcdi_execute(enp, &req);
750
751         if (req.emr_rc != 0) {
752                 rc = req.emr_rc;
753                 goto fail1;
754         }
755
756         if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
757                 rc = EMSGSIZE;
758                 goto fail2;
759         }
760
761         memcpy(data,
762             MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
763             size);
764
765         return (0);
766
767 fail2:
768         EFSYS_PROBE(fail2);
769 fail1:
770         EFSYS_PROBE1(fail1, efx_rc_t, rc);
771
772         return (rc);
773 }
774
775         __checkReturn           efx_rc_t
776 efx_mcdi_nvram_erase(
777         __in                    efx_nic_t *enp,
778         __in                    uint32_t partn,
779         __in                    uint32_t offset,
780         __in                    size_t size)
781 {
782         efx_mcdi_req_t req;
783         uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
784                             MC_CMD_NVRAM_ERASE_OUT_LEN)];
785         efx_rc_t rc;
786
787         (void) memset(payload, 0, sizeof (payload));
788         req.emr_cmd = MC_CMD_NVRAM_ERASE;
789         req.emr_in_buf = payload;
790         req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
791         req.emr_out_buf = payload;
792         req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
793
794         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
795         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
796         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
797
798         efx_mcdi_execute(enp, &req);
799
800         if (req.emr_rc != 0) {
801                 rc = req.emr_rc;
802                 goto fail1;
803         }
804
805         return (0);
806
807 fail1:
808         EFSYS_PROBE1(fail1, efx_rc_t, rc);
809
810         return (rc);
811 }
812
813 /*
814  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
815  * Sienna and EF10 based boards.  However EF10 based boards support the use
816  * of this command with payloads up to the maximum MCDI V2 payload length.
817  */
818         __checkReturn           efx_rc_t
819 efx_mcdi_nvram_write(
820         __in                    efx_nic_t *enp,
821         __in                    uint32_t partn,
822         __in                    uint32_t offset,
823         __out_bcount(size)      caddr_t data,
824         __in                    size_t size)
825 {
826         efx_mcdi_req_t req;
827         uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
828                             MCDI_CTL_SDU_LEN_MAX_V2)];
829         efx_rc_t rc;
830         size_t max_data_size;
831
832         max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
833             - MC_CMD_NVRAM_WRITE_IN_LEN(0);
834         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
835         EFSYS_ASSERT3U(max_data_size, <,
836                     enp->en_nic_cfg.enc_mcdi_max_payload_length);
837
838         if (size > max_data_size) {
839                 rc = EINVAL;
840                 goto fail1;
841         }
842
843         (void) memset(payload, 0, sizeof (payload));
844         req.emr_cmd = MC_CMD_NVRAM_WRITE;
845         req.emr_in_buf = payload;
846         req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
847         req.emr_out_buf = payload;
848         req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
849
850         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
851         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
852         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
853
854         memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
855             data, size);
856
857         efx_mcdi_execute(enp, &req);
858
859         if (req.emr_rc != 0) {
860                 rc = req.emr_rc;
861                 goto fail2;
862         }
863
864         return (0);
865
866 fail2:
867         EFSYS_PROBE(fail2);
868 fail1:
869         EFSYS_PROBE1(fail1, efx_rc_t, rc);
870
871         return (rc);
872 }
873
874         __checkReturn           efx_rc_t
875 efx_mcdi_nvram_update_finish(
876         __in                    efx_nic_t *enp,
877         __in                    uint32_t partn,
878         __in                    boolean_t reboot)
879 {
880         efx_mcdi_req_t req;
881         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
882                             MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
883         efx_rc_t rc;
884
885         (void) memset(payload, 0, sizeof (payload));
886         req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
887         req.emr_in_buf = payload;
888         req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
889         req.emr_out_buf = payload;
890         req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
891
892         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
893         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
894
895         efx_mcdi_execute(enp, &req);
896
897         if (req.emr_rc != 0) {
898                 rc = req.emr_rc;
899                 goto fail1;
900         }
901
902         return (0);
903
904 fail1:
905         EFSYS_PROBE1(fail1, efx_rc_t, rc);
906
907         return (rc);
908 }
909
910 #if EFSYS_OPT_DIAG
911
912         __checkReturn           efx_rc_t
913 efx_mcdi_nvram_test(
914         __in                    efx_nic_t *enp,
915         __in                    uint32_t partn)
916 {
917         efx_mcdi_req_t req;
918         uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
919                             MC_CMD_NVRAM_TEST_OUT_LEN)];
920         int result;
921         efx_rc_t rc;
922
923         (void) memset(payload, 0, sizeof (payload));
924         req.emr_cmd = MC_CMD_NVRAM_TEST;
925         req.emr_in_buf = payload;
926         req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
927         req.emr_out_buf = payload;
928         req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
929
930         MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
931
932         efx_mcdi_execute(enp, &req);
933
934         if (req.emr_rc != 0) {
935                 rc = req.emr_rc;
936                 goto fail1;
937         }
938
939         if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
940                 rc = EMSGSIZE;
941                 goto fail2;
942         }
943
944         result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
945         if (result == MC_CMD_NVRAM_TEST_FAIL) {
946
947                 EFSYS_PROBE1(nvram_test_failure, int, partn);
948
949                 rc = (EINVAL);
950                 goto fail3;
951         }
952
953         return (0);
954
955 fail3:
956         EFSYS_PROBE(fail3);
957 fail2:
958         EFSYS_PROBE(fail2);
959 fail1:
960         EFSYS_PROBE1(fail1, efx_rc_t, rc);
961
962         return (rc);
963 }
964
965 #endif  /* EFSYS_OPT_DIAG */
966
967
968 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */