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