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