1 /*- 2 * Copyright (c) 2009-2015 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "efx.h" 35 #include "efx_impl.h" 36 37 #if EFSYS_OPT_NVRAM 38 39 #if EFSYS_OPT_FALCON 40 41 static efx_nvram_ops_t __efx_nvram_falcon_ops = { 42 #if EFSYS_OPT_DIAG 43 falcon_nvram_test, /* envo_test */ 44 #endif /* EFSYS_OPT_DIAG */ 45 falcon_nvram_size, /* envo_size */ 46 falcon_nvram_get_version, /* envo_get_version */ 47 falcon_nvram_rw_start, /* envo_rw_start */ 48 falcon_nvram_read_chunk, /* envo_read_chunk */ 49 falcon_nvram_erase, /* envo_erase */ 50 falcon_nvram_write_chunk, /* envo_write_chunk */ 51 falcon_nvram_rw_finish, /* envo_rw_finish */ 52 falcon_nvram_set_version, /* envo_set_version */ 53 falcon_nvram_type_to_partn, /* envo_type_to_partn */ 54 }; 55 56 #endif /* EFSYS_OPT_FALCON */ 57 58 #if EFSYS_OPT_SIENA 59 60 static efx_nvram_ops_t __efx_nvram_siena_ops = { 61 #if EFSYS_OPT_DIAG 62 siena_nvram_test, /* envo_test */ 63 #endif /* EFSYS_OPT_DIAG */ 64 siena_nvram_size, /* envo_size */ 65 siena_nvram_get_version, /* envo_get_version */ 66 siena_nvram_rw_start, /* envo_rw_start */ 67 siena_nvram_read_chunk, /* envo_read_chunk */ 68 siena_nvram_erase, /* envo_erase */ 69 siena_nvram_write_chunk, /* envo_write_chunk */ 70 siena_nvram_rw_finish, /* envo_rw_finish */ 71 siena_nvram_set_version, /* envo_set_version */ 72 siena_nvram_type_to_partn, /* envo_type_to_partn */ 73 }; 74 75 #endif /* EFSYS_OPT_SIENA */ 76 77 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 78 79 static efx_nvram_ops_t __efx_nvram_ef10_ops = { 80 #if EFSYS_OPT_DIAG 81 ef10_nvram_test, /* envo_test */ 82 #endif /* EFSYS_OPT_DIAG */ 83 ef10_nvram_size, /* envo_size */ 84 ef10_nvram_get_version, /* envo_get_version */ 85 ef10_nvram_rw_start, /* envo_rw_start */ 86 ef10_nvram_read_chunk, /* envo_read_chunk */ 87 ef10_nvram_erase, /* envo_erase */ 88 ef10_nvram_write_chunk, /* envo_write_chunk */ 89 ef10_nvram_rw_finish, /* envo_rw_finish */ 90 ef10_nvram_set_version, /* envo_set_version */ 91 ef10_nvram_type_to_partn, /* envo_type_to_partn */ 92 }; 93 94 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 95 96 __checkReturn efx_rc_t 97 efx_nvram_init( 98 __in efx_nic_t *enp) 99 { 100 efx_nvram_ops_t *envop; 101 efx_rc_t rc; 102 103 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 104 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 105 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM)); 106 107 switch (enp->en_family) { 108 #if EFSYS_OPT_FALCON 109 case EFX_FAMILY_FALCON: 110 envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops; 111 break; 112 #endif /* EFSYS_OPT_FALCON */ 113 114 #if EFSYS_OPT_SIENA 115 case EFX_FAMILY_SIENA: 116 envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops; 117 break; 118 #endif /* EFSYS_OPT_SIENA */ 119 120 #if EFSYS_OPT_HUNTINGTON 121 case EFX_FAMILY_HUNTINGTON: 122 envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; 123 break; 124 #endif /* EFSYS_OPT_HUNTINGTON */ 125 126 #if EFSYS_OPT_MEDFORD 127 case EFX_FAMILY_MEDFORD: 128 envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; 129 break; 130 #endif /* EFSYS_OPT_MEDFORD */ 131 132 default: 133 EFSYS_ASSERT(0); 134 rc = ENOTSUP; 135 goto fail1; 136 } 137 138 enp->en_envop = envop; 139 enp->en_mod_flags |= EFX_MOD_NVRAM; 140 141 return (0); 142 143 fail1: 144 EFSYS_PROBE1(fail1, efx_rc_t, rc); 145 146 return (rc); 147 } 148 149 #if EFSYS_OPT_DIAG 150 151 __checkReturn efx_rc_t 152 efx_nvram_test( 153 __in efx_nic_t *enp) 154 { 155 efx_nvram_ops_t *envop = enp->en_envop; 156 efx_rc_t rc; 157 158 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 159 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 160 161 if ((rc = envop->envo_test(enp)) != 0) 162 goto fail1; 163 164 return (0); 165 166 fail1: 167 EFSYS_PROBE1(fail1, efx_rc_t, rc); 168 169 return (rc); 170 } 171 172 #endif /* EFSYS_OPT_DIAG */ 173 174 __checkReturn efx_rc_t 175 efx_nvram_size( 176 __in efx_nic_t *enp, 177 __in efx_nvram_type_t type, 178 __out size_t *sizep) 179 { 180 efx_nvram_ops_t *envop = enp->en_envop; 181 efx_rc_t rc; 182 183 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 184 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 185 186 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 187 188 if ((rc = envop->envo_size(enp, type, sizep)) != 0) 189 goto fail1; 190 191 return (0); 192 193 fail1: 194 EFSYS_PROBE1(fail1, efx_rc_t, rc); 195 196 return (rc); 197 } 198 199 __checkReturn efx_rc_t 200 efx_nvram_get_version( 201 __in efx_nic_t *enp, 202 __in efx_nvram_type_t type, 203 __out uint32_t *subtypep, 204 __out_ecount(4) uint16_t version[4]) 205 { 206 efx_nvram_ops_t *envop = enp->en_envop; 207 efx_rc_t rc; 208 209 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 210 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 211 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 212 213 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 214 215 if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0) 216 goto fail1; 217 218 return (0); 219 220 fail1: 221 EFSYS_PROBE1(fail1, efx_rc_t, rc); 222 223 return (rc); 224 } 225 226 __checkReturn efx_rc_t 227 efx_nvram_rw_start( 228 __in efx_nic_t *enp, 229 __in efx_nvram_type_t type, 230 __out_opt size_t *chunk_sizep) 231 { 232 efx_nvram_ops_t *envop = enp->en_envop; 233 efx_rc_t rc; 234 235 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 236 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 237 238 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 239 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 240 241 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 242 243 if ((rc = envop->envo_rw_start(enp, type, chunk_sizep)) != 0) 244 goto fail1; 245 246 enp->en_nvram_locked = type; 247 248 return (0); 249 250 fail1: 251 EFSYS_PROBE1(fail1, efx_rc_t, rc); 252 253 return (rc); 254 } 255 256 __checkReturn efx_rc_t 257 efx_nvram_read_chunk( 258 __in efx_nic_t *enp, 259 __in efx_nvram_type_t type, 260 __in unsigned int offset, 261 __out_bcount(size) caddr_t data, 262 __in size_t size) 263 { 264 efx_nvram_ops_t *envop = enp->en_envop; 265 efx_rc_t rc; 266 267 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 268 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 269 270 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 271 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 272 273 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 274 275 if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0) 276 goto fail1; 277 278 return (0); 279 280 fail1: 281 EFSYS_PROBE1(fail1, efx_rc_t, rc); 282 283 return (rc); 284 } 285 286 __checkReturn efx_rc_t 287 efx_nvram_erase( 288 __in efx_nic_t *enp, 289 __in efx_nvram_type_t type) 290 { 291 efx_nvram_ops_t *envop = enp->en_envop; 292 efx_rc_t rc; 293 294 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 295 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 296 297 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 298 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 299 300 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 301 302 if ((rc = envop->envo_erase(enp, type)) != 0) 303 goto fail1; 304 305 return (0); 306 307 fail1: 308 EFSYS_PROBE1(fail1, efx_rc_t, rc); 309 310 return (rc); 311 } 312 313 __checkReturn efx_rc_t 314 efx_nvram_write_chunk( 315 __in efx_nic_t *enp, 316 __in efx_nvram_type_t type, 317 __in unsigned int offset, 318 __in_bcount(size) caddr_t data, 319 __in size_t size) 320 { 321 efx_nvram_ops_t *envop = enp->en_envop; 322 efx_rc_t rc; 323 324 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 325 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 326 327 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 328 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 329 330 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 331 332 if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0) 333 goto fail1; 334 335 return (0); 336 337 fail1: 338 EFSYS_PROBE1(fail1, efx_rc_t, rc); 339 340 return (rc); 341 } 342 343 void 344 efx_nvram_rw_finish( 345 __in efx_nic_t *enp, 346 __in efx_nvram_type_t type) 347 { 348 efx_nvram_ops_t *envop = enp->en_envop; 349 350 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 351 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 352 353 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 354 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 355 356 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 357 358 envop->envo_rw_finish(enp, type); 359 360 enp->en_nvram_locked = EFX_NVRAM_INVALID; 361 } 362 363 __checkReturn efx_rc_t 364 efx_nvram_set_version( 365 __in efx_nic_t *enp, 366 __in efx_nvram_type_t type, 367 __in_ecount(4) uint16_t version[4]) 368 { 369 efx_nvram_ops_t *envop = enp->en_envop; 370 efx_rc_t rc; 371 372 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 373 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 374 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 375 376 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 377 378 /* 379 * The Siena implementation of envo_set_version() will attempt to 380 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector. 381 * Therefore, you can't have already acquired the NVRAM_UPDATE lock. 382 */ 383 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 384 385 if ((rc = envop->envo_set_version(enp, type, version)) != 0) 386 goto fail1; 387 388 return (0); 389 390 fail1: 391 EFSYS_PROBE1(fail1, efx_rc_t, rc); 392 393 return (rc); 394 } 395 396 void 397 efx_nvram_fini( 398 __in efx_nic_t *enp) 399 { 400 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 401 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 402 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 403 404 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 405 406 enp->en_envop = NULL; 407 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 408 } 409 410 #endif /* EFSYS_OPT_NVRAM */ 411 412 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 413 414 /* 415 * Internal MCDI request handling 416 */ 417 418 __checkReturn efx_rc_t 419 efx_mcdi_nvram_partitions( 420 __in efx_nic_t *enp, 421 __out_bcount(size) caddr_t data, 422 __in size_t size, 423 __out unsigned int *npartnp) 424 { 425 efx_mcdi_req_t req; 426 uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN, 427 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)]; 428 unsigned int npartn; 429 efx_rc_t rc; 430 431 (void) memset(payload, 0, sizeof (payload)); 432 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 433 req.emr_in_buf = payload; 434 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 435 req.emr_out_buf = payload; 436 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 437 438 efx_mcdi_execute(enp, &req); 439 440 if (req.emr_rc != 0) { 441 rc = req.emr_rc; 442 goto fail1; 443 } 444 445 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 446 rc = EMSGSIZE; 447 goto fail2; 448 } 449 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 450 451 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 452 rc = ENOENT; 453 goto fail3; 454 } 455 456 if (size < npartn * sizeof (uint32_t)) { 457 rc = ENOSPC; 458 goto fail3; 459 } 460 461 *npartnp = npartn; 462 463 memcpy(data, 464 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 465 (npartn * sizeof (uint32_t))); 466 467 return (0); 468 469 fail3: 470 EFSYS_PROBE(fail3); 471 fail2: 472 EFSYS_PROBE(fail2); 473 fail1: 474 EFSYS_PROBE1(fail1, efx_rc_t, rc); 475 476 return (rc); 477 } 478 479 __checkReturn efx_rc_t 480 efx_mcdi_nvram_metadata( 481 __in efx_nic_t *enp, 482 __in uint32_t partn, 483 __out uint32_t *subtypep, 484 __out_ecount(4) uint16_t version[4], 485 __out_bcount_opt(size) char *descp, 486 __in size_t size) 487 { 488 efx_mcdi_req_t req; 489 uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN, 490 MC_CMD_NVRAM_METADATA_OUT_LENMAX)]; 491 efx_rc_t rc; 492 493 (void) memset(payload, 0, sizeof (payload)); 494 req.emr_cmd = MC_CMD_NVRAM_METADATA; 495 req.emr_in_buf = payload; 496 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 497 req.emr_out_buf = payload; 498 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 499 500 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 501 502 efx_mcdi_execute(enp, &req); 503 504 if (req.emr_rc != 0) { 505 rc = req.emr_rc; 506 goto fail1; 507 } 508 509 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 510 rc = EMSGSIZE; 511 goto fail2; 512 } 513 514 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 515 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 516 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 517 } else { 518 *subtypep = 0; 519 } 520 521 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 522 NVRAM_METADATA_OUT_VERSION_VALID)) { 523 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 524 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 525 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 526 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 527 } else { 528 version[0] = version[1] = version[2] = version[3] = 0; 529 } 530 531 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 532 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 533 /* Return optional descrition string */ 534 if ((descp != NULL) && (size > 0)) { 535 size_t desclen; 536 537 descp[0] = '\0'; 538 desclen = (req.emr_out_length_used 539 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 540 541 EFSYS_ASSERT3U(desclen, <=, 542 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 543 544 if (size < desclen) { 545 rc = ENOSPC; 546 goto fail3; 547 } 548 549 memcpy(descp, MCDI_OUT2(req, char, 550 NVRAM_METADATA_OUT_DESCRIPTION), 551 desclen); 552 553 /* Ensure string is NUL terminated */ 554 descp[desclen] = '\0'; 555 } 556 } 557 558 return (0); 559 560 fail3: 561 EFSYS_PROBE(fail3); 562 fail2: 563 EFSYS_PROBE(fail2); 564 fail1: 565 EFSYS_PROBE1(fail1, efx_rc_t, rc); 566 567 return (rc); 568 } 569 570 __checkReturn efx_rc_t 571 efx_mcdi_nvram_info( 572 __in efx_nic_t *enp, 573 __in uint32_t partn, 574 __out_opt size_t *sizep, 575 __out_opt uint32_t *addressp, 576 __out_opt uint32_t *erase_sizep, 577 __out_opt uint32_t *write_sizep) 578 { 579 uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, 580 MC_CMD_NVRAM_INFO_V2_OUT_LEN)]; 581 efx_mcdi_req_t req; 582 efx_rc_t rc; 583 584 (void) memset(payload, 0, sizeof (payload)); 585 req.emr_cmd = MC_CMD_NVRAM_INFO; 586 req.emr_in_buf = payload; 587 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 588 req.emr_out_buf = payload; 589 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 590 591 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 592 593 efx_mcdi_execute_quiet(enp, &req); 594 595 if (req.emr_rc != 0) { 596 rc = req.emr_rc; 597 goto fail1; 598 } 599 600 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 601 rc = EMSGSIZE; 602 goto fail2; 603 } 604 605 if (sizep) 606 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 607 608 if (addressp) 609 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 610 611 if (erase_sizep) 612 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 613 614 if (write_sizep) { 615 *write_sizep = 616 (req.emr_out_length_used < 617 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 618 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 619 } 620 621 return (0); 622 623 fail2: 624 EFSYS_PROBE(fail2); 625 fail1: 626 EFSYS_PROBE1(fail1, efx_rc_t, rc); 627 628 return (rc); 629 } 630 631 __checkReturn efx_rc_t 632 efx_mcdi_nvram_update_start( 633 __in efx_nic_t *enp, 634 __in uint32_t partn) 635 { 636 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN, 637 MC_CMD_NVRAM_UPDATE_START_OUT_LEN)]; 638 efx_mcdi_req_t req; 639 efx_rc_t rc; 640 641 (void) memset(payload, 0, sizeof (payload)); 642 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 643 req.emr_in_buf = payload; 644 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; 645 req.emr_out_buf = payload; 646 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 647 648 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); 649 650 efx_mcdi_execute(enp, &req); 651 652 if (req.emr_rc != 0) { 653 rc = req.emr_rc; 654 goto fail1; 655 } 656 657 return (0); 658 659 fail1: 660 EFSYS_PROBE1(fail1, efx_rc_t, rc); 661 662 return (rc); 663 } 664 665 __checkReturn efx_rc_t 666 efx_mcdi_nvram_read( 667 __in efx_nic_t *enp, 668 __in uint32_t partn, 669 __in uint32_t offset, 670 __out_bcount(size) caddr_t data, 671 __in size_t size) 672 { 673 efx_mcdi_req_t req; 674 uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN, 675 MC_CMD_NVRAM_READ_OUT_LENMAX)]; 676 efx_rc_t rc; 677 678 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 679 rc = EINVAL; 680 goto fail1; 681 } 682 683 (void) memset(payload, 0, sizeof (payload)); 684 req.emr_cmd = MC_CMD_NVRAM_READ; 685 req.emr_in_buf = payload; 686 req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN; 687 req.emr_out_buf = payload; 688 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 689 690 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn); 691 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset); 692 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size); 693 694 efx_mcdi_execute(enp, &req); 695 696 if (req.emr_rc != 0) { 697 rc = req.emr_rc; 698 goto fail1; 699 } 700 701 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 702 rc = EMSGSIZE; 703 goto fail2; 704 } 705 706 memcpy(data, 707 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 708 size); 709 710 return (0); 711 712 fail2: 713 EFSYS_PROBE(fail2); 714 fail1: 715 EFSYS_PROBE1(fail1, efx_rc_t, rc); 716 717 return (rc); 718 } 719 720 __checkReturn efx_rc_t 721 efx_mcdi_nvram_erase( 722 __in efx_nic_t *enp, 723 __in uint32_t partn, 724 __in uint32_t offset, 725 __in size_t size) 726 { 727 efx_mcdi_req_t req; 728 uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN, 729 MC_CMD_NVRAM_ERASE_OUT_LEN)]; 730 efx_rc_t rc; 731 732 (void) memset(payload, 0, sizeof (payload)); 733 req.emr_cmd = MC_CMD_NVRAM_ERASE; 734 req.emr_in_buf = payload; 735 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 736 req.emr_out_buf = payload; 737 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 738 739 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 740 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 741 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 742 743 efx_mcdi_execute(enp, &req); 744 745 if (req.emr_rc != 0) { 746 rc = req.emr_rc; 747 goto fail1; 748 } 749 750 return (0); 751 752 fail1: 753 EFSYS_PROBE1(fail1, efx_rc_t, rc); 754 755 return (rc); 756 } 757 758 /* 759 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 760 * Sienna and EF10 based boards. However EF10 based boards support the use 761 * of this command with payloads up to the maximum MCDI V2 payload length. 762 */ 763 __checkReturn efx_rc_t 764 efx_mcdi_nvram_write( 765 __in efx_nic_t *enp, 766 __in uint32_t partn, 767 __in uint32_t offset, 768 __out_bcount(size) caddr_t data, 769 __in size_t size) 770 { 771 efx_mcdi_req_t req; 772 uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1, 773 MCDI_CTL_SDU_LEN_MAX_V2)]; 774 efx_rc_t rc; 775 size_t max_data_size; 776 777 max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length 778 - MC_CMD_NVRAM_WRITE_IN_LEN(0); 779 EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0); 780 EFSYS_ASSERT3U(max_data_size, <, 781 enp->en_nic_cfg.enc_mcdi_max_payload_length); 782 783 if (size > max_data_size) { 784 rc = EINVAL; 785 goto fail1; 786 } 787 788 (void) memset(payload, 0, sizeof (payload)); 789 req.emr_cmd = MC_CMD_NVRAM_WRITE; 790 req.emr_in_buf = payload; 791 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 792 req.emr_out_buf = payload; 793 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 794 795 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 796 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 797 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 798 799 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 800 data, size); 801 802 efx_mcdi_execute(enp, &req); 803 804 if (req.emr_rc != 0) { 805 rc = req.emr_rc; 806 goto fail2; 807 } 808 809 return (0); 810 811 fail2: 812 EFSYS_PROBE(fail2); 813 fail1: 814 EFSYS_PROBE1(fail1, efx_rc_t, rc); 815 816 return (rc); 817 } 818 819 __checkReturn efx_rc_t 820 efx_mcdi_nvram_update_finish( 821 __in efx_nic_t *enp, 822 __in uint32_t partn, 823 __in boolean_t reboot) 824 { 825 efx_mcdi_req_t req; 826 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN, 827 MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)]; 828 efx_rc_t rc; 829 830 (void) memset(payload, 0, sizeof (payload)); 831 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 832 req.emr_in_buf = payload; 833 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; 834 req.emr_out_buf = payload; 835 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN; 836 837 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); 838 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); 839 840 efx_mcdi_execute(enp, &req); 841 842 if (req.emr_rc != 0) { 843 rc = req.emr_rc; 844 goto fail1; 845 } 846 847 return (0); 848 849 fail1: 850 EFSYS_PROBE1(fail1, efx_rc_t, rc); 851 852 return (rc); 853 } 854 855 #if EFSYS_OPT_DIAG 856 857 __checkReturn efx_rc_t 858 efx_mcdi_nvram_test( 859 __in efx_nic_t *enp, 860 __in uint32_t partn) 861 { 862 efx_mcdi_req_t req; 863 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 864 MC_CMD_NVRAM_TEST_OUT_LEN)]; 865 int result; 866 efx_rc_t rc; 867 868 (void) memset(payload, 0, sizeof (payload)); 869 req.emr_cmd = MC_CMD_NVRAM_TEST; 870 req.emr_in_buf = payload; 871 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 872 req.emr_out_buf = payload; 873 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 874 875 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 876 877 efx_mcdi_execute(enp, &req); 878 879 if (req.emr_rc != 0) { 880 rc = req.emr_rc; 881 goto fail1; 882 } 883 884 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 885 rc = EMSGSIZE; 886 goto fail2; 887 } 888 889 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 890 if (result == MC_CMD_NVRAM_TEST_FAIL) { 891 892 EFSYS_PROBE1(nvram_test_failure, int, partn); 893 894 rc = (EINVAL); 895 goto fail3; 896 } 897 898 return (0); 899 900 fail3: 901 EFSYS_PROBE(fail3); 902 fail2: 903 EFSYS_PROBE(fail2); 904 fail1: 905 EFSYS_PROBE1(fail1, efx_rc_t, rc); 906 907 return (rc); 908 } 909 910 #endif /* EFSYS_OPT_DIAG */ 911 912 913 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 914