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 40siena_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 79fail3: 80 EFSYS_PROBE(fail3); 81fail2: 82 EFSYS_PROBE(fail2); 83fail1: 84 EFSYS_PROBE1(fail1, int, rc); 85 86 return (rc); 87} 88 89 __checkReturn int 90siena_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 116fail1: 117 EFSYS_PROBE1(fail1, int, rc); 118 119 return (rc); 120} 121 122 __checkReturn int 123siena_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 174fail2: 175 EFSYS_PROBE(fail2); 176fail1: 177 EFSYS_PROBE1(fail1, int, rc); 178 179 return (rc); 180} 181 182 __checkReturn int 183siena_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 213fail1: 214 EFSYS_PROBE1(fail1, int, rc); 215 216 return (rc); 217} 218 219 __checkReturn int 220siena_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 263fail1: 264 EFSYS_PROBE1(fail1, int, rc); 265 266 return (rc); 267} 268 269 void 270siena_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 306fail1: 307 EFSYS_PROBE1(fail1, int, rc); 308} 309 310#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 311 312#if EFSYS_OPT_NVRAM 313 314typedef 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 320static 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 336static __checkReturn siena_parttbl_entry_t * 337siena_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 357siena_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 409fail3: 410 EFSYS_PROBE(fail3); 411fail2: 412 EFSYS_PROBE(fail2); 413fail1: 414 EFSYS_PROBE1(fail1, int, rc); 415 416 return (rc); 417} 418 419#endif /* EFSYS_OPT_DIAG */ 420 421 __checkReturn int 422siena_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 440fail2: 441 EFSYS_PROBE(fail2); 442fail1: 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 455siena_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 538invalid4: 539 EFSYS_PROBE(invalid4); 540invalid3: 541 EFSYS_PROBE(invalid3); 542invalid2: 543 EFSYS_PROBE(invalid2); 544invalid1: 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 562done: 563 *dcfgp = dcfg; 564 *sizep = size; 565 566 return (0); 567 568fail4: 569 EFSYS_PROBE(fail4); 570fail3: 571 EFSYS_PROBE(fail3); 572fail2: 573 EFSYS_PROBE(fail2); 574 575 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 576 577fail1: 578 EFSYS_PROBE1(fail1, int, rc); 579 580 return (rc); 581} 582 583static __checkReturn int 584siena_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_LENMAX]; 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_LENMIN) { 609 rc = EMSGSIZE; 610 goto fail2; 611 } 612 613 if (req.emr_out_length_used < 614 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST +
|
616 rc = ENOENT; 617 goto fail3; 618 } 619 620 fw_list = MCDI_OUT2(req, efx_word_t, 621 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 622 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 623 624 return (0); 625 626fail3: 627 EFSYS_PROBE(fail3); 628fail2: 629 EFSYS_PROBE(fail2); 630fail1: 631 EFSYS_PROBE1(fail1, int, rc); 632 633 return (rc); 634} 635 636 __checkReturn int 637siena_nvram_get_version( 638 __in efx_nic_t *enp, 639 __in efx_nvram_type_t type, 640 __out uint32_t *subtypep, 641 __out_ecount(4) uint16_t version[4]) 642{ 643 siena_mc_dynamic_config_hdr_t *dcfg; 644 siena_parttbl_entry_t *entry; 645 unsigned int dcfg_partn; 646 unsigned int partn; 647 int rc; 648 649 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 650 rc = ENOTSUP; 651 goto fail1; 652 } 653 partn = entry->partn; 654 655 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 656 rc = ENOTSUP; 657 goto fail2; 658 } 659 660 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 661 goto fail3; 662 663 /* 664 * Some partitions are accessible from both ports (for instance BOOTROM) 665 * Find the highest version reported by all dcfg structures on ports 666 * that have access to this partition. 667 */ 668 version[0] = version[1] = version[2] = version[3] = 0; 669 for (entry = siena_parttbl; entry->port > 0; ++entry) { 670 unsigned int nitems; 671 uint16_t temp[4]; 672 size_t length; 673 674 if (entry->partn != partn) 675 continue; 676 677 dcfg_partn = (entry->port == 1) 678 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 679 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 680 /* 681 * Ingore missing partitions on port 2, assuming they're due 682 * to to running on a single port part. 683 */ 684 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 685 if (entry->port == 2) 686 continue; 687 } 688 689 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 690 B_FALSE, &dcfg, &length)) != 0) 691 goto fail4; 692 693 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 694 EFX_DWORD_0); 695 if (nitems < entry->partn) 696 goto done; 697 698 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 699 EFX_WORD_0); 700 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 701 EFX_WORD_0); 702 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 703 EFX_WORD_0); 704 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 705 EFX_WORD_0); 706 if (memcmp(version, temp, sizeof (temp)) < 0) 707 memcpy(version, temp, sizeof (temp)); 708 709 done: 710 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 711 } 712 713 return (0); 714 715fail4: 716 EFSYS_PROBE(fail4); 717fail3: 718 EFSYS_PROBE(fail3); 719fail2: 720 EFSYS_PROBE(fail2); 721fail1: 722 EFSYS_PROBE1(fail1, int, rc); 723 724 return (rc); 725} 726 727 __checkReturn int 728siena_nvram_rw_start( 729 __in efx_nic_t *enp, 730 __in efx_nvram_type_t type, 731 __out size_t *chunk_sizep) 732{ 733 siena_parttbl_entry_t *entry; 734 int rc; 735 736 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 737 rc = ENOTSUP; 738 goto fail1; 739 } 740 741 if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0) 742 goto fail2; 743 744 if (chunk_sizep != NULL) 745 *chunk_sizep = SIENA_NVRAM_CHUNK; 746 747 return (0); 748 749fail2: 750 EFSYS_PROBE(fail2); 751fail1: 752 EFSYS_PROBE1(fail1, int, rc); 753 754 return (rc); 755} 756 757 __checkReturn int 758siena_nvram_read_chunk( 759 __in efx_nic_t *enp, 760 __in efx_nvram_type_t type, 761 __in unsigned int offset, 762 __out_bcount(size) caddr_t data, 763 __in size_t size) 764{ 765 siena_parttbl_entry_t *entry; 766 int rc; 767 768 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 769 rc = ENOTSUP; 770 goto fail1; 771 } 772 773 if ((rc = siena_nvram_partn_read(enp, entry->partn, 774 offset, data, size)) != 0) 775 goto fail2; 776 777 return (0); 778 779fail2: 780 EFSYS_PROBE(fail2); 781fail1: 782 EFSYS_PROBE1(fail1, int, rc); 783 784 return (rc); 785} 786 787 __checkReturn int 788siena_nvram_erase( 789 __in efx_nic_t *enp, 790 __in efx_nvram_type_t type) 791{ 792 siena_parttbl_entry_t *entry; 793 size_t size; 794 int rc; 795 796 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 797 rc = ENOTSUP; 798 goto fail1; 799 } 800 801 if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0) 802 goto fail2; 803 804 if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0) 805 goto fail3; 806 807 return (0); 808 809fail3: 810 EFSYS_PROBE(fail3); 811fail2: 812 EFSYS_PROBE(fail2); 813fail1: 814 EFSYS_PROBE1(fail1, int, rc); 815 816 return (rc); 817} 818 819 __checkReturn int 820siena_nvram_write_chunk( 821 __in efx_nic_t *enp, 822 __in efx_nvram_type_t type, 823 __in unsigned int offset, 824 __in_bcount(size) caddr_t data, 825 __in size_t size) 826{ 827 siena_parttbl_entry_t *entry; 828 int rc; 829 830 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 831 rc = ENOTSUP; 832 goto fail1; 833 } 834 835 if ((rc = siena_nvram_partn_write(enp, entry->partn, 836 offset, data, size)) != 0) 837 goto fail2; 838 839 return (0); 840 841fail2: 842 EFSYS_PROBE(fail2); 843fail1: 844 EFSYS_PROBE1(fail1, int, rc); 845 846 return (rc); 847} 848 849 void 850siena_nvram_rw_finish( 851 __in efx_nic_t *enp, 852 __in efx_nvram_type_t type) 853{ 854 siena_parttbl_entry_t *entry; 855 856 if ((entry = siena_parttbl_entry(enp, type)) != NULL) 857 siena_nvram_partn_unlock(enp, entry->partn); 858} 859 860 __checkReturn int 861siena_nvram_set_version( 862 __in efx_nic_t *enp, 863 __in efx_nvram_type_t type, 864 __out uint16_t version[4]) 865{ 866 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 867 siena_parttbl_entry_t *entry; 868 unsigned int dcfg_partn; 869 size_t partn_size; 870 unsigned int hdr_length; 871 unsigned int vpd_length; 872 unsigned int vpd_offset; 873 unsigned int nitems; 874 unsigned int required_hdr_length; 875 unsigned int pos; 876 uint8_t cksum; 877 uint32_t subtype; 878 size_t length; 879 int rc; 880 881 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 882 rc = ENOTSUP; 883 goto fail1; 884 } 885 886 dcfg_partn = (entry->port == 1) 887 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 888 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 889 890 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 891 goto fail2; 892 893 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 894 goto fail2; 895 896 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 897 B_TRUE, &dcfg, &length)) != 0) 898 goto fail3; 899 900 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 901 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 902 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 903 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 904 905 /* 906 * NOTE: This function will blatt any fields trailing the version 907 * vector, or the VPD chunk. 908 */ 909 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1); 910 if (required_hdr_length + vpd_length > length) { 911 rc = ENOSPC; 912 goto fail4; 913 } 914 915 if (vpd_offset < required_hdr_length) { 916 (void) memmove((caddr_t)dcfg + required_hdr_length, 917 (caddr_t)dcfg + vpd_offset, vpd_length); 918 vpd_offset = required_hdr_length; 919 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 920 EFX_DWORD_0, vpd_offset); 921 } 922 923 if (hdr_length < required_hdr_length) { 924 (void) memset((caddr_t)dcfg + hdr_length, 0, 925 required_hdr_length - hdr_length); 926 hdr_length = required_hdr_length; 927 EFX_POPULATE_WORD_1(dcfg->length, 928 EFX_WORD_0, hdr_length); 929 } 930 931 /* Get the subtype to insert into the fw_subtype array */ 932 if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0) 933 goto fail5; 934 935 /* Fill out the new version */ 936 EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype, 937 EFX_DWORD_0, subtype); 938 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w, 939 EFX_WORD_0, version[0]); 940 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x, 941 EFX_WORD_0, version[1]); 942 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y, 943 EFX_WORD_0, version[2]); 944 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z, 945 EFX_WORD_0, version[3]); 946 947 /* Update the version count */ 948 if (nitems < entry->partn + 1) { 949 nitems = entry->partn + 1; 950 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 951 EFX_DWORD_0, nitems); 952 } 953 954 /* Update the checksum */ 955 cksum = 0; 956 for (pos = 0; pos < hdr_length; pos++) 957 cksum += ((uint8_t *)dcfg)[pos]; 958 dcfg->csum.eb_u8[0] -= cksum; 959 960 /* Erase and write the new partition */ 961 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 962 goto fail6; 963 964 /* Write out the new structure to nvram */ 965 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 966 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 967 goto fail7; 968 969 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 970 971 siena_nvram_partn_unlock(enp, dcfg_partn); 972 973 return (0); 974 975fail7: 976 EFSYS_PROBE(fail7); 977fail6: 978 EFSYS_PROBE(fail6); 979fail5: 980 EFSYS_PROBE(fail5); 981fail4: 982 EFSYS_PROBE(fail4); 983 984 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 985fail3: 986 EFSYS_PROBE(fail3); 987fail2: 988 EFSYS_PROBE(fail2); 989fail1: 990 EFSYS_PROBE1(fail1, int, rc); 991 992 return (rc); 993} 994 995#endif /* EFSYS_OPT_NVRAM */ 996 997#endif /* EFSYS_OPT_SIENA */
|