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