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