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 */