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