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