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