]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_nvram.c
MFC r291923
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / efx_nvram.c
1 /*-
2  * Copyright (c) 2009-2015 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 <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_impl.h"
39
40 #if EFSYS_OPT_NVRAM
41
42 #if EFSYS_OPT_FALCON
43
44 static efx_nvram_ops_t  __efx_nvram_falcon_ops = {
45 #if EFSYS_OPT_DIAG
46         falcon_nvram_test,              /* envo_test */
47 #endif  /* EFSYS_OPT_DIAG */
48         falcon_nvram_size,              /* envo_size */
49         falcon_nvram_get_version,       /* envo_get_version */
50         falcon_nvram_rw_start,          /* envo_rw_start */
51         falcon_nvram_read_chunk,        /* envo_read_chunk */
52         falcon_nvram_erase,             /* envo_erase */
53         falcon_nvram_write_chunk,       /* envo_write_chunk */
54         falcon_nvram_rw_finish,         /* envo_rw_finish */
55         falcon_nvram_set_version,       /* envo_set_version */
56 };
57
58 #endif  /* EFSYS_OPT_FALCON */
59
60 #if EFSYS_OPT_SIENA
61
62 static efx_nvram_ops_t  __efx_nvram_siena_ops = {
63 #if EFSYS_OPT_DIAG
64         siena_nvram_test,               /* envo_test */
65 #endif  /* EFSYS_OPT_DIAG */
66         siena_nvram_size,               /* envo_size */
67         siena_nvram_get_version,        /* envo_get_version */
68         siena_nvram_rw_start,           /* envo_rw_start */
69         siena_nvram_read_chunk,         /* envo_read_chunk */
70         siena_nvram_erase,              /* envo_erase */
71         siena_nvram_write_chunk,        /* envo_write_chunk */
72         siena_nvram_rw_finish,          /* envo_rw_finish */
73         siena_nvram_set_version,        /* envo_set_version */
74 };
75
76 #endif  /* EFSYS_OPT_SIENA */
77
78 #if EFSYS_OPT_HUNTINGTON
79
80 static efx_nvram_ops_t  __efx_nvram_hunt_ops = {
81 #if EFSYS_OPT_DIAG
82         hunt_nvram_test,                /* envo_test */
83 #endif  /* EFSYS_OPT_DIAG */
84         hunt_nvram_size,                /* envo_size */
85         hunt_nvram_get_version,         /* envo_get_version */
86         hunt_nvram_rw_start,            /* envo_rw_start */
87         hunt_nvram_read_chunk,          /* envo_read_chunk */
88         hunt_nvram_erase,               /* envo_erase */
89         hunt_nvram_write_chunk,         /* envo_write_chunk */
90         hunt_nvram_rw_finish,           /* envo_rw_finish */
91         hunt_nvram_set_version,         /* envo_set_version */
92 };
93
94 #endif  /* EFSYS_OPT_HUNTINGTON */
95
96         __checkReturn   efx_rc_t
97 efx_nvram_init(
98         __in            efx_nic_t *enp)
99 {
100         efx_nvram_ops_t *envop;
101         efx_rc_t rc;
102
103         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
104         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
105         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
106
107         switch (enp->en_family) {
108 #if EFSYS_OPT_FALCON
109         case EFX_FAMILY_FALCON:
110                 envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops;
111                 break;
112 #endif  /* EFSYS_OPT_FALCON */
113
114 #if EFSYS_OPT_SIENA
115         case EFX_FAMILY_SIENA:
116                 envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops;
117                 break;
118 #endif  /* EFSYS_OPT_SIENA */
119
120 #if EFSYS_OPT_HUNTINGTON
121         case EFX_FAMILY_HUNTINGTON:
122                 envop = (efx_nvram_ops_t *)&__efx_nvram_hunt_ops;
123                 break;
124 #endif  /* EFSYS_OPT_HUNTINGTON */
125
126         default:
127                 EFSYS_ASSERT(0);
128                 rc = ENOTSUP;
129                 goto fail1;
130         }
131
132         enp->en_envop = envop;
133         enp->en_mod_flags |= EFX_MOD_NVRAM;
134
135         return (0);
136
137 fail1:
138         EFSYS_PROBE1(fail1, efx_rc_t, rc);
139
140         return (rc);
141 }
142
143 #if EFSYS_OPT_DIAG
144
145         __checkReturn           efx_rc_t
146 efx_nvram_test(
147         __in                    efx_nic_t *enp)
148 {
149         efx_nvram_ops_t *envop = enp->en_envop;
150         efx_rc_t rc;
151
152         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
153         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
154
155         if ((rc = envop->envo_test(enp)) != 0)
156                 goto fail1;
157
158         return (0);
159
160 fail1:
161         EFSYS_PROBE1(fail1, efx_rc_t, rc);
162
163         return (rc);
164 }
165
166 #endif  /* EFSYS_OPT_DIAG */
167
168         __checkReturn           efx_rc_t
169 efx_nvram_size(
170         __in                    efx_nic_t *enp,
171         __in                    efx_nvram_type_t type,
172         __out                   size_t *sizep)
173 {
174         efx_nvram_ops_t *envop = enp->en_envop;
175         efx_rc_t rc;
176
177         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
178         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
179
180         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
181
182         if ((rc = envop->envo_size(enp, type, sizep)) != 0)
183                 goto fail1;
184
185         return (0);
186
187 fail1:
188         EFSYS_PROBE1(fail1, efx_rc_t, rc);
189
190         return (rc);
191 }
192
193         __checkReturn           efx_rc_t
194 efx_nvram_get_version(
195         __in                    efx_nic_t *enp,
196         __in                    efx_nvram_type_t type,
197         __out                   uint32_t *subtypep,
198         __out_ecount(4)         uint16_t version[4])
199 {
200         efx_nvram_ops_t *envop = enp->en_envop;
201         efx_rc_t rc;
202
203         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
206
207         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
208
209         if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0)
210                 goto fail1;
211
212         return (0);
213
214 fail1:
215         EFSYS_PROBE1(fail1, efx_rc_t, rc);
216
217         return (rc);
218 }
219
220         __checkReturn           efx_rc_t
221 efx_nvram_rw_start(
222         __in                    efx_nic_t *enp,
223         __in                    efx_nvram_type_t type,
224         __out_opt               size_t *chunk_sizep)
225 {
226         efx_nvram_ops_t *envop = enp->en_envop;
227         efx_rc_t rc;
228
229         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
230         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
231
232         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
233         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
234
235         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
236
237         if ((rc = envop->envo_rw_start(enp, type, chunk_sizep)) != 0)
238                 goto fail1;
239
240         enp->en_nvram_locked = type;
241
242         return (0);
243
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         efx_nvram_ops_t *envop = enp->en_envop;
259         efx_rc_t rc;
260
261         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
263
264         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
265         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
266
267         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
268
269         if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0)
270                 goto fail1;
271
272         return (0);
273
274 fail1:
275         EFSYS_PROBE1(fail1, efx_rc_t, rc);
276
277         return (rc);
278 }
279
280         __checkReturn           efx_rc_t
281 efx_nvram_erase(
282         __in                    efx_nic_t *enp,
283         __in                    efx_nvram_type_t type)
284 {
285         efx_nvram_ops_t *envop = enp->en_envop;
286         efx_rc_t rc;
287
288         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
289         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
290
291         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
292         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
293
294         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
295
296         if ((rc = envop->envo_erase(enp, type)) != 0)
297                 goto fail1;
298
299         return (0);
300
301 fail1:
302         EFSYS_PROBE1(fail1, efx_rc_t, rc);
303
304         return (rc);
305 }
306
307         __checkReturn           efx_rc_t
308 efx_nvram_write_chunk(
309         __in                    efx_nic_t *enp,
310         __in                    efx_nvram_type_t type,
311         __in                    unsigned int offset,
312         __in_bcount(size)       caddr_t data,
313         __in                    size_t size)
314 {
315         efx_nvram_ops_t *envop = enp->en_envop;
316         efx_rc_t rc;
317
318         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
319         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
320
321         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
322         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
323
324         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
325
326         if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
327                 goto fail1;
328
329         return (0);
330
331 fail1:
332         EFSYS_PROBE1(fail1, efx_rc_t, rc);
333
334         return (rc);
335 }
336
337                                 void
338 efx_nvram_rw_finish(
339         __in                    efx_nic_t *enp,
340         __in                    efx_nvram_type_t type)
341 {
342         efx_nvram_ops_t *envop = enp->en_envop;
343
344         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
345         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
346
347         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
348         EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
349
350         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
351
352         envop->envo_rw_finish(enp, type);
353
354         enp->en_nvram_locked = EFX_NVRAM_INVALID;
355 }
356
357         __checkReturn           efx_rc_t
358 efx_nvram_set_version(
359         __in                    efx_nic_t *enp,
360         __in                    efx_nvram_type_t type,
361         __in_ecount(4)          uint16_t version[4])
362 {
363         efx_nvram_ops_t *envop = enp->en_envop;
364         efx_rc_t rc;
365
366         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
367         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
368         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
369
370         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
371
372         /*
373          * The Siena implementation of envo_set_version() will attempt to
374          * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
375          * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
376          */
377         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
378
379         if ((rc = envop->envo_set_version(enp, type, version)) != 0)
380                 goto fail1;
381
382         return (0);
383
384 fail1:
385         EFSYS_PROBE1(fail1, efx_rc_t, rc);
386
387         return (rc);
388 }
389
390 void
391 efx_nvram_fini(
392         __in            efx_nic_t *enp)
393 {
394         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
395         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
396         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
397
398         EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
399
400         enp->en_envop = NULL;
401         enp->en_mod_flags &= ~EFX_MOD_NVRAM;
402 }
403
404 #endif  /* EFSYS_OPT_NVRAM */
405
406 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
407
408 /*
409  * Internal MCDI request handling
410  */
411
412         __checkReturn           efx_rc_t
413 efx_mcdi_nvram_partitions(
414         __in                    efx_nic_t *enp,
415         __out_bcount(size)      caddr_t data,
416         __in                    size_t size,
417         __out                   unsigned int *npartnp)
418 {
419         efx_mcdi_req_t req;
420         uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
421                             MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
422         unsigned int npartn;
423         efx_rc_t rc;
424
425         (void) memset(payload, 0, sizeof (payload));
426         req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
427         req.emr_in_buf = payload;
428         req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
429         req.emr_out_buf = payload;
430         req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
431
432         efx_mcdi_execute(enp, &req);
433
434         if (req.emr_rc != 0) {
435                 rc = req.emr_rc;
436                 goto fail1;
437         }
438
439         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
440                 rc = EMSGSIZE;
441                 goto fail2;
442         }
443         npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
444
445         if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
446                 rc = ENOENT;
447                 goto fail3;
448         }
449
450         if (size < npartn * sizeof (uint32_t)) {
451                 rc = ENOSPC;
452                 goto fail3;
453         }
454
455         *npartnp = npartn;
456
457         memcpy(data,
458             MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
459             (npartn * sizeof (uint32_t)));
460
461         return (0);
462
463 fail3:
464         EFSYS_PROBE(fail3);
465 fail2:
466         EFSYS_PROBE(fail2);
467 fail1:
468         EFSYS_PROBE1(fail1, efx_rc_t, rc);
469
470         return (rc);
471 }
472
473         __checkReturn           efx_rc_t
474 efx_mcdi_nvram_metadata(
475         __in                    efx_nic_t *enp,
476         __in                    uint32_t partn,
477         __out                   uint32_t *subtypep,
478         __out_ecount(4)         uint16_t version[4],
479         __out_bcount_opt(size)  char *descp,
480         __in                    size_t size)
481 {
482         efx_mcdi_req_t req;
483         uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
484                             MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
485         efx_rc_t rc;
486
487         (void) memset(payload, 0, sizeof (payload));
488         req.emr_cmd = MC_CMD_NVRAM_METADATA;
489         req.emr_in_buf = payload;
490         req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
491         req.emr_out_buf = payload;
492         req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
493
494         MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
495
496         efx_mcdi_execute(enp, &req);
497
498         if (req.emr_rc != 0) {
499                 rc = req.emr_rc;
500                 goto fail1;
501         }
502
503         if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
504                 rc = EMSGSIZE;
505                 goto fail2;
506         }
507
508         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
509                 NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
510                 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
511         } else {
512                 *subtypep = 0;
513         }
514
515         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
516                 NVRAM_METADATA_OUT_VERSION_VALID)) {
517                 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
518                 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
519                 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
520                 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
521         } else {
522                 version[0] = version[1] = version[2] = version[3] = 0;
523         }
524
525         if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
526                 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
527                 /* Return optional descrition string */
528                 if ((descp != NULL) && (size > 0)) {
529                         size_t desclen;
530
531                         descp[0] = '\0';
532                         desclen = (req.emr_out_length_used
533                             - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
534
535                         EFSYS_ASSERT3U(desclen, <=,
536                             MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
537
538                         if (size < desclen) {
539                                 rc = ENOSPC;
540                                 goto fail3;
541                         }
542
543                         memcpy(descp, MCDI_OUT2(req, char,
544                                 NVRAM_METADATA_OUT_DESCRIPTION),
545                             desclen);
546
547                         /* Ensure string is NUL terminated */
548                         descp[desclen] = '\0';
549                 }
550         }
551
552         return (0);
553
554 fail3:
555         EFSYS_PROBE(fail3);
556 fail2:
557         EFSYS_PROBE(fail2);
558 fail1:
559         EFSYS_PROBE1(fail1, efx_rc_t, rc);
560
561         return (rc);
562 }
563
564         __checkReturn           efx_rc_t
565 efx_mcdi_nvram_info(
566         __in                    efx_nic_t *enp,
567         __in                    uint32_t partn,
568         __out_opt               size_t *sizep,
569         __out_opt               uint32_t *addressp,
570         __out_opt               uint32_t *erase_sizep,
571         __out_opt               uint32_t *write_sizep)
572 {
573         uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
574                             MC_CMD_NVRAM_INFO_V2_OUT_LEN)];
575         efx_mcdi_req_t req;
576         efx_rc_t rc;
577
578         (void) memset(payload, 0, sizeof (payload));
579         req.emr_cmd = MC_CMD_NVRAM_INFO;
580         req.emr_in_buf = payload;
581         req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
582         req.emr_out_buf = payload;
583         req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
584
585         MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
586
587         efx_mcdi_execute_quiet(enp, &req);
588
589         if (req.emr_rc != 0) {
590                 rc = req.emr_rc;
591                 goto fail1;
592         }
593
594         if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
595                 rc = EMSGSIZE;
596                 goto fail2;
597         }
598
599         if (sizep)
600                 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
601
602         if (addressp)
603                 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
604
605         if (erase_sizep)
606                 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
607
608         if (write_sizep) {
609                 *write_sizep =
610                         (req.emr_out_length_used <
611                             MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
612                         0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
613         }
614
615         return (0);
616
617 fail2:
618         EFSYS_PROBE(fail2);
619 fail1:
620         EFSYS_PROBE1(fail1, efx_rc_t, rc);
621
622         return (rc);
623 }
624
625         __checkReturn           efx_rc_t
626 efx_mcdi_nvram_update_start(
627         __in                    efx_nic_t *enp,
628         __in                    uint32_t partn)
629 {
630         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
631                             MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
632         efx_mcdi_req_t req;
633         efx_rc_t rc;
634
635         (void) memset(payload, 0, sizeof (payload));
636         req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
637         req.emr_in_buf = payload;
638         req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
639         req.emr_out_buf = payload;
640         req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
641
642         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
643
644         efx_mcdi_execute(enp, &req);
645
646         if (req.emr_rc != 0) {
647                 rc = req.emr_rc;
648                 goto fail1;
649         }
650
651         return (0);
652
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_read(
661         __in                    efx_nic_t *enp,
662         __in                    uint32_t partn,
663         __in                    uint32_t offset,
664         __out_bcount(size)      caddr_t data,
665         __in                    size_t size)
666 {
667         efx_mcdi_req_t req;
668         uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
669                             MC_CMD_NVRAM_READ_OUT_LENMAX)];
670         efx_rc_t rc;
671
672         if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
673                 rc = EINVAL;
674                 goto fail1;
675         }
676
677         (void) memset(payload, 0, sizeof (payload));
678         req.emr_cmd = MC_CMD_NVRAM_READ;
679         req.emr_in_buf = payload;
680         req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
681         req.emr_out_buf = payload;
682         req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
683
684         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
685         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
686         MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
687
688         efx_mcdi_execute(enp, &req);
689
690         if (req.emr_rc != 0) {
691                 rc = req.emr_rc;
692                 goto fail1;
693         }
694
695         if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
696                 rc = EMSGSIZE;
697                 goto fail2;
698         }
699
700         memcpy(data,
701             MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
702             size);
703
704         return (0);
705
706 fail2:
707         EFSYS_PROBE(fail2);
708 fail1:
709         EFSYS_PROBE1(fail1, efx_rc_t, rc);
710
711         return (rc);
712 }
713
714         __checkReturn           efx_rc_t
715 efx_mcdi_nvram_erase(
716         __in                    efx_nic_t *enp,
717         __in                    uint32_t partn,
718         __in                    uint32_t offset,
719         __in                    size_t size)
720 {
721         efx_mcdi_req_t req;
722         uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
723                             MC_CMD_NVRAM_ERASE_OUT_LEN)];
724         efx_rc_t rc;
725
726         (void) memset(payload, 0, sizeof (payload));
727         req.emr_cmd = MC_CMD_NVRAM_ERASE;
728         req.emr_in_buf = payload;
729         req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
730         req.emr_out_buf = payload;
731         req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
732
733         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
734         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
735         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
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 /*
753  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
754  * Sienna and EF10 based boards.  However EF10 based boards support the use
755  * of this command with payloads up to the maximum MCDI V2 payload length.
756  */
757         __checkReturn           efx_rc_t
758 efx_mcdi_nvram_write(
759         __in                    efx_nic_t *enp,
760         __in                    uint32_t partn,
761         __in                    uint32_t offset,
762         __out_bcount(size)      caddr_t data,
763         __in                    size_t size)
764 {
765         efx_mcdi_req_t req;
766         uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1,
767                             MCDI_CTL_SDU_LEN_MAX_V2)];
768         efx_rc_t rc;
769         size_t max_data_size;
770
771         max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length
772             - MC_CMD_NVRAM_WRITE_IN_LEN(0);
773         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0);
774         EFSYS_ASSERT3U(max_data_size, <,
775                     enp->en_nic_cfg.enc_mcdi_max_payload_length);
776
777         if (size > max_data_size) {
778                 rc = EINVAL;
779                 goto fail1;
780         }
781
782         (void) memset(payload, 0, sizeof (payload));
783         req.emr_cmd = MC_CMD_NVRAM_WRITE;
784         req.emr_in_buf = payload;
785         req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
786         req.emr_out_buf = payload;
787         req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
788
789         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
790         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
791         MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
792
793         memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
794             data, size);
795
796         efx_mcdi_execute(enp, &req);
797
798         if (req.emr_rc != 0) {
799                 rc = req.emr_rc;
800                 goto fail2;
801         }
802
803         return (0);
804
805 fail2:
806         EFSYS_PROBE(fail2);
807 fail1:
808         EFSYS_PROBE1(fail1, efx_rc_t, rc);
809
810         return (rc);
811 }
812
813         __checkReturn           efx_rc_t
814 efx_mcdi_nvram_update_finish(
815         __in                    efx_nic_t *enp,
816         __in                    uint32_t partn,
817         __in                    boolean_t reboot)
818 {
819         efx_mcdi_req_t req;
820         uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
821                             MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
822         efx_rc_t rc;
823
824         (void) memset(payload, 0, sizeof (payload));
825         req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
826         req.emr_in_buf = payload;
827         req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
828         req.emr_out_buf = payload;
829         req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
830
831         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
832         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
833
834         efx_mcdi_execute(enp, &req);
835
836         if (req.emr_rc != 0) {
837                 rc = req.emr_rc;
838                 goto fail1;
839         }
840
841         return (0);
842
843 fail1:
844         EFSYS_PROBE1(fail1, efx_rc_t, rc);
845
846         return (rc);
847 }
848
849 #if EFSYS_OPT_DIAG
850
851         __checkReturn           efx_rc_t
852 efx_mcdi_nvram_test(
853         __in                    efx_nic_t *enp,
854         __in                    uint32_t partn)
855 {
856         efx_mcdi_req_t req;
857         uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
858                             MC_CMD_NVRAM_TEST_OUT_LEN)];
859         int result;
860         efx_rc_t rc;
861
862         (void) memset(payload, 0, sizeof (payload));
863         req.emr_cmd = MC_CMD_NVRAM_TEST;
864         req.emr_in_buf = payload;
865         req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
866         req.emr_out_buf = payload;
867         req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
868
869         MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
870
871         efx_mcdi_execute(enp, &req);
872
873         if (req.emr_rc != 0) {
874                 rc = req.emr_rc;
875                 goto fail1;
876         }
877
878         if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
879                 rc = EMSGSIZE;
880                 goto fail2;
881         }
882
883         result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
884         if (result == MC_CMD_NVRAM_TEST_FAIL) {
885
886                 EFSYS_PROBE1(nvram_test_failure, int, partn);
887
888                 rc = (EINVAL);
889                 goto fail3;
890         }
891
892         return (0);
893
894 fail3:
895         EFSYS_PROBE(fail3);
896 fail2:
897         EFSYS_PROBE(fail2);
898 fail1:
899         EFSYS_PROBE1(fail1, efx_rc_t, rc);
900
901         return (rc);
902 }
903
904 #endif  /* EFSYS_OPT_DIAG */
905
906
907 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */