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 */