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