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 44siena_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 63fail2: 64 EFSYS_PROBE(fail2); 65fail1: 66 EFSYS_PROBE1(fail1, efx_rc_t, rc); 67 68 return (rc); 69} 70 71 __checkReturn efx_rc_t 72siena_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 84fail1: 85 EFSYS_PROBE1(fail1, efx_rc_t, rc); 86 87 return (rc); 88} 89 90 __checkReturn efx_rc_t 91siena_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 116fail1: 117 EFSYS_PROBE1(fail1, efx_rc_t, rc); 118 119 return (rc); 120} 121 122 __checkReturn efx_rc_t 123siena_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 137fail1: 138 EFSYS_PROBE1(fail1, efx_rc_t, rc); 139 140 return (rc); 141} 142 143 __checkReturn efx_rc_t 144siena_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 169fail1: 170 EFSYS_PROBE1(fail1, efx_rc_t, rc); 171 172 return (rc); 173} 174 175 __checkReturn efx_rc_t 176siena_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 197fail1: 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 207typedef 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 213static 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 239siena_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 266siena_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 292fail1: 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 306siena_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 389invalid4: 390 EFSYS_PROBE(invalid4); 391invalid3: 392 EFSYS_PROBE(invalid3); 393invalid2: 394 EFSYS_PROBE(invalid2); 395invalid1: 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 413done: 414 *dcfgp = dcfg; 415 *sizep = size; 416 417 return (0); 418 419fail4: 420 EFSYS_PROBE(fail4); 421fail3: 422 EFSYS_PROBE(fail3); 423 424 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 425 426fail2: 427 EFSYS_PROBE(fail2); 428fail1: 429 EFSYS_PROBE1(fail1, efx_rc_t, rc); 430 431 return (rc); 432} 433 434 __checkReturn efx_rc_t 435siena_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 EFX_MCDI_DECLARE_BUF(payload, 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 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 447 req.emr_in_buf = payload; 448 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 449 req.emr_out_buf = payload; 450 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX; 451 452 efx_mcdi_execute(enp, &req); 453 454 if (req.emr_rc != 0) { 455 rc = req.emr_rc; 456 goto fail1; 457 } 458 459 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 460 rc = EMSGSIZE; 461 goto fail2; 462 } 463 464 if (req.emr_out_length_used < 465 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST + 466 (partn + 1) * sizeof (efx_word_t)) { 467 rc = ENOENT; 468 goto fail3; 469 } 470 471 fw_list = MCDI_OUT2(req, efx_word_t, 472 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 473 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 474 475 return (0); 476 477fail3: 478 EFSYS_PROBE(fail3); 479fail2: 480 EFSYS_PROBE(fail2); 481fail1: 482 EFSYS_PROBE1(fail1, efx_rc_t, rc); 483 484 return (rc); 485} 486 487 __checkReturn efx_rc_t 488siena_nvram_partn_get_version( 489 __in efx_nic_t *enp, 490 __in uint32_t partn, 491 __out uint32_t *subtypep, 492 __out_ecount(4) uint16_t version[4]) 493{ 494 siena_mc_dynamic_config_hdr_t *dcfg; 495 siena_parttbl_entry_t *entry; 496 uint32_t dcfg_partn; 497 unsigned int i; 498 efx_rc_t rc; 499 500 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 501 rc = ENOTSUP; 502 goto fail1; 503 } 504 505 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 506 goto fail2; 507 508 /* 509 * Some partitions are accessible from both ports (for instance BOOTROM) 510 * Find the highest version reported by all dcfg structures on ports 511 * that have access to this partition. 512 */ 513 version[0] = version[1] = version[2] = version[3] = 0; 514 for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 515 siena_mc_fw_version_t *verp; 516 unsigned int nitems; 517 uint16_t temp[4]; 518 size_t length; 519 520 entry = &siena_parttbl[i]; 521 if (entry->partn != partn) 522 continue; 523 524 dcfg_partn = (entry->port == 1) 525 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 526 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 527 /* 528 * Ingore missing partitions on port 2, assuming they're due 529 * to running on a single port part. 530 */ 531 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 532 if (entry->port == 2) 533 continue; 534 } 535 536 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 537 B_FALSE, &dcfg, &length)) != 0) 538 goto fail3; 539 540 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 541 EFX_DWORD_0); 542 if (nitems < entry->partn) 543 goto done; 544 545 verp = &dcfg->fw_version[partn]; 546 temp[0] = EFX_WORD_FIELD(verp->version_w, EFX_WORD_0); 547 temp[1] = EFX_WORD_FIELD(verp->version_x, EFX_WORD_0); 548 temp[2] = EFX_WORD_FIELD(verp->version_y, EFX_WORD_0); 549 temp[3] = EFX_WORD_FIELD(verp->version_z, EFX_WORD_0); 550 if (memcmp(version, temp, sizeof (temp)) < 0) 551 memcpy(version, temp, sizeof (temp)); 552 553done: 554 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 555 } 556 557 return (0); 558 559fail3: 560 EFSYS_PROBE(fail3); 561fail2: 562 EFSYS_PROBE(fail2); 563fail1: 564 EFSYS_PROBE1(fail1, efx_rc_t, rc); 565 566 return (rc); 567} 568 569 __checkReturn efx_rc_t 570siena_nvram_partn_rw_start( 571 __in efx_nic_t *enp, 572 __in uint32_t partn, 573 __out size_t *chunk_sizep) 574{ 575 efx_rc_t rc; 576 577 if ((rc = siena_nvram_partn_lock(enp, partn)) != 0) 578 goto fail1; 579 580 if (chunk_sizep != NULL) 581 *chunk_sizep = SIENA_NVRAM_CHUNK; 582 583 return (0); 584 585fail1: 586 EFSYS_PROBE1(fail1, efx_rc_t, rc); 587 588 return (rc); 589} 590 591 __checkReturn efx_rc_t 592siena_nvram_partn_rw_finish( 593 __in efx_nic_t *enp, 594 __in uint32_t partn) 595{ 596 efx_rc_t rc; 597 598 if ((rc = siena_nvram_partn_unlock(enp, partn)) != 0) 599 goto fail1; 600 601 return (0); 602 603fail1: 604 EFSYS_PROBE1(fail1, efx_rc_t, rc); 605 606 return (rc); 607} 608 609 __checkReturn efx_rc_t 610siena_nvram_partn_set_version( 611 __in efx_nic_t *enp, 612 __in uint32_t partn, 613 __in_ecount(4) uint16_t version[4]) 614{ 615 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 616 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 617 siena_mc_fw_version_t *fwverp; 618 uint32_t dcfg_partn; 619 size_t dcfg_size; 620 unsigned int hdr_length; 621 unsigned int vpd_length; 622 unsigned int vpd_offset; 623 unsigned int nitems; 624 unsigned int required_hdr_length; 625 unsigned int pos; 626 uint8_t cksum; 627 uint32_t subtype; 628 size_t length; 629 efx_rc_t rc; 630 631 dcfg_partn = (emip->emi_port == 1) 632 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 633 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 634 635 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0) 636 goto fail1; 637 638 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 639 goto fail2; 640 641 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 642 B_TRUE, &dcfg, &length)) != 0) 643 goto fail3; 644 645 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 646 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 647 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 648 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 649 650 /* 651 * NOTE: This function will blatt any fields trailing the version 652 * vector, or the VPD chunk. 653 */ 654 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1); 655 if (required_hdr_length + vpd_length > length) { 656 rc = ENOSPC; 657 goto fail4; 658 } 659 660 if (vpd_offset < required_hdr_length) { 661 (void) memmove((caddr_t)dcfg + required_hdr_length, 662 (caddr_t)dcfg + vpd_offset, vpd_length); 663 vpd_offset = required_hdr_length; 664 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 665 EFX_DWORD_0, vpd_offset); 666 } 667 668 if (hdr_length < required_hdr_length) { 669 (void) memset((caddr_t)dcfg + hdr_length, 0, 670 required_hdr_length - hdr_length); 671 hdr_length = required_hdr_length; 672 EFX_POPULATE_WORD_1(dcfg->length, 673 EFX_WORD_0, hdr_length); 674 } 675 676 /* Get the subtype to insert into the fw_subtype array */ 677 if ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0) 678 goto fail5; 679 680 /* Fill out the new version */ 681 fwverp = &dcfg->fw_version[partn]; 682 EFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype); 683 EFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]); 684 EFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]); 685 EFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]); 686 EFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]); 687 688 /* Update the version count */ 689 if (nitems < partn + 1) { 690 nitems = partn + 1; 691 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 692 EFX_DWORD_0, nitems); 693 } 694 695 /* Update the checksum */ 696 cksum = 0; 697 for (pos = 0; pos < hdr_length; pos++) 698 cksum += ((uint8_t *)dcfg)[pos]; 699 dcfg->csum.eb_u8[0] -= cksum; 700 701 /* Erase and write the new partition */ 702 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0) 703 goto fail6; 704 705 /* Write out the new structure to nvram */ 706 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 707 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 708 goto fail7; 709 710 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 711 712 siena_nvram_partn_unlock(enp, dcfg_partn); 713 714 return (0); 715 716fail7: 717 EFSYS_PROBE(fail7); 718fail6: 719 EFSYS_PROBE(fail6); 720fail5: 721 EFSYS_PROBE(fail5); 722fail4: 723 EFSYS_PROBE(fail4); 724 725 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 726fail3: 727 EFSYS_PROBE(fail3); 728fail2: 729 EFSYS_PROBE(fail2); 730fail1: 731 EFSYS_PROBE1(fail1, efx_rc_t, rc); 732 733 return (rc); 734} 735 736#endif /* EFSYS_OPT_NVRAM */ 737 738#endif /* EFSYS_OPT_SIENA */ 739