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