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