1 /*
   2  * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  * 1. Redistributions of source code must retain the above copyright
   8  *    notice, this list of conditions and the following disclaimer.
   9  * 2. Redistributions in binary form must reproduce the above copyright
  10  *    notice, this list of conditions and the following disclaimer in the
  11  *    documentation and/or other materials provided with the distribution.
  12  *
  13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
  14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23  * SUCH DAMAGE.
  24  */
  25 
  26 #include "efsys.h"
  27 #include "efx.h"
  28 #include "efx_types.h"
  29 #include "efx_regs.h"
  30 #include "efx_impl.h"
  31 
  32 #if EFSYS_OPT_VPD
  33 
  34 #if EFSYS_OPT_SIENA
  35 
  36 static  __checkReturn                   int
  37 siena_vpd_get_static(
  38         __in                            efx_nic_t *enp,
  39         __in                            unsigned int partn,
  40         __deref_out_bcount_opt(*sizep)  caddr_t *svpdp,
  41         __out                           size_t *sizep)
  42 {
  43         siena_mc_static_config_hdr_t *scfg;
  44         caddr_t svpd;
  45         size_t size;
  46         uint8_t cksum;
  47         unsigned int vpd_offset;
  48         unsigned int vpd_length;
  49         unsigned int hdr_length;
  50         unsigned int pos;
  51         unsigned int region;
  52         int rc;
  53 
  54         EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
  55                     partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
  56 
  57         /* Allocate sufficient memory for the entire static cfg area */
  58         if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
  59                 goto fail1;
  60 
  61         EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
  62         if (scfg == NULL) {
  63                 rc = ENOMEM;
  64                 goto fail2;
  65         }
  66 
  67         if ((rc = siena_nvram_partn_read(enp, partn, 0,
  68             (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
  69                 goto fail3;
  70 
  71         /* Verify the magic number */
  72         if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
  73             SIENA_MC_STATIC_CONFIG_MAGIC) {
  74                 rc = EINVAL;
  75                 goto fail4;
  76         }
  77 
  78         /* All future versions of the structure must be backwards compatable */
  79         EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
  80 
  81         hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
  82         vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
  83         vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
  84 
  85         /* Verify the hdr doesn't overflow the sector size */
  86         if (hdr_length > size || vpd_offset > size || vpd_length > size ||
  87             vpd_length + vpd_offset > size) {
  88                 rc = EINVAL;
  89                 goto fail5;
  90         }
  91 
  92         /* Read the remainder of scfg + static vpd */
  93         region = vpd_offset + vpd_length;
  94         if (region > SIENA_NVRAM_CHUNK) {
  95                 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
  96                     (caddr_t)scfg + SIENA_NVRAM_CHUNK,
  97                     region - SIENA_NVRAM_CHUNK)) != 0)
  98                         goto fail6;
  99         }
 100 
 101         /* Verify checksum */
 102         cksum = 0;
 103         for (pos = 0; pos < hdr_length; pos++)
 104                 cksum += ((uint8_t *)scfg)[pos];
 105         if (cksum != 0) {
 106                 rc = EINVAL;
 107                 goto fail7;
 108         }
 109 
 110         if (vpd_length == 0)
 111                 svpd = NULL;
 112         else {
 113                 /* Copy the vpd data out */
 114                 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
 115                 if (svpd == NULL) {
 116                         rc = ENOMEM;
 117                         goto fail8;
 118                 }
 119                 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
 120         }
 121 
 122         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
 123 
 124         *svpdp = svpd;
 125         *sizep = vpd_length;
 126 
 127         return (0);
 128 
 129 fail8:
 130         EFSYS_PROBE(fail8);
 131 fail7:
 132         EFSYS_PROBE(fail7);
 133 fail6:
 134         EFSYS_PROBE(fail6);
 135 fail5:
 136         EFSYS_PROBE(fail5);
 137 fail4:
 138         EFSYS_PROBE(fail4);
 139 fail3:
 140         EFSYS_PROBE(fail3);
 141 fail2:
 142         EFSYS_PROBE(fail2);
 143 
 144         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
 145 
 146 fail1:
 147         EFSYS_PROBE1(fail1, int, rc);
 148 
 149         return (rc);
 150 }
 151 
 152         __checkReturn           int
 153 siena_vpd_init(
 154         __in                    efx_nic_t *enp)
 155 {
 156         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 157         caddr_t svpd = NULL;
 158         unsigned partn;
 159         size_t size = 0;
 160         int rc;
 161 
 162         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 163 
 164         partn = (emip->emi_port == 1)
 165                 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
 166                 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
 167 
 168         /*
 169          * We need the static VPD sector to present a unified static+dynamic
 170          * VPD, that is, basically on every read, write, verify cycle. Since
 171          * it should *never* change we can just cache it here.
 172          */
 173         if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
 174                 goto fail1;
 175 
 176         if (svpd != NULL && size > 0) {
 177                 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
 178                         goto fail2;
 179         }
 180 
 181         enp->en_u.siena.enu_svpd = svpd;
 182         enp->en_u.siena.enu_svpd_length = size;
 183 
 184         return (0);
 185 
 186 fail2:
 187         EFSYS_PROBE(fail2);
 188 
 189         EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
 190 fail1:
 191         EFSYS_PROBE1(fail1, int, rc);
 192 
 193         return (rc);
 194 }
 195 
 196         __checkReturn           int
 197 siena_vpd_size(
 198         __in                    efx_nic_t *enp,
 199         __out                   size_t *sizep)
 200 {
 201         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 202         unsigned int partn;
 203         int rc;
 204 
 205         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 206 
 207         /*
 208          * This function returns the total size the user should allocate
 209          * for all VPD operations. We've already cached the static vpd,
 210          * so we just need to return an upper bound on the dynamic vpd.
 211          * Since the dynamic_config structure can change under our feet,
 212          * (as version numbers are inserted), just be safe and return the
 213          * total size of the dynamic_config *sector*
 214          */
 215         partn = (emip->emi_port == 1)
 216                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
 217                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
 218 
 219         if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
 220                 goto fail1;
 221 
 222         return (0);
 223 
 224 fail1:
 225         EFSYS_PROBE1(fail1, int, rc);
 226 
 227         return (rc);
 228 }
 229 
 230         __checkReturn           int
 231 siena_vpd_read(
 232         __in                    efx_nic_t *enp,
 233         __out_bcount(size)      caddr_t data,
 234         __in                    size_t size)
 235 {
 236         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 237         siena_mc_dynamic_config_hdr_t *dcfg;
 238         unsigned int vpd_length;
 239         unsigned int vpd_offset;
 240         unsigned int dcfg_partn;
 241         size_t dcfg_size;
 242         int rc;
 243 
 244         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 245 
 246         dcfg_partn = (emip->emi_port == 1)
 247                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
 248                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
 249 
 250         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
 251             B_TRUE, &dcfg, &dcfg_size)) != 0)
 252                 goto fail1;
 253 
 254         vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
 255         vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
 256 
 257         if (vpd_length > size) {
 258                 rc = EFAULT;    /* Invalid dcfg: header bigger than sector */
 259                 goto fail2;
 260         }
 261 
 262         EFSYS_ASSERT3U(vpd_length, <=, size);
 263         memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
 264 
 265         /* Pad data with all-1s, consistent with update operations */
 266         memset(data + vpd_length, 0xff, size - vpd_length);
 267 
 268         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
 269 
 270         return (0);
 271 
 272 fail2:
 273         EFSYS_PROBE(fail2);
 274 
 275         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
 276 fail1:
 277         EFSYS_PROBE1(fail1, int, rc);
 278 
 279         return (rc);
 280 }
 281 
 282         __checkReturn           int
 283 siena_vpd_verify(
 284         __in                    efx_nic_t *enp,
 285         __in_bcount(size)       caddr_t data,
 286         __in                    size_t size)
 287 {
 288         efx_vpd_tag_t stag;
 289         efx_vpd_tag_t dtag;
 290         efx_vpd_keyword_t skey;
 291         efx_vpd_keyword_t dkey;
 292         unsigned int scont;
 293         unsigned int dcont;
 294 
 295         int rc;
 296 
 297         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 298 
 299         /*
 300          * Strictly you could take the view that dynamic vpd is optional.
 301          * Instead, to conform more closely to the read/verify/reinit()
 302          * paradigm, we require dynamic vpd. siena_vpd_reinit() will
 303          * reinitialize it as required.
 304          */
 305         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
 306                 goto fail1;
 307 
 308         /*
 309          * Verify that there is no duplication between the static and
 310          * dynamic cfg sectors.
 311          */
 312         if (enp->en_u.siena.enu_svpd_length == 0)
 313                 goto done;
 314 
 315         dcont = 0;
 316         _NOTE(CONSTANTCONDITION)
 317         while (1) {
 318                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
 319                     &dkey, NULL, NULL, &dcont)) != 0)
 320                         goto fail2;
 321                 if (dcont == 0)
 322                         break;
 323 
 324                 scont = 0;
 325                 _NOTE(CONSTANTCONDITION)
 326                 while (1) {
 327                         if ((rc = efx_vpd_hunk_next(
 328                             enp->en_u.siena.enu_svpd,
 329                             enp->en_u.siena.enu_svpd_length, &stag, &skey,
 330                             NULL, NULL, &scont)) != 0)
 331                                 goto fail3;
 332                         if (scont == 0)
 333                                 break;
 334 
 335                         if (stag == dtag && skey == dkey) {
 336                                 rc = EEXIST;
 337                                 goto fail4;
 338                         }
 339                 }
 340         }
 341 
 342 done:
 343         return (0);
 344 
 345 fail4:
 346         EFSYS_PROBE(fail4);
 347 fail3:
 348         EFSYS_PROBE(fail3);
 349 fail2:
 350         EFSYS_PROBE(fail2);
 351 fail1:
 352         EFSYS_PROBE1(fail1, int, rc);
 353 
 354         return (rc);
 355 }
 356 
 357         __checkReturn           int
 358 siena_vpd_reinit(
 359         __in                    efx_nic_t *enp,
 360         __in_bcount(size)       caddr_t data,
 361         __in                    size_t size)
 362 {
 363         boolean_t wantpid;
 364         int rc;
 365 
 366         /*
 367          * Only create a PID if the dynamic cfg doesn't have one
 368          */
 369         if (enp->en_u.siena.enu_svpd_length == 0)
 370                 wantpid = B_TRUE;
 371         else {
 372                 unsigned int offset;
 373                 uint8_t length;
 374 
 375                 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
 376                                     enp->en_u.siena.enu_svpd_length,
 377                                     EFX_VPD_ID, 0, &offset, &length);
 378                 if (rc == 0)
 379                         wantpid = B_FALSE;
 380                 else if (rc == ENOENT)
 381                         wantpid = B_TRUE;
 382                 else
 383                         goto fail1;
 384         }
 385 
 386         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
 387                 goto fail2;
 388 
 389         return (0);
 390 
 391 fail2:
 392         EFSYS_PROBE(fail2);
 393 fail1:
 394         EFSYS_PROBE1(fail1, int, rc);
 395 
 396         return (rc);
 397 }
 398 
 399         __checkReturn           int
 400 siena_vpd_get(
 401         __in                    efx_nic_t *enp,
 402         __in_bcount(size)       caddr_t data,
 403         __in                    size_t size,
 404         __inout                 efx_vpd_value_t *evvp)
 405 {
 406         unsigned int offset;
 407         uint8_t length;
 408         int rc;
 409 
 410         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 411 
 412         /* Attempt to satisfy the request from svpd first */
 413         if (enp->en_u.siena.enu_svpd_length > 0) {
 414                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
 415                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
 416                     evvp->evv_keyword, &offset, &length)) == 0) {
 417                         evvp->evv_length = length;
 418                         memcpy(evvp->evv_value,
 419                             enp->en_u.siena.enu_svpd + offset, length);
 420                         return (0);
 421                 } else if (rc != ENOENT)
 422                         goto fail1;
 423         }
 424 
 425         /* And then from the provided data buffer */
 426         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
 427             evvp->evv_keyword, &offset, &length)) != 0)
 428                 goto fail2;
 429 
 430         evvp->evv_length = length;
 431         memcpy(evvp->evv_value, data + offset, length);
 432 
 433         return (0);
 434 
 435 fail2:
 436         EFSYS_PROBE(fail2);
 437 fail1:
 438         EFSYS_PROBE1(fail1, int, rc);
 439 
 440         return (rc);
 441 }
 442 
 443         __checkReturn           int
 444 siena_vpd_set(
 445         __in                    efx_nic_t *enp,
 446         __in_bcount(size)       caddr_t data,
 447         __in                    size_t size,
 448         __in                    efx_vpd_value_t *evvp)
 449 {
 450         int rc;
 451 
 452         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 453 
 454         /* If the provided (tag,keyword) exists in svpd, then it is readonly */
 455         if (enp->en_u.siena.enu_svpd_length > 0) {
 456                 unsigned int offset;
 457                 uint8_t length;
 458 
 459                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
 460                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
 461                     evvp->evv_keyword, &offset, &length)) == 0) {
 462                         rc = EACCES;
 463                         goto fail1;
 464                 }
 465         }
 466 
 467         if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
 468                 goto fail2;
 469 
 470         return (0);
 471 
 472 fail2:
 473         EFSYS_PROBE(fail2);
 474 fail1:
 475         EFSYS_PROBE1(fail1, int, rc);
 476 
 477         return (rc);
 478 }
 479 
 480         __checkReturn           int
 481 siena_vpd_next(
 482         __in                    efx_nic_t *enp,
 483         __in_bcount(size)       caddr_t data,
 484         __in                    size_t size,
 485         __out                   efx_vpd_value_t *evvp,
 486         __inout                 unsigned int *contp)
 487 {
 488         _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
 489 
 490         return (ENOTSUP);
 491 }
 492 
 493         __checkReturn           int
 494 siena_vpd_write(
 495         __in                    efx_nic_t *enp,
 496         __in_bcount(size)       caddr_t data,
 497         __in                    size_t size)
 498 {
 499         efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
 500         siena_mc_dynamic_config_hdr_t *dcfg;
 501         unsigned int vpd_offset;
 502         unsigned int dcfg_partn;
 503         unsigned int hdr_length;
 504         unsigned int pos;
 505         uint8_t cksum;
 506         size_t partn_size, dcfg_size;
 507         size_t vpd_length;
 508         int rc;
 509 
 510         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 511 
 512         /* Determine total length of all tags */
 513         if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
 514                 goto fail1;
 515 
 516         /* Lock dynamic config sector for write, and read structure only */
 517         dcfg_partn = (emip->emi_port == 1)
 518                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
 519                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
 520 
 521         if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
 522                 goto fail2;
 523 
 524         if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
 525                 goto fail2;
 526 
 527         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
 528             B_FALSE, &dcfg, &dcfg_size)) != 0)
 529                 goto fail3;
 530 
 531         hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
 532 
 533         /* Allocated memory should have room for the new VPD */
 534         if (hdr_length + vpd_length > dcfg_size) {
 535                 rc = ENOSPC;
 536                 goto fail3;
 537         }
 538 
 539         /* Copy in new vpd and update header */
 540         vpd_offset = dcfg_size - vpd_length;
 541         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
 542         memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
 543         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length,
 544                             EFX_DWORD_0, vpd_length);
 545 
 546         /* Update the checksum */
 547         cksum = 0;
 548         for (pos = 0; pos < hdr_length; pos++)
 549                 cksum += ((uint8_t *)dcfg)[pos];
 550         dcfg->csum.eb_u8[0] -= cksum;
 551 
 552         /* Erase and write the new sector */
 553         if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
 554                 goto fail4;
 555 
 556         /* Write out the new structure to nvram */
 557         if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
 558             vpd_offset + vpd_length)) != 0)
 559                 goto fail5;
 560 
 561         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
 562 
 563         siena_nvram_partn_unlock(enp, dcfg_partn);
 564 
 565         return (0);
 566 
 567 fail5:
 568         EFSYS_PROBE(fail5);
 569 fail4:
 570         EFSYS_PROBE(fail4);
 571 fail3:
 572         EFSYS_PROBE(fail3);
 573 
 574         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
 575 fail2:
 576         EFSYS_PROBE(fail2);
 577 
 578         siena_nvram_partn_unlock(enp, dcfg_partn);
 579 fail1:
 580         EFSYS_PROBE1(fail1, int, rc);
 581 
 582         return (rc);
 583 }
 584 
 585                                 void
 586 siena_vpd_fini(
 587         __in                    efx_nic_t *enp)
 588 {
 589         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
 590 
 591         if (enp->en_u.siena.enu_svpd_length > 0) {
 592                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
 593                                 enp->en_u.siena.enu_svpd);
 594 
 595                 enp->en_u.siena.enu_svpd = NULL;
 596                 enp->en_u.siena.enu_svpd_length = 0;
 597         }
 598 }
 599 
 600 #endif  /* EFSYS_OPT_SIENA */
 601 
 602 #endif  /* EFSYS_OPT_VPD */