1 /*- 2 * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include "efsys.h" 30 #include "efx.h" 31 #include "efx_types.h" 32 #include "efx_regs.h" 33 #include "efx_impl.h" 34 35 #if EFSYS_OPT_SIENA 36 37 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 38 39 __checkReturn int 40 siena_nvram_partn_size( 41 __in efx_nic_t *enp, 42 __in unsigned int partn, 43 __out size_t *sizep) 44 { 45 efx_mcdi_req_t req; 46 uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, 47 MC_CMD_NVRAM_INFO_OUT_LEN)]; 48 int rc; 49 50 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 51 rc = ENOTSUP; 52 goto fail1; 53 } 54 55 req.emr_cmd = MC_CMD_NVRAM_INFO; 56 req.emr_in_buf = payload; 57 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 58 req.emr_out_buf = payload; 59 req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN; 60 61 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 62 63 efx_mcdi_execute(enp, &req); 64 65 if (req.emr_rc != 0) { 66 rc = req.emr_rc; 67 goto fail2; 68 } 69 70 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 71 rc = EMSGSIZE; 72 goto fail3; 73 } 74 75 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 76 77 return (0); 78 79 fail3: 80 EFSYS_PROBE(fail3); 81 fail2: 82 EFSYS_PROBE(fail2); 83 fail1: 84 EFSYS_PROBE1(fail1, int, rc); 85 86 return (rc); 87 } 88 89 __checkReturn int 90 siena_nvram_partn_lock( 91 __in efx_nic_t *enp, 92 __in unsigned int partn) 93 { 94 efx_mcdi_req_t req; 95 uint8_t payload[MC_CMD_NVRAM_UPDATE_START_IN_LEN]; 96 int rc; 97 98 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 99 req.emr_in_buf = payload; 100 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; 101 EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_START_OUT_LEN == 0); 102 req.emr_out_buf = NULL; 103 req.emr_out_length = 0; 104 105 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); 106 107 efx_mcdi_execute(enp, &req); 108 109 if (req.emr_rc != 0) { 110 rc = req.emr_rc; 111 goto fail1; 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_read( 124 __in efx_nic_t *enp, 125 __in unsigned int partn, 126 __in unsigned int offset, 127 __out_bcount(size) caddr_t data, 128 __in size_t size) 129 { 130 efx_mcdi_req_t req; 131 uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN, 132 MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK))]; 133 size_t chunk; 134 int rc; 135 136 while (size > 0) { 137 chunk = MIN(size, SIENA_NVRAM_CHUNK); 138 139 req.emr_cmd = MC_CMD_NVRAM_READ; 140 req.emr_in_buf = payload; 141 req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN; 142 req.emr_out_buf = payload; 143 req.emr_out_length = 144 MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK); 145 146 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn); 147 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset); 148 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, chunk); 149 150 efx_mcdi_execute(enp, &req); 151 152 if (req.emr_rc != 0) { 153 rc = req.emr_rc; 154 goto fail1; 155 } 156 157 if (req.emr_out_length_used < 158 MC_CMD_NVRAM_READ_OUT_LEN(chunk)) { 159 rc = EMSGSIZE; 160 goto fail2; 161 } 162 163 memcpy(data, 164 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 165 chunk); 166 167 size -= chunk; 168 data += chunk; 169 offset += chunk; 170 } 171 172 return (0); 173 174 fail2: 175 EFSYS_PROBE(fail2); 176 fail1: 177 EFSYS_PROBE1(fail1, int, rc); 178 179 return (rc); 180 } 181 182 __checkReturn int 183 siena_nvram_partn_erase( 184 __in efx_nic_t *enp, 185 __in unsigned int partn, 186 __in unsigned int offset, 187 __in size_t size) 188 { 189 efx_mcdi_req_t req; 190 uint8_t payload[MC_CMD_NVRAM_ERASE_IN_LEN]; 191 int rc; 192 193 req.emr_cmd = MC_CMD_NVRAM_ERASE; 194 req.emr_in_buf = payload; 195 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 196 EFX_STATIC_ASSERT(MC_CMD_NVRAM_ERASE_OUT_LEN == 0); 197 req.emr_out_buf = NULL; 198 req.emr_out_length = 0; 199 200 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 201 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 202 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 203 204 efx_mcdi_execute(enp, &req); 205 206 if (req.emr_rc != 0) { 207 rc = req.emr_rc; 208 goto fail1; 209 } 210 211 return (0); 212 213 fail1: 214 EFSYS_PROBE1(fail1, int, rc); 215 216 return (rc); 217 } 218 219 __checkReturn int 220 siena_nvram_partn_write( 221 __in efx_nic_t *enp, 222 __in unsigned int partn, 223 __in unsigned int offset, 224 __out_bcount(size) caddr_t data, 225 __in size_t size) 226 { 227 efx_mcdi_req_t req; 228 uint8_t payload[MC_CMD_NVRAM_WRITE_IN_LEN(SIENA_NVRAM_CHUNK)]; 229 size_t chunk; 230 int rc; 231 232 while (size > 0) { 233 chunk = MIN(size, SIENA_NVRAM_CHUNK); 234 235 req.emr_cmd = MC_CMD_NVRAM_WRITE; 236 req.emr_in_buf = payload; 237 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(chunk); 238 EFX_STATIC_ASSERT(MC_CMD_NVRAM_WRITE_OUT_LEN == 0); 239 req.emr_out_buf = NULL; 240 req.emr_out_length = 0; 241 242 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 243 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 244 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, chunk); 245 246 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 247 data, chunk); 248 249 efx_mcdi_execute(enp, &req); 250 251 if (req.emr_rc != 0) { 252 rc = req.emr_rc; 253 goto fail1; 254 } 255 256 size -= chunk; 257 data += chunk; 258 offset += chunk; 259 } 260 261 return (0); 262 263 fail1: 264 EFSYS_PROBE1(fail1, int, rc); 265 266 return (rc); 267 } 268 269 void 270 siena_nvram_partn_unlock( 271 __in efx_nic_t *enp, 272 __in unsigned int partn) 273 { 274 efx_mcdi_req_t req; 275 uint8_t payload[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN]; 276 uint32_t reboot; 277 int rc; 278 279 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 280 req.emr_in_buf = payload; 281 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; 282 EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN == 0); 283 req.emr_out_buf = NULL; 284 req.emr_out_length = 0; 285 286 /* 287 * Reboot into the new image only for PHYs. The driver has to 288 * explicitly cope with an MC reboot after a firmware update. 289 */ 290 reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 || 291 partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 || 292 partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO); 293 294 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); 295 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); 296 297 efx_mcdi_execute(enp, &req); 298 299 if (req.emr_rc != 0) { 300 rc = req.emr_rc; 301 goto fail1; 302 } 303 304 return; 305 306 fail1: 307 EFSYS_PROBE1(fail1, int, rc); 308 } 309 310 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 311 312 #if EFSYS_OPT_NVRAM 313 314 typedef struct siena_parttbl_entry_s { 315 unsigned int partn; 316 unsigned int port; 317 efx_nvram_type_t nvtype; 318 } siena_parttbl_entry_t; 319 320 static siena_parttbl_entry_t siena_parttbl[] = { 321 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 1, EFX_NVRAM_NULLPHY}, 322 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 2, EFX_NVRAM_NULLPHY}, 323 {MC_CMD_NVRAM_TYPE_MC_FW, 1, EFX_NVRAM_MC_FIRMWARE}, 324 {MC_CMD_NVRAM_TYPE_MC_FW, 2, EFX_NVRAM_MC_FIRMWARE}, 325 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 326 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 327 {MC_CMD_NVRAM_TYPE_EXP_ROM, 1, EFX_NVRAM_BOOTROM}, 328 {MC_CMD_NVRAM_TYPE_EXP_ROM, 2, EFX_NVRAM_BOOTROM}, 329 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 330 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 331 {MC_CMD_NVRAM_TYPE_PHY_PORT0, 1, EFX_NVRAM_PHY}, 332 {MC_CMD_NVRAM_TYPE_PHY_PORT1, 2, EFX_NVRAM_PHY}, 333 {0, 0, 0}, 334 }; 335 336 static __checkReturn siena_parttbl_entry_t * 337 siena_parttbl_entry( 338 __in efx_nic_t *enp, 339 __in efx_nvram_type_t type) 340 { 341 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 342 siena_parttbl_entry_t *entry; 343 344 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 345 346 for (entry = siena_parttbl; entry->port > 0; ++entry) { 347 if (entry->port == emip->emi_port && entry->nvtype == type) 348 return (entry); 349 } 350 351 return (NULL); 352 } 353 354 #if EFSYS_OPT_DIAG 355 356 __checkReturn int 357 siena_nvram_test( 358 __in efx_nic_t *enp) 359 { 360 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 361 siena_parttbl_entry_t *entry; 362 efx_mcdi_req_t req; 363 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 364 MC_CMD_NVRAM_TEST_OUT_LEN)]; 365 int result; 366 int rc; 367 368 req.emr_cmd = MC_CMD_NVRAM_TEST; 369 req.emr_in_buf = payload; 370 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 371 req.emr_out_buf = payload; 372 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 373 374 /* 375 * Iterate over the list of supported partition types 376 * applicable to *this* port 377 */ 378 for (entry = siena_parttbl; entry->port > 0; ++entry) { 379 if (entry->port != emip->emi_port || 380 !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 381 continue; 382 383 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn); 384 385 efx_mcdi_execute(enp, &req); 386 387 if (req.emr_rc != 0) { 388 rc = req.emr_rc; 389 goto fail1; 390 } 391 392 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 393 rc = EMSGSIZE; 394 goto fail2; 395 } 396 397 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 398 if (result == MC_CMD_NVRAM_TEST_FAIL) { 399 400 EFSYS_PROBE1(nvram_test_failure, int, entry->partn); 401 402 rc = (EINVAL); 403 goto fail3; 404 } 405 } 406 407 return (0); 408 409 fail3: 410 EFSYS_PROBE(fail3); 411 fail2: 412 EFSYS_PROBE(fail2); 413 fail1: 414 EFSYS_PROBE1(fail1, int, rc); 415 416 return (rc); 417 } 418 419 #endif /* EFSYS_OPT_DIAG */ 420 421 __checkReturn int 422 siena_nvram_size( 423 __in efx_nic_t *enp, 424 __in efx_nvram_type_t type, 425 __out size_t *sizep) 426 { 427 siena_parttbl_entry_t *entry; 428 int rc; 429 430 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 431 rc = ENOTSUP; 432 goto fail1; 433 } 434 435 if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0) 436 goto fail2; 437 438 return (0); 439 440 fail2: 441 EFSYS_PROBE(fail2); 442 fail1: 443 EFSYS_PROBE1(fail1, int, rc); 444 445 *sizep = 0; 446 447 return (rc); 448 } 449 450 #define SIENA_DYNAMIC_CFG_SIZE(_nitems) \ 451 (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \ 452 sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0]))) 453 454 __checkReturn int 455 siena_nvram_get_dynamic_cfg( 456 __in efx_nic_t *enp, 457 __in unsigned int partn, 458 __in boolean_t vpd, 459 __out siena_mc_dynamic_config_hdr_t **dcfgp, 460 __out size_t *sizep) 461 { 462 siena_mc_dynamic_config_hdr_t *dcfg; 463 size_t size; 464 uint8_t cksum; 465 unsigned int vpd_offset; 466 unsigned int vpd_length; 467 unsigned int hdr_length; 468 unsigned int nversions; 469 unsigned int pos; 470 unsigned int region; 471 int rc; 472 473 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 || 474 partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1); 475 476 /* 477 * Allocate sufficient memory for the entire dynamiccfg area, even 478 * if we're not actually going to read in the VPD. 479 */ 480 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 481 goto fail1; 482 483 EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 484 if (dcfg == NULL) { 485 rc = ENOMEM; 486 goto fail2; 487 } 488 489 if ((rc = siena_nvram_partn_read(enp, partn, 0, 490 (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 491 goto fail3; 492 493 /* Verify the magic */ 494 if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 495 != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 496 goto invalid1; 497 498 /* All future versions of the structure must be backwards compatable */ 499 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 500 501 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 502 nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 503 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 504 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 505 506 /* Verify the hdr doesn't overflow the partn size */ 507 if (hdr_length > size || vpd_offset > size || vpd_length > size || 508 vpd_length + vpd_offset > size) 509 goto invalid2; 510 511 /* Verify the header has room for all it's versions */ 512 if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 513 hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 514 goto invalid3; 515 516 /* 517 * Read the remaining portion of the dcfg, either including 518 * the whole of VPD (there is no vpd length in this structure, 519 * so we have to parse each tag), or just the dcfg header itself 520 */ 521 region = vpd ? vpd_offset + vpd_length : hdr_length; 522 if (region > SIENA_NVRAM_CHUNK) { 523 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 524 (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 525 region - SIENA_NVRAM_CHUNK)) != 0) 526 goto fail4; 527 } 528 529 /* Verify checksum */ 530 cksum = 0; 531 for (pos = 0; pos < hdr_length; pos++) 532 cksum += ((uint8_t *)dcfg)[pos]; 533 if (cksum != 0) 534 goto invalid4; 535 536 goto done; 537 538 invalid4: 539 EFSYS_PROBE(invalid4); 540 invalid3: 541 EFSYS_PROBE(invalid3); 542 invalid2: 543 EFSYS_PROBE(invalid2); 544 invalid1: 545 EFSYS_PROBE(invalid1); 546 547 /* 548 * Construct a new "null" dcfg, with an empty version vector, 549 * and an empty VPD chunk trailing. This has the neat side effect 550 * of testing the exception paths in the write path. 551 */ 552 EFX_POPULATE_DWORD_1(dcfg->magic, 553 EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 554 EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 555 EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 556 SIENA_MC_DYNAMIC_CONFIG_VERSION); 557 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 558 EFX_DWORD_0, sizeof (*dcfg)); 559 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 560 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 561 562 done: 563 *dcfgp = dcfg; 564 *sizep = size; 565 566 return (0); 567 568 fail4: 569 EFSYS_PROBE(fail4); 570 fail3: 571 EFSYS_PROBE(fail3); 572 fail2: 573 EFSYS_PROBE(fail2); 574 575 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 576 577 fail1: 578 EFSYS_PROBE1(fail1, int, rc); 579 580 return (rc); 581 } 582 583 static __checkReturn int 584 siena_nvram_get_subtype( 585 __in efx_nic_t *enp, 586 __in unsigned int partn, 587 __out uint32_t *subtypep) 588 { 589 efx_mcdi_req_t req; 590 uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; 591 efx_word_t *fw_list; 592 int rc; 593 594 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 595 EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0); 596 req.emr_in_buf = NULL; 597 req.emr_in_length = 0; 598 req.emr_out_buf = outbuf; 599 req.emr_out_length = sizeof (outbuf); 600 601 efx_mcdi_execute(enp, &req); 602 603 if (req.emr_rc != 0) { 604 rc = req.emr_rc; 605 goto fail1; 606 } 607 608 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LEN) { 609 rc = EMSGSIZE; 610 goto fail2; 611 } 612 613 fw_list = MCDI_OUT2(req, efx_word_t, 614 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 615 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 616 617 return (0); 618 619 fail2: 620 EFSYS_PROBE(fail2); 621 fail1: 622 EFSYS_PROBE1(fail1, int, rc); 623 624 return (rc); 625 } 626 627 __checkReturn int 628 siena_nvram_get_version( 629 __in efx_nic_t *enp, 630 __in efx_nvram_type_t type, 631 __out uint32_t *subtypep, 632 __out_ecount(4) uint16_t version[4]) 633 { 634 siena_mc_dynamic_config_hdr_t *dcfg; 635 siena_parttbl_entry_t *entry; 636 unsigned int dcfg_partn; 637 unsigned int partn; 638 int rc; 639 640 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 641 rc = ENOTSUP; 642 goto fail1; 643 } 644 partn = entry->partn; 645 646 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 647 rc = ENOTSUP; 648 goto fail2; 649 } 650 651 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 652 goto fail3; 653 654 /* 655 * Some partitions are accessible from both ports (for instance BOOTROM) 656 * Find the highest version reported by all dcfg structures on ports 657 * that have access to this partition. 658 */ 659 version[0] = version[1] = version[2] = version[3] = 0; 660 for (entry = siena_parttbl; entry->port > 0; ++entry) { 661 unsigned int nitems; 662 uint16_t temp[4]; 663 size_t length; 664 665 if (entry->partn != partn) 666 continue; 667 668 dcfg_partn = (entry->port == 1) 669 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 670 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 671 /* 672 * Ingore missing partitions on port 2, assuming they're due 673 * to to running on a single port part. 674 */ 675 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 676 if (entry->port == 2) 677 continue; 678 } 679 680 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 681 B_FALSE, &dcfg, &length)) != 0) 682 goto fail4; 683 684 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 685 EFX_DWORD_0); 686 if (nitems < entry->partn) 687 goto done; 688 689 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 690 EFX_WORD_0); 691 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 692 EFX_WORD_0); 693 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 694 EFX_WORD_0); 695 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 696 EFX_WORD_0); 697 if (memcmp(version, temp, sizeof (temp)) < 0) 698 memcpy(version, temp, sizeof (temp)); 699 700 done: 701 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 702 } 703 704 return (0); 705 706 fail4: 707 EFSYS_PROBE(fail4); 708 fail3: 709 EFSYS_PROBE(fail3); 710 fail2: 711 EFSYS_PROBE(fail2); 712 fail1: 713 EFSYS_PROBE1(fail1, int, rc); 714 715 return (rc); 716 } 717 718 __checkReturn int 719 siena_nvram_rw_start( 720 __in efx_nic_t *enp, 721 __in efx_nvram_type_t type, 722 __out size_t *chunk_sizep) 723 { 724 siena_parttbl_entry_t *entry; 725 int rc; 726 727 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 728 rc = ENOTSUP; 729 goto fail1; 730 } 731 732 if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0) 733 goto fail2; 734 735 if (chunk_sizep != NULL) 736 *chunk_sizep = SIENA_NVRAM_CHUNK; 737 738 return (0); 739 740 fail2: 741 EFSYS_PROBE(fail2); 742 fail1: 743 EFSYS_PROBE1(fail1, int, rc); 744 745 return (rc); 746 } 747 748 __checkReturn int 749 siena_nvram_read_chunk( 750 __in efx_nic_t *enp, 751 __in efx_nvram_type_t type, 752 __in unsigned int offset, 753 __out_bcount(size) caddr_t data, 754 __in size_t size) 755 { 756 siena_parttbl_entry_t *entry; 757 int rc; 758 759 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 760 rc = ENOTSUP; 761 goto fail1; 762 } 763 764 if ((rc = siena_nvram_partn_read(enp, entry->partn, 765 offset, data, size)) != 0) 766 goto fail2; 767 768 return (0); 769 770 fail2: 771 EFSYS_PROBE(fail2); 772 fail1: 773 EFSYS_PROBE1(fail1, int, rc); 774 775 return (rc); 776 } 777 778 __checkReturn int 779 siena_nvram_erase( 780 __in efx_nic_t *enp, 781 __in efx_nvram_type_t type) 782 { 783 siena_parttbl_entry_t *entry; 784 size_t size; 785 int rc; 786 787 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 788 rc = ENOTSUP; 789 goto fail1; 790 } 791 792 if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0) 793 goto fail2; 794 795 if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0) 796 goto fail3; 797 798 return (0); 799 800 fail3: 801 EFSYS_PROBE(fail3); 802 fail2: 803 EFSYS_PROBE(fail2); 804 fail1: 805 EFSYS_PROBE1(fail1, int, rc); 806 807 return (rc); 808 } 809 810 __checkReturn int 811 siena_nvram_write_chunk( 812 __in efx_nic_t *enp, 813 __in efx_nvram_type_t type, 814 __in unsigned int offset, 815 __in_bcount(size) caddr_t data, 816 __in size_t size) 817 { 818 siena_parttbl_entry_t *entry; 819 int rc; 820 821 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 822 rc = ENOTSUP; 823 goto fail1; 824 } 825 826 if ((rc = siena_nvram_partn_write(enp, entry->partn, 827 offset, data, size)) != 0) 828 goto fail2; 829 830 return (0); 831 832 fail2: 833 EFSYS_PROBE(fail2); 834 fail1: 835 EFSYS_PROBE1(fail1, int, rc); 836 837 return (rc); 838 } 839 840 void 841 siena_nvram_rw_finish( 842 __in efx_nic_t *enp, 843 __in efx_nvram_type_t type) 844 { 845 siena_parttbl_entry_t *entry; 846 847 if ((entry = siena_parttbl_entry(enp, type)) != NULL) 848 siena_nvram_partn_unlock(enp, entry->partn); 849 } 850 851 __checkReturn int 852 siena_nvram_set_version( 853 __in efx_nic_t *enp, 854 __in efx_nvram_type_t type, 855 __out uint16_t version[4]) 856 { 857 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 858 siena_parttbl_entry_t *entry; 859 unsigned int dcfg_partn; 860 size_t partn_size; 861 unsigned int hdr_length; 862 unsigned int vpd_length; 863 unsigned int vpd_offset; 864 unsigned int nitems; 865 unsigned int required_hdr_length; 866 unsigned int pos; 867 uint8_t cksum; 868 uint32_t subtype; 869 size_t length; 870 int rc; 871 872 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 873 rc = ENOTSUP; 874 goto fail1; 875 } 876 877 dcfg_partn = (entry->port == 1) 878 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 879 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 880 881 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 882 goto fail2; 883 884 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 885 goto fail2; 886 887 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 888 B_TRUE, &dcfg, &length)) != 0) 889 goto fail3; 890 891 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 892 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 893 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 894 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 895 896 /* 897 * NOTE: This function will blatt any fields trailing the version 898 * vector, or the VPD chunk. 899 */ 900 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1); 901 if (required_hdr_length + vpd_length > length) { 902 rc = ENOSPC; 903 goto fail4; 904 } 905 906 if (vpd_offset < required_hdr_length) { 907 (void) memmove((caddr_t)dcfg + required_hdr_length, 908 (caddr_t)dcfg + vpd_offset, vpd_length); 909 vpd_offset = required_hdr_length; 910 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 911 EFX_DWORD_0, vpd_offset); 912 } 913 914 if (hdr_length < required_hdr_length) { 915 (void) memset((caddr_t)dcfg + hdr_length, 0, 916 required_hdr_length - hdr_length); 917 hdr_length = required_hdr_length; 918 EFX_POPULATE_WORD_1(dcfg->length, 919 EFX_WORD_0, hdr_length); 920 } 921 922 /* Get the subtype to insert into the fw_subtype array */ 923 if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0) 924 goto fail5; 925 926 /* Fill out the new version */ 927 EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype, 928 EFX_DWORD_0, subtype); 929 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w, 930 EFX_WORD_0, version[0]); 931 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x, 932 EFX_WORD_0, version[1]); 933 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y, 934 EFX_WORD_0, version[2]); 935 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z, 936 EFX_WORD_0, version[3]); 937 938 /* Update the version count */ 939 if (nitems < entry->partn + 1) { 940 nitems = entry->partn + 1; 941 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 942 EFX_DWORD_0, nitems); 943 } 944 945 /* Update the checksum */ 946 cksum = 0; 947 for (pos = 0; pos < hdr_length; pos++) 948 cksum += ((uint8_t *)dcfg)[pos]; 949 dcfg->csum.eb_u8[0] -= cksum; 950 951 /* Erase and write the new partition */ 952 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 953 goto fail6; 954 955 /* Write out the new structure to nvram */ 956 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 957 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 958 goto fail7; 959 960 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 961 962 siena_nvram_partn_unlock(enp, dcfg_partn); 963 964 return (0); 965 966 fail7: 967 EFSYS_PROBE(fail7); 968 fail6: 969 EFSYS_PROBE(fail6); 970 fail5: 971 EFSYS_PROBE(fail5); 972 fail4: 973 EFSYS_PROBE(fail4); 974 975 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 976 fail3: 977 EFSYS_PROBE(fail3); 978 fail2: 979 EFSYS_PROBE(fail2); 980 fail1: 981 EFSYS_PROBE1(fail1, int, rc); 982 983 return (rc); 984 } 985 986 #endif /* EFSYS_OPT_NVRAM */ 987 988 #endif /* EFSYS_OPT_SIENA */ 989