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