]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/sfxge/common/siena_nvram.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / sfxge / common / siena_nvram.c
1 /*-
2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_types.h"
32 #include "efx_regs.h"
33 #include "efx_impl.h"
34
35 #if EFSYS_OPT_SIENA
36
37 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
38
39         __checkReturn           int
40 siena_nvram_partn_size(
41         __in                    efx_nic_t *enp,
42         __in                    unsigned int partn,
43         __out                   size_t *sizep)
44 {
45         efx_mcdi_req_t req;
46         uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
47                             MC_CMD_NVRAM_INFO_OUT_LEN)];
48         int rc;
49
50         if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
51                 rc = ENOTSUP;
52                 goto fail1;
53         }
54
55         req.emr_cmd = MC_CMD_NVRAM_INFO;
56         req.emr_in_buf = payload;
57         req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
58         req.emr_out_buf = payload;
59         req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
60
61         MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
62
63         efx_mcdi_execute(enp, &req);
64
65         if (req.emr_rc != 0) {
66                 rc = req.emr_rc;
67                 goto fail2;
68         }
69
70         if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
71                 rc = EMSGSIZE;
72                 goto fail3;
73         }
74
75         *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
76
77         return (0);
78
79 fail3:
80         EFSYS_PROBE(fail3);
81 fail2:
82         EFSYS_PROBE(fail2);
83 fail1:
84         EFSYS_PROBE1(fail1, int, rc);
85
86         return (rc);
87 }
88
89         __checkReturn           int
90 siena_nvram_partn_lock(
91         __in                    efx_nic_t *enp,
92         __in                    unsigned int partn)
93 {
94         efx_mcdi_req_t req;
95         uint8_t payload[MC_CMD_NVRAM_UPDATE_START_IN_LEN];
96         int rc;
97
98         req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
99         req.emr_in_buf = payload;
100         req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
101         EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_START_OUT_LEN == 0);
102         req.emr_out_buf = NULL;
103         req.emr_out_length = 0;
104
105         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
106
107         efx_mcdi_execute(enp, &req);
108
109         if (req.emr_rc != 0) {
110                 rc = req.emr_rc;
111                 goto fail1;
112         }
113
114         return (0);
115
116 fail1:
117         EFSYS_PROBE1(fail1, int, rc);
118
119         return (rc);
120 }
121
122         __checkReturn           int
123 siena_nvram_partn_read(
124         __in                    efx_nic_t *enp,
125         __in                    unsigned int partn,
126         __in                    unsigned int offset,
127         __out_bcount(size)      caddr_t data,
128         __in                    size_t size)
129 {
130         efx_mcdi_req_t req;
131         uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
132                             MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK))];
133         size_t chunk;
134         int rc;
135
136         while (size > 0) {
137                 chunk = MIN(size, SIENA_NVRAM_CHUNK);
138
139                 req.emr_cmd = MC_CMD_NVRAM_READ;
140                 req.emr_in_buf = payload;
141                 req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
142                 req.emr_out_buf = payload;
143                 req.emr_out_length =
144                         MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK);
145
146                 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
147                 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
148                 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, chunk);
149
150                 efx_mcdi_execute(enp, &req);
151
152                 if (req.emr_rc != 0) {
153                         rc = req.emr_rc;
154                         goto fail1;
155                 }
156
157                 if (req.emr_out_length_used <
158                     MC_CMD_NVRAM_READ_OUT_LEN(chunk)) {
159                         rc = EMSGSIZE;
160                         goto fail2;
161                 }
162
163                 memcpy(data,
164                     MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
165                     chunk);
166
167                 size -= chunk;
168                 data += chunk;
169                 offset += chunk;
170         }
171
172         return (0);
173
174 fail2:
175         EFSYS_PROBE(fail2);
176 fail1:
177         EFSYS_PROBE1(fail1, int, rc);
178
179         return (rc);
180 }
181
182         __checkReturn           int
183 siena_nvram_partn_erase(
184         __in                    efx_nic_t *enp,
185         __in                    unsigned int partn,
186         __in                    unsigned int offset,
187         __in                    size_t size)
188 {
189         efx_mcdi_req_t req;
190         uint8_t payload[MC_CMD_NVRAM_ERASE_IN_LEN];
191         int rc;
192
193         req.emr_cmd = MC_CMD_NVRAM_ERASE;
194         req.emr_in_buf = payload;
195         req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
196         EFX_STATIC_ASSERT(MC_CMD_NVRAM_ERASE_OUT_LEN == 0);
197         req.emr_out_buf = NULL;
198         req.emr_out_length = 0;
199
200         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
201         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
202         MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
203
204         efx_mcdi_execute(enp, &req);
205
206         if (req.emr_rc != 0) {
207                 rc = req.emr_rc;
208                 goto fail1;
209         }
210
211         return (0);
212
213 fail1:
214         EFSYS_PROBE1(fail1, int, rc);
215
216         return (rc);
217 }
218
219         __checkReturn           int
220 siena_nvram_partn_write(
221         __in                    efx_nic_t *enp,
222         __in                    unsigned int partn,
223         __in                    unsigned int offset,
224         __out_bcount(size)      caddr_t data,
225         __in                    size_t size)
226 {
227         efx_mcdi_req_t req;
228         uint8_t payload[MC_CMD_NVRAM_WRITE_IN_LEN(SIENA_NVRAM_CHUNK)];
229         size_t chunk;
230         int rc;
231
232         while (size > 0) {
233                 chunk = MIN(size, SIENA_NVRAM_CHUNK);
234
235                 req.emr_cmd = MC_CMD_NVRAM_WRITE;
236                 req.emr_in_buf = payload;
237                 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(chunk);
238                 EFX_STATIC_ASSERT(MC_CMD_NVRAM_WRITE_OUT_LEN == 0);
239                 req.emr_out_buf = NULL;
240                 req.emr_out_length = 0;
241
242                 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
243                 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
244                 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, chunk);
245
246                 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
247                     data, chunk);
248
249                 efx_mcdi_execute(enp, &req);
250
251                 if (req.emr_rc != 0) {
252                         rc = req.emr_rc;
253                         goto fail1;
254                 }
255
256                 size -= chunk;
257                 data += chunk;
258                 offset += chunk;
259         }
260
261         return (0);
262
263 fail1:
264         EFSYS_PROBE1(fail1, int, rc);
265
266         return (rc);
267 }
268
269                                 void
270 siena_nvram_partn_unlock(
271         __in                    efx_nic_t *enp,
272         __in                    unsigned int partn)
273 {
274         efx_mcdi_req_t req;
275         uint8_t payload[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN];
276         uint32_t reboot;
277         int rc;
278
279         req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
280         req.emr_in_buf = payload;
281         req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
282         EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN == 0);
283         req.emr_out_buf = NULL;
284         req.emr_out_length = 0;
285
286         /*
287          * Reboot into the new image only for PHYs. The driver has to
288          * explicitly cope with an MC reboot after a firmware update.
289          */
290         reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||
291                     partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
292                     partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
293
294         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
295         MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
296
297         efx_mcdi_execute(enp, &req);
298
299         if (req.emr_rc != 0) {
300                 rc = req.emr_rc;
301                 goto fail1;
302         }
303
304         return;
305
306 fail1:
307         EFSYS_PROBE1(fail1, int, rc);
308 }
309
310 #endif  /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
311
312 #if EFSYS_OPT_NVRAM
313
314 typedef struct siena_parttbl_entry_s {
315         unsigned int            partn;
316         unsigned int            port;
317         efx_nvram_type_t        nvtype;
318 } siena_parttbl_entry_t;
319
320 static siena_parttbl_entry_t siena_parttbl[] = {
321         {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,   1, EFX_NVRAM_NULLPHY},
322         {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,   2, EFX_NVRAM_NULLPHY},
323         {MC_CMD_NVRAM_TYPE_MC_FW,               1, EFX_NVRAM_MC_FIRMWARE},
324         {MC_CMD_NVRAM_TYPE_MC_FW,               2, EFX_NVRAM_MC_FIRMWARE},
325         {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,        1, EFX_NVRAM_MC_GOLDEN},
326         {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,        2, EFX_NVRAM_MC_GOLDEN},
327         {MC_CMD_NVRAM_TYPE_EXP_ROM,             1, EFX_NVRAM_BOOTROM},
328         {MC_CMD_NVRAM_TYPE_EXP_ROM,             2, EFX_NVRAM_BOOTROM},
329         {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0,   1, EFX_NVRAM_BOOTROM_CFG},
330         {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1,   2, EFX_NVRAM_BOOTROM_CFG},
331         {MC_CMD_NVRAM_TYPE_PHY_PORT0,           1, EFX_NVRAM_PHY},
332         {MC_CMD_NVRAM_TYPE_PHY_PORT1,           2, EFX_NVRAM_PHY},
333         {0, 0, 0},
334 };
335
336 static  __checkReturn           siena_parttbl_entry_t *
337 siena_parttbl_entry(
338         __in                    efx_nic_t *enp,
339         __in                    efx_nvram_type_t type)
340 {
341         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
342         siena_parttbl_entry_t *entry;
343
344         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
345
346         for (entry = siena_parttbl; entry->port > 0; ++entry) {
347                 if (entry->port == emip->emi_port && entry->nvtype == type)
348                         return (entry);
349         }
350
351         return (NULL);
352 }
353
354 #if EFSYS_OPT_DIAG
355
356         __checkReturn           int
357 siena_nvram_test(
358         __in                    efx_nic_t *enp)
359 {
360         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
361         siena_parttbl_entry_t *entry;
362         efx_mcdi_req_t req;
363         uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
364                             MC_CMD_NVRAM_TEST_OUT_LEN)];
365         int result;
366         int rc;
367
368         req.emr_cmd = MC_CMD_NVRAM_TEST;
369         req.emr_in_buf = payload;
370         req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
371         req.emr_out_buf = payload;
372         req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
373
374         /*
375          * Iterate over the list of supported partition types
376          * applicable to *this* port
377          */
378         for (entry = siena_parttbl; entry->port > 0; ++entry) {
379                 if (entry->port != emip->emi_port ||
380                     !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))
381                         continue;
382
383                 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn);
384
385                 efx_mcdi_execute(enp, &req);
386
387                 if (req.emr_rc != 0) {
388                         rc = req.emr_rc;
389                         goto fail1;
390                 }
391
392                 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
393                         rc = EMSGSIZE;
394                         goto fail2;
395                 }
396
397                 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
398                 if (result == MC_CMD_NVRAM_TEST_FAIL) {
399
400                         EFSYS_PROBE1(nvram_test_failure, int, entry->partn);
401
402                         rc = (EINVAL);
403                         goto fail3;
404                 }
405         }
406
407         return (0);
408
409 fail3:
410         EFSYS_PROBE(fail3);
411 fail2:
412         EFSYS_PROBE(fail2);
413 fail1:
414         EFSYS_PROBE1(fail1, int, rc);
415
416         return (rc);
417 }
418
419 #endif  /* EFSYS_OPT_DIAG */
420
421         __checkReturn           int
422 siena_nvram_size(
423         __in                    efx_nic_t *enp,
424         __in                    efx_nvram_type_t type,
425         __out                   size_t *sizep)
426 {
427         siena_parttbl_entry_t *entry;
428         int rc;
429
430         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
431                 rc = ENOTSUP;
432                 goto fail1;
433         }
434
435         if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0)
436                 goto fail2;
437
438         return (0);
439
440 fail2:
441         EFSYS_PROBE(fail2);
442 fail1:
443         EFSYS_PROBE1(fail1, int, rc);
444
445         *sizep = 0;
446
447         return (rc);
448 }
449
450 #define SIENA_DYNAMIC_CFG_SIZE(_nitems)                                 \
451         (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) *          \
452         sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))
453
454         __checkReturn           int
455 siena_nvram_get_dynamic_cfg(
456         __in                    efx_nic_t *enp,
457         __in                    unsigned int partn,
458         __in                    boolean_t vpd,
459         __out                   siena_mc_dynamic_config_hdr_t **dcfgp,
460         __out                   size_t *sizep)
461 {
462         siena_mc_dynamic_config_hdr_t *dcfg;
463         size_t size;
464         uint8_t cksum;
465         unsigned int vpd_offset;
466         unsigned int vpd_length;
467         unsigned int hdr_length;
468         unsigned int nversions;
469         unsigned int pos;
470         unsigned int region;
471         int rc;
472
473         EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 ||
474                     partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1);
475
476         /*
477          * Allocate sufficient memory for the entire dynamiccfg area, even
478          * if we're not actually going to read in the VPD.
479          */
480         if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
481                 goto fail1;
482
483         EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg);
484         if (dcfg == NULL) {
485                 rc = ENOMEM;
486                 goto fail2;
487         }
488
489         if ((rc = siena_nvram_partn_read(enp, partn, 0,
490             (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0)
491                 goto fail3;
492
493         /* Verify the magic */
494         if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0)
495             != SIENA_MC_DYNAMIC_CONFIG_MAGIC)
496                 goto invalid1;
497
498         /* All future versions of the structure must be backwards compatable */
499         EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0);
500
501         hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
502         nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
503         vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
504         vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
505
506         /* Verify the hdr doesn't overflow the partn size */
507         if (hdr_length > size || vpd_offset > size || vpd_length > size ||
508             vpd_length + vpd_offset > size)
509                 goto invalid2;
510
511         /* Verify the header has room for all it's versions */
512         if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) ||
513             hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions))
514                 goto invalid3;
515
516         /*
517          * Read the remaining portion of the dcfg, either including
518          * the whole of VPD (there is no vpd length in this structure,
519          * so we have to parse each tag), or just the dcfg header itself
520          */
521         region = vpd ? vpd_offset + vpd_length : hdr_length;
522         if (region > SIENA_NVRAM_CHUNK) {
523                 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
524                     (caddr_t)dcfg + SIENA_NVRAM_CHUNK,
525                     region - SIENA_NVRAM_CHUNK)) != 0)
526                         goto fail4;
527         }
528
529         /* Verify checksum */
530         cksum = 0;
531         for (pos = 0; pos < hdr_length; pos++)
532                 cksum += ((uint8_t *)dcfg)[pos];
533         if (cksum != 0)
534                 goto invalid4;
535
536         goto done;
537
538 invalid4:
539         EFSYS_PROBE(invalid4);
540 invalid3:
541         EFSYS_PROBE(invalid3);
542 invalid2:
543         EFSYS_PROBE(invalid2);
544 invalid1:
545         EFSYS_PROBE(invalid1);
546
547         /*
548          * Construct a new "null" dcfg, with an empty version vector,
549          * and an empty VPD chunk trailing. This has the neat side effect
550          * of testing the exception paths in the write path.
551          */
552         EFX_POPULATE_DWORD_1(dcfg->magic,
553                             EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC);
554         EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg));
555         EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0,
556                             SIENA_MC_DYNAMIC_CONFIG_VERSION);
557         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
558                             EFX_DWORD_0, sizeof (*dcfg));
559         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0);
560         EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0);
561
562 done:
563         *dcfgp = dcfg;
564         *sizep = size;
565
566         return (0);
567
568 fail4:
569         EFSYS_PROBE(fail4);
570 fail3:
571         EFSYS_PROBE(fail3);
572 fail2:
573         EFSYS_PROBE(fail2);
574
575         EFSYS_KMEM_FREE(enp->en_esip, size, dcfg);
576
577 fail1:
578         EFSYS_PROBE1(fail1, int, rc);
579
580         return (rc);
581 }
582
583 static  __checkReturn           int
584 siena_nvram_get_subtype(
585         __in                    efx_nic_t *enp,
586         __in                    unsigned int partn,
587         __out                   uint32_t *subtypep)
588 {
589         efx_mcdi_req_t req;
590         uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN];
591         efx_word_t *fw_list;
592         int rc;
593
594         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
595         EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0);
596         req.emr_in_buf = NULL;
597         req.emr_in_length = 0;
598         req.emr_out_buf = outbuf;
599         req.emr_out_length = sizeof (outbuf);
600
601         efx_mcdi_execute(enp, &req);
602
603         if (req.emr_rc != 0) {
604                 rc = req.emr_rc;
605                 goto fail1;
606         }
607
608         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LEN) {
609                 rc = EMSGSIZE;
610                 goto fail2;
611         }
612
613         fw_list = MCDI_OUT2(req, efx_word_t,
614                             GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
615         *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0);
616
617         return (0);
618
619 fail2:
620         EFSYS_PROBE(fail2);
621 fail1:
622         EFSYS_PROBE1(fail1, int, rc);
623
624         return (rc);
625 }
626
627         __checkReturn           int
628 siena_nvram_get_version(
629         __in                    efx_nic_t *enp,
630         __in                    efx_nvram_type_t type,
631         __out                   uint32_t *subtypep,
632         __out_ecount(4)         uint16_t version[4])
633 {
634         siena_mc_dynamic_config_hdr_t *dcfg;
635         siena_parttbl_entry_t *entry;
636         unsigned int dcfg_partn;
637         unsigned int partn;
638         int rc;
639
640         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
641                 rc = ENOTSUP;
642                 goto fail1;
643         }
644         partn = entry->partn;
645
646         if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
647                 rc = ENOTSUP;
648                 goto fail2;
649         }
650
651         if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0)
652                 goto fail3;
653
654         /*
655          * Some partitions are accessible from both ports (for instance BOOTROM)
656          * Find the highest version reported by all dcfg structures on ports
657          * that have access to this partition.
658          */
659         version[0] = version[1] = version[2] = version[3] = 0;
660         for (entry = siena_parttbl; entry->port > 0; ++entry) {
661                 unsigned int nitems;
662                 uint16_t temp[4];
663                 size_t length;
664
665                 if (entry->partn != partn)
666                         continue;
667
668                 dcfg_partn = (entry->port == 1)
669                         ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
670                         : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
671                 /*
672                  * Ingore missing partitions on port 2, assuming they're due
673                  * to to running on a single port part.
674                  */
675                 if ((1 << dcfg_partn) &  ~enp->en_u.siena.enu_partn_mask) {
676                         if (entry->port == 2)
677                                 continue;
678                 }
679
680                 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
681                     B_FALSE, &dcfg, &length)) != 0)
682                         goto fail4;
683
684                 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items,
685                             EFX_DWORD_0);
686                 if (nitems < entry->partn)
687                         goto done;
688
689                 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w,
690                             EFX_WORD_0);
691                 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x,
692                             EFX_WORD_0);
693                 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y,
694                             EFX_WORD_0);
695                 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z,
696                             EFX_WORD_0);
697                 if (memcmp(version, temp, sizeof (temp)) < 0)
698                         memcpy(version, temp, sizeof (temp));
699
700         done:
701                 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
702         }
703
704         return (0);
705
706 fail4:
707         EFSYS_PROBE(fail4);
708 fail3:
709         EFSYS_PROBE(fail3);
710 fail2:
711         EFSYS_PROBE(fail2);
712 fail1:
713         EFSYS_PROBE1(fail1, int, rc);
714
715         return (rc);
716 }
717
718         __checkReturn           int
719 siena_nvram_rw_start(
720         __in                    efx_nic_t *enp,
721         __in                    efx_nvram_type_t type,
722         __out                   size_t *chunk_sizep)
723 {
724         siena_parttbl_entry_t *entry;
725         int rc;
726
727         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
728                 rc = ENOTSUP;
729                 goto fail1;
730         }
731
732         if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0)
733                 goto fail2;
734
735         if (chunk_sizep != NULL)
736                 *chunk_sizep = SIENA_NVRAM_CHUNK;
737
738         return (0);
739
740 fail2:
741         EFSYS_PROBE(fail2);
742 fail1:
743         EFSYS_PROBE1(fail1, int, rc);
744
745         return (rc);
746 }
747
748         __checkReturn           int
749 siena_nvram_read_chunk(
750         __in                    efx_nic_t *enp,
751         __in                    efx_nvram_type_t type,
752         __in                    unsigned int offset,
753         __out_bcount(size)      caddr_t data,
754         __in                    size_t size)
755 {
756         siena_parttbl_entry_t *entry;
757         int rc;
758
759         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
760                 rc = ENOTSUP;
761                 goto fail1;
762         }
763
764         if ((rc = siena_nvram_partn_read(enp, entry->partn,
765             offset, data, size)) != 0)
766                 goto fail2;
767
768         return (0);
769
770 fail2:
771         EFSYS_PROBE(fail2);
772 fail1:
773         EFSYS_PROBE1(fail1, int, rc);
774
775         return (rc);
776 }
777
778         __checkReturn           int
779 siena_nvram_erase(
780         __in                    efx_nic_t *enp,
781         __in                    efx_nvram_type_t type)
782 {
783         siena_parttbl_entry_t *entry;
784         size_t size;
785         int rc;
786
787         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
788                 rc = ENOTSUP;
789                 goto fail1;
790         }
791
792         if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0)
793                 goto fail2;
794
795         if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0)
796                 goto fail3;
797
798         return (0);
799
800 fail3:
801         EFSYS_PROBE(fail3);
802 fail2:
803         EFSYS_PROBE(fail2);
804 fail1:
805         EFSYS_PROBE1(fail1, int, rc);
806
807         return (rc);
808 }
809
810         __checkReturn           int
811 siena_nvram_write_chunk(
812         __in                    efx_nic_t *enp,
813         __in                    efx_nvram_type_t type,
814         __in                    unsigned int offset,
815         __in_bcount(size)       caddr_t data,
816         __in                    size_t size)
817 {
818         siena_parttbl_entry_t *entry;
819         int rc;
820
821         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
822                 rc = ENOTSUP;
823                 goto fail1;
824         }
825
826         if ((rc = siena_nvram_partn_write(enp, entry->partn,
827             offset, data, size)) != 0)
828                 goto fail2;
829
830         return (0);
831
832 fail2:
833         EFSYS_PROBE(fail2);
834 fail1:
835         EFSYS_PROBE1(fail1, int, rc);
836
837         return (rc);
838 }
839
840                                 void
841 siena_nvram_rw_finish(
842         __in                    efx_nic_t *enp,
843         __in                    efx_nvram_type_t type)
844 {
845         siena_parttbl_entry_t *entry;
846
847         if ((entry = siena_parttbl_entry(enp, type)) != NULL)
848                 siena_nvram_partn_unlock(enp, entry->partn);
849 }
850
851         __checkReturn           int
852 siena_nvram_set_version(
853         __in                    efx_nic_t *enp,
854         __in                    efx_nvram_type_t type,
855         __out                   uint16_t version[4])
856 {
857         siena_mc_dynamic_config_hdr_t *dcfg = NULL;
858         siena_parttbl_entry_t *entry;
859         unsigned int dcfg_partn;
860         size_t partn_size;
861         unsigned int hdr_length;
862         unsigned int vpd_length;
863         unsigned int vpd_offset;
864         unsigned int nitems;
865         unsigned int required_hdr_length;
866         unsigned int pos;
867         uint8_t cksum;
868         uint32_t subtype;
869         size_t length;
870         int rc;
871
872         if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
873                 rc = ENOTSUP;
874                 goto fail1;
875         }
876
877         dcfg_partn = (entry->port == 1)
878                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
879                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
880
881         if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
882                 goto fail2;
883
884         if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
885                 goto fail2;
886
887         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
888             B_TRUE, &dcfg, &length)) != 0)
889                 goto fail3;
890
891         hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
892         nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
893         vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
894         vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
895
896         /*
897          * NOTE: This function will blatt any fields trailing the version
898          * vector, or the VPD chunk.
899          */
900         required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1);
901         if (required_hdr_length + vpd_length > length) {
902                 rc = ENOSPC;
903                 goto fail4;
904         }
905
906         if (vpd_offset < required_hdr_length) {
907                 (void) memmove((caddr_t)dcfg + required_hdr_length,
908                         (caddr_t)dcfg + vpd_offset, vpd_length);
909                 vpd_offset = required_hdr_length;
910                 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
911                                     EFX_DWORD_0, vpd_offset);
912         }
913
914         if (hdr_length < required_hdr_length) {
915                 (void) memset((caddr_t)dcfg + hdr_length, 0,
916                         required_hdr_length - hdr_length);
917                 hdr_length = required_hdr_length;
918                 EFX_POPULATE_WORD_1(dcfg->length,
919                                     EFX_WORD_0, hdr_length);
920         }
921
922         /* Get the subtype to insert into the fw_subtype array */
923         if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0)
924                 goto fail5;
925
926         /* Fill out the new version */
927         EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype,
928                             EFX_DWORD_0, subtype);
929         EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w,
930                             EFX_WORD_0, version[0]);
931         EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x,
932                             EFX_WORD_0, version[1]);
933         EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y,
934                             EFX_WORD_0, version[2]);
935         EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z,
936                             EFX_WORD_0, version[3]);
937
938         /* Update the version count */
939         if (nitems < entry->partn + 1) {
940                 nitems = entry->partn + 1;
941                 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items,
942                                     EFX_DWORD_0, nitems);
943         }
944
945         /* Update the checksum */
946         cksum = 0;
947         for (pos = 0; pos < hdr_length; pos++)
948                 cksum += ((uint8_t *)dcfg)[pos];
949         dcfg->csum.eb_u8[0] -= cksum;
950
951         /* Erase and write the new partition */
952         if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
953                 goto fail6;
954
955         /* Write out the new structure to nvram */
956         if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0,
957             (caddr_t)dcfg, vpd_offset + vpd_length)) != 0)
958                 goto fail7;
959
960         EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
961
962         siena_nvram_partn_unlock(enp, dcfg_partn);
963
964         return (0);
965
966 fail7:
967         EFSYS_PROBE(fail7);
968 fail6:
969         EFSYS_PROBE(fail6);
970 fail5:
971         EFSYS_PROBE(fail5);
972 fail4:
973         EFSYS_PROBE(fail4);
974
975         EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
976 fail3:
977         EFSYS_PROBE(fail3);
978 fail2:
979         EFSYS_PROBE(fail2);
980 fail1:
981         EFSYS_PROBE1(fail1, int, rc);
982
983         return (rc);
984 }
985
986 #endif  /* EFSYS_OPT_NVRAM */
987
988 #endif  /* EFSYS_OPT_SIENA */