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