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