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