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 {MC_CMD_NVRAM_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 334 {MC_CMD_NVRAM_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 335 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 336 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 337 {MC_CMD_NVRAM_TYPE_FC_FW, 1, EFX_NVRAM_FCFW}, 338 {MC_CMD_NVRAM_TYPE_FC_FW, 2, EFX_NVRAM_FCFW}, 339 {MC_CMD_NVRAM_TYPE_CPLD, 1, EFX_NVRAM_CPLD}, 340 {MC_CMD_NVRAM_TYPE_CPLD, 2, EFX_NVRAM_CPLD}, 341 {0, 0, 0}, 342 }; 343 344 static __checkReturn siena_parttbl_entry_t * 345 siena_parttbl_entry( 346 __in efx_nic_t *enp, 347 __in efx_nvram_type_t type) 348 { 349 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 350 siena_parttbl_entry_t *entry; 351 352 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 353 354 for (entry = siena_parttbl; entry->port > 0; ++entry) { 355 if (entry->port == emip->emi_port && entry->nvtype == type) 356 return (entry); 357 } 358 359 return (NULL); 360 } 361 362 #if EFSYS_OPT_DIAG 363 364 __checkReturn int 365 siena_nvram_test( 366 __in efx_nic_t *enp) 367 { 368 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 369 siena_parttbl_entry_t *entry; 370 efx_mcdi_req_t req; 371 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 372 MC_CMD_NVRAM_TEST_OUT_LEN)]; 373 int result; 374 int rc; 375 376 req.emr_cmd = MC_CMD_NVRAM_TEST; 377 req.emr_in_buf = payload; 378 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 379 req.emr_out_buf = payload; 380 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 381 382 /* 383 * Iterate over the list of supported partition types 384 * applicable to *this* port 385 */ 386 for (entry = siena_parttbl; entry->port > 0; ++entry) { 387 if (entry->port != emip->emi_port || 388 !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 389 continue; 390 391 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn); 392 393 efx_mcdi_execute(enp, &req); 394 395 if (req.emr_rc != 0) { 396 rc = req.emr_rc; 397 goto fail1; 398 } 399 400 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 401 rc = EMSGSIZE; 402 goto fail2; 403 } 404 405 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 406 if (result == MC_CMD_NVRAM_TEST_FAIL) { 407 408 EFSYS_PROBE1(nvram_test_failure, int, entry->partn); 409 410 rc = (EINVAL); 411 goto fail3; 412 } 413 } 414 415 return (0); 416 417 fail3: 418 EFSYS_PROBE(fail3); 419 fail2: 420 EFSYS_PROBE(fail2); 421 fail1: 422 EFSYS_PROBE1(fail1, int, rc); 423 424 return (rc); 425 } 426 427 #endif /* EFSYS_OPT_DIAG */ 428 429 __checkReturn int 430 siena_nvram_size( 431 __in efx_nic_t *enp, 432 __in efx_nvram_type_t type, 433 __out size_t *sizep) 434 { 435 siena_parttbl_entry_t *entry; 436 int rc; 437 438 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 439 rc = ENOTSUP; 440 goto fail1; 441 } 442 443 if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0) 444 goto fail2; 445 446 return (0); 447 448 fail2: 449 EFSYS_PROBE(fail2); 450 fail1: 451 EFSYS_PROBE1(fail1, int, rc); 452 453 *sizep = 0; 454 455 return (rc); 456 } 457 458 #define SIENA_DYNAMIC_CFG_SIZE(_nitems) \ 459 (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \ 460 sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0]))) 461 462 __checkReturn int 463 siena_nvram_get_dynamic_cfg( 464 __in efx_nic_t *enp, 465 __in unsigned int partn, 466 __in boolean_t vpd, 467 __out siena_mc_dynamic_config_hdr_t **dcfgp, 468 __out size_t *sizep) 469 { 470 siena_mc_dynamic_config_hdr_t *dcfg; 471 size_t size; 472 uint8_t cksum; 473 unsigned int vpd_offset; 474 unsigned int vpd_length; 475 unsigned int hdr_length; 476 unsigned int nversions; 477 unsigned int pos; 478 unsigned int region; 479 int rc; 480 481 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 || 482 partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1); 483 484 /* 485 * Allocate sufficient memory for the entire dynamiccfg area, even 486 * if we're not actually going to read in the VPD. 487 */ 488 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 489 goto fail1; 490 491 EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 492 if (dcfg == NULL) { 493 rc = ENOMEM; 494 goto fail2; 495 } 496 497 if ((rc = siena_nvram_partn_read(enp, partn, 0, 498 (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 499 goto fail3; 500 501 /* Verify the magic */ 502 if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 503 != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 504 goto invalid1; 505 506 /* All future versions of the structure must be backwards compatable */ 507 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 508 509 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 510 nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 511 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 512 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 513 514 /* Verify the hdr doesn't overflow the partn size */ 515 if (hdr_length > size || vpd_offset > size || vpd_length > size || 516 vpd_length + vpd_offset > size) 517 goto invalid2; 518 519 /* Verify the header has room for all it's versions */ 520 if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 521 hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 522 goto invalid3; 523 524 /* 525 * Read the remaining portion of the dcfg, either including 526 * the whole of VPD (there is no vpd length in this structure, 527 * so we have to parse each tag), or just the dcfg header itself 528 */ 529 region = vpd ? vpd_offset + vpd_length : hdr_length; 530 if (region > SIENA_NVRAM_CHUNK) { 531 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 532 (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 533 region - SIENA_NVRAM_CHUNK)) != 0) 534 goto fail4; 535 } 536 537 /* Verify checksum */ 538 cksum = 0; 539 for (pos = 0; pos < hdr_length; pos++) 540 cksum += ((uint8_t *)dcfg)[pos]; 541 if (cksum != 0) 542 goto invalid4; 543 544 goto done; 545 546 invalid4: 547 EFSYS_PROBE(invalid4); 548 invalid3: 549 EFSYS_PROBE(invalid3); 550 invalid2: 551 EFSYS_PROBE(invalid2); 552 invalid1: 553 EFSYS_PROBE(invalid1); 554 555 /* 556 * Construct a new "null" dcfg, with an empty version vector, 557 * and an empty VPD chunk trailing. This has the neat side effect 558 * of testing the exception paths in the write path. 559 */ 560 EFX_POPULATE_DWORD_1(dcfg->magic, 561 EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 562 EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 563 EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 564 SIENA_MC_DYNAMIC_CONFIG_VERSION); 565 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 566 EFX_DWORD_0, sizeof (*dcfg)); 567 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 568 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 569 570 done: 571 *dcfgp = dcfg; 572 *sizep = size; 573 574 return (0); 575 576 fail4: 577 EFSYS_PROBE(fail4); 578 fail3: 579 EFSYS_PROBE(fail3); 580 fail2: 581 EFSYS_PROBE(fail2); 582 583 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 584 585 fail1: 586 EFSYS_PROBE1(fail1, int, rc); 587 588 return (rc); 589 } 590 591 static __checkReturn int 592 siena_nvram_get_subtype( 593 __in efx_nic_t *enp, 594 __in unsigned int partn, 595 __out uint32_t *subtypep) 596 { 597 efx_mcdi_req_t req; 598 uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX]; 599 efx_word_t *fw_list; 600 int rc; 601 602 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 603 EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0); 604 req.emr_in_buf = NULL; 605 req.emr_in_length = 0; 606 req.emr_out_buf = outbuf; 607 req.emr_out_length = sizeof (outbuf); 608 609 efx_mcdi_execute(enp, &req); 610 611 if (req.emr_rc != 0) { 612 rc = req.emr_rc; 613 goto fail1; 614 } 615 616 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 617 rc = EMSGSIZE; 618 goto fail2; 619 } 620 621 if (req.emr_out_length_used < 622 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST + 623 (partn + 1) * sizeof (efx_word_t)) { 624 rc = ENOENT; 625 goto fail3; 626 } 627 628 fw_list = MCDI_OUT2(req, efx_word_t, 629 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 630 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 631 632 return (0); 633 634 fail3: 635 EFSYS_PROBE(fail3); 636 fail2: 637 EFSYS_PROBE(fail2); 638 fail1: 639 EFSYS_PROBE1(fail1, int, rc); 640 641 return (rc); 642 } 643 644 __checkReturn int 645 siena_nvram_get_version( 646 __in efx_nic_t *enp, 647 __in efx_nvram_type_t type, 648 __out uint32_t *subtypep, 649 __out_ecount(4) uint16_t version[4]) 650 { 651 siena_mc_dynamic_config_hdr_t *dcfg; 652 siena_parttbl_entry_t *entry; 653 unsigned int dcfg_partn; 654 unsigned int partn; 655 int rc; 656 657 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 658 rc = ENOTSUP; 659 goto fail1; 660 } 661 partn = entry->partn; 662 663 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 664 rc = ENOTSUP; 665 goto fail2; 666 } 667 668 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 669 goto fail3; 670 671 /* 672 * Some partitions are accessible from both ports (for instance BOOTROM) 673 * Find the highest version reported by all dcfg structures on ports 674 * that have access to this partition. 675 */ 676 version[0] = version[1] = version[2] = version[3] = 0; 677 for (entry = siena_parttbl; entry->port > 0; ++entry) { 678 unsigned int nitems; 679 uint16_t temp[4]; 680 size_t length; 681 682 if (entry->partn != partn) 683 continue; 684 685 dcfg_partn = (entry->port == 1) 686 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 687 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 688 /* 689 * Ingore missing partitions on port 2, assuming they're due 690 * to to running on a single port part. 691 */ 692 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 693 if (entry->port == 2) 694 continue; 695 } 696 697 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 698 B_FALSE, &dcfg, &length)) != 0) 699 goto fail4; 700 701 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 702 EFX_DWORD_0); 703 if (nitems < entry->partn) 704 goto done; 705 706 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 707 EFX_WORD_0); 708 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 709 EFX_WORD_0); 710 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 711 EFX_WORD_0); 712 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 713 EFX_WORD_0); 714 if (memcmp(version, temp, sizeof (temp)) < 0) 715 memcpy(version, temp, sizeof (temp)); 716 717 done: 718 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 719 } 720 721 return (0); 722 723 fail4: 724 EFSYS_PROBE(fail4); 725 fail3: 726 EFSYS_PROBE(fail3); 727 fail2: 728 EFSYS_PROBE(fail2); 729 fail1: 730 EFSYS_PROBE1(fail1, int, rc); 731 732 return (rc); 733 } 734 735 __checkReturn int 736 siena_nvram_rw_start( 737 __in efx_nic_t *enp, 738 __in efx_nvram_type_t type, 739 __out size_t *chunk_sizep) 740 { 741 siena_parttbl_entry_t *entry; 742 int rc; 743 744 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 745 rc = ENOTSUP; 746 goto fail1; 747 } 748 749 if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0) 750 goto fail2; 751 752 if (chunk_sizep != NULL) 753 *chunk_sizep = SIENA_NVRAM_CHUNK; 754 755 return (0); 756 757 fail2: 758 EFSYS_PROBE(fail2); 759 fail1: 760 EFSYS_PROBE1(fail1, int, rc); 761 762 return (rc); 763 } 764 765 __checkReturn int 766 siena_nvram_read_chunk( 767 __in efx_nic_t *enp, 768 __in efx_nvram_type_t type, 769 __in unsigned int offset, 770 __out_bcount(size) caddr_t data, 771 __in size_t size) 772 { 773 siena_parttbl_entry_t *entry; 774 int rc; 775 776 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 777 rc = ENOTSUP; 778 goto fail1; 779 } 780 781 if ((rc = siena_nvram_partn_read(enp, entry->partn, 782 offset, data, size)) != 0) 783 goto fail2; 784 785 return (0); 786 787 fail2: 788 EFSYS_PROBE(fail2); 789 fail1: 790 EFSYS_PROBE1(fail1, int, rc); 791 792 return (rc); 793 } 794 795 __checkReturn int 796 siena_nvram_erase( 797 __in efx_nic_t *enp, 798 __in efx_nvram_type_t type) 799 { 800 siena_parttbl_entry_t *entry; 801 size_t size; 802 int rc; 803 804 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 805 rc = ENOTSUP; 806 goto fail1; 807 } 808 809 if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0) 810 goto fail2; 811 812 if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0) 813 goto fail3; 814 815 return (0); 816 817 fail3: 818 EFSYS_PROBE(fail3); 819 fail2: 820 EFSYS_PROBE(fail2); 821 fail1: 822 EFSYS_PROBE1(fail1, int, rc); 823 824 return (rc); 825 } 826 827 __checkReturn int 828 siena_nvram_write_chunk( 829 __in efx_nic_t *enp, 830 __in efx_nvram_type_t type, 831 __in unsigned int offset, 832 __in_bcount(size) caddr_t data, 833 __in size_t size) 834 { 835 siena_parttbl_entry_t *entry; 836 int rc; 837 838 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 839 rc = ENOTSUP; 840 goto fail1; 841 } 842 843 if ((rc = siena_nvram_partn_write(enp, entry->partn, 844 offset, data, size)) != 0) 845 goto fail2; 846 847 return (0); 848 849 fail2: 850 EFSYS_PROBE(fail2); 851 fail1: 852 EFSYS_PROBE1(fail1, int, rc); 853 854 return (rc); 855 } 856 857 void 858 siena_nvram_rw_finish( 859 __in efx_nic_t *enp, 860 __in efx_nvram_type_t type) 861 { 862 siena_parttbl_entry_t *entry; 863 864 if ((entry = siena_parttbl_entry(enp, type)) != NULL) 865 siena_nvram_partn_unlock(enp, entry->partn); 866 } 867 868 __checkReturn int 869 siena_nvram_set_version( 870 __in efx_nic_t *enp, 871 __in efx_nvram_type_t type, 872 __out uint16_t version[4]) 873 { 874 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 875 siena_parttbl_entry_t *entry; 876 unsigned int dcfg_partn; 877 size_t partn_size; 878 unsigned int hdr_length; 879 unsigned int vpd_length; 880 unsigned int vpd_offset; 881 unsigned int nitems; 882 unsigned int required_hdr_length; 883 unsigned int pos; 884 uint8_t cksum; 885 uint32_t subtype; 886 size_t length; 887 int rc; 888 889 if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 890 rc = ENOTSUP; 891 goto fail1; 892 } 893 894 dcfg_partn = (entry->port == 1) 895 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 896 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 897 898 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 899 goto fail2; 900 901 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 902 goto fail2; 903 904 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 905 B_TRUE, &dcfg, &length)) != 0) 906 goto fail3; 907 908 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 909 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 910 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 911 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 912 913 /* 914 * NOTE: This function will blatt any fields trailing the version 915 * vector, or the VPD chunk. 916 */ 917 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1); 918 if (required_hdr_length + vpd_length > length) { 919 rc = ENOSPC; 920 goto fail4; 921 } 922 923 if (vpd_offset < required_hdr_length) { 924 (void) memmove((caddr_t)dcfg + required_hdr_length, 925 (caddr_t)dcfg + vpd_offset, vpd_length); 926 vpd_offset = required_hdr_length; 927 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 928 EFX_DWORD_0, vpd_offset); 929 } 930 931 if (hdr_length < required_hdr_length) { 932 (void) memset((caddr_t)dcfg + hdr_length, 0, 933 required_hdr_length - hdr_length); 934 hdr_length = required_hdr_length; 935 EFX_POPULATE_WORD_1(dcfg->length, 936 EFX_WORD_0, hdr_length); 937 } 938 939 /* Get the subtype to insert into the fw_subtype array */ 940 if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0) 941 goto fail5; 942 943 /* Fill out the new version */ 944 EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype, 945 EFX_DWORD_0, subtype); 946 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w, 947 EFX_WORD_0, version[0]); 948 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x, 949 EFX_WORD_0, version[1]); 950 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y, 951 EFX_WORD_0, version[2]); 952 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z, 953 EFX_WORD_0, version[3]); 954 955 /* Update the version count */ 956 if (nitems < entry->partn + 1) { 957 nitems = entry->partn + 1; 958 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 959 EFX_DWORD_0, nitems); 960 } 961 962 /* Update the checksum */ 963 cksum = 0; 964 for (pos = 0; pos < hdr_length; pos++) 965 cksum += ((uint8_t *)dcfg)[pos]; 966 dcfg->csum.eb_u8[0] -= cksum; 967 968 /* Erase and write the new partition */ 969 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 970 goto fail6; 971 972 /* Write out the new structure to nvram */ 973 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 974 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 975 goto fail7; 976 977 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 978 979 siena_nvram_partn_unlock(enp, dcfg_partn); 980 981 return (0); 982 983 fail7: 984 EFSYS_PROBE(fail7); 985 fail6: 986 EFSYS_PROBE(fail6); 987 fail5: 988 EFSYS_PROBE(fail5); 989 fail4: 990 EFSYS_PROBE(fail4); 991 992 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 993 fail3: 994 EFSYS_PROBE(fail3); 995 fail2: 996 EFSYS_PROBE(fail2); 997 fail1: 998 EFSYS_PROBE1(fail1, int, rc); 999 1000 return (rc); 1001 } 1002 1003 #endif /* EFSYS_OPT_NVRAM */ 1004 1005 #endif /* EFSYS_OPT_SIENA */ 1006