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