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 void 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 373 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 374 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 375 376 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 377 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 378 379 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 380 381 if (envop->envo_type_to_partn(enp, type, &partn) == 0) 382 envop->envo_partn_rw_finish(enp, partn); 383 384 enp->en_nvram_locked = EFX_NVRAM_INVALID; 385 } 386 387 __checkReturn efx_rc_t 388 efx_nvram_set_version( 389 __in efx_nic_t *enp, 390 __in efx_nvram_type_t type, 391 __in_ecount(4) uint16_t version[4]) 392 { 393 const efx_nvram_ops_t *envop = enp->en_envop; 394 uint32_t partn; 395 efx_rc_t rc; 396 397 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 398 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 399 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 400 401 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 402 403 /* 404 * The Siena implementation of envo_set_version() will attempt to 405 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector. 406 * Therefore, you can't have already acquired the NVRAM_UPDATE lock. 407 */ 408 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 409 410 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 411 goto fail1; 412 413 if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0) 414 goto fail2; 415 416 return (0); 417 418 fail2: 419 EFSYS_PROBE(fail2); 420 fail1: 421 EFSYS_PROBE1(fail1, efx_rc_t, rc); 422 423 return (rc); 424 } 425 426 /* Validate buffer contents (before writing to flash) */ 427 __checkReturn efx_rc_t 428 efx_nvram_validate( 429 __in efx_nic_t *enp, 430 __in efx_nvram_type_t type, 431 __in_bcount(partn_size) caddr_t partn_data, 432 __in size_t partn_size) 433 { 434 const efx_nvram_ops_t *envop = enp->en_envop; 435 uint32_t partn; 436 efx_rc_t rc; 437 438 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 439 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 440 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 441 442 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 443 444 445 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 446 goto fail1; 447 448 if (envop->envo_type_to_partn != NULL && 449 ((rc = envop->envo_buffer_validate(enp, partn, 450 partn_data, partn_size)) != 0)) 451 goto fail2; 452 453 return (0); 454 455 fail2: 456 EFSYS_PROBE(fail2); 457 fail1: 458 EFSYS_PROBE1(fail1, efx_rc_t, rc); 459 460 return (rc); 461 } 462 463 464 void 465 efx_nvram_fini( 466 __in efx_nic_t *enp) 467 { 468 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 469 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 470 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 471 472 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 473 474 enp->en_envop = NULL; 475 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 476 } 477 478 #endif /* EFSYS_OPT_NVRAM */ 479 480 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 481 482 /* 483 * Internal MCDI request handling 484 */ 485 486 __checkReturn efx_rc_t 487 efx_mcdi_nvram_partitions( 488 __in efx_nic_t *enp, 489 __out_bcount(size) caddr_t data, 490 __in size_t size, 491 __out unsigned int *npartnp) 492 { 493 efx_mcdi_req_t req; 494 uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN, 495 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)]; 496 unsigned int npartn; 497 efx_rc_t rc; 498 499 (void) memset(payload, 0, sizeof (payload)); 500 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 501 req.emr_in_buf = payload; 502 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 503 req.emr_out_buf = payload; 504 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 505 506 efx_mcdi_execute(enp, &req); 507 508 if (req.emr_rc != 0) { 509 rc = req.emr_rc; 510 goto fail1; 511 } 512 513 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 514 rc = EMSGSIZE; 515 goto fail2; 516 } 517 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 518 519 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 520 rc = ENOENT; 521 goto fail3; 522 } 523 524 if (size < npartn * sizeof (uint32_t)) { 525 rc = ENOSPC; 526 goto fail3; 527 } 528 529 *npartnp = npartn; 530 531 memcpy(data, 532 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 533 (npartn * sizeof (uint32_t))); 534 535 return (0); 536 537 fail3: 538 EFSYS_PROBE(fail3); 539 fail2: 540 EFSYS_PROBE(fail2); 541 fail1: 542 EFSYS_PROBE1(fail1, efx_rc_t, rc); 543 544 return (rc); 545 } 546 547 __checkReturn efx_rc_t 548 efx_mcdi_nvram_metadata( 549 __in efx_nic_t *enp, 550 __in uint32_t partn, 551 __out uint32_t *subtypep, 552 __out_ecount(4) uint16_t version[4], 553 __out_bcount_opt(size) char *descp, 554 __in size_t size) 555 { 556 efx_mcdi_req_t req; 557 uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN, 558 MC_CMD_NVRAM_METADATA_OUT_LENMAX)]; 559 efx_rc_t rc; 560 561 (void) memset(payload, 0, sizeof (payload)); 562 req.emr_cmd = MC_CMD_NVRAM_METADATA; 563 req.emr_in_buf = payload; 564 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 565 req.emr_out_buf = payload; 566 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 567 568 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 569 570 efx_mcdi_execute(enp, &req); 571 572 if (req.emr_rc != 0) { 573 rc = req.emr_rc; 574 goto fail1; 575 } 576 577 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 578 rc = EMSGSIZE; 579 goto fail2; 580 } 581 582 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 583 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 584 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 585 } else { 586 *subtypep = 0; 587 } 588 589 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 590 NVRAM_METADATA_OUT_VERSION_VALID)) { 591 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 592 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 593 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 594 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 595 } else { 596 version[0] = version[1] = version[2] = version[3] = 0; 597 } 598 599 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 600 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 601 /* Return optional descrition string */ 602 if ((descp != NULL) && (size > 0)) { 603 size_t desclen; 604 605 descp[0] = '\0'; 606 desclen = (req.emr_out_length_used 607 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 608 609 EFSYS_ASSERT3U(desclen, <=, 610 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 611 612 if (size < desclen) { 613 rc = ENOSPC; 614 goto fail3; 615 } 616 617 memcpy(descp, MCDI_OUT2(req, char, 618 NVRAM_METADATA_OUT_DESCRIPTION), 619 desclen); 620 621 /* Ensure string is NUL terminated */ 622 descp[desclen] = '\0'; 623 } 624 } 625 626 return (0); 627 628 fail3: 629 EFSYS_PROBE(fail3); 630 fail2: 631 EFSYS_PROBE(fail2); 632 fail1: 633 EFSYS_PROBE1(fail1, efx_rc_t, rc); 634 635 return (rc); 636 } 637 638 __checkReturn efx_rc_t 639 efx_mcdi_nvram_info( 640 __in efx_nic_t *enp, 641 __in uint32_t partn, 642 __out_opt size_t *sizep, 643 __out_opt uint32_t *addressp, 644 __out_opt uint32_t *erase_sizep, 645 __out_opt uint32_t *write_sizep) 646 { 647 uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, 648 MC_CMD_NVRAM_INFO_V2_OUT_LEN)]; 649 efx_mcdi_req_t req; 650 efx_rc_t rc; 651 652 (void) memset(payload, 0, sizeof (payload)); 653 req.emr_cmd = MC_CMD_NVRAM_INFO; 654 req.emr_in_buf = payload; 655 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 656 req.emr_out_buf = payload; 657 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 658 659 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 660 661 efx_mcdi_execute_quiet(enp, &req); 662 663 if (req.emr_rc != 0) { 664 rc = req.emr_rc; 665 goto fail1; 666 } 667 668 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 669 rc = EMSGSIZE; 670 goto fail2; 671 } 672 673 if (sizep) 674 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 675 676 if (addressp) 677 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 678 679 if (erase_sizep) 680 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 681 682 if (write_sizep) { 683 *write_sizep = 684 (req.emr_out_length_used < 685 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 686 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 687 } 688 689 return (0); 690 691 fail2: 692 EFSYS_PROBE(fail2); 693 fail1: 694 EFSYS_PROBE1(fail1, efx_rc_t, rc); 695 696 return (rc); 697 } 698 699 __checkReturn efx_rc_t 700 efx_mcdi_nvram_update_start( 701 __in efx_nic_t *enp, 702 __in uint32_t partn) 703 { 704 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN, 705 MC_CMD_NVRAM_UPDATE_START_OUT_LEN)]; 706 efx_mcdi_req_t req; 707 efx_rc_t rc; 708 709 (void) memset(payload, 0, sizeof (payload)); 710 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 711 req.emr_in_buf = payload; 712 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; 713 req.emr_out_buf = payload; 714 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 715 716 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); 717 718 efx_mcdi_execute(enp, &req); 719 720 if (req.emr_rc != 0) { 721 rc = req.emr_rc; 722 goto fail1; 723 } 724 725 return (0); 726 727 fail1: 728 EFSYS_PROBE1(fail1, efx_rc_t, rc); 729 730 return (rc); 731 } 732 733 __checkReturn efx_rc_t 734 efx_mcdi_nvram_read( 735 __in efx_nic_t *enp, 736 __in uint32_t partn, 737 __in uint32_t offset, 738 __out_bcount(size) caddr_t data, 739 __in size_t size, 740 __in uint32_t mode) 741 { 742 efx_mcdi_req_t req; 743 uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN, 744 MC_CMD_NVRAM_READ_OUT_LENMAX)]; 745 efx_rc_t rc; 746 747 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 748 rc = EINVAL; 749 goto fail1; 750 } 751 752 (void) memset(payload, 0, sizeof (payload)); 753 req.emr_cmd = MC_CMD_NVRAM_READ; 754 req.emr_in_buf = payload; 755 req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN; 756 req.emr_out_buf = payload; 757 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 758 759 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn); 760 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset); 761 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size); 762 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode); 763 764 efx_mcdi_execute(enp, &req); 765 766 if (req.emr_rc != 0) { 767 rc = req.emr_rc; 768 goto fail1; 769 } 770 771 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 772 rc = EMSGSIZE; 773 goto fail2; 774 } 775 776 memcpy(data, 777 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 778 size); 779 780 return (0); 781 782 fail2: 783 EFSYS_PROBE(fail2); 784 fail1: 785 EFSYS_PROBE1(fail1, efx_rc_t, rc); 786 787 return (rc); 788 } 789 790 __checkReturn efx_rc_t 791 efx_mcdi_nvram_erase( 792 __in efx_nic_t *enp, 793 __in uint32_t partn, 794 __in uint32_t offset, 795 __in size_t size) 796 { 797 efx_mcdi_req_t req; 798 uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN, 799 MC_CMD_NVRAM_ERASE_OUT_LEN)]; 800 efx_rc_t rc; 801 802 (void) memset(payload, 0, sizeof (payload)); 803 req.emr_cmd = MC_CMD_NVRAM_ERASE; 804 req.emr_in_buf = payload; 805 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 806 req.emr_out_buf = payload; 807 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 808 809 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 810 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 811 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 812 813 efx_mcdi_execute(enp, &req); 814 815 if (req.emr_rc != 0) { 816 rc = req.emr_rc; 817 goto fail1; 818 } 819 820 return (0); 821 822 fail1: 823 EFSYS_PROBE1(fail1, efx_rc_t, rc); 824 825 return (rc); 826 } 827 828 /* 829 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 830 * Sienna and EF10 based boards. However EF10 based boards support the use 831 * of this command with payloads up to the maximum MCDI V2 payload length. 832 */ 833 __checkReturn efx_rc_t 834 efx_mcdi_nvram_write( 835 __in efx_nic_t *enp, 836 __in uint32_t partn, 837 __in uint32_t offset, 838 __out_bcount(size) caddr_t data, 839 __in size_t size) 840 { 841 efx_mcdi_req_t req; 842 uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1, 843 MCDI_CTL_SDU_LEN_MAX_V2)]; 844 efx_rc_t rc; 845 size_t max_data_size; 846 847 max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length 848 - MC_CMD_NVRAM_WRITE_IN_LEN(0); 849 EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0); 850 EFSYS_ASSERT3U(max_data_size, <, 851 enp->en_nic_cfg.enc_mcdi_max_payload_length); 852 853 if (size > max_data_size) { 854 rc = EINVAL; 855 goto fail1; 856 } 857 858 (void) memset(payload, 0, sizeof (payload)); 859 req.emr_cmd = MC_CMD_NVRAM_WRITE; 860 req.emr_in_buf = payload; 861 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 862 req.emr_out_buf = payload; 863 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 864 865 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 866 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 867 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 868 869 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 870 data, size); 871 872 efx_mcdi_execute(enp, &req); 873 874 if (req.emr_rc != 0) { 875 rc = req.emr_rc; 876 goto fail2; 877 } 878 879 return (0); 880 881 fail2: 882 EFSYS_PROBE(fail2); 883 fail1: 884 EFSYS_PROBE1(fail1, efx_rc_t, rc); 885 886 return (rc); 887 } 888 889 __checkReturn efx_rc_t 890 efx_mcdi_nvram_update_finish( 891 __in efx_nic_t *enp, 892 __in uint32_t partn, 893 __in boolean_t reboot) 894 { 895 efx_mcdi_req_t req; 896 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN, 897 MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)]; 898 efx_rc_t rc; 899 900 (void) memset(payload, 0, sizeof (payload)); 901 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 902 req.emr_in_buf = payload; 903 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; 904 req.emr_out_buf = payload; 905 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN; 906 907 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); 908 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); 909 910 efx_mcdi_execute(enp, &req); 911 912 if (req.emr_rc != 0) { 913 rc = req.emr_rc; 914 goto fail1; 915 } 916 917 return (0); 918 919 fail1: 920 EFSYS_PROBE1(fail1, efx_rc_t, rc); 921 922 return (rc); 923 } 924 925 #if EFSYS_OPT_DIAG 926 927 __checkReturn efx_rc_t 928 efx_mcdi_nvram_test( 929 __in efx_nic_t *enp, 930 __in uint32_t partn) 931 { 932 efx_mcdi_req_t req; 933 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 934 MC_CMD_NVRAM_TEST_OUT_LEN)]; 935 int result; 936 efx_rc_t rc; 937 938 (void) memset(payload, 0, sizeof (payload)); 939 req.emr_cmd = MC_CMD_NVRAM_TEST; 940 req.emr_in_buf = payload; 941 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 942 req.emr_out_buf = payload; 943 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 944 945 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 946 947 efx_mcdi_execute(enp, &req); 948 949 if (req.emr_rc != 0) { 950 rc = req.emr_rc; 951 goto fail1; 952 } 953 954 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 955 rc = EMSGSIZE; 956 goto fail2; 957 } 958 959 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 960 if (result == MC_CMD_NVRAM_TEST_FAIL) { 961 962 EFSYS_PROBE1(nvram_test_failure, int, partn); 963 964 rc = (EINVAL); 965 goto fail3; 966 } 967 968 return (0); 969 970 fail3: 971 EFSYS_PROBE(fail3); 972 fail2: 973 EFSYS_PROBE(fail2); 974 fail1: 975 EFSYS_PROBE1(fail1, efx_rc_t, rc); 976 977 return (rc); 978 } 979 980 #endif /* EFSYS_OPT_DIAG */ 981 982 983 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 984