]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/efx_nvram.c
MFV r309299:
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / efx_nvram.c
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$");
33
34 #include "efx.h"
35 #include "efx_impl.h"
36
37 #if EFSYS_OPT_NVRAM
38
39 #if EFSYS_OPT_SIENA
40
41 static 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
61 static 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
80 efx_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
120 fail1:
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
129 efx_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
143 fail1:
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
152 efx_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
174 fail2:
175         EFSYS_PROBE(fail2);
176 fail1:
177         EFSYS_PROBE1(fail1, efx_rc_t, rc);
178         *sizep = 0;
179
180         return (rc);
181 }
182
183         __checkReturn           efx_rc_t
184 efx_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
209 fail2:
210         EFSYS_PROBE(fail2);
211 fail1:
212         EFSYS_PROBE1(fail1, efx_rc_t, rc);
213
214         return (rc);
215 }
216
217         __checkReturn           efx_rc_t
218 efx_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
245 fail2:
246         EFSYS_PROBE(fail2);
247 fail1:
248         EFSYS_PROBE1(fail1, efx_rc_t, rc);
249
250         return (rc);
251 }
252
253         __checkReturn           efx_rc_t
254 efx_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
281 fail2:
282         EFSYS_PROBE(fail2);
283 fail1:
284         EFSYS_PROBE1(fail1, efx_rc_t, rc);
285
286         return (rc);
287 }
288
289         __checkReturn           efx_rc_t
290 efx_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
319 fail3:
320         EFSYS_PROBE(fail3);
321 fail2:
322         EFSYS_PROBE(fail2);
323 fail1:
324         EFSYS_PROBE1(fail1, efx_rc_t, rc);
325
326         return (rc);
327 }
328
329         __checkReturn           efx_rc_t
330 efx_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
357 fail2:
358         EFSYS_PROBE(fail2);
359 fail1:
360         EFSYS_PROBE1(fail1, efx_rc_t, rc);
361
362         return (rc);
363 }
364
365                                 void
366 efx_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
388 efx_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
418 fail2:
419         EFSYS_PROBE(fail2);
420 fail1:
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
428 efx_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
455 fail2:
456         EFSYS_PROBE(fail2);
457 fail1:
458         EFSYS_PROBE1(fail1, efx_rc_t, rc);
459
460         return (rc);
461 }
462
463
464 void
465 efx_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
487 efx_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
537 fail3:
538         EFSYS_PROBE(fail3);
539 fail2:
540         EFSYS_PROBE(fail2);
541 fail1:
542         EFSYS_PROBE1(fail1, efx_rc_t, rc);
543
544         return (rc);
545 }
546
547         __checkReturn           efx_rc_t
548 efx_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
628 fail3:
629         EFSYS_PROBE(fail3);
630 fail2:
631         EFSYS_PROBE(fail2);
632 fail1:
633         EFSYS_PROBE1(fail1, efx_rc_t, rc);
634
635         return (rc);
636 }
637
638         __checkReturn           efx_rc_t
639 efx_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
691 fail2:
692         EFSYS_PROBE(fail2);
693 fail1:
694         EFSYS_PROBE1(fail1, efx_rc_t, rc);
695
696         return (rc);
697 }
698
699         __checkReturn           efx_rc_t
700 efx_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
727 fail1:
728         EFSYS_PROBE1(fail1, efx_rc_t, rc);
729
730         return (rc);
731 }
732
733         __checkReturn           efx_rc_t
734 efx_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
782 fail2:
783         EFSYS_PROBE(fail2);
784 fail1:
785         EFSYS_PROBE1(fail1, efx_rc_t, rc);
786
787         return (rc);
788 }
789
790         __checkReturn           efx_rc_t
791 efx_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
822 fail1:
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
834 efx_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
881 fail2:
882         EFSYS_PROBE(fail2);
883 fail1:
884         EFSYS_PROBE1(fail1, efx_rc_t, rc);
885
886         return (rc);
887 }
888
889         __checkReturn           efx_rc_t
890 efx_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
919 fail1:
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
928 efx_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
970 fail3:
971         EFSYS_PROBE(fail3);
972 fail2:
973         EFSYS_PROBE(fail2);
974 fail1:
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 */