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