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_NVRAM 40 41 #if EFSYS_OPT_SIENA 42 43 static const efx_nvram_ops_t __efx_nvram_siena_ops = { 44 #if EFSYS_OPT_DIAG 45 siena_nvram_test, /* envo_test */ 46 #endif /* EFSYS_OPT_DIAG */ 47 siena_nvram_type_to_partn, /* envo_type_to_partn */ 48 siena_nvram_partn_size, /* envo_partn_size */ 49 siena_nvram_partn_rw_start, /* envo_partn_rw_start */ 50 siena_nvram_partn_read, /* envo_partn_read */ 51 siena_nvram_partn_read, /* envo_partn_read_backup */ 52 siena_nvram_partn_erase, /* envo_partn_erase */ 53 siena_nvram_partn_write, /* envo_partn_write */ 54 siena_nvram_partn_rw_finish, /* envo_partn_rw_finish */ 55 siena_nvram_partn_get_version, /* envo_partn_get_version */ 56 siena_nvram_partn_set_version, /* envo_partn_set_version */ 57 NULL, /* envo_partn_validate */ 58 }; 59 60 #endif /* EFSYS_OPT_SIENA */ 61 62 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 63 64 static const efx_nvram_ops_t __efx_nvram_ef10_ops = { 65 #if EFSYS_OPT_DIAG 66 ef10_nvram_test, /* envo_test */ 67 #endif /* EFSYS_OPT_DIAG */ 68 ef10_nvram_type_to_partn, /* envo_type_to_partn */ 69 ef10_nvram_partn_size, /* envo_partn_size */ 70 ef10_nvram_partn_rw_start, /* envo_partn_rw_start */ 71 ef10_nvram_partn_read, /* envo_partn_read */ 72 ef10_nvram_partn_read_backup, /* envo_partn_read_backup */ 73 ef10_nvram_partn_erase, /* envo_partn_erase */ 74 ef10_nvram_partn_write, /* envo_partn_write */ 75 ef10_nvram_partn_rw_finish, /* envo_partn_rw_finish */ 76 ef10_nvram_partn_get_version, /* envo_partn_get_version */ 77 ef10_nvram_partn_set_version, /* envo_partn_set_version */ 78 ef10_nvram_buffer_validate, /* envo_buffer_validate */ 79 }; 80 81 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 82 83 __checkReturn efx_rc_t 84 efx_nvram_init( 85 __in efx_nic_t *enp) 86 { 87 const efx_nvram_ops_t *envop; 88 efx_rc_t rc; 89 90 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 91 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 92 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM)); 93 94 switch (enp->en_family) { 95 #if EFSYS_OPT_SIENA 96 case EFX_FAMILY_SIENA: 97 envop = &__efx_nvram_siena_ops; 98 break; 99 #endif /* EFSYS_OPT_SIENA */ 100 101 #if EFSYS_OPT_HUNTINGTON 102 case EFX_FAMILY_HUNTINGTON: 103 envop = &__efx_nvram_ef10_ops; 104 break; 105 #endif /* EFSYS_OPT_HUNTINGTON */ 106 107 #if EFSYS_OPT_MEDFORD 108 case EFX_FAMILY_MEDFORD: 109 envop = &__efx_nvram_ef10_ops; 110 break; 111 #endif /* EFSYS_OPT_MEDFORD */ 112 113 #if EFSYS_OPT_MEDFORD2 114 case EFX_FAMILY_MEDFORD2: 115 envop = &__efx_nvram_ef10_ops; 116 break; 117 #endif /* EFSYS_OPT_MEDFORD2 */ 118 119 default: 120 EFSYS_ASSERT(0); 121 rc = ENOTSUP; 122 goto fail1; 123 } 124 125 enp->en_envop = envop; 126 enp->en_mod_flags |= EFX_MOD_NVRAM; 127 128 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 129 130 return (0); 131 132 fail1: 133 EFSYS_PROBE1(fail1, efx_rc_t, rc); 134 135 return (rc); 136 } 137 138 #if EFSYS_OPT_DIAG 139 140 __checkReturn efx_rc_t 141 efx_nvram_test( 142 __in efx_nic_t *enp) 143 { 144 const efx_nvram_ops_t *envop = enp->en_envop; 145 efx_rc_t rc; 146 147 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 148 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 149 150 if ((rc = envop->envo_test(enp)) != 0) 151 goto fail1; 152 153 return (0); 154 155 fail1: 156 EFSYS_PROBE1(fail1, efx_rc_t, rc); 157 158 return (rc); 159 } 160 161 #endif /* EFSYS_OPT_DIAG */ 162 163 __checkReturn efx_rc_t 164 efx_nvram_size( 165 __in efx_nic_t *enp, 166 __in efx_nvram_type_t type, 167 __out size_t *sizep) 168 { 169 const efx_nvram_ops_t *envop = enp->en_envop; 170 uint32_t partn; 171 efx_rc_t rc; 172 173 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 174 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 175 176 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 177 goto fail1; 178 179 if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0) 180 goto fail2; 181 182 return (0); 183 184 fail2: 185 EFSYS_PROBE(fail2); 186 fail1: 187 EFSYS_PROBE1(fail1, efx_rc_t, rc); 188 *sizep = 0; 189 190 return (rc); 191 } 192 193 __checkReturn efx_rc_t 194 efx_nvram_get_version( 195 __in efx_nic_t *enp, 196 __in efx_nvram_type_t type, 197 __out uint32_t *subtypep, 198 __out_ecount(4) uint16_t version[4]) 199 { 200 const efx_nvram_ops_t *envop = enp->en_envop; 201 uint32_t partn; 202 efx_rc_t rc; 203 204 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 205 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 206 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 207 208 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 209 goto fail1; 210 211 if ((rc = envop->envo_partn_get_version(enp, partn, 212 subtypep, version)) != 0) 213 goto fail2; 214 215 return (0); 216 217 fail2: 218 EFSYS_PROBE(fail2); 219 fail1: 220 EFSYS_PROBE1(fail1, efx_rc_t, rc); 221 222 return (rc); 223 } 224 225 __checkReturn efx_rc_t 226 efx_nvram_rw_start( 227 __in efx_nic_t *enp, 228 __in efx_nvram_type_t type, 229 __out_opt size_t *chunk_sizep) 230 { 231 const efx_nvram_ops_t *envop = enp->en_envop; 232 uint32_t partn; 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 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 239 goto fail1; 240 241 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 242 243 if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0) 244 goto fail2; 245 246 enp->en_nvram_partn_locked = partn; 247 248 return (0); 249 250 fail2: 251 EFSYS_PROBE(fail2); 252 fail1: 253 EFSYS_PROBE1(fail1, efx_rc_t, rc); 254 255 return (rc); 256 } 257 258 __checkReturn efx_rc_t 259 efx_nvram_read_chunk( 260 __in efx_nic_t *enp, 261 __in efx_nvram_type_t type, 262 __in unsigned int offset, 263 __out_bcount(size) caddr_t data, 264 __in size_t size) 265 { 266 const efx_nvram_ops_t *envop = enp->en_envop; 267 uint32_t partn; 268 efx_rc_t rc; 269 270 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 271 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 272 273 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 274 goto fail1; 275 276 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 277 278 if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0) 279 goto fail2; 280 281 return (0); 282 283 fail2: 284 EFSYS_PROBE(fail2); 285 fail1: 286 EFSYS_PROBE1(fail1, efx_rc_t, rc); 287 288 return (rc); 289 } 290 291 /* 292 * Read from the backup (writeable) store of an A/B partition. 293 * For non A/B partitions, there is only a single store, and so this 294 * function has the same behaviour as efx_nvram_read_chunk(). 295 */ 296 __checkReturn efx_rc_t 297 efx_nvram_read_backup( 298 __in efx_nic_t *enp, 299 __in efx_nvram_type_t type, 300 __in unsigned int offset, 301 __out_bcount(size) caddr_t data, 302 __in size_t size) 303 { 304 const efx_nvram_ops_t *envop = enp->en_envop; 305 uint32_t partn; 306 efx_rc_t rc; 307 308 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 309 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 310 311 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 312 goto fail1; 313 314 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 315 316 if ((rc = envop->envo_partn_read_backup(enp, partn, offset, 317 data, size)) != 0) 318 goto fail2; 319 320 return (0); 321 322 fail2: 323 EFSYS_PROBE(fail2); 324 fail1: 325 EFSYS_PROBE1(fail1, efx_rc_t, rc); 326 327 return (rc); 328 } 329 330 __checkReturn efx_rc_t 331 efx_nvram_erase( 332 __in efx_nic_t *enp, 333 __in efx_nvram_type_t type) 334 { 335 const efx_nvram_ops_t *envop = enp->en_envop; 336 unsigned int offset = 0; 337 size_t size = 0; 338 uint32_t partn; 339 efx_rc_t rc; 340 341 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 342 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 343 344 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 345 goto fail1; 346 347 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 348 349 if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0) 350 goto fail2; 351 352 if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0) 353 goto fail3; 354 355 return (0); 356 357 fail3: 358 EFSYS_PROBE(fail3); 359 fail2: 360 EFSYS_PROBE(fail2); 361 fail1: 362 EFSYS_PROBE1(fail1, efx_rc_t, rc); 363 364 return (rc); 365 } 366 367 __checkReturn efx_rc_t 368 efx_nvram_write_chunk( 369 __in efx_nic_t *enp, 370 __in efx_nvram_type_t type, 371 __in unsigned int offset, 372 __in_bcount(size) caddr_t data, 373 __in size_t size) 374 { 375 const efx_nvram_ops_t *envop = enp->en_envop; 376 uint32_t partn; 377 efx_rc_t rc; 378 379 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 380 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 381 382 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 383 goto fail1; 384 385 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 386 387 if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0) 388 goto fail2; 389 390 return (0); 391 392 fail2: 393 EFSYS_PROBE(fail2); 394 fail1: 395 EFSYS_PROBE1(fail1, efx_rc_t, rc); 396 397 return (rc); 398 } 399 400 __checkReturn efx_rc_t 401 efx_nvram_rw_finish( 402 __in efx_nic_t *enp, 403 __in efx_nvram_type_t type, 404 __out_opt uint32_t *verify_resultp) 405 { 406 const efx_nvram_ops_t *envop = enp->en_envop; 407 uint32_t partn; 408 uint32_t verify_result = 0; 409 efx_rc_t rc; 410 411 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 412 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 413 414 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 415 goto fail1; 416 417 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn); 418 419 if ((rc = envop->envo_partn_rw_finish(enp, partn, &verify_result)) != 0) 420 goto fail2; 421 422 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 423 424 if (verify_resultp != NULL) 425 *verify_resultp = verify_result; 426 427 return (0); 428 429 fail2: 430 EFSYS_PROBE(fail2); 431 enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID; 432 433 fail1: 434 EFSYS_PROBE1(fail1, efx_rc_t, rc); 435 436 /* Always report verification result */ 437 if (verify_resultp != NULL) 438 *verify_resultp = verify_result; 439 440 return (rc); 441 } 442 443 __checkReturn efx_rc_t 444 efx_nvram_set_version( 445 __in efx_nic_t *enp, 446 __in efx_nvram_type_t type, 447 __in_ecount(4) uint16_t version[4]) 448 { 449 const efx_nvram_ops_t *envop = enp->en_envop; 450 uint32_t partn; 451 efx_rc_t rc; 452 453 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 454 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 455 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 456 457 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 458 goto fail1; 459 460 /* 461 * The Siena implementation of envo_set_version() will attempt to 462 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG partition. 463 * Therefore, you can't have already acquired the NVRAM_UPDATE lock. 464 */ 465 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 466 467 if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0) 468 goto fail2; 469 470 return (0); 471 472 fail2: 473 EFSYS_PROBE(fail2); 474 fail1: 475 EFSYS_PROBE1(fail1, efx_rc_t, rc); 476 477 return (rc); 478 } 479 480 /* Validate buffer contents (before writing to flash) */ 481 __checkReturn efx_rc_t 482 efx_nvram_validate( 483 __in efx_nic_t *enp, 484 __in efx_nvram_type_t type, 485 __in_bcount(partn_size) caddr_t partn_data, 486 __in size_t partn_size) 487 { 488 const efx_nvram_ops_t *envop = enp->en_envop; 489 uint32_t partn; 490 efx_rc_t rc; 491 492 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 493 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 494 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 495 496 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 497 goto fail1; 498 499 if (envop->envo_buffer_validate != NULL) { 500 if ((rc = envop->envo_buffer_validate(partn, 501 partn_data, partn_size)) != 0) 502 goto fail2; 503 } 504 505 return (0); 506 507 fail2: 508 EFSYS_PROBE(fail2); 509 fail1: 510 EFSYS_PROBE1(fail1, efx_rc_t, rc); 511 512 return (rc); 513 } 514 515 516 void 517 efx_nvram_fini( 518 __in efx_nic_t *enp) 519 { 520 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 521 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 522 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 523 524 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 525 526 enp->en_envop = NULL; 527 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 528 } 529 530 #endif /* EFSYS_OPT_NVRAM */ 531 532 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 533 534 /* 535 * Internal MCDI request handling 536 */ 537 538 __checkReturn efx_rc_t 539 efx_mcdi_nvram_partitions( 540 __in efx_nic_t *enp, 541 __out_bcount(size) caddr_t data, 542 __in size_t size, 543 __out unsigned int *npartnp) 544 { 545 efx_mcdi_req_t req; 546 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN, 547 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX); 548 unsigned int npartn; 549 efx_rc_t rc; 550 551 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 552 req.emr_in_buf = payload; 553 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 554 req.emr_out_buf = payload; 555 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 556 557 efx_mcdi_execute(enp, &req); 558 559 if (req.emr_rc != 0) { 560 rc = req.emr_rc; 561 goto fail1; 562 } 563 564 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 565 rc = EMSGSIZE; 566 goto fail2; 567 } 568 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 569 570 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 571 rc = ENOENT; 572 goto fail3; 573 } 574 575 if (size < npartn * sizeof (uint32_t)) { 576 rc = ENOSPC; 577 goto fail3; 578 } 579 580 *npartnp = npartn; 581 582 memcpy(data, 583 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 584 (npartn * sizeof (uint32_t))); 585 586 return (0); 587 588 fail3: 589 EFSYS_PROBE(fail3); 590 fail2: 591 EFSYS_PROBE(fail2); 592 fail1: 593 EFSYS_PROBE1(fail1, efx_rc_t, rc); 594 595 return (rc); 596 } 597 598 __checkReturn efx_rc_t 599 efx_mcdi_nvram_metadata( 600 __in efx_nic_t *enp, 601 __in uint32_t partn, 602 __out uint32_t *subtypep, 603 __out_ecount(4) uint16_t version[4], 604 __out_bcount_opt(size) char *descp, 605 __in size_t size) 606 { 607 efx_mcdi_req_t req; 608 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN, 609 MC_CMD_NVRAM_METADATA_OUT_LENMAX); 610 efx_rc_t rc; 611 612 req.emr_cmd = MC_CMD_NVRAM_METADATA; 613 req.emr_in_buf = payload; 614 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 615 req.emr_out_buf = payload; 616 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 617 618 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 619 620 efx_mcdi_execute_quiet(enp, &req); 621 622 if (req.emr_rc != 0) { 623 rc = req.emr_rc; 624 goto fail1; 625 } 626 627 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 628 rc = EMSGSIZE; 629 goto fail2; 630 } 631 632 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 633 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 634 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 635 } else { 636 *subtypep = 0; 637 } 638 639 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 640 NVRAM_METADATA_OUT_VERSION_VALID)) { 641 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 642 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 643 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 644 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 645 } else { 646 version[0] = version[1] = version[2] = version[3] = 0; 647 } 648 649 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 650 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 651 /* Return optional descrition string */ 652 if ((descp != NULL) && (size > 0)) { 653 size_t desclen; 654 655 descp[0] = '\0'; 656 desclen = (req.emr_out_length_used 657 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 658 659 EFSYS_ASSERT3U(desclen, <=, 660 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 661 662 if (size < desclen) { 663 rc = ENOSPC; 664 goto fail3; 665 } 666 667 memcpy(descp, MCDI_OUT2(req, char, 668 NVRAM_METADATA_OUT_DESCRIPTION), 669 desclen); 670 671 /* Ensure string is NUL terminated */ 672 descp[desclen] = '\0'; 673 } 674 } 675 676 return (0); 677 678 fail3: 679 EFSYS_PROBE(fail3); 680 fail2: 681 EFSYS_PROBE(fail2); 682 fail1: 683 EFSYS_PROBE1(fail1, efx_rc_t, rc); 684 685 return (rc); 686 } 687 688 __checkReturn efx_rc_t 689 efx_mcdi_nvram_info( 690 __in efx_nic_t *enp, 691 __in uint32_t partn, 692 __out_opt size_t *sizep, 693 __out_opt uint32_t *addressp, 694 __out_opt uint32_t *erase_sizep, 695 __out_opt uint32_t *write_sizep) 696 { 697 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN, 698 MC_CMD_NVRAM_INFO_V2_OUT_LEN); 699 efx_mcdi_req_t req; 700 efx_rc_t rc; 701 702 req.emr_cmd = MC_CMD_NVRAM_INFO; 703 req.emr_in_buf = payload; 704 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 705 req.emr_out_buf = payload; 706 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 707 708 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 709 710 efx_mcdi_execute_quiet(enp, &req); 711 712 if (req.emr_rc != 0) { 713 rc = req.emr_rc; 714 goto fail1; 715 } 716 717 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 718 rc = EMSGSIZE; 719 goto fail2; 720 } 721 722 if (sizep) 723 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 724 725 if (addressp) 726 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 727 728 if (erase_sizep) 729 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 730 731 if (write_sizep) { 732 *write_sizep = 733 (req.emr_out_length_used < 734 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 735 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 736 } 737 738 return (0); 739 740 fail2: 741 EFSYS_PROBE(fail2); 742 fail1: 743 EFSYS_PROBE1(fail1, efx_rc_t, rc); 744 745 return (rc); 746 } 747 748 /* 749 * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified 750 * NVRAM updates. Older firmware will ignore the flags field in the request. 751 */ 752 __checkReturn efx_rc_t 753 efx_mcdi_nvram_update_start( 754 __in efx_nic_t *enp, 755 __in uint32_t partn) 756 { 757 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN, 758 MC_CMD_NVRAM_UPDATE_START_OUT_LEN); 759 efx_mcdi_req_t req; 760 efx_rc_t rc; 761 762 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 763 req.emr_in_buf = payload; 764 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN; 765 req.emr_out_buf = payload; 766 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 767 768 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn); 769 770 MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS, 771 NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); 772 773 efx_mcdi_execute(enp, &req); 774 775 if (req.emr_rc != 0) { 776 rc = req.emr_rc; 777 goto fail1; 778 } 779 780 return (0); 781 782 fail1: 783 EFSYS_PROBE1(fail1, efx_rc_t, rc); 784 785 return (rc); 786 } 787 788 __checkReturn efx_rc_t 789 efx_mcdi_nvram_read( 790 __in efx_nic_t *enp, 791 __in uint32_t partn, 792 __in uint32_t offset, 793 __out_bcount(size) caddr_t data, 794 __in size_t size, 795 __in uint32_t mode) 796 { 797 efx_mcdi_req_t req; 798 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN, 799 MC_CMD_NVRAM_READ_OUT_LENMAX); 800 efx_rc_t rc; 801 802 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 803 rc = EINVAL; 804 goto fail1; 805 } 806 807 req.emr_cmd = MC_CMD_NVRAM_READ; 808 req.emr_in_buf = payload; 809 req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN; 810 req.emr_out_buf = payload; 811 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 812 813 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn); 814 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset); 815 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size); 816 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode); 817 818 efx_mcdi_execute(enp, &req); 819 820 if (req.emr_rc != 0) { 821 rc = req.emr_rc; 822 goto fail1; 823 } 824 825 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 826 rc = EMSGSIZE; 827 goto fail2; 828 } 829 830 memcpy(data, 831 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 832 size); 833 834 return (0); 835 836 fail2: 837 EFSYS_PROBE(fail2); 838 fail1: 839 EFSYS_PROBE1(fail1, efx_rc_t, rc); 840 841 return (rc); 842 } 843 844 __checkReturn efx_rc_t 845 efx_mcdi_nvram_erase( 846 __in efx_nic_t *enp, 847 __in uint32_t partn, 848 __in uint32_t offset, 849 __in size_t size) 850 { 851 efx_mcdi_req_t req; 852 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN, 853 MC_CMD_NVRAM_ERASE_OUT_LEN); 854 efx_rc_t rc; 855 856 req.emr_cmd = MC_CMD_NVRAM_ERASE; 857 req.emr_in_buf = payload; 858 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 859 req.emr_out_buf = payload; 860 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 861 862 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 863 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 864 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 865 866 efx_mcdi_execute(enp, &req); 867 868 if (req.emr_rc != 0) { 869 rc = req.emr_rc; 870 goto fail1; 871 } 872 873 return (0); 874 875 fail1: 876 EFSYS_PROBE1(fail1, efx_rc_t, rc); 877 878 return (rc); 879 } 880 881 /* 882 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 883 * Sienna and EF10 based boards. However EF10 based boards support the use 884 * of this command with payloads up to the maximum MCDI V2 payload length. 885 */ 886 __checkReturn efx_rc_t 887 efx_mcdi_nvram_write( 888 __in efx_nic_t *enp, 889 __in uint32_t partn, 890 __in uint32_t offset, 891 __in_bcount(size) caddr_t data, 892 __in size_t size) 893 { 894 efx_mcdi_req_t req; 895 uint8_t *payload; 896 efx_rc_t rc; 897 size_t max_data_size; 898 size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length; 899 900 max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0); 901 EFSYS_ASSERT3U(payload_len, >, 0); 902 EFSYS_ASSERT3U(max_data_size, <, payload_len); 903 904 if (size > max_data_size) { 905 rc = EINVAL; 906 goto fail1; 907 } 908 909 EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload); 910 if (payload == NULL) { 911 rc = ENOMEM; 912 goto fail2; 913 } 914 915 (void) memset(payload, 0, payload_len); 916 req.emr_cmd = MC_CMD_NVRAM_WRITE; 917 req.emr_in_buf = payload; 918 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 919 req.emr_out_buf = payload; 920 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 921 922 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 923 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 924 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 925 926 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 927 data, size); 928 929 efx_mcdi_execute(enp, &req); 930 931 if (req.emr_rc != 0) { 932 rc = req.emr_rc; 933 goto fail3; 934 } 935 936 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 937 938 return (0); 939 940 fail3: 941 EFSYS_PROBE(fail3); 942 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 943 fail2: 944 EFSYS_PROBE(fail2); 945 fail1: 946 EFSYS_PROBE1(fail1, efx_rc_t, rc); 947 948 return (rc); 949 } 950 951 952 /* 953 * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified 954 * NVRAM updates. Older firmware will ignore the flags field in the request. 955 */ 956 __checkReturn efx_rc_t 957 efx_mcdi_nvram_update_finish( 958 __in efx_nic_t *enp, 959 __in uint32_t partn, 960 __in boolean_t reboot, 961 __out_opt uint32_t *verify_resultp) 962 { 963 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 964 efx_mcdi_req_t req; 965 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN, 966 MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN); 967 uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 968 efx_rc_t rc; 969 970 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 971 req.emr_in_buf = payload; 972 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN; 973 req.emr_out_buf = payload; 974 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN; 975 976 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn); 977 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot); 978 979 MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, 980 NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); 981 982 efx_mcdi_execute(enp, &req); 983 984 if (req.emr_rc != 0) { 985 rc = req.emr_rc; 986 goto fail1; 987 } 988 989 if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { 990 verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 991 if (encp->enc_nvram_update_verify_result_supported) { 992 /* Result of update verification is missing */ 993 rc = EMSGSIZE; 994 goto fail2; 995 } 996 } else { 997 verify_result = 998 MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); 999 } 1000 1001 if ((encp->enc_nvram_update_verify_result_supported) && 1002 (verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)) { 1003 /* Update verification failed */ 1004 rc = EINVAL; 1005 goto fail3; 1006 } 1007 1008 if (verify_resultp != NULL) 1009 *verify_resultp = verify_result; 1010 1011 return (0); 1012 1013 fail3: 1014 EFSYS_PROBE(fail3); 1015 fail2: 1016 EFSYS_PROBE(fail2); 1017 fail1: 1018 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1019 1020 /* Always report verification result */ 1021 if (verify_resultp != NULL) 1022 *verify_resultp = verify_result; 1023 1024 return (rc); 1025 } 1026 1027 #if EFSYS_OPT_DIAG 1028 1029 __checkReturn efx_rc_t 1030 efx_mcdi_nvram_test( 1031 __in efx_nic_t *enp, 1032 __in uint32_t partn) 1033 { 1034 efx_mcdi_req_t req; 1035 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN, 1036 MC_CMD_NVRAM_TEST_OUT_LEN); 1037 int result; 1038 efx_rc_t rc; 1039 1040 req.emr_cmd = MC_CMD_NVRAM_TEST; 1041 req.emr_in_buf = payload; 1042 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 1043 req.emr_out_buf = payload; 1044 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 1045 1046 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 1047 1048 efx_mcdi_execute(enp, &req); 1049 1050 if (req.emr_rc != 0) { 1051 rc = req.emr_rc; 1052 goto fail1; 1053 } 1054 1055 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 1056 rc = EMSGSIZE; 1057 goto fail2; 1058 } 1059 1060 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 1061 if (result == MC_CMD_NVRAM_TEST_FAIL) { 1062 1063 EFSYS_PROBE1(nvram_test_failure, int, partn); 1064 1065 rc = (EINVAL); 1066 goto fail3; 1067 } 1068 1069 return (0); 1070 1071 fail3: 1072 EFSYS_PROBE(fail3); 1073 fail2: 1074 EFSYS_PROBE(fail2); 1075 fail1: 1076 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1077 1078 return (rc); 1079 } 1080 1081 #endif /* EFSYS_OPT_DIAG */ 1082 1083 1084 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 1085