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 void 516 efx_nvram_fini( 517 __in efx_nic_t *enp) 518 { 519 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 520 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 521 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 522 523 EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID); 524 525 enp->en_envop = NULL; 526 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 527 } 528 529 #endif /* EFSYS_OPT_NVRAM */ 530 531 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 532 533 /* 534 * Internal MCDI request handling 535 */ 536 537 __checkReturn efx_rc_t 538 efx_mcdi_nvram_partitions( 539 __in efx_nic_t *enp, 540 __out_bcount(size) caddr_t data, 541 __in size_t size, 542 __out unsigned int *npartnp) 543 { 544 efx_mcdi_req_t req; 545 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN, 546 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX); 547 unsigned int npartn; 548 efx_rc_t rc; 549 550 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 551 req.emr_in_buf = payload; 552 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 553 req.emr_out_buf = payload; 554 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 555 556 efx_mcdi_execute(enp, &req); 557 558 if (req.emr_rc != 0) { 559 rc = req.emr_rc; 560 goto fail1; 561 } 562 563 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 564 rc = EMSGSIZE; 565 goto fail2; 566 } 567 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 568 569 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 570 rc = ENOENT; 571 goto fail3; 572 } 573 574 if (size < npartn * sizeof (uint32_t)) { 575 rc = ENOSPC; 576 goto fail3; 577 } 578 579 *npartnp = npartn; 580 581 memcpy(data, 582 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 583 (npartn * sizeof (uint32_t))); 584 585 return (0); 586 587 fail3: 588 EFSYS_PROBE(fail3); 589 fail2: 590 EFSYS_PROBE(fail2); 591 fail1: 592 EFSYS_PROBE1(fail1, efx_rc_t, rc); 593 594 return (rc); 595 } 596 597 __checkReturn efx_rc_t 598 efx_mcdi_nvram_metadata( 599 __in efx_nic_t *enp, 600 __in uint32_t partn, 601 __out uint32_t *subtypep, 602 __out_ecount(4) uint16_t version[4], 603 __out_bcount_opt(size) char *descp, 604 __in size_t size) 605 { 606 efx_mcdi_req_t req; 607 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN, 608 MC_CMD_NVRAM_METADATA_OUT_LENMAX); 609 efx_rc_t rc; 610 611 req.emr_cmd = MC_CMD_NVRAM_METADATA; 612 req.emr_in_buf = payload; 613 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 614 req.emr_out_buf = payload; 615 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 616 617 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 618 619 efx_mcdi_execute_quiet(enp, &req); 620 621 if (req.emr_rc != 0) { 622 rc = req.emr_rc; 623 goto fail1; 624 } 625 626 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 627 rc = EMSGSIZE; 628 goto fail2; 629 } 630 631 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 632 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 633 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 634 } else { 635 *subtypep = 0; 636 } 637 638 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 639 NVRAM_METADATA_OUT_VERSION_VALID)) { 640 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 641 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 642 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 643 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 644 } else { 645 version[0] = version[1] = version[2] = version[3] = 0; 646 } 647 648 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 649 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 650 /* Return optional descrition string */ 651 if ((descp != NULL) && (size > 0)) { 652 size_t desclen; 653 654 descp[0] = '\0'; 655 desclen = (req.emr_out_length_used 656 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 657 658 EFSYS_ASSERT3U(desclen, <=, 659 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 660 661 if (size < desclen) { 662 rc = ENOSPC; 663 goto fail3; 664 } 665 666 memcpy(descp, MCDI_OUT2(req, char, 667 NVRAM_METADATA_OUT_DESCRIPTION), 668 desclen); 669 670 /* Ensure string is NUL terminated */ 671 descp[desclen] = '\0'; 672 } 673 } 674 675 return (0); 676 677 fail3: 678 EFSYS_PROBE(fail3); 679 fail2: 680 EFSYS_PROBE(fail2); 681 fail1: 682 EFSYS_PROBE1(fail1, efx_rc_t, rc); 683 684 return (rc); 685 } 686 687 __checkReturn efx_rc_t 688 efx_mcdi_nvram_info( 689 __in efx_nic_t *enp, 690 __in uint32_t partn, 691 __out_opt size_t *sizep, 692 __out_opt uint32_t *addressp, 693 __out_opt uint32_t *erase_sizep, 694 __out_opt uint32_t *write_sizep) 695 { 696 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN, 697 MC_CMD_NVRAM_INFO_V2_OUT_LEN); 698 efx_mcdi_req_t req; 699 efx_rc_t rc; 700 701 req.emr_cmd = MC_CMD_NVRAM_INFO; 702 req.emr_in_buf = payload; 703 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 704 req.emr_out_buf = payload; 705 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 706 707 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 708 709 efx_mcdi_execute_quiet(enp, &req); 710 711 if (req.emr_rc != 0) { 712 rc = req.emr_rc; 713 goto fail1; 714 } 715 716 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 717 rc = EMSGSIZE; 718 goto fail2; 719 } 720 721 if (sizep) 722 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 723 724 if (addressp) 725 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 726 727 if (erase_sizep) 728 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 729 730 if (write_sizep) { 731 *write_sizep = 732 (req.emr_out_length_used < 733 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 734 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 735 } 736 737 return (0); 738 739 fail2: 740 EFSYS_PROBE(fail2); 741 fail1: 742 EFSYS_PROBE1(fail1, efx_rc_t, rc); 743 744 return (rc); 745 } 746 747 /* 748 * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified 749 * NVRAM updates. Older firmware will ignore the flags field in the request. 750 */ 751 __checkReturn efx_rc_t 752 efx_mcdi_nvram_update_start( 753 __in efx_nic_t *enp, 754 __in uint32_t partn) 755 { 756 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN, 757 MC_CMD_NVRAM_UPDATE_START_OUT_LEN); 758 efx_mcdi_req_t req; 759 efx_rc_t rc; 760 761 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 762 req.emr_in_buf = payload; 763 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN; 764 req.emr_out_buf = payload; 765 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 766 767 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn); 768 769 MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS, 770 NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); 771 772 efx_mcdi_execute(enp, &req); 773 774 if (req.emr_rc != 0) { 775 rc = req.emr_rc; 776 goto fail1; 777 } 778 779 return (0); 780 781 fail1: 782 EFSYS_PROBE1(fail1, efx_rc_t, rc); 783 784 return (rc); 785 } 786 787 __checkReturn efx_rc_t 788 efx_mcdi_nvram_read( 789 __in efx_nic_t *enp, 790 __in uint32_t partn, 791 __in uint32_t offset, 792 __out_bcount(size) caddr_t data, 793 __in size_t size, 794 __in uint32_t mode) 795 { 796 efx_mcdi_req_t req; 797 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN, 798 MC_CMD_NVRAM_READ_OUT_LENMAX); 799 efx_rc_t rc; 800 801 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 802 rc = EINVAL; 803 goto fail1; 804 } 805 806 req.emr_cmd = MC_CMD_NVRAM_READ; 807 req.emr_in_buf = payload; 808 req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN; 809 req.emr_out_buf = payload; 810 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 811 812 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn); 813 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset); 814 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size); 815 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode); 816 817 efx_mcdi_execute(enp, &req); 818 819 if (req.emr_rc != 0) { 820 rc = req.emr_rc; 821 goto fail1; 822 } 823 824 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 825 rc = EMSGSIZE; 826 goto fail2; 827 } 828 829 memcpy(data, 830 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 831 size); 832 833 return (0); 834 835 fail2: 836 EFSYS_PROBE(fail2); 837 fail1: 838 EFSYS_PROBE1(fail1, efx_rc_t, rc); 839 840 return (rc); 841 } 842 843 __checkReturn efx_rc_t 844 efx_mcdi_nvram_erase( 845 __in efx_nic_t *enp, 846 __in uint32_t partn, 847 __in uint32_t offset, 848 __in size_t size) 849 { 850 efx_mcdi_req_t req; 851 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN, 852 MC_CMD_NVRAM_ERASE_OUT_LEN); 853 efx_rc_t rc; 854 855 req.emr_cmd = MC_CMD_NVRAM_ERASE; 856 req.emr_in_buf = payload; 857 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 858 req.emr_out_buf = payload; 859 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 860 861 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 862 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 863 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 864 865 efx_mcdi_execute(enp, &req); 866 867 if (req.emr_rc != 0) { 868 rc = req.emr_rc; 869 goto fail1; 870 } 871 872 return (0); 873 874 fail1: 875 EFSYS_PROBE1(fail1, efx_rc_t, rc); 876 877 return (rc); 878 } 879 880 /* 881 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 882 * Sienna and EF10 based boards. However EF10 based boards support the use 883 * of this command with payloads up to the maximum MCDI V2 payload length. 884 */ 885 __checkReturn efx_rc_t 886 efx_mcdi_nvram_write( 887 __in efx_nic_t *enp, 888 __in uint32_t partn, 889 __in uint32_t offset, 890 __in_bcount(size) caddr_t data, 891 __in size_t size) 892 { 893 efx_mcdi_req_t req; 894 uint8_t *payload; 895 efx_rc_t rc; 896 size_t max_data_size; 897 size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length; 898 899 max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0); 900 EFSYS_ASSERT3U(payload_len, >, 0); 901 EFSYS_ASSERT3U(max_data_size, <, payload_len); 902 903 if (size > max_data_size) { 904 rc = EINVAL; 905 goto fail1; 906 } 907 908 EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload); 909 if (payload == NULL) { 910 rc = ENOMEM; 911 goto fail2; 912 } 913 914 (void) memset(payload, 0, payload_len); 915 req.emr_cmd = MC_CMD_NVRAM_WRITE; 916 req.emr_in_buf = payload; 917 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 918 req.emr_out_buf = payload; 919 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 920 921 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 922 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 923 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 924 925 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 926 data, size); 927 928 efx_mcdi_execute(enp, &req); 929 930 if (req.emr_rc != 0) { 931 rc = req.emr_rc; 932 goto fail3; 933 } 934 935 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 936 937 return (0); 938 939 fail3: 940 EFSYS_PROBE(fail3); 941 EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload); 942 fail2: 943 EFSYS_PROBE(fail2); 944 fail1: 945 EFSYS_PROBE1(fail1, efx_rc_t, rc); 946 947 return (rc); 948 } 949 950 /* 951 * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified 952 * NVRAM updates. Older firmware will ignore the flags field in the request. 953 */ 954 __checkReturn efx_rc_t 955 efx_mcdi_nvram_update_finish( 956 __in efx_nic_t *enp, 957 __in uint32_t partn, 958 __in boolean_t reboot, 959 __out_opt uint32_t *verify_resultp) 960 { 961 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 962 efx_mcdi_req_t req; 963 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN, 964 MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN); 965 uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 966 efx_rc_t rc; 967 968 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 969 req.emr_in_buf = payload; 970 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN; 971 req.emr_out_buf = payload; 972 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN; 973 974 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn); 975 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot); 976 977 MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, 978 NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1); 979 980 efx_mcdi_execute(enp, &req); 981 982 if (req.emr_rc != 0) { 983 rc = req.emr_rc; 984 goto fail1; 985 } 986 987 if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { 988 verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 989 if (encp->enc_nvram_update_verify_result_supported) { 990 /* Result of update verification is missing */ 991 rc = EMSGSIZE; 992 goto fail2; 993 } 994 } else { 995 verify_result = 996 MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); 997 } 998 999 if ((encp->enc_nvram_update_verify_result_supported) && 1000 (verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)) { 1001 /* Update verification failed */ 1002 rc = EINVAL; 1003 goto fail3; 1004 } 1005 1006 if (verify_resultp != NULL) 1007 *verify_resultp = verify_result; 1008 1009 return (0); 1010 1011 fail3: 1012 EFSYS_PROBE(fail3); 1013 fail2: 1014 EFSYS_PROBE(fail2); 1015 fail1: 1016 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1017 1018 /* Always report verification result */ 1019 if (verify_resultp != NULL) 1020 *verify_resultp = verify_result; 1021 1022 return (rc); 1023 } 1024 1025 #if EFSYS_OPT_DIAG 1026 1027 __checkReturn efx_rc_t 1028 efx_mcdi_nvram_test( 1029 __in efx_nic_t *enp, 1030 __in uint32_t partn) 1031 { 1032 efx_mcdi_req_t req; 1033 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN, 1034 MC_CMD_NVRAM_TEST_OUT_LEN); 1035 int result; 1036 efx_rc_t rc; 1037 1038 req.emr_cmd = MC_CMD_NVRAM_TEST; 1039 req.emr_in_buf = payload; 1040 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 1041 req.emr_out_buf = payload; 1042 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 1043 1044 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 1045 1046 efx_mcdi_execute(enp, &req); 1047 1048 if (req.emr_rc != 0) { 1049 rc = req.emr_rc; 1050 goto fail1; 1051 } 1052 1053 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 1054 rc = EMSGSIZE; 1055 goto fail2; 1056 } 1057 1058 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 1059 if (result == MC_CMD_NVRAM_TEST_FAIL) { 1060 EFSYS_PROBE1(nvram_test_failure, int, partn); 1061 1062 rc = (EINVAL); 1063 goto fail3; 1064 } 1065 1066 return (0); 1067 1068 fail3: 1069 EFSYS_PROBE(fail3); 1070 fail2: 1071 EFSYS_PROBE(fail2); 1072 fail1: 1073 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1074 1075 return (rc); 1076 } 1077 1078 #endif /* EFSYS_OPT_DIAG */ 1079 1080 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 1081