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