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