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