6ee2a71d623d20feec22d3ee888b3af589aeebf2
[deb_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 {
367         const efx_nvram_ops_t *envop = enp->en_envop;
368         uint32_t partn;
369         efx_rc_t rc;
370
371         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
372         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
373
374         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
375         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
376
377         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
378
379         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
380                 goto fail1;
381
382         if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
383                 goto fail2;
384
385         enp->en_nvram_locked = EFX_NVRAM_INVALID;
386
387         return (0);
388
389 fail2:
390         EFSYS_PROBE(fail2);
391         enp->en_nvram_locked = EFX_NVRAM_INVALID;
392
393 fail1:
394         EFSYS_PROBE1(fail1, efx_rc_t, rc);
395
396         return (rc);
397 }
398
399         __checkReturn           efx_rc_t
400 efx_nvram_set_version(
401         __in                    efx_nic_t *enp,
402         __in                    efx_nvram_type_t type,
403         __in_ecount(4)          uint16_t version[4])
404 {
405         const efx_nvram_ops_t *envop = enp->en_envop;
406         uint32_t partn;
407         efx_rc_t rc;
408
409         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
410         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
411         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
412
413         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
414
415         /*
416          * The Siena implementation of envo_set_version() will attempt to
417          * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
418          * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
419          */
420         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
421
422         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
423                 goto fail1;
424
425         if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
426                 goto fail2;
427
428         return (0);
429
430 fail2:
431         EFSYS_PROBE(fail2);
432 fail1:
433         EFSYS_PROBE1(fail1, efx_rc_t, rc);
434
435         return (rc);
436 }
437
438 /* Validate buffer contents (before writing to flash) */
439         __checkReturn           efx_rc_t
440 efx_nvram_validate(
441         __in                    efx_nic_t *enp,
442         __in                    efx_nvram_type_t type,
443         __in_bcount(partn_size) caddr_t partn_data,
444         __in                    size_t partn_size)
445 {
446         const efx_nvram_ops_t *envop = enp->en_envop;
447         uint32_t partn;
448         efx_rc_t rc;
449
450         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
451         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
452         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
453
454         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
455
456
457         if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
458                 goto fail1;
459
460         if (envop->envo_type_to_partn != NULL &&
461             ((rc = envop->envo_buffer_validate(enp, partn,
462             partn_data, partn_size)) != 0))
463                 goto fail2;
464
465         return (0);
466
467 fail2:
468         EFSYS_PROBE(fail2);
469 fail1:
470         EFSYS_PROBE1(fail1, efx_rc_t, rc);
471
472         return (rc);
473 }
474
475
476 void
477 efx_nvram_fini(
478         __in            efx_nic_t *enp)
479 {
480         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
481         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
482         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
483
484         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
485
486         enp->en_envop = NULL;
487         enp->en_mod_flags &= ~EFX_MOD_NVRAM;
488 }
489
490 #endif  /* EFSYS_OPT_NVRAM */
491
492 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
493
494 /*
495  * Internal MCDI request handling
496  */
497
498         __checkReturn           efx_rc_t
499 efx_mcdi_nvram_partitions(
500         __in                    efx_nic_t *enp,
501         __out_bcount(size)      caddr_t data,
502         __in                    size_t size,
503         __out                   unsigned int *npartnp)
504 {
505         efx_mcdi_req_t req;
506         uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
507                             MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
508         unsigned int npartn;
509         efx_rc_t rc;
510
511         (void) memset(payload, 0, sizeof (payload));
512         req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
513         req.emr_in_buf = payload;
514         req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
515         req.emr_out_buf = payload;
516         req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
517
518         efx_mcdi_execute(enp, &req);
519
520         if (req.emr_rc != 0) {
521                 rc = req.emr_rc;
522                 goto fail1;
523         }
524
525         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
526                 rc = EMSGSIZE;
527                 goto fail2;
528         }
529         npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
530
531         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
532                 rc = ENOENT;
533                 goto fail3;
534         }
535
536         if (size < npartn * sizeof (uint32_t)) {
537                 rc = ENOSPC;
538                 goto fail3;
539         }
540
541         *npartnp = npartn;
542
543         memcpy(data,
544             MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
545             (npartn * sizeof (uint32_t)));
546
547         return (0);
548
549 fail3:
550         EFSYS_PROBE(fail3);
551 fail2:
552         EFSYS_PROBE(fail2);
553 fail1:
554         EFSYS_PROBE1(fail1, efx_rc_t, rc);
555
556         return (rc);
557 }
558
559         __checkReturn           efx_rc_t
560 efx_mcdi_nvram_metadata(
561         __in                    efx_nic_t *enp,
562         __in                    uint32_t partn,
563         __out                   uint32_t *subtypep,
564         __out_ecount(4)         uint16_t version[4],
565         __out_bcount_opt(size)  char *descp,
566         __in                    size_t size)
567 {
568         efx_mcdi_req_t req;
569         uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
570                             MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
571         efx_rc_t rc;
572
573         (void) memset(payload, 0, sizeof (payload));
574         req.emr_cmd = MC_CMD_NVRAM_METADATA;
575         req.emr_in_buf = payload;
576         req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
577         req.emr_out_buf = payload;
578         req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
579
580         MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
581
582         efx_mcdi_execute(enp, &req);
583
584         if (req.emr_rc != 0) {
585                 rc = req.emr_rc;
586                 goto fail1;
587         }
588
589         if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
590                 rc = EMSGSIZE;
591                 goto fail2;
592         }
593
594         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
595                 NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
596                 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
597         } else {
598                 *subtypep = 0;
599         }
600
601         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
602                 NVRAM_METADATA_OUT_VERSION_VALID)) {
603                 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
604                 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
605                 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
606                 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
607         } else {
608                 version[0] = version[1] = version[2] = version[3] = 0;
609         }
610
611         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
612                 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
613                 /* Return optional descrition string */
614                 if ((descp != NULL) && (size > 0)) {
615                         size_t desclen;
616
617                         descp[0] = '\0';
618                         desclen = (req.emr_out_length_used
619                             - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
620
621                         EFSYS_ASSERT3U(desclen, <=,
622                             MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
623
624                         if (size < desclen) {
625                                 rc = ENOSPC;
626                                 goto fail3;
627                         }
628
629                         memcpy(descp, MCDI_OUT2(req, char,
630                                 NVRAM_METADATA_OUT_DESCRIPTION),
631                             desclen);
632
633                         /* Ensure string is NUL terminated */
634                         descp[desclen] = '\0';
635                 }
636         }
637
638         return (0);
639
640 fail3:
641         EFSYS_PROBE(fail3);
642 fail2:
643         EFSYS_PROBE(fail2);
644 fail1:
645         EFSYS_PROBE1(fail1, efx_rc_t, rc);
646
647         return (rc);
648 }
649
650         __checkReturn           efx_rc_t
651 efx_mcdi_nvram_info(
652         __in                    efx_nic_t *enp,
653         __in                    uint32_t partn,
654         __out_opt               size_t *sizep,
655         __out_opt               uint32_t *addressp,
656         __out_opt               uint32_t *erase_sizep,
657         __out_opt               uint32_t *write_sizep)
658 {
659         uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
660                             MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
661         efx_mcdi_req_t req;
662         efx_rc_t rc;
663
664         (void) memset(payload, 0, sizeof (payload));
665         req.emr_cmd = MC_CMD_NVRAM_INFO;
666         req.emr_in_buf = payload;
667         req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
668         req.emr_out_buf = payload;
669         req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
670
671         MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
672
673         efx_mcdi_execute_quiet(enp, &req);
674
675         if (req.emr_rc != 0) {
676                 rc = req.emr_rc;
677                 goto fail1;
678         }
679
680         if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
681                 rc = EMSGSIZE;
682                 goto fail2;
683         }
684
685         if (sizep)
686                 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
687
688         if (addressp)
689                 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
690
691         if (erase_sizep)
692                 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
693
694         if (write_sizep) {
695                 *write_sizep =
696                         (req.emr_out_length_used <
697                             MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
698                         0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
699         }
700
701         return (0);
702
703 fail2:
704         EFSYS_PROBE(fail2);
705 fail1:
706         EFSYS_PROBE1(fail1, efx_rc_t, rc);
707
708         return (rc);
709 }
710
711 /*
712  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
713  * NVRAM updates. Older firmware will ignore the flags field in the request.
714  */
715         __checkReturn           efx_rc_t
716 efx_mcdi_nvram_update_start(
717         __in                    efx_nic_t *enp,
718         __in                    uint32_t partn)
719 {
720         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
721                             MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
722         efx_mcdi_req_t req;
723         efx_rc_t rc;
724
725         (void) memset(payload, 0, sizeof (payload));
726         req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
727         req.emr_in_buf = payload;
728         req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
729         req.emr_out_buf = payload;
730         req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
731
732         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
733
734         MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
735             NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
736
737         efx_mcdi_execute(enp, &req);
738
739         if (req.emr_rc != 0) {
740                 rc = req.emr_rc;
741                 goto fail1;
742         }
743
744         return (0);
745
746 fail1:
747         EFSYS_PROBE1(fail1, efx_rc_t, rc);
748
749         return (rc);
750 }
751
752         __checkReturn           efx_rc_t
753 efx_mcdi_nvram_read(
754         __in                    efx_nic_t *enp,
755         __in                    uint32_t partn,
756         __in                    uint32_t offset,
757         __out_bcount(size)      caddr_t data,
758         __in                    size_t size,
759         __in                    uint32_t mode)
760 {
761         efx_mcdi_req_t req;
762         uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN,
763                             MC_CMD_NVRAM_READ_OUT_LENMAX)];
764         efx_rc_t rc;
765
766         if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
767                 rc = EINVAL;
768                 goto fail1;
769         }
770
771         (void) memset(payload, 0, sizeof (payload));
772         req.emr_cmd = MC_CMD_NVRAM_READ;
773         req.emr_in_buf = payload;
774         req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
775         req.emr_out_buf = payload;
776         req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
777
778         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
779         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
780         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
781         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
782
783         efx_mcdi_execute(enp, &req);
784
785         if (req.emr_rc != 0) {
786                 rc = req.emr_rc;
787                 goto fail1;
788         }
789
790         if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
791                 rc = EMSGSIZE;
792                 goto fail2;
793         }
794
795         memcpy(data,
796             MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
797             size);
798
799         return (0);
800
801 fail2:
802         EFSYS_PROBE(fail2);
803 fail1:
804         EFSYS_PROBE1(fail1, efx_rc_t, rc);
805
806         return (rc);
807 }
808
809         __checkReturn           efx_rc_t
810 efx_mcdi_nvram_erase(
811         __in                    efx_nic_t *enp,
812         __in                    uint32_t partn,
813         __in                    uint32_t offset,
814         __in                    size_t size)
815 {
816         efx_mcdi_req_t req;
817         uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
818                             MC_CMD_NVRAM_ERASE_OUT_LEN)];
819         efx_rc_t rc;
820
821         (void) memset(payload, 0, sizeof (payload));
822         req.emr_cmd = MC_CMD_NVRAM_ERASE;
823         req.emr_in_buf = payload;
824         req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
825         req.emr_out_buf = payload;
826         req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
827
828         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
829         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
830         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
831
832         efx_mcdi_execute(enp, &req);
833
834         if (req.emr_rc != 0) {
835                 rc = req.emr_rc;
836                 goto fail1;
837         }
838
839         return (0);
840
841 fail1:
842         EFSYS_PROBE1(fail1, efx_rc_t, rc);
843
844         return (rc);
845 }
846
847 /*
848  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
849  * Sienna and EF10 based boards.  However EF10 based boards support the use
850  * of this command with payloads up to the maximum MCDI V2 payload length.
851  */
852         __checkReturn           efx_rc_t
853 efx_mcdi_nvram_write(
854         __in                    efx_nic_t *enp,
855         __in                    uint32_t partn,
856         __in                    uint32_t offset,
857         __out_bcount(size)      caddr_t data,
858         __in                    size_t size)
859 {
860         efx_mcdi_req_t req;
861         uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
862                             MCDI_CTL_SDU_LEN_MAX_V2)];
863         efx_rc_t rc;
864         size_t max_data_size;
865
866         max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
867             - MC_CMD_NVRAM_WRITE_IN_LEN(0);
868         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
869         EFSYS_ASSERT3U(max_data_size, <,
870                     enp->en_nic_cfg.enc_mcdi_max_payload_length);
871
872         if (size > max_data_size) {
873                 rc = EINVAL;
874                 goto fail1;
875         }
876
877         (void) memset(payload, 0, sizeof (payload));
878         req.emr_cmd = MC_CMD_NVRAM_WRITE;
879         req.emr_in_buf = payload;
880         req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
881         req.emr_out_buf = payload;
882         req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
883
884         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
885         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
886         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
887
888         memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
889             data, size);
890
891         efx_mcdi_execute(enp, &req);
892
893         if (req.emr_rc != 0) {
894                 rc = req.emr_rc;
895                 goto fail2;
896         }
897
898         return (0);
899
900 fail2:
901         EFSYS_PROBE(fail2);
902 fail1:
903         EFSYS_PROBE1(fail1, efx_rc_t, rc);
904
905         return (rc);
906 }
907
908
909 /*
910  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
911  * NVRAM updates. Older firmware will ignore the flags field in the request.
912  */
913         __checkReturn           efx_rc_t
914 efx_mcdi_nvram_update_finish(
915         __in                    efx_nic_t *enp,
916         __in                    uint32_t partn,
917         __in                    boolean_t reboot,
918         __out_opt               uint32_t *resultp)
919 {
920         const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
921         efx_mcdi_req_t req;
922         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
923                             MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN)];
924         uint32_t result = 0; /* FIXME: use MC_CMD_NVRAM_VERIFY_RC_UNKNOWN */
925         efx_rc_t rc;
926
927         (void) memset(payload, 0, sizeof (payload));
928         req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
929         req.emr_in_buf = payload;
930         req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
931         req.emr_out_buf = payload;
932         req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
933
934         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
935         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
936
937         MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
938             NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
939
940         efx_mcdi_execute(enp, &req);
941
942         if (req.emr_rc != 0) {
943                 rc = req.emr_rc;
944                 goto fail1;
945         }
946
947         if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
948                 /* Report success if verified updates are not supported. */
949                 result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
950         } else {
951                 /* Firmware-verified NVRAM updates are required */
952                 if (req.emr_out_length_used <
953                     MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
954                         rc = EMSGSIZE;
955                         goto fail2;
956                 }
957                 result =
958                     MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
959
960                 if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
961                         /* Mandatory verification failed */
962                         rc = EINVAL;
963                         goto fail3;
964                 }
965         }
966
967         if (resultp != NULL)
968                 *resultp = result;
969
970         return (0);
971
972 fail3:
973         EFSYS_PROBE(fail3);
974 fail2:
975         EFSYS_PROBE(fail2);
976 fail1:
977         EFSYS_PROBE1(fail1, efx_rc_t, rc);
978
979         /* Always report verification result */
980         if (resultp != NULL)
981                 *resultp = result;
982
983         return (rc);
984 }
985
986 #if EFSYS_OPT_DIAG
987
988         __checkReturn           efx_rc_t
989 efx_mcdi_nvram_test(
990         __in                    efx_nic_t *enp,
991         __in                    uint32_t partn)
992 {
993         efx_mcdi_req_t req;
994         uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
995                             MC_CMD_NVRAM_TEST_OUT_LEN)];
996         int result;
997         efx_rc_t rc;
998
999         (void) memset(payload, 0, sizeof (payload));
1000         req.emr_cmd = MC_CMD_NVRAM_TEST;
1001         req.emr_in_buf = payload;
1002         req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
1003         req.emr_out_buf = payload;
1004         req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
1005
1006         MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
1007
1008         efx_mcdi_execute(enp, &req);
1009
1010         if (req.emr_rc != 0) {
1011                 rc = req.emr_rc;
1012                 goto fail1;
1013         }
1014
1015         if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
1016                 rc = EMSGSIZE;
1017                 goto fail2;
1018         }
1019
1020         result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
1021         if (result == MC_CMD_NVRAM_TEST_FAIL) {
1022
1023                 EFSYS_PROBE1(nvram_test_failure, int, partn);
1024
1025                 rc = (EINVAL);
1026                 goto fail3;
1027         }
1028
1029         return (0);
1030
1031 fail3:
1032         EFSYS_PROBE(fail3);
1033 fail2:
1034         EFSYS_PROBE(fail2);
1035 fail1:
1036         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1037
1038         return (rc);
1039 }
1040
1041 #endif  /* EFSYS_OPT_DIAG */
1042
1043
1044 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */