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