1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 __out_opt uint32_t *verify_resultp) 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 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, verify_resultp); 193 if (rc != 0) 194 goto fail1; 195 196 return (0); 197 198 fail1: 199 EFSYS_PROBE1(fail1, efx_rc_t, rc); 200 201 return (rc); 202 } 203 204 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 205 206 #if EFSYS_OPT_NVRAM 207 208 typedef struct siena_parttbl_entry_s { 209 unsigned int partn; 210 unsigned int port; 211 efx_nvram_type_t nvtype; 212 } siena_parttbl_entry_t; 213 214 static siena_parttbl_entry_t siena_parttbl[] = { 215 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 1, EFX_NVRAM_NULLPHY}, 216 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 2, EFX_NVRAM_NULLPHY}, 217 {MC_CMD_NVRAM_TYPE_MC_FW, 1, EFX_NVRAM_MC_FIRMWARE}, 218 {MC_CMD_NVRAM_TYPE_MC_FW, 2, EFX_NVRAM_MC_FIRMWARE}, 219 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 220 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 221 {MC_CMD_NVRAM_TYPE_EXP_ROM, 1, EFX_NVRAM_BOOTROM}, 222 {MC_CMD_NVRAM_TYPE_EXP_ROM, 2, EFX_NVRAM_BOOTROM}, 223 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 224 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 225 {MC_CMD_NVRAM_TYPE_PHY_PORT0, 1, EFX_NVRAM_PHY}, 226 {MC_CMD_NVRAM_TYPE_PHY_PORT1, 2, EFX_NVRAM_PHY}, 227 {MC_CMD_NVRAM_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 228 {MC_CMD_NVRAM_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 229 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 230 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 231 {MC_CMD_NVRAM_TYPE_FC_FW, 1, EFX_NVRAM_FCFW}, 232 {MC_CMD_NVRAM_TYPE_FC_FW, 2, EFX_NVRAM_FCFW}, 233 {MC_CMD_NVRAM_TYPE_CPLD, 1, EFX_NVRAM_CPLD}, 234 {MC_CMD_NVRAM_TYPE_CPLD, 2, EFX_NVRAM_CPLD}, 235 {MC_CMD_NVRAM_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 236 {MC_CMD_NVRAM_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE} 237 }; 238 239 __checkReturn efx_rc_t 240 siena_nvram_type_to_partn( 241 __in efx_nic_t *enp, 242 __in efx_nvram_type_t type, 243 __out uint32_t *partnp) 244 { 245 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 246 unsigned int i; 247 248 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 249 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 250 EFSYS_ASSERT(partnp != NULL); 251 252 for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 253 siena_parttbl_entry_t *entry = &siena_parttbl[i]; 254 255 if (entry->port == emip->emi_port && entry->nvtype == type) { 256 *partnp = entry->partn; 257 return (0); 258 } 259 } 260 261 return (ENOTSUP); 262 } 263 264 #if EFSYS_OPT_DIAG 265 266 __checkReturn efx_rc_t 267 siena_nvram_test( 268 __in efx_nic_t *enp) 269 { 270 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 271 siena_parttbl_entry_t *entry; 272 unsigned int i; 273 efx_rc_t rc; 274 275 /* 276 * Iterate over the list of supported partition types 277 * applicable to *this* port 278 */ 279 for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 280 entry = &siena_parttbl[i]; 281 282 if (entry->port != emip->emi_port || 283 !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 284 continue; 285 286 if ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) { 287 goto fail1; 288 } 289 } 290 291 return (0); 292 293 fail1: 294 EFSYS_PROBE1(fail1, efx_rc_t, rc); 295 296 return (rc); 297 } 298 299 #endif /* EFSYS_OPT_DIAG */ 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 if (size < SIENA_NVRAM_CHUNK) { 335 rc = EINVAL; 336 goto fail2; 337 } 338 339 EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 340 if (dcfg == NULL) { 341 rc = ENOMEM; 342 goto fail3; 343 } 344 345 if ((rc = siena_nvram_partn_read(enp, partn, 0, 346 (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 347 goto fail4; 348 349 /* Verify the magic */ 350 if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 351 != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 352 goto invalid1; 353 354 /* All future versions of the structure must be backwards compatible */ 355 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 356 357 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 358 nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 359 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 360 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 361 362 /* Verify the hdr doesn't overflow the partn size */ 363 if (hdr_length > size || vpd_offset > size || vpd_length > size || 364 vpd_length + vpd_offset > size) 365 goto invalid2; 366 367 /* Verify the header has room for all it's versions */ 368 if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 369 hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 370 goto invalid3; 371 372 /* 373 * Read the remaining portion of the dcfg, either including 374 * the whole of VPD (there is no vpd length in this structure, 375 * so we have to parse each tag), or just the dcfg header itself 376 */ 377 region = vpd ? vpd_offset + vpd_length : hdr_length; 378 if (region > SIENA_NVRAM_CHUNK) { 379 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 380 (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 381 region - SIENA_NVRAM_CHUNK)) != 0) 382 goto fail5; 383 } 384 385 /* Verify checksum */ 386 cksum = 0; 387 for (pos = 0; pos < hdr_length; pos++) 388 cksum += ((uint8_t *)dcfg)[pos]; 389 if (cksum != 0) 390 goto invalid4; 391 392 goto done; 393 394 invalid4: 395 EFSYS_PROBE(invalid4); 396 invalid3: 397 EFSYS_PROBE(invalid3); 398 invalid2: 399 EFSYS_PROBE(invalid2); 400 invalid1: 401 EFSYS_PROBE(invalid1); 402 403 /* 404 * Construct a new "null" dcfg, with an empty version vector, 405 * and an empty VPD chunk trailing. This has the neat side effect 406 * of testing the exception paths in the write path. 407 */ 408 EFX_POPULATE_DWORD_1(dcfg->magic, 409 EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 410 EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 411 EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 412 SIENA_MC_DYNAMIC_CONFIG_VERSION); 413 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 414 EFX_DWORD_0, sizeof (*dcfg)); 415 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 416 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 417 418 done: 419 *dcfgp = dcfg; 420 *sizep = size; 421 422 return (0); 423 424 fail5: 425 EFSYS_PROBE(fail5); 426 fail4: 427 EFSYS_PROBE(fail4); 428 429 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 430 431 fail3: 432 EFSYS_PROBE(fail3); 433 fail2: 434 EFSYS_PROBE(fail2); 435 fail1: 436 EFSYS_PROBE1(fail1, efx_rc_t, rc); 437 438 return (rc); 439 } 440 441 __checkReturn efx_rc_t 442 siena_nvram_get_subtype( 443 __in efx_nic_t *enp, 444 __in uint32_t partn, 445 __out uint32_t *subtypep) 446 { 447 efx_mcdi_req_t req; 448 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN, 449 MC_CMD_GET_BOARD_CFG_OUT_LENMAX); 450 efx_word_t *fw_list; 451 efx_rc_t rc; 452 453 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 454 req.emr_in_buf = payload; 455 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 456 req.emr_out_buf = payload; 457 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX; 458 459 efx_mcdi_execute(enp, &req); 460 461 if (req.emr_rc != 0) { 462 rc = req.emr_rc; 463 goto fail1; 464 } 465 466 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 467 rc = EMSGSIZE; 468 goto fail2; 469 } 470 471 if (req.emr_out_length_used < 472 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST + 473 (partn + 1) * sizeof (efx_word_t)) { 474 rc = ENOENT; 475 goto fail3; 476 } 477 478 fw_list = MCDI_OUT2(req, efx_word_t, 479 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 480 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 481 482 return (0); 483 484 fail3: 485 EFSYS_PROBE(fail3); 486 fail2: 487 EFSYS_PROBE(fail2); 488 fail1: 489 EFSYS_PROBE1(fail1, efx_rc_t, rc); 490 491 return (rc); 492 } 493 494 __checkReturn efx_rc_t 495 siena_nvram_partn_get_version( 496 __in efx_nic_t *enp, 497 __in uint32_t partn, 498 __out uint32_t *subtypep, 499 __out_ecount(4) uint16_t version[4]) 500 { 501 siena_mc_dynamic_config_hdr_t *dcfg; 502 siena_parttbl_entry_t *entry; 503 uint32_t dcfg_partn; 504 unsigned int i; 505 efx_rc_t rc; 506 507 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 508 rc = ENOTSUP; 509 goto fail1; 510 } 511 512 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 513 goto fail2; 514 515 /* 516 * Some partitions are accessible from both ports (for instance BOOTROM) 517 * Find the highest version reported by all dcfg structures on ports 518 * that have access to this partition. 519 */ 520 version[0] = version[1] = version[2] = version[3] = 0; 521 for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 522 siena_mc_fw_version_t *verp; 523 unsigned int nitems; 524 uint16_t temp[4]; 525 size_t length; 526 527 entry = &siena_parttbl[i]; 528 if (entry->partn != partn) 529 continue; 530 531 dcfg_partn = (entry->port == 1) 532 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 533 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 534 /* 535 * Ingore missing partitions on port 2, assuming they're due 536 * to running on a single port part. 537 */ 538 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 539 if (entry->port == 2) 540 continue; 541 } 542 543 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 544 B_FALSE, &dcfg, &length)) != 0) 545 goto fail3; 546 547 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 548 EFX_DWORD_0); 549 if (nitems < entry->partn) 550 goto done; 551 552 verp = &dcfg->fw_version[partn]; 553 temp[0] = EFX_WORD_FIELD(verp->version_w, EFX_WORD_0); 554 temp[1] = EFX_WORD_FIELD(verp->version_x, EFX_WORD_0); 555 temp[2] = EFX_WORD_FIELD(verp->version_y, EFX_WORD_0); 556 temp[3] = EFX_WORD_FIELD(verp->version_z, EFX_WORD_0); 557 if (memcmp(version, temp, sizeof (temp)) < 0) 558 memcpy(version, temp, sizeof (temp)); 559 560 done: 561 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 562 } 563 564 return (0); 565 566 fail3: 567 EFSYS_PROBE(fail3); 568 fail2: 569 EFSYS_PROBE(fail2); 570 fail1: 571 EFSYS_PROBE1(fail1, efx_rc_t, rc); 572 573 return (rc); 574 } 575 576 __checkReturn efx_rc_t 577 siena_nvram_partn_rw_start( 578 __in efx_nic_t *enp, 579 __in uint32_t partn, 580 __out size_t *chunk_sizep) 581 { 582 efx_rc_t rc; 583 584 if ((rc = siena_nvram_partn_lock(enp, partn)) != 0) 585 goto fail1; 586 587 if (chunk_sizep != NULL) 588 *chunk_sizep = SIENA_NVRAM_CHUNK; 589 590 return (0); 591 592 fail1: 593 EFSYS_PROBE1(fail1, efx_rc_t, rc); 594 595 return (rc); 596 } 597 598 __checkReturn efx_rc_t 599 siena_nvram_partn_rw_finish( 600 __in efx_nic_t *enp, 601 __in uint32_t partn, 602 __out_opt uint32_t *verify_resultp) 603 { 604 efx_rc_t rc; 605 606 if ((rc = siena_nvram_partn_unlock(enp, partn, verify_resultp)) != 0) 607 goto fail1; 608 609 return (0); 610 611 fail1: 612 EFSYS_PROBE1(fail1, efx_rc_t, rc); 613 614 return (rc); 615 } 616 617 __checkReturn efx_rc_t 618 siena_nvram_partn_set_version( 619 __in efx_nic_t *enp, 620 __in uint32_t partn, 621 __in_ecount(4) uint16_t version[4]) 622 { 623 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 624 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 625 siena_mc_fw_version_t *fwverp; 626 uint32_t dcfg_partn; 627 size_t dcfg_size; 628 unsigned int hdr_length; 629 unsigned int vpd_length; 630 unsigned int vpd_offset; 631 unsigned int nitems; 632 unsigned int required_hdr_length; 633 unsigned int pos; 634 uint8_t cksum; 635 uint32_t subtype; 636 size_t length; 637 efx_rc_t rc; 638 639 dcfg_partn = (emip->emi_port == 1) 640 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 641 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 642 643 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0) 644 goto fail1; 645 646 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 647 goto fail2; 648 649 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 650 B_TRUE, &dcfg, &length)) != 0) 651 goto fail3; 652 653 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 654 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 655 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 656 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 657 658 /* 659 * NOTE: This function will blatt any fields trailing the version 660 * vector, or the VPD chunk. 661 */ 662 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1); 663 if (required_hdr_length + vpd_length > length) { 664 rc = ENOSPC; 665 goto fail4; 666 } 667 668 if (vpd_offset < required_hdr_length) { 669 (void) memmove((caddr_t)dcfg + required_hdr_length, 670 (caddr_t)dcfg + vpd_offset, vpd_length); 671 vpd_offset = required_hdr_length; 672 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 673 EFX_DWORD_0, vpd_offset); 674 } 675 676 if (hdr_length < required_hdr_length) { 677 (void) memset((caddr_t)dcfg + hdr_length, 0, 678 required_hdr_length - hdr_length); 679 hdr_length = required_hdr_length; 680 EFX_POPULATE_WORD_1(dcfg->length, 681 EFX_WORD_0, hdr_length); 682 } 683 684 /* Get the subtype to insert into the fw_subtype array */ 685 if ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0) 686 goto fail5; 687 688 /* Fill out the new version */ 689 fwverp = &dcfg->fw_version[partn]; 690 EFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype); 691 EFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]); 692 EFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]); 693 EFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]); 694 EFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]); 695 696 /* Update the version count */ 697 if (nitems < partn + 1) { 698 nitems = partn + 1; 699 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 700 EFX_DWORD_0, nitems); 701 } 702 703 /* Update the checksum */ 704 cksum = 0; 705 for (pos = 0; pos < hdr_length; pos++) 706 cksum += ((uint8_t *)dcfg)[pos]; 707 dcfg->csum.eb_u8[0] -= cksum; 708 709 /* Erase and write the new partition */ 710 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0) 711 goto fail6; 712 713 /* Write out the new structure to nvram */ 714 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 715 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 716 goto fail7; 717 718 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 719 720 siena_nvram_partn_unlock(enp, dcfg_partn, NULL); 721 722 return (0); 723 724 fail7: 725 EFSYS_PROBE(fail7); 726 fail6: 727 EFSYS_PROBE(fail6); 728 fail5: 729 EFSYS_PROBE(fail5); 730 fail4: 731 EFSYS_PROBE(fail4); 732 733 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 734 fail3: 735 EFSYS_PROBE(fail3); 736 fail2: 737 EFSYS_PROBE(fail2); 738 fail1: 739 EFSYS_PROBE1(fail1, efx_rc_t, rc); 740 741 return (rc); 742 } 743 744 #endif /* EFSYS_OPT_NVRAM */ 745 746 #endif /* EFSYS_OPT_SIENA */ 747