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