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