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