]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_nvram.c
MFC r310765
[FreeBSD/stable/10.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         __checkReturn           efx_rc_t
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         efx_rc_t rc;
373
374         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
375         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
376
377         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
378         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
379
380         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
381
382         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
383                 goto fail1;
384
385         if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
386                 goto fail2;
387
388         enp->en_nvram_locked = EFX_NVRAM_INVALID;
389
390         return (0);
391
392 fail2:
393         EFSYS_PROBE(fail2);
394         enp->en_nvram_locked = EFX_NVRAM_INVALID;
395
396 fail1:
397         EFSYS_PROBE1(fail1, efx_rc_t, rc);
398
399         return (rc);
400 }
401
402         __checkReturn           efx_rc_t
403 efx_nvram_set_version(
404         __in                    efx_nic_t *enp,
405         __in                    efx_nvram_type_t type,
406         __in_ecount(4)          uint16_t version[4])
407 {
408         const efx_nvram_ops_t *envop = enp->en_envop;
409         uint32_t partn;
410         efx_rc_t rc;
411
412         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
415
416         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
417
418         /*
419          * The Siena implementation of envo_set_version() will attempt to
420          * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
421          * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
422          */
423         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
424
425         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
426                 goto fail1;
427
428         if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
429                 goto fail2;
430
431         return (0);
432
433 fail2:
434         EFSYS_PROBE(fail2);
435 fail1:
436         EFSYS_PROBE1(fail1, efx_rc_t, rc);
437
438         return (rc);
439 }
440
441 /* Validate buffer contents (before writing to flash) */
442         __checkReturn           efx_rc_t
443 efx_nvram_validate(
444         __in                    efx_nic_t *enp,
445         __in                    efx_nvram_type_t type,
446         __in_bcount(partn_size) caddr_t partn_data,
447         __in                    size_t partn_size)
448 {
449         const efx_nvram_ops_t *envop = enp->en_envop;
450         uint32_t partn;
451         efx_rc_t rc;
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(type, <, EFX_NVRAM_NTYPES);
458
459
460         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
461                 goto fail1;
462
463         if (envop->envo_type_to_partn != NULL &&
464             ((rc = envop->envo_buffer_validate(enp, partn,
465             partn_data, partn_size)) != 0))
466                 goto fail2;
467
468         return (0);
469
470 fail2:
471         EFSYS_PROBE(fail2);
472 fail1:
473         EFSYS_PROBE1(fail1, efx_rc_t, rc);
474
475         return (rc);
476 }
477
478
479 void
480 efx_nvram_fini(
481         __in            efx_nic_t *enp)
482 {
483         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
484         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
485         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
486
487         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
488
489         enp->en_envop = NULL;
490         enp->en_mod_flags &= ~EFX_MOD_NVRAM;
491 }
492
493 #endif  /* EFSYS_OPT_NVRAM */
494
495 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
496
497 /*
498  * Internal MCDI request handling
499  */
500
501         __checkReturn           efx_rc_t
502 efx_mcdi_nvram_partitions(
503         __in                    efx_nic_t *enp,
504         __out_bcount(size)      caddr_t data,
505         __in                    size_t size,
506         __out                   unsigned int *npartnp)
507 {
508         efx_mcdi_req_t req;
509         uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
510                             MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
511         unsigned int npartn;
512         efx_rc_t rc;
513
514         (void) memset(payload, 0, sizeof (payload));
515         req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
516         req.emr_in_buf = payload;
517         req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
518         req.emr_out_buf = payload;
519         req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
520
521         efx_mcdi_execute(enp, &req);
522
523         if (req.emr_rc != 0) {
524                 rc = req.emr_rc;
525                 goto fail1;
526         }
527
528         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
529                 rc = EMSGSIZE;
530                 goto fail2;
531         }
532         npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
533
534         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
535                 rc = ENOENT;
536                 goto fail3;
537         }
538
539         if (size < npartn * sizeof (uint32_t)) {
540                 rc = ENOSPC;
541                 goto fail3;
542         }
543
544         *npartnp = npartn;
545
546         memcpy(data,
547             MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
548             (npartn * sizeof (uint32_t)));
549
550         return (0);
551
552 fail3:
553         EFSYS_PROBE(fail3);
554 fail2:
555         EFSYS_PROBE(fail2);
556 fail1:
557         EFSYS_PROBE1(fail1, efx_rc_t, rc);
558
559         return (rc);
560 }
561
562         __checkReturn           efx_rc_t
563 efx_mcdi_nvram_metadata(
564         __in                    efx_nic_t *enp,
565         __in                    uint32_t partn,
566         __out                   uint32_t *subtypep,
567         __out_ecount(4)         uint16_t version[4],
568         __out_bcount_opt(size)  char *descp,
569         __in                    size_t size)
570 {
571         efx_mcdi_req_t req;
572         uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
573                             MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
574         efx_rc_t rc;
575
576         (void) memset(payload, 0, sizeof (payload));
577         req.emr_cmd = MC_CMD_NVRAM_METADATA;
578         req.emr_in_buf = payload;
579         req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
580         req.emr_out_buf = payload;
581         req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
582
583         MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
584
585         efx_mcdi_execute(enp, &req);
586
587         if (req.emr_rc != 0) {
588                 rc = req.emr_rc;
589                 goto fail1;
590         }
591
592         if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
593                 rc = EMSGSIZE;
594                 goto fail2;
595         }
596
597         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
598                 NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
599                 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
600         } else {
601                 *subtypep = 0;
602         }
603
604         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
605                 NVRAM_METADATA_OUT_VERSION_VALID)) {
606                 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
607                 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
608                 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
609                 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
610         } else {
611                 version[0] = version[1] = version[2] = version[3] = 0;
612         }
613
614         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
615                 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
616                 /* Return optional descrition string */
617                 if ((descp != NULL) && (size > 0)) {
618                         size_t desclen;
619
620                         descp[0] = '\0';
621                         desclen = (req.emr_out_length_used
622                             - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
623
624                         EFSYS_ASSERT3U(desclen, <=,
625                             MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
626
627                         if (size < desclen) {
628                                 rc = ENOSPC;
629                                 goto fail3;
630                         }
631
632                         memcpy(descp, MCDI_OUT2(req, char,
633                                 NVRAM_METADATA_OUT_DESCRIPTION),
634                             desclen);
635
636                         /* Ensure string is NUL terminated */
637                         descp[desclen] = '\0';
638                 }
639         }
640
641         return (0);
642
643 fail3:
644         EFSYS_PROBE(fail3);
645 fail2:
646         EFSYS_PROBE(fail2);
647 fail1:
648         EFSYS_PROBE1(fail1, efx_rc_t, rc);
649
650         return (rc);
651 }
652
653         __checkReturn           efx_rc_t
654 efx_mcdi_nvram_info(
655         __in                    efx_nic_t *enp,
656         __in                    uint32_t partn,
657         __out_opt               size_t *sizep,
658         __out_opt               uint32_t *addressp,
659         __out_opt               uint32_t *erase_sizep,
660         __out_opt               uint32_t *write_sizep)
661 {
662         uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
663                             MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
664         efx_mcdi_req_t req;
665         efx_rc_t rc;
666
667         (void) memset(payload, 0, sizeof (payload));
668         req.emr_cmd = MC_CMD_NVRAM_INFO;
669         req.emr_in_buf = payload;
670         req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
671         req.emr_out_buf = payload;
672         req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
673
674         MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
675
676         efx_mcdi_execute_quiet(enp, &req);
677
678         if (req.emr_rc != 0) {
679                 rc = req.emr_rc;
680                 goto fail1;
681         }
682
683         if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
684                 rc = EMSGSIZE;
685                 goto fail2;
686         }
687
688         if (sizep)
689                 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
690
691         if (addressp)
692                 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
693
694         if (erase_sizep)
695                 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
696
697         if (write_sizep) {
698                 *write_sizep =
699                         (req.emr_out_length_used <
700                             MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
701                         0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
702         }
703
704         return (0);
705
706 fail2:
707         EFSYS_PROBE(fail2);
708 fail1:
709         EFSYS_PROBE1(fail1, efx_rc_t, rc);
710
711         return (rc);
712 }
713
714 /*
715  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
716  * NVRAM updates. Older firmware will ignore the flags field in the request.
717  */
718         __checkReturn           efx_rc_t
719 efx_mcdi_nvram_update_start(
720         __in                    efx_nic_t *enp,
721         __in                    uint32_t partn)
722 {
723         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
724                             MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
725         efx_mcdi_req_t req;
726         efx_rc_t rc;
727
728         (void) memset(payload, 0, sizeof (payload));
729         req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
730         req.emr_in_buf = payload;
731         req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
732         req.emr_out_buf = payload;
733         req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
734
735         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
736
737         MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
738             NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
739
740         efx_mcdi_execute(enp, &req);
741
742         if (req.emr_rc != 0) {
743                 rc = req.emr_rc;
744                 goto fail1;
745         }
746
747         return (0);
748
749 fail1:
750         EFSYS_PROBE1(fail1, efx_rc_t, rc);
751
752         return (rc);
753 }
754
755         __checkReturn           efx_rc_t
756 efx_mcdi_nvram_read(
757         __in                    efx_nic_t *enp,
758         __in                    uint32_t partn,
759         __in                    uint32_t offset,
760         __out_bcount(size)      caddr_t data,
761         __in                    size_t size,
762         __in                    uint32_t mode)
763 {
764         efx_mcdi_req_t req;
765         uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
766                             MC_CMD_NVRAM_READ_OUT_LENMAX)];
767         efx_rc_t rc;
768
769         if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
770                 rc = EINVAL;
771                 goto fail1;
772         }
773
774         (void) memset(payload, 0, sizeof (payload));
775         req.emr_cmd = MC_CMD_NVRAM_READ;
776         req.emr_in_buf = payload;
777         req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
778         req.emr_out_buf = payload;
779         req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
780
781         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
782         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
783         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
784         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
785
786         efx_mcdi_execute(enp, &req);
787
788         if (req.emr_rc != 0) {
789                 rc = req.emr_rc;
790                 goto fail1;
791         }
792
793         if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
794                 rc = EMSGSIZE;
795                 goto fail2;
796         }
797
798         memcpy(data,
799             MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
800             size);
801
802         return (0);
803
804 fail2:
805         EFSYS_PROBE(fail2);
806 fail1:
807         EFSYS_PROBE1(fail1, efx_rc_t, rc);
808
809         return (rc);
810 }
811
812         __checkReturn           efx_rc_t
813 efx_mcdi_nvram_erase(
814         __in                    efx_nic_t *enp,
815         __in                    uint32_t partn,
816         __in                    uint32_t offset,
817         __in                    size_t size)
818 {
819         efx_mcdi_req_t req;
820         uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
821                             MC_CMD_NVRAM_ERASE_OUT_LEN)];
822         efx_rc_t rc;
823
824         (void) memset(payload, 0, sizeof (payload));
825         req.emr_cmd = MC_CMD_NVRAM_ERASE;
826         req.emr_in_buf = payload;
827         req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
828         req.emr_out_buf = payload;
829         req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
830
831         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
832         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
833         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
834
835         efx_mcdi_execute(enp, &req);
836
837         if (req.emr_rc != 0) {
838                 rc = req.emr_rc;
839                 goto fail1;
840         }
841
842         return (0);
843
844 fail1:
845         EFSYS_PROBE1(fail1, efx_rc_t, rc);
846
847         return (rc);
848 }
849
850 /*
851  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
852  * Sienna and EF10 based boards.  However EF10 based boards support the use
853  * of this command with payloads up to the maximum MCDI V2 payload length.
854  */
855         __checkReturn           efx_rc_t
856 efx_mcdi_nvram_write(
857         __in                    efx_nic_t *enp,
858         __in                    uint32_t partn,
859         __in                    uint32_t offset,
860         __out_bcount(size)      caddr_t data,
861         __in                    size_t size)
862 {
863         efx_mcdi_req_t req;
864         uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
865                             MCDI_CTL_SDU_LEN_MAX_V2)];
866         efx_rc_t rc;
867         size_t max_data_size;
868
869         max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
870             - MC_CMD_NVRAM_WRITE_IN_LEN(0);
871         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
872         EFSYS_ASSERT3U(max_data_size, <,
873                     enp->en_nic_cfg.enc_mcdi_max_payload_length);
874
875         if (size > max_data_size) {
876                 rc = EINVAL;
877                 goto fail1;
878         }
879
880         (void) memset(payload, 0, sizeof (payload));
881         req.emr_cmd = MC_CMD_NVRAM_WRITE;
882         req.emr_in_buf = payload;
883         req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
884         req.emr_out_buf = payload;
885         req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
886
887         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
888         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
889         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
890
891         memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
892             data, size);
893
894         efx_mcdi_execute(enp, &req);
895
896         if (req.emr_rc != 0) {
897                 rc = req.emr_rc;
898                 goto fail2;
899         }
900
901         return (0);
902
903 fail2:
904         EFSYS_PROBE(fail2);
905 fail1:
906         EFSYS_PROBE1(fail1, efx_rc_t, rc);
907
908         return (rc);
909 }
910
911
912 /*
913  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
914  * NVRAM updates. Older firmware will ignore the flags field in the request.
915  */
916         __checkReturn           efx_rc_t
917 efx_mcdi_nvram_update_finish(
918         __in                    efx_nic_t *enp,
919         __in                    uint32_t partn,
920         __in                    boolean_t reboot,
921         __out_opt               uint32_t *resultp)
922 {
923         const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
924         efx_mcdi_req_t req;
925         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
926                             MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
927         uint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */
928         efx_rc_t rc;
929
930         (void) memset(payload, 0, sizeof (payload));
931         req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
932         req.emr_in_buf = payload;
933         req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
934         req.emr_out_buf = payload;
935         req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
936
937         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
938         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
939
940         MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
941             NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
942
943         efx_mcdi_execute(enp, &req);
944
945         if (req.emr_rc != 0) {
946                 rc = req.emr_rc;
947                 goto fail1;
948         }
949
950         if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
951                 /* Report success if verified updates are not supported. */
952                 result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
953         } else {
954                 /* Firmware-verified NVRAM updates are required */
955                 if (req.emr_out_length_used <
956                     MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
957                         rc = EMSGSIZE;
958                         goto fail2;
959                 }
960                 result =
961                     MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
962
963                 if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
964                         /* Mandatory verification failed */
965                         rc = EINVAL;
966                         goto fail3;
967                 }
968         }
969
970         if (resultp != NULL)
971                 *resultp = result;
972
973         return (0);
974
975 fail3:
976         EFSYS_PROBE(fail3);
977 fail2:
978         EFSYS_PROBE(fail2);
979 fail1:
980         EFSYS_PROBE1(fail1, efx_rc_t, rc);
981
982         /* Always report verification result */
983         if (resultp != NULL)
984                 *resultp = result;
985
986         return (rc);
987 }
988
989 #if EFSYS_OPT_DIAG
990
991         __checkReturn           efx_rc_t
992 efx_mcdi_nvram_test(
993         __in                    efx_nic_t *enp,
994         __in                    uint32_t partn)
995 {
996         efx_mcdi_req_t req;
997         uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
998                             MC_CMD_NVRAM_TEST_OUT_LEN)];
999         int result;
1000         efx_rc_t rc;
1001
1002         (void) memset(payload, 0, sizeof (payload));
1003         req.emr_cmd = MC_CMD_NVRAM_TEST;
1004         req.emr_in_buf = payload;
1005         req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
1006         req.emr_out_buf = payload;
1007         req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
1008
1009         MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
1010
1011         efx_mcdi_execute(enp, &req);
1012
1013         if (req.emr_rc != 0) {
1014                 rc = req.emr_rc;
1015                 goto fail1;
1016         }
1017
1018         if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
1019                 rc = EMSGSIZE;
1020                 goto fail2;
1021         }
1022
1023         result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
1024         if (result == MC_CMD_NVRAM_TEST_FAIL) {
1025
1026                 EFSYS_PROBE1(nvram_test_failure, int, partn);
1027
1028                 rc = (EINVAL);
1029                 goto fail3;
1030         }
1031
1032         return (0);
1033
1034 fail3:
1035         EFSYS_PROBE(fail3);
1036 fail2:
1037         EFSYS_PROBE(fail2);
1038 fail1:
1039         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1040
1041         return (rc);
1042 }
1043
1044 #endif  /* EFSYS_OPT_DIAG */
1045
1046
1047 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */