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 {0, 0, 0}, 331 }; 332 333 static __checkReturn siena_parttbl_entry_t * 334 siena_parttbl_entry( 335 __in efx_nic_t *enp, 336 __in efx_nvram_type_t type) 337 { 338 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 339 siena_parttbl_entry_t *entry; 340 341 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 342 343 for (entry = siena_parttbl; entry->port > 0; ++entry) { 344 if (entry->port == emip->emi_port && entry->nvtype == type) 345 return (entry); 346 } 347 348 return (NULL); 349 } 350 351 #if EFSYS_OPT_DIAG 352 353 __checkReturn int 354 siena_nvram_test( 355 __in efx_nic_t *enp) 356 { 357 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 358 siena_parttbl_entry_t *entry; 359 efx_mcdi_req_t req; 360 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 361 MC_CMD_NVRAM_TEST_OUT_LEN)]; 362 int result; 363 int rc; 364 365 req.emr_cmd = MC_CMD_NVRAM_TEST; 366 req.emr_in_buf = payload; 367 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 368 req.emr_out_buf = payload; 369 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 370 371 /* 372 * Iterate over the list of supported partition types 373 * applicable to *this* port 374 */ 375 for (entry = siena_parttbl; entry->port > 0; ++entry) { 376 if (entry->port != emip->emi_port || 377 !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 378 continue; 379 380 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn); 381 382 efx_mcdi_execute(enp, &req); 383 384 if (req.emr_rc != 0) { 385 rc = req.emr_rc; 386 goto fail1; 387 } 388 389 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 390 rc = EMSGSIZE; 391 goto fail2; 392 } 393 394 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 395 if (result == MC_CMD_NVRAM_TEST_FAIL) { 396 397 EFSYS_PROBE1(nvram_test_failure, int, entry->partn); 398 399 rc = (EINVAL); 400 goto fail3; 401 } 402 } 403 404 return (0); 405 406 fail3: 407 EFSYS_PROBE(fail3); 408 fail2: 409 EFSYS_PROBE(fail2); 410 fail1: 411 EFSYS_PROBE1(fail1, int, rc); 412 413 return (rc); 414 } 415 416 #endif /* EFSYS_OPT_DIAG */ 417 418 __checkReturn int 419 siena_nvram_size( 420 __in efx_nic_t *enp, 421 __in efx_nvram_type_t type, 422 __out size_t *sizep) 423 { 424 siena_parttbl_entry_t *entry; 425 int rc; 426 427 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 428 rc = ENOTSUP; 429 goto fail1; 430 } 431 432 if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0) 433 goto fail2; 434 435 return (0); 436 437 fail2: 438 EFSYS_PROBE(fail2); 439 fail1: 440 EFSYS_PROBE1(fail1, int, rc); 441 442 *sizep = 0; 443 444 return (rc); 445 } 446 447 #define SIENA_DYNAMIC_CFG_SIZE(_nitems) \ 448 (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \ 449 sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0]))) 450 451 __checkReturn int 452 siena_nvram_get_dynamic_cfg( 453 __in efx_nic_t *enp, 454 __in unsigned int partn, 455 __in boolean_t vpd, 456 __out siena_mc_dynamic_config_hdr_t **dcfgp, 457 __out size_t *sizep) 458 { 459 siena_mc_dynamic_config_hdr_t *dcfg; 460 size_t size; 461 uint8_t cksum; 462 unsigned int vpd_offset; 463 unsigned int vpd_length; 464 unsigned int hdr_length; 465 unsigned int nversions; 466 unsigned int pos; 467 unsigned int region; 468 int rc; 469 470 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 || 471 partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1); 472 473 /* 474 * Allocate sufficient memory for the entire dynamiccfg area, even 475 * if we're not actually going to read in the VPD. 476 */ 477 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 478 goto fail1; 479 480 EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 481 if (dcfg == NULL) { 482 rc = ENOMEM; 483 goto fail2; 484 } 485 486 if ((rc = siena_nvram_partn_read(enp, partn, 0, 487 (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 488 goto fail3; 489 490 /* Verify the magic */ 491 if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 492 != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 493 goto invalid1; 494 495 /* All future versions of the structure must be backwards compatable */ 496 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 497 498 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 499 nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 500 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 501 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 502 503 /* Verify the hdr doesn't overflow the partn size */ 504 if (hdr_length > size || vpd_offset > size || vpd_length > size || 505 vpd_length + vpd_offset > size) 506 goto invalid2; 507 508 /* Verify the header has room for all it's versions */ 509 if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 510 hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 511 goto invalid3; 512 513 /* 514 * Read the remaining portion of the dcfg, either including 515 * the whole of VPD (there is no vpd length in this structure, 516 * so we have to parse each tag), or just the dcfg header itself 517 */ 518 region = vpd ? vpd_offset + vpd_length : hdr_length; 519 if (region > SIENA_NVRAM_CHUNK) { 520 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 521 (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 522 region - SIENA_NVRAM_CHUNK)) != 0) 523 goto fail4; 524 } 525 526 /* Verify checksum */ 527 cksum = 0; 528 for (pos = 0; pos < hdr_length; pos++) 529 cksum += ((uint8_t *)dcfg)[pos]; 530 if (cksum != 0) 531 goto invalid4; 532 533 goto done; 534 535 invalid4: 536 EFSYS_PROBE(invalid4); 537 invalid3: 538 EFSYS_PROBE(invalid3); 539 invalid2: 540 EFSYS_PROBE(invalid2); 541 invalid1: 542 EFSYS_PROBE(invalid1); 543 544 /* 545 * Construct a new "null" dcfg, with an empty version vector, 546 * and an empty VPD chunk trailing. This has the neat side effect 547 * of testing the exception paths in the write path. 548 */ 549 EFX_POPULATE_DWORD_1(dcfg->magic, 550 EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 551 EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 552 EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 553 SIENA_MC_DYNAMIC_CONFIG_VERSION); 554 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 555 EFX_DWORD_0, sizeof (*dcfg)); 556 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 557 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 558 559 done: 560 *dcfgp = dcfg; 561 *sizep = size; 562 563 return (0); 564 565 fail4: 566 EFSYS_PROBE(fail4); 567 fail3: 568 EFSYS_PROBE(fail3); 569 fail2: 570 EFSYS_PROBE(fail2); 571 572 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 573 574 fail1: 575 EFSYS_PROBE1(fail1, int, rc); 576 577 return (rc); 578 } 579 580 static __checkReturn int 581 siena_nvram_get_subtype( 582 __in efx_nic_t *enp, 583 __in unsigned int partn, 584 __out uint32_t *subtypep) 585 { 586 efx_mcdi_req_t req; 587 uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; 588 efx_word_t *fw_list; 589 int rc; 590 591 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 592 EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0); 593 req.emr_in_buf = NULL; 594 req.emr_in_length = 0; 595 req.emr_out_buf = outbuf; 596 req.emr_out_length = sizeof (outbuf); 597 598 efx_mcdi_execute(enp, &req); 599 600 if (req.emr_rc != 0) { 601 rc = req.emr_rc; 602 goto fail1; 603 } 604 605 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LEN) { 606 rc = EMSGSIZE; 607 goto fail2; 608 } 609 610 fw_list = MCDI_OUT2(req, efx_word_t, 611 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 612 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 613 614 return (0); 615 616 fail2: 617 EFSYS_PROBE(fail2); 618 fail1: 619 EFSYS_PROBE1(fail1, int, rc); 620 621 return (rc); 622 } 623 624 __checkReturn int 625 siena_nvram_get_version( 626 __in efx_nic_t *enp, 627 __in efx_nvram_type_t type, 628 __out uint32_t *subtypep, 629 __out_ecount(4) uint16_t version[4]) 630 { 631 siena_mc_dynamic_config_hdr_t *dcfg; 632 siena_parttbl_entry_t *entry; 633 unsigned int dcfg_partn; 634 unsigned int partn; 635 int rc; 636 637 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 638 rc = ENOTSUP; 639 goto fail1; 640 } 641 partn = entry->partn; 642 643 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 644 rc = ENOTSUP; 645 goto fail2; 646 } 647 648 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 649 goto fail3; 650 651 /* 652 * Some partitions are accessible from both ports (for instance BOOTROM) 653 * Find the highest version reported by all dcfg structures on ports 654 * that have access to this partition. 655 */ 656 version[0] = version[1] = version[2] = version[3] = 0; 657 for (entry = siena_parttbl; entry->port > 0; ++entry) { 658 unsigned int nitems; 659 uint16_t temp[4]; 660 size_t length; 661 662 if (entry->partn != partn) 663 continue; 664 665 dcfg_partn = (entry->port == 1) 666 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 667 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 668 /* 669 * Ingore missing partitions on port 2, assuming they're due 670 * to to running on a single port part. 671 */ 672 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 673 if (entry->port == 2) 674 continue; 675 } 676 677 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 678 B_FALSE, &dcfg, &length)) != 0) 679 goto fail4; 680 681 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 682 EFX_DWORD_0); 683 if (nitems < entry->partn) 684 goto done; 685 686 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 687 EFX_WORD_0); 688 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 689 EFX_WORD_0); 690 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 691 EFX_WORD_0); 692 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 693 EFX_WORD_0); 694 if (memcmp(version, temp, sizeof (temp)) < 0) 695 memcpy(version, temp, sizeof (temp)); 696 697 done: 698 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 699 } 700 701 return (0); 702 703 fail4: 704 EFSYS_PROBE(fail4); 705 fail3: 706 EFSYS_PROBE(fail3); 707 fail2: 708 EFSYS_PROBE(fail2); 709 fail1: 710 EFSYS_PROBE1(fail1, int, rc); 711 712 return (rc); 713 } 714 715 __checkReturn int 716 siena_nvram_rw_start( 717 __in efx_nic_t *enp, 718 __in efx_nvram_type_t type, 719 __out size_t *chunk_sizep) 720 { 721 siena_parttbl_entry_t *entry; 722 int rc; 723 724 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 725 rc = ENOTSUP; 726 goto fail1; 727 } 728 729 if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0) 730 goto fail2; 731 732 if (chunk_sizep != NULL) 733 *chunk_sizep = SIENA_NVRAM_CHUNK; 734 735 return (0); 736 737 fail2: 738 EFSYS_PROBE(fail2); 739 fail1: 740 EFSYS_PROBE1(fail1, int, rc); 741 742 return (rc); 743 } 744 745 __checkReturn int 746 siena_nvram_read_chunk( 747 __in efx_nic_t *enp, 748 __in efx_nvram_type_t type, 749 __in unsigned int offset, 750 __out_bcount(size) caddr_t data, 751 __in size_t size) 752 { 753 siena_parttbl_entry_t *entry; 754 int rc; 755 756 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 757 rc = ENOTSUP; 758 goto fail1; 759 } 760 761 if ((rc = siena_nvram_partn_read(enp, entry->partn, 762 offset, data, size)) != 0) 763 goto fail2; 764 765 return (0); 766 767 fail2: 768 EFSYS_PROBE(fail2); 769 fail1: 770 EFSYS_PROBE1(fail1, int, rc); 771 772 return (rc); 773 } 774 775 __checkReturn int 776 siena_nvram_erase( 777 __in efx_nic_t *enp, 778 __in efx_nvram_type_t type) 779 { 780 siena_parttbl_entry_t *entry; 781 size_t size; 782 int rc; 783 784 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 785 rc = ENOTSUP; 786 goto fail1; 787 } 788 789 if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0) 790 goto fail2; 791 792 if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0) 793 goto fail3; 794 795 return (0); 796 797 fail3: 798 EFSYS_PROBE(fail3); 799 fail2: 800 EFSYS_PROBE(fail2); 801 fail1: 802 EFSYS_PROBE1(fail1, int, rc); 803 804 return (rc); 805 } 806 807 __checkReturn int 808 siena_nvram_write_chunk( 809 __in efx_nic_t *enp, 810 __in efx_nvram_type_t type, 811 __in unsigned int offset, 812 __in_bcount(size) caddr_t data, 813 __in size_t size) 814 { 815 siena_parttbl_entry_t *entry; 816 int rc; 817 818 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 819 rc = ENOTSUP; 820 goto fail1; 821 } 822 823 if ((rc = siena_nvram_partn_write(enp, entry->partn, 824 offset, data, size)) != 0) 825 goto fail2; 826 827 return (0); 828 829 fail2: 830 EFSYS_PROBE(fail2); 831 fail1: 832 EFSYS_PROBE1(fail1, int, rc); 833 834 return (rc); 835 } 836 837 void 838 siena_nvram_rw_finish( 839 __in efx_nic_t *enp, 840 __in efx_nvram_type_t type) 841 { 842 siena_parttbl_entry_t *entry; 843 844 if ((entry = siena_parttbl_entry(enp, type)) != NULL) 845 siena_nvram_partn_unlock(enp, entry->partn); 846 } 847 848 __checkReturn int 849 siena_nvram_set_version( 850 __in efx_nic_t *enp, 851 __in efx_nvram_type_t type, 852 __out uint16_t version[4]) 853 { 854 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 855 siena_parttbl_entry_t *entry; 856 unsigned int dcfg_partn; 857 size_t partn_size; 858 unsigned int hdr_length; 859 unsigned int vpd_length; 860 unsigned int vpd_offset; 861 unsigned int nitems; 862 unsigned int required_hdr_length; 863 unsigned int pos; 864 uint8_t cksum; 865 uint32_t subtype; 866 size_t length; 867 int rc; 868 869 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 870 rc = ENOTSUP; 871 goto fail1; 872 } 873 874 dcfg_partn = (entry->port == 1) 875 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 876 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 877 878 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 879 goto fail2; 880 881 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 882 goto fail2; 883 884 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 885 B_TRUE, &dcfg, &length)) != 0) 886 goto fail3; 887 888 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 889 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 890 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 891 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 892 893 /* 894 * NOTE: This function will blatt any fields trailing the version 895 * vector, or the VPD chunk. 896 */ 897 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1); 898 if (required_hdr_length + vpd_length > length) { 899 rc = ENOSPC; 900 goto fail4; 901 } 902 903 if (vpd_offset < required_hdr_length) { 904 (void) memmove((caddr_t)dcfg + required_hdr_length, 905 (caddr_t)dcfg + vpd_offset, vpd_length); 906 vpd_offset = required_hdr_length; 907 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 908 EFX_DWORD_0, vpd_offset); 909 } 910 911 if (hdr_length < required_hdr_length) { 912 (void) memset((caddr_t)dcfg + hdr_length, 0, 913 required_hdr_length - hdr_length); 914 hdr_length = required_hdr_length; 915 EFX_POPULATE_WORD_1(dcfg->length, 916 EFX_WORD_0, hdr_length); 917 } 918 919 /* Get the subtype to insert into the fw_subtype array */ 920 if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0) 921 goto fail5; 922 923 /* Fill out the new version */ 924 EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype, 925 EFX_DWORD_0, subtype); 926 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w, 927 EFX_WORD_0, version[0]); 928 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x, 929 EFX_WORD_0, version[1]); 930 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y, 931 EFX_WORD_0, version[2]); 932 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z, 933 EFX_WORD_0, version[3]); 934 935 /* Update the version count */ 936 if (nitems < entry->partn + 1) { 937 nitems = entry->partn + 1; 938 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 939 EFX_DWORD_0, nitems); 940 } 941 942 /* Update the checksum */ 943 cksum = 0; 944 for (pos = 0; pos < hdr_length; pos++) 945 cksum += ((uint8_t *)dcfg)[pos]; 946 dcfg->csum.eb_u8[0] -= cksum; 947 948 /* Erase and write the new partition */ 949 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 950 goto fail6; 951 952 /* Write out the new structure to nvram */ 953 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 954 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 955 goto fail7; 956 957 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 958 959 siena_nvram_partn_unlock(enp, dcfg_partn); 960 961 return (0); 962 963 fail7: 964 EFSYS_PROBE(fail7); 965 fail6: 966 EFSYS_PROBE(fail6); 967 fail5: 968 EFSYS_PROBE(fail5); 969 fail4: 970 EFSYS_PROBE(fail4); 971 972 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 973 fail3: 974 EFSYS_PROBE(fail3); 975 fail2: 976 EFSYS_PROBE(fail2); 977 fail1: 978 EFSYS_PROBE1(fail1, int, rc); 979 980 return (rc); 981 } 982 983 #endif /* EFSYS_OPT_NVRAM */ 984 985 #endif /* EFSYS_OPT_SIENA */ 986