1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at
   9  * http://www.opensource.org/licenses/cddl1.txt.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  26  */
  27 
  28 #define EMLXS_FW_TABLE_DEF
  29 #define EMLXS_MODEL_DEF
  30 
  31 #include <emlxs.h>
  32 
  33 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
  34 EMLXS_MSG_DEF(EMLXS_HBA_C);
  35 
  36 
  37 static void emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp,
  38     IOCBQ *iocbq);
  39 
  40 static void emlxs_pci_cap_offsets(emlxs_hba_t *hba);
  41 
  42 #ifdef MSI_SUPPORT
  43 uint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
  44         {EMLXS_MSI_MAP1, EMLXS_MSI_MAP2, EMLXS_MSI_MAP4, EMLXS_MSI_MAP8};
  45 uint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
  46         {EMLXS_MSI0_MASK1, EMLXS_MSI0_MASK2, EMLXS_MSI0_MASK4,
  47         EMLXS_MSI0_MASK8};
  48 #endif /* MSI_SUPPORT */
  49 
  50 emlxs_firmware_t emlxs_fw_table[] = EMLXS_FW_TABLE;
  51 int emlxs_fw_count = sizeof (emlxs_fw_table) / sizeof (emlxs_firmware_t);
  52 
  53 emlxs_table_t emlxs_pci_cap[] = {
  54         {PCI_CAP_ID_PM, "PCI_CAP_ID_PM"},
  55         {PCI_CAP_ID_AGP, "PCI_CAP_ID_AGP"},
  56         {PCI_CAP_ID_VPD, "PCI_CAP_ID_VPD"},
  57         {PCI_CAP_ID_SLOT_ID, "PCI_CAP_ID_SLOT_ID"},
  58         {PCI_CAP_ID_MSI, "PCI_CAP_ID_MSI"},
  59         {PCI_CAP_ID_cPCI_HS, "PCI_CAP_ID_cPCI_HS"},
  60         {PCI_CAP_ID_PCIX, "PCI_CAP_ID_PCIX"},
  61         {PCI_CAP_ID_HT, "PCI_CAP_ID_HT"},
  62         {PCI_CAP_ID_VS, "PCI_CAP_ID_VS"},
  63         {PCI_CAP_ID_DEBUG_PORT, "PCI_CAP_ID_DEBUG_PORT"},
  64         {PCI_CAP_ID_cPCI_CRC, "PCI_CAP_ID_cPCI_CRC"},
  65         {PCI_CAP_ID_PCI_HOTPLUG, "PCI_CAP_ID_PCI_HOTPLUG"},
  66         {PCI_CAP_ID_P2P_SUBSYS, "PCI_CAP_ID_P2P_SUBSYS"},
  67         {PCI_CAP_ID_AGP_8X, "PCI_CAP_ID_AGP_8X"},
  68         {PCI_CAP_ID_SECURE_DEV, "PCI_CAP_ID_SECURE_DEV"},
  69         {PCI_CAP_ID_PCI_E, "PCI_CAP_ID_PCI_E"},
  70         {PCI_CAP_ID_MSI_X, "PCI_CAP_ID_MSI_X"},
  71         {PCI_CAP_ID_SATA, "PCI_CAP_ID_SATA"},
  72         {PCI_CAP_ID_FLR, "PCI_CAP_ID_FLR"}
  73 
  74 }; /* emlxs_pci_cap */
  75 
  76 emlxs_table_t emlxs_pci_ecap[] = {
  77         {PCIE_EXT_CAP_ID_AER, "PCIE_EXT_CAP_ID_AER"},
  78         {PCIE_EXT_CAP_ID_VC, "PCIE_EXT_CAP_ID_VC"},
  79         {PCIE_EXT_CAP_ID_SER, "PCIE_EXT_CAP_ID_SER"},
  80         {PCIE_EXT_CAP_ID_PWR_BUDGET, "PCIE_EXT_CAP_ID_PWR_BUDGET"},
  81         {PCIE_EXT_CAP_ID_RC_LINK_DECL, "PCIE_EXT_CAP_ID_RC_LINK_DECL"},
  82         {PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "PCIE_EXT_CAP_ID_RC_INT_LINKCTRL"},
  83         {PCIE_EXT_CAP_ID_RC_EVNT_CEA, "PCIE_EXT_CAP_ID_RC_EVNT_CEA"},
  84         {PCIE_EXT_CAP_ID_MFVC, "PCIE_EXT_CAP_ID_MFVC"},
  85         {PCIE_EXT_CAP_ID_VC_WITH_MFVC, "PCIE_EXT_CAP_ID_VC_WITH_MFVC"},
  86         {PCIE_EXT_CAP_ID_RCRB, "PCIE_EXT_CAP_ID_RCRB"},
  87         {PCIE_EXT_CAP_ID_VS, "PCIE_EXT_CAP_ID_VS"},
  88         {PCIE_EXT_CAP_ID_CAC, "PCIE_EXT_CAP_ID_CAC"},
  89         {PCIE_EXT_CAP_ID_ACS, "PCIE_EXT_CAP_ID_ACS"},
  90         {PCIE_EXT_CAP_ID_ARI, "PCIE_EXT_CAP_ID_ARI"},
  91         {PCIE_EXT_CAP_ID_ATS, "PCIE_EXT_CAP_ID_ATS"},
  92         {PCI_EXT_CAP_ID_SRIOV, "PCI_EXT_CAP_ID_SRIOV"},
  93         {PCI_EXT_CAP_ID_TPH, "PCI_EXT_CAP_ID_TPH"},
  94         {PCI_EXT_CAP_ID_SEC_PCI, "PCI_EXT_CAP_ID_SEC_PCI"}
  95 
  96 }; /* emlxs_pci_ecap */
  97 
  98 
  99 emlxs_table_t emlxs_ring_table[] = {
 100         {FC_FCP_RING, "FCP Ring"},
 101         {FC_IP_RING, "IP  Ring"},
 102         {FC_ELS_RING, "ELS Ring"},
 103         {FC_CT_RING, "CT  Ring"}
 104 
 105 }; /* emlxs_ring_table */
 106 
 107 emlxs_table_t emlxs_ffstate_table[] = {
 108         {0, "NULL"},
 109         {FC_ERROR, "ERROR"},
 110         {FC_KILLED, "KILLED"},
 111         {FC_WARM_START, "WARM_START"},
 112         {FC_INIT_START, "INIT_START"},
 113         {FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
 114         {FC_INIT_REV, "INIT_REV"},
 115         {FC_INIT_CFGPORT, "INIT_CFGPORT"},
 116         {FC_INIT_CFGRING, "INIT_CFGRING"},
 117         {FC_INIT_INITLINK, "INIT_INITLINK"},
 118         {FC_LINK_DOWN, "LINK_DOWN"},
 119         {FC_LINK_UP, "LINK_UP"},
 120         {FC_CLEAR_LA, "CLEAR_LA"},
 121         {FC_READY, "READY"}
 122 
 123 }; /* emlxs_ffstate_table */
 124 
 125 
 126 #ifdef MSI_SUPPORT
 127 /* EMLXS_INTR_INIT */
 128 int32_t
 129 emlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
 130 {
 131         emlxs_port_t *port = &PPORT;
 132         int32_t pass = 0;
 133         int32_t type = 0;
 134         char s_type[16];
 135         int32_t types;
 136         int32_t count;
 137         int32_t nintrs;
 138         int32_t mode;
 139         int32_t actual;
 140         int32_t new_actual;
 141         int32_t i;
 142         int32_t ret;
 143         ddi_intr_handle_t *htable = NULL;
 144         ddi_intr_handle_t *new_htable = NULL;
 145         uint32_t *intr_pri = NULL;
 146         int32_t *intr_cap = NULL;
 147         int32_t hilevel_pri;
 148         emlxs_config_t *cfg = &CFG;
 149 
 150         if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
 151                 return (emlxs_intx_init(hba, max));
 152         }
 153 
 154         if (hba->intr_flags & EMLXS_MSI_INITED) {
 155                 return (DDI_SUCCESS);
 156         }
 157 
 158         /* Set max interrupt count if not specified */
 159         if (max == 0) {
 160                 if ((cfg[CFG_MSI_MODE].current == 2) ||
 161                     (cfg[CFG_MSI_MODE].current == 3)) {
 162                         max = EMLXS_MSI_MAX_INTRS;
 163                 } else {
 164                         max = 1;
 165                 }
 166         }
 167 
 168         /* Filter max interrupt count with adapter model specification */
 169         if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
 170                 max = hba->model_info.intr_limit;
 171         }
 172 
 173         /* Get the available interrupt types from the kernel */
 174         types = 0;
 175         ret = ddi_intr_get_supported_types(hba->dip, &types);
 176 
 177         if ((ret != DDI_SUCCESS)) {
 178                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 179                     "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
 180 
 181                 /* Default to fixed type */
 182                 types = DDI_INTR_TYPE_FIXED;
 183         }
 184 
 185         /* Check if fixed interrupts are being forced */
 186         if (cfg[CFG_MSI_MODE].current == 0) {
 187                 types &= DDI_INTR_TYPE_FIXED;
 188         }
 189 
 190         /* Check if MSI interrupts are being forced */
 191         else if ((cfg[CFG_MSI_MODE].current == 1) ||
 192             (cfg[CFG_MSI_MODE].current == 2)) {
 193                 types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
 194         }
 195 
 196 begin:
 197 
 198         /* Set interrupt type and interrupt count */
 199         type = 0;
 200 
 201         /* Check if MSIX is fully supported */
 202         if ((types & DDI_INTR_TYPE_MSIX) &&
 203             (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
 204                 /* Get the max interrupt count from the adapter */
 205                 nintrs = 0;
 206                 ret =
 207                     ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX,
 208                     &nintrs);
 209 
 210                 if (ret == DDI_SUCCESS && nintrs) {
 211                         type = DDI_INTR_TYPE_MSIX;
 212                         (void) strlcpy(s_type, "TYPE_MSIX", sizeof (s_type));
 213                         goto initialize;
 214                 }
 215         }
 216 
 217         /* Check if MSI is fully supported */
 218         if ((types & DDI_INTR_TYPE_MSI) &&
 219             (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
 220                 /* Get the max interrupt count from the adapter */
 221                 nintrs = 0;
 222                 ret =
 223                     ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
 224 
 225                 if (ret == DDI_SUCCESS && nintrs) {
 226                         type = DDI_INTR_TYPE_MSI;
 227                         (void) strlcpy(s_type, "TYPE_MSI", sizeof (s_type));
 228                         goto initialize;
 229                 }
 230         }
 231 
 232         /* Check if fixed interrupts are fully supported */
 233         if ((types & DDI_INTR_TYPE_FIXED) &&
 234             (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
 235                 /* Get the max interrupt count from the adapter */
 236                 nintrs = 0;
 237                 ret =
 238                     ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED,
 239                     &nintrs);
 240 
 241                 if (ret == DDI_SUCCESS) {
 242                         type = DDI_INTR_TYPE_FIXED;
 243                         (void) strlcpy(s_type, "TYPE_FIXED", sizeof (s_type));
 244                         goto initialize;
 245                 }
 246         }
 247 
 248         goto init_failed;
 249 
 250 
 251 initialize:
 252 
 253         pass++;
 254         mode = 0;
 255         actual = 0;
 256         htable = NULL;
 257         intr_pri = NULL;
 258         intr_cap = NULL;
 259         hilevel_pri = 0;
 260 
 261         if (pass == 1) {
 262                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 263                     "MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
 264                     cfg[CFG_MSI_MODE].current, types, nintrs);
 265         }
 266 
 267         /* Validate interrupt count */
 268         count = min(nintrs, max);
 269 
 270         if (count >= 8) {
 271                 count = 8;
 272         } else if (count >= 4) {
 273                 count = 4;
 274         } else if (count >= 2) {
 275                 count = 2;
 276         } else {
 277                 count = 1;
 278         }
 279 
 280         /* Allocate an array of interrupt handles */
 281         htable =
 282             kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)),
 283             KM_SLEEP);
 284 
 285         /* Allocate 'count' interrupts */
 286         ret =
 287             ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
 288             &actual, DDI_INTR_ALLOC_NORMAL);
 289 
 290         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 291             "MSI: %s: count=%d actual=%d ret=%d", s_type, count, actual, ret);
 292 
 293         if ((ret != DDI_SUCCESS) || (actual == 0)) {
 294                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 295                     "MSI: Unable to allocate interrupts. error=%d", ret);
 296 
 297                 actual = 0;
 298                 goto init_failed;
 299         }
 300 
 301         if (actual != count) {
 302                 /* Validate actual count */
 303                 if (actual >= 8) {
 304                         new_actual = 8;
 305                 } else if (actual >= 4) {
 306                         new_actual = 4;
 307                 } else if (actual >= 2) {
 308                         new_actual = 2;
 309                 } else {
 310                         new_actual = 1;
 311                 }
 312 
 313                 if (new_actual < actual) {
 314                         /* Free extra handles */
 315                         for (i = new_actual; i < actual; i++) {
 316                                 (void) ddi_intr_free(htable[i]);
 317                         }
 318 
 319                         actual = new_actual;
 320                 }
 321 
 322                 /* Allocate a new array of interrupt handles */
 323                 new_htable =
 324                     kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
 325                     KM_SLEEP);
 326 
 327                 /* Copy old array to new array */
 328                 bcopy((uint8_t *)htable, (uint8_t *)new_htable,
 329                     (actual * sizeof (ddi_intr_handle_t)));
 330 
 331                 /* Free the old array */
 332                 kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
 333 
 334                 htable = new_htable;
 335                 count = actual;
 336         }
 337 
 338         /* Allocate interrupt priority table */
 339         intr_pri =
 340             (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
 341             KM_SLEEP);
 342 
 343         /* Allocate interrupt capability table */
 344         intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
 345 
 346         /* Get minimum hilevel priority */
 347         hilevel_pri = ddi_intr_get_hilevel_pri();
 348 
 349         /* Fill the priority and capability tables */
 350         for (i = 0; i < count; ++i) {
 351                 ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
 352 
 353                 if (ret != DDI_SUCCESS) {
 354                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 355                             "MSI: ddi_intr_get_pri(%d) failed. "
 356                             "handle=%p ret=%d",
 357                             i, &htable[i], ret);
 358 
 359                         /* Clean up the interrupts */
 360                         goto init_failed;
 361                 }
 362 
 363                 if (intr_pri[i] >= hilevel_pri) {
 364                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 365                             "MSI: Interrupt(%d) level too high. "
 366                             "pri=0x%x hilevel=0x%x",
 367                             i, intr_pri[i], hilevel_pri);
 368 
 369                         /* Clean up the interrupts */
 370                         goto init_failed;
 371                 }
 372 
 373                 ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
 374 
 375                 if (ret != DDI_SUCCESS) {
 376                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 377                             "MSI: ddi_intr_get_cap(%d) failed. "
 378                             "handle=%p ret=%d",
 379                             i, &htable[i], ret);
 380 
 381                         /* Clean up the interrupts */
 382                         goto init_failed;
 383                 }
 384 
 385                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 386                     "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
 387                     intr_cap[i], intr_pri[i], hilevel_pri);
 388 
 389         }
 390 
 391         /* Set mode */
 392         switch (count) {
 393         case 8:
 394                 mode = EMLXS_MSI_MODE8;
 395                 break;
 396 
 397         case 4:
 398                 mode = EMLXS_MSI_MODE4;
 399                 break;
 400 
 401         case 2:
 402                 mode = EMLXS_MSI_MODE2;
 403                 break;
 404 
 405         default:
 406                 mode = EMLXS_MSI_MODE1;
 407         }
 408 
 409         /* Save the info */
 410         hba->intr_htable = htable;
 411         hba->intr_count = count;
 412         hba->intr_pri = intr_pri;
 413         hba->intr_cap = intr_cap;
 414         hba->intr_type = type;
 415         hba->intr_arg = (void *)((unsigned long)intr_pri[0]);
 416         hba->intr_mask = emlxs_msi_mask[mode];
 417 
 418         hba->intr_cond = 0;
 419 
 420         /* Adjust number of channels based on intr_count */
 421         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
 422                 hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
 423         }
 424 
 425         for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
 426                 hba->intr_map[i] = emlxs_msi_map[mode][i];
 427                 hba->intr_cond |= emlxs_msi_map[mode][i];
 428 
 429                 mutex_init(&hba->intr_lock[i], NULL, MUTEX_DRIVER,
 430                     DDI_INTR_PRI(hba->intr_arg));
 431         }
 432 
 433         /* Set flag to indicate support */
 434         hba->intr_flags |= EMLXS_MSI_INITED;
 435 
 436         /* Create the interrupt threads */
 437         for (i = 0; i < hba->chan_count; i++) {
 438                 mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
 439                     DDI_INTR_PRI(hba->intr_arg));
 440 
 441                 emlxs_thread_create(hba, &hba->chan[i].intr_thread);
 442         }
 443 
 444         return (DDI_SUCCESS);
 445 
 446 init_failed:
 447 
 448         if (intr_cap) {
 449                 kmem_free(intr_cap, (count * sizeof (int32_t)));
 450         }
 451 
 452         if (intr_pri) {
 453                 kmem_free(intr_pri, (count * sizeof (int32_t)));
 454         }
 455 
 456         if (htable) {
 457                 /* Process the interrupt handlers */
 458                 for (i = 0; i < actual; i++) {
 459                         /* Free the handle[i] */
 460                         (void) ddi_intr_free(htable[i]);
 461                 }
 462 
 463                 kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
 464         }
 465 
 466         /* Initialize */
 467         hba->intr_htable = NULL;
 468         hba->intr_count = 0;
 469         hba->intr_pri = NULL;
 470         hba->intr_cap = NULL;
 471         hba->intr_type = 0;
 472         hba->intr_arg = NULL;
 473         hba->intr_cond = 0;
 474         bzero(hba->intr_map, sizeof (hba->intr_map));
 475         bzero(hba->intr_lock, sizeof (hba->intr_lock));
 476 
 477         if (type == DDI_INTR_TYPE_MSIX) {
 478                 types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
 479                 goto begin;
 480         } else if (type == DDI_INTR_TYPE_MSI) {
 481                 types &= DDI_INTR_TYPE_FIXED;
 482                 goto begin;
 483         }
 484 
 485         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
 486             "MSI: Unable to initialize interrupts");
 487 
 488         return (DDI_FAILURE);
 489 
 490 
 491 } /* emlxs_msi_init() */
 492 
 493 
 494 /* EMLXS_INTR_UNINIT */
 495 int32_t
 496 emlxs_msi_uninit(emlxs_hba_t *hba)
 497 {
 498         uint32_t count;
 499         int32_t i;
 500         ddi_intr_handle_t *htable;
 501         uint32_t *intr_pri;
 502         int32_t *intr_cap;
 503         int32_t ret;
 504 
 505         if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
 506                 return (emlxs_intx_uninit(hba));
 507         }
 508 
 509         /*
 510          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 511          *    "MSI: msi_uninit called. flags=%x",
 512          *    hba->intr_flags);
 513          */
 514 
 515         /* Make sure interrupts have been removed first */
 516         if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
 517                 ret = emlxs_msi_remove(hba);
 518 
 519                 if (ret != DDI_SUCCESS) {
 520                         return (ret);
 521                 }
 522         }
 523 
 524         /* Check if the interrupts are still initialized */
 525         if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
 526                 return (DDI_SUCCESS);
 527         }
 528         hba->intr_flags &= ~EMLXS_MSI_INITED;
 529 
 530         /* Get handle table parameters */
 531         htable = hba->intr_htable;
 532         count = hba->intr_count;
 533         intr_pri = hba->intr_pri;
 534         intr_cap = hba->intr_cap;
 535 
 536         /* Clean up */
 537         hba->intr_count = 0;
 538         hba->intr_htable = NULL;
 539         hba->intr_pri = NULL;
 540         hba->intr_cap = NULL;
 541         hba->intr_type = 0;
 542         hba->intr_arg = NULL;
 543         hba->intr_cond = 0;
 544         bzero(hba->intr_map, sizeof (hba->intr_map));
 545 
 546         if (intr_cap) {
 547                 kmem_free(intr_cap, (count * sizeof (int32_t)));
 548         }
 549 
 550         if (intr_pri) {
 551                 kmem_free(intr_pri, (count * sizeof (int32_t)));
 552         }
 553 
 554         if (htable) {
 555                 /* Process the interrupt handlers */
 556                 for (i = 0; i < count; ++i) {
 557                         /* Free the handle[i] */
 558                         ret = ddi_intr_free(htable[i]);
 559                 }
 560 
 561                 kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
 562         }
 563 
 564         /* Destroy the intr locks */
 565         for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
 566                 mutex_destroy(&hba->intr_lock[i]);
 567         }
 568 
 569         /* Destroy the interrupt threads */
 570         for (i = 0; i < hba->chan_count; i++) {
 571                 emlxs_thread_destroy(&hba->chan[i].intr_thread);
 572                 mutex_destroy(&hba->chan[i].rsp_lock);
 573         }
 574 
 575         /*
 576          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 577          *    "MSI: msi_uninit done. flags=%x",
 578          *    hba->intr_flags);
 579          */
 580 
 581         return (DDI_SUCCESS);
 582 
 583 } /* emlxs_msi_uninit() */
 584 
 585 
 586 /* EMLXS_INTR_ADD */
 587 int32_t
 588 emlxs_msi_add(emlxs_hba_t *hba)
 589 {
 590         emlxs_port_t *port = &PPORT;
 591         int32_t count;
 592         int32_t i;
 593         int32_t ret;
 594         ddi_intr_handle_t *htable = NULL;
 595         int32_t *intr_cap = NULL;
 596 
 597         if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
 598                 return (emlxs_intx_add(hba));
 599         }
 600 
 601         /* Check if interrupts have already been added */
 602         if (hba->intr_flags & EMLXS_MSI_ADDED) {
 603                 return (DDI_SUCCESS);
 604         }
 605 
 606         /* Check if interrupts have been initialized */
 607         if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
 608                 ret = emlxs_msi_init(hba, 0);
 609 
 610                 if (ret != DDI_SUCCESS) {
 611                         return (ret);
 612                 }
 613         }
 614 
 615         /* Get handle table parameters */
 616         htable = hba->intr_htable;
 617         count = hba->intr_count;
 618         intr_cap = hba->intr_cap;
 619 
 620         /* Add the interrupt handlers */
 621         for (i = 0; i < count; ++i) {
 622                 /* add handler for handle[i] */
 623                 ret =
 624                     ddi_intr_add_handler(htable[i], EMLXS_SLI_MSI_INTR,
 625                     (char *)hba, (char *)((unsigned long)i));
 626 
 627                 if (ret != DDI_SUCCESS) {
 628                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
 629                             "MSI: ddi_intr_add_handler(%d) failed. "
 630                             "handle=%p ret=%d",
 631                             i, &htable[i], ret);
 632 
 633                         /* Process the remaining interrupt handlers */
 634                         while (i) {
 635                                 /* Decrement i */
 636                                 i--;
 637 
 638                                 /* Remove the handler */
 639                                 ret = ddi_intr_remove_handler(htable[i]);
 640 
 641                         }
 642 
 643                         return (DDI_FAILURE);
 644                 }
 645         }
 646 
 647         /* Enable the interrupts */
 648         if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
 649                 ret = ddi_intr_block_enable(htable, count);
 650 
 651                 if (ret != DDI_SUCCESS) {
 652                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 653                             "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
 654                             count, ret);
 655 
 656                         for (i = 0; i < count; ++i) {
 657                                 ret = ddi_intr_enable(htable[i]);
 658 
 659                                 if (ret != DDI_SUCCESS) {
 660                                         EMLXS_MSGF(EMLXS_CONTEXT,
 661                                             &emlxs_init_debug_msg,
 662                                             "MSI: ddi_intr_enable(%d) failed. "
 663                                             "ret=%d",
 664                                             i, ret);
 665                                 }
 666                         }
 667                 }
 668         } else {
 669                 for (i = 0; i < count; ++i) {
 670                         ret = ddi_intr_enable(htable[i]);
 671 
 672                         if (ret != DDI_SUCCESS) {
 673                                 EMLXS_MSGF(EMLXS_CONTEXT,
 674                                     &emlxs_init_debug_msg,
 675                                     "MSI: ddi_intr_enable(%d) failed. ret=%d",
 676                                     i, ret);
 677                         }
 678                 }
 679         }
 680 
 681 
 682         /* Set flag to indicate support */
 683         hba->intr_flags |= EMLXS_MSI_ADDED;
 684 
 685         return (DDI_SUCCESS);
 686 
 687 } /* emlxs_msi_add() */
 688 
 689 
 690 
 691 /* EMLXS_INTR_REMOVE */
 692 int32_t
 693 emlxs_msi_remove(emlxs_hba_t *hba)
 694 {
 695         emlxs_port_t *port = &PPORT;
 696         uint32_t count;
 697         int32_t i;
 698         ddi_intr_handle_t *htable;
 699         int32_t *intr_cap;
 700         int32_t ret;
 701 
 702         if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
 703                 return (emlxs_intx_remove(hba));
 704         }
 705 
 706         /*
 707          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 708          *    "MSI: msi_remove called. flags=%x",
 709          *    hba->intr_flags);
 710          */
 711 
 712         /* Check if interrupts have already been removed */
 713         if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
 714                 return (DDI_SUCCESS);
 715         }
 716         hba->intr_flags &= ~EMLXS_MSI_ADDED;
 717 
 718         /* Disable all adapter interrupts */
 719         EMLXS_SLI_DISABLE_INTR(hba, 0);
 720 
 721         /* Get handle table parameters */
 722         htable = hba->intr_htable;
 723         count = hba->intr_count;
 724         intr_cap = hba->intr_cap;
 725 
 726         /* Disable the interrupts */
 727         if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
 728                 ret = ddi_intr_block_disable(htable, count);
 729 
 730                 if (ret != DDI_SUCCESS) {
 731                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
 732                             "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
 733                             count, ret);
 734 
 735                         for (i = 0; i < count; i++) {
 736                                 ret = ddi_intr_disable(htable[i]);
 737 
 738                                 if (ret != DDI_SUCCESS) {
 739                                         EMLXS_MSGF(EMLXS_CONTEXT,
 740                                             &emlxs_init_debug_msg,
 741                                             "MSI: ddi_intr_disable(%d) failed. "
 742                                             "ret=%d",
 743                                             i, ret);
 744                                 }
 745                         }
 746                 }
 747         } else {
 748                 for (i = 0; i < count; i++) {
 749                         ret = ddi_intr_disable(htable[i]);
 750 
 751                         if (ret != DDI_SUCCESS) {
 752                                 EMLXS_MSGF(EMLXS_CONTEXT,
 753                                     &emlxs_init_debug_msg,
 754                                     "MSI: ddi_intr_disable(%d) failed. ret=%d",
 755                                     i, ret);
 756                         }
 757                 }
 758         }
 759 
 760         /* Process the interrupt handlers */
 761         for (i = 0; i < count; i++) {
 762                 /* Remove the handler */
 763                 ret = ddi_intr_remove_handler(htable[i]);
 764 
 765 
 766         }
 767 
 768         return (DDI_SUCCESS);
 769 
 770 } /* emlxs_msi_remove() */
 771 
 772 #endif /* MSI_SUPPORT */
 773 
 774 
 775 /* EMLXS_INTR_INIT */
 776 /* ARGSUSED */
 777 int32_t
 778 emlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
 779 {
 780         emlxs_port_t *port = &PPORT;
 781         emlxs_config_t *cfg = &CFG;
 782         int32_t ret;
 783         uint32_t i;
 784 
 785         /* Check if interrupts have already been initialized */
 786         if (hba->intr_flags & EMLXS_INTX_INITED) {
 787                 return (DDI_SUCCESS);
 788         }
 789 
 790         /* Check if adapter is flagged for INTX support */
 791         if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
 792                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
 793                     "INTX: %s does not support INTX.  flags=0x%x",
 794                     hba->model_info.model, hba->model_info.flags);
 795 
 796                 return (DDI_FAILURE);
 797         }
 798 
 799         /*
 800          * Interrupt number '0' is a high-level interrupt. This driver
 801          * does not support having its interrupts mapped above scheduler
 802          * priority; i.e., we always expect to be able to call general
 803          * kernel routines that may invoke the scheduler.
 804          */
 805         if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
 806                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
 807                     "INTX: High-level interrupt not supported.");
 808 
 809                 return (DDI_FAILURE);
 810         }
 811 
 812         /* Get an iblock cookie */
 813         ret =
 814             ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
 815             (ddi_iblock_cookie_t *)&hba->intr_arg);
 816         if (ret != DDI_SUCCESS) {
 817                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
 818                     "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
 819 
 820                 return (ret);
 821         }
 822 
 823         hba->intr_flags |= EMLXS_INTX_INITED;
 824 
 825         hba->intr_count = 1;
 826         /* Adjust number of channels based on intr_count */
 827         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
 828                 hba->chan_count = cfg[CFG_NUM_WQ].current;
 829         }
 830 
 831         /* Create the interrupt threads */
 832         for (i = 0; i < hba->chan_count; i++) {
 833                 mutex_init(&hba->chan[i].rsp_lock, NULL, MUTEX_DRIVER,
 834                     DDI_INTR_PRI(hba->intr_arg));
 835 
 836                 emlxs_thread_create(hba, &hba->chan[i].intr_thread);
 837         }
 838 
 839         return (DDI_SUCCESS);
 840 
 841 } /* emlxs_intx_init() */
 842 
 843 
 844 /* EMLXS_INTR_UNINIT */
 845 int32_t
 846 emlxs_intx_uninit(emlxs_hba_t *hba)
 847 {
 848         int32_t ret;
 849         uint32_t i;
 850 
 851         /* Make sure interrupts have been removed */
 852         if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
 853                 ret = emlxs_intx_remove(hba);
 854 
 855                 if (ret != DDI_SUCCESS) {
 856                         return (ret);
 857                 }
 858         }
 859 
 860         /* Check if the interrupts are still initialized */
 861         if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
 862                 return (DDI_SUCCESS);
 863         }
 864         hba->intr_flags &= ~EMLXS_INTX_INITED;
 865 
 866         hba->intr_arg = NULL;
 867 
 868         /* Create the interrupt threads */
 869         for (i = 0; i < hba->chan_count; i++) {
 870                 emlxs_thread_destroy(&hba->chan[i].intr_thread);
 871                 mutex_destroy(&hba->chan[i].rsp_lock);
 872         }
 873 
 874         return (DDI_SUCCESS);
 875 
 876 } /* emlxs_intx_uninit() */
 877 
 878 
 879 /*
 880  * This is the legacy method for adding interrupts in Solaris
 881  * EMLXS_INTR_ADD
 882  */
 883 int32_t
 884 emlxs_intx_add(emlxs_hba_t *hba)
 885 {
 886         emlxs_port_t *port = &PPORT;
 887         int32_t ret;
 888 
 889         /* Check if interrupts have already been added */
 890         if (hba->intr_flags & EMLXS_INTX_ADDED) {
 891                 return (DDI_SUCCESS);
 892         }
 893 
 894         /* Check if interrupts have been initialized */
 895         if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
 896                 ret = emlxs_intx_init(hba, 0);
 897 
 898                 if (ret != DDI_SUCCESS) {
 899                         return (ret);
 900                 }
 901         }
 902 
 903         /* add intrrupt handler routine */
 904         ret = ddi_add_intr((void *)hba->dip,
 905             (uint_t)EMLXS_INUMBER,
 906             (ddi_iblock_cookie_t *)&hba->intr_arg,
 907             (ddi_idevice_cookie_t *)0,
 908             (uint_t(*)())EMLXS_SLI_INTX_INTR, (caddr_t)hba);
 909 
 910         if (ret != DDI_SUCCESS) {
 911                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
 912                     "INTX: ddi_add_intr failed. ret=%d", ret);
 913 
 914                 return (ret);
 915         }
 916 
 917         hba->intr_flags |= EMLXS_INTX_ADDED;
 918 
 919         return (DDI_SUCCESS);
 920 
 921 } /* emlxs_intx_add() */
 922 
 923 
 924 /* EMLXS_INTR_REMOVE */
 925 int32_t
 926 emlxs_intx_remove(emlxs_hba_t *hba)
 927 {
 928         /* Check if interrupts have already been removed */
 929         if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
 930                 return (DDI_SUCCESS);
 931         }
 932         hba->intr_flags &= ~EMLXS_INTX_ADDED;
 933 
 934         /* Diable all adapter interrupts */
 935         EMLXS_SLI_DISABLE_INTR(hba, 0);
 936 
 937         /* Remove the interrupt */
 938         (void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
 939             hba->intr_arg);
 940 
 941         return (DDI_SUCCESS);
 942 
 943 } /* emlxs_intx_remove() */
 944 
 945 
 946 extern void
 947 emlxs_process_link_speed(emlxs_hba_t *hba)
 948 {
 949         emlxs_vpd_t *vpd;
 950         emlxs_config_t *cfg;
 951         uint32_t hi;
 952 
 953         /*
 954          * This routine modifies the link-speed config parameter entry
 955          * based on adapter capabilities
 956          */
 957         vpd = &VPD;
 958         cfg = &hba->config[CFG_LINK_SPEED];
 959 
 960         (void) strlcpy(cfg->help, "Select link speed. [0=Auto",
 961             EMLXS_CFG_HELP_SIZE);
 962         hi = 0;
 963 
 964         if (vpd->link_speed & LMT_1GB_CAPABLE) {
 965                 (void) strlcat(cfg->help, ", 1=1Gb", EMLXS_CFG_HELP_SIZE);
 966                 hi = 1;
 967         }
 968 
 969         if (vpd->link_speed & LMT_2GB_CAPABLE) {
 970                 (void) strlcat(cfg->help, ", 2=2Gb", EMLXS_CFG_HELP_SIZE);
 971                 hi = 2;
 972         }
 973 
 974         if (vpd->link_speed & LMT_4GB_CAPABLE) {
 975                 (void) strlcat(cfg->help, ", 4=4Gb", EMLXS_CFG_HELP_SIZE);
 976                 hi = 4;
 977         }
 978 
 979         if (vpd->link_speed & LMT_8GB_CAPABLE) {
 980                 (void) strlcat(cfg->help, ", 8=8Gb", EMLXS_CFG_HELP_SIZE);
 981                 hi = 8;
 982         }
 983 
 984         if (vpd->link_speed & LMT_10GB_CAPABLE) {
 985                 (void) strlcat(cfg->help, ", 10=10Gb", EMLXS_CFG_HELP_SIZE);
 986                 hi = 10;
 987         }
 988 
 989         if (vpd->link_speed & LMT_16GB_CAPABLE) {
 990                 (void) strlcat(cfg->help, ", 16=16Gb", EMLXS_CFG_HELP_SIZE);
 991                 hi = 16;
 992         }
 993 
 994         (void) strlcat(cfg->help, "]", EMLXS_CFG_HELP_SIZE);
 995         cfg->hi = hi;
 996 
 997         /* Now revalidate the current parameter setting */
 998         cfg->current = emlxs_check_parm(hba, CFG_LINK_SPEED, cfg->current);
 999 
1000         return;
1001 
1002 } /* emlxs_process_link_speed() */
1003 
1004 
1005 /*
1006  * emlxs_parse_vpd()
1007  *
1008  * This routine will parse the VPD data
1009  */
1010 extern int
1011 emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd_buf, uint32_t size)
1012 {
1013         emlxs_port_t *port = &PPORT;
1014         char tag[3];
1015         uint8_t lenlo, lenhi;
1016         uint32_t n;
1017         uint16_t block_size;
1018         uint32_t block_index = 0;
1019         uint8_t sub_size;
1020         uint32_t sub_index;
1021         int32_t finished = 0;
1022         int32_t index = 0;
1023         char buffer[128];
1024         emlxs_vpd_t *vpd;
1025 
1026         vpd = &VPD;
1027 
1028 
1029         while (!finished && (block_index < size)) {
1030                 /*
1031                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1032                  *    "block_index = %x", block_index);
1033                  */
1034 
1035                 switch (vpd_buf[block_index]) {
1036                 case 0x82:
1037                         index = block_index;
1038                         index += 1;
1039                         lenlo = vpd_buf[index];
1040                         index += 1;
1041                         lenhi = vpd_buf[index];
1042                         index += 1;
1043                         block_index = index;
1044 
1045                         block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1046                         block_index += block_size;
1047 
1048                         /*
1049                          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1050                          *    "block_size = %x", block_size);
1051                          */
1052 
1053                         n = sizeof (buffer);
1054                         bzero(buffer, n);
1055                         bcopy(&vpd_buf[index], buffer,
1056                             (block_size < (n - 1)) ? block_size : (n - 1));
1057 
1058                         (void) strncpy(vpd->id, buffer, (sizeof (vpd->id)-1));
1059                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "ID: %s",
1060                             vpd->id);
1061 
1062                         break;
1063 
1064                 case 0x90:
1065                         index = block_index;
1066                         index += 1;
1067                         lenlo = vpd_buf[index];
1068                         index += 1;
1069                         lenhi = vpd_buf[index];
1070                         index += 1;
1071                         block_index = index;
1072                         sub_index = index;
1073 
1074                         block_size = ((((uint16_t)lenhi) << 8) + lenlo);
1075                         block_index += block_size;
1076 
1077                         /*
1078                          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1079                          *    "block_size = %x", block_size);
1080                          */
1081 
1082                         /* Scan for sub-blocks */
1083                         while ((sub_index < block_index) &&
1084                             (sub_index < size)) {
1085                                 /*
1086                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1087                                  *    "sub_index = %x", sub_index);
1088                                  */
1089 
1090                                 index = sub_index;
1091                                 tag[0] = vpd_buf[index++];
1092                                 tag[1] = vpd_buf[index++];
1093                                 tag[2] = 0;
1094                                 sub_size = vpd_buf[index++];
1095 
1096                                 /*
1097                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1098                                  *    "sub_size = %x", sub_size);
1099                                  */
1100 
1101                                 sub_index = (index + sub_size);
1102 
1103                                 n = sizeof (buffer);
1104                                 bzero(buffer, n);
1105                                 bcopy(&vpd_buf[index], buffer,
1106                                     (sub_size < (n - 1)) ? sub_size : (n - 1));
1107 
1108                                 /*
1109                                  * Look for Engineering Change (EC)
1110                                  */
1111                                 if (strcmp(tag, "EC") == 0) {
1112                                         (void) strncpy(vpd->eng_change, buffer,
1113                                             (sizeof (vpd->eng_change)-1));
1114                                         EMLXS_MSGF(EMLXS_CONTEXT,
1115                                             &emlxs_vpd_msg, "EC: %s",
1116                                             vpd->eng_change);
1117                                 }
1118                                 /*
1119                                  * Look for Manufacturer (MN)
1120                                  */
1121                                 else if (strcmp(tag, "MN") == 0) {
1122                                         (void) strncpy(vpd->manufacturer,
1123                                             buffer,
1124                                             (sizeof (vpd->manufacturer)-1));
1125                                         EMLXS_MSGF(EMLXS_CONTEXT,
1126                                             &emlxs_vpd_msg, "MN: %s",
1127                                             vpd->manufacturer);
1128                                 }
1129                                 /*
1130                                  * Look for Serial Number (SN)
1131                                  */
1132                                 else if (strcmp(tag, "SN") == 0) {
1133                                         (void) strncpy(vpd->serial_num, buffer,
1134                                             (sizeof (vpd->serial_num)-1));
1135                                         EMLXS_MSGF(EMLXS_CONTEXT,
1136                                             &emlxs_vpd_msg, "SN: %s",
1137                                             vpd->serial_num);
1138 
1139                                         /* Validate the serial number */
1140                                         if (strncmp(buffer, "FFFFFFFFFF", 10) ==
1141                                             0 ||
1142                                             strncmp(buffer, "0000000000", 10) ==
1143                                             0) {
1144                                                 vpd->serial_num[0] = 0;
1145                                         }
1146                                 }
1147                                 /*
1148                                  * Look for Part Number (PN)
1149                                  */
1150                                 else if (strcmp(tag, "PN") == 0) {
1151                                         (void) strncpy(vpd->part_num, buffer,
1152                                             (sizeof (vpd->part_num)-1));
1153                                         EMLXS_MSGF(EMLXS_CONTEXT,
1154                                             &emlxs_vpd_msg, "PN: %s",
1155                                             vpd->part_num);
1156                                 }
1157                                 /*
1158                                  * Look for (V0)
1159                                  */
1160                                 else if (strcmp(tag, "V0") == 0) {
1161                                         /* Not used */
1162                                         EMLXS_MSGF(EMLXS_CONTEXT,
1163                                             &emlxs_vpd_msg, "V0: %s", buffer);
1164                                 }
1165                                 /*
1166                                  * Look for model description (V1)
1167                                  */
1168                                 else if (strcmp(tag, "V1") == 0) {
1169                                         (void) strncpy(vpd->model_desc, buffer,
1170                                             (sizeof (vpd->model_desc)-1));
1171                                         EMLXS_MSGF(EMLXS_CONTEXT,
1172                                             &emlxs_vpd_msg, "Desc: %s",
1173                                             vpd->model_desc);
1174                                 }
1175                                 /*
1176                                  * Look for model (V2)
1177                                  */
1178                                 else if (strcmp(tag, "V2") == 0) {
1179                                         (void) strncpy(vpd->model, buffer,
1180                                             (sizeof (vpd->model)-1));
1181                                         EMLXS_MSGF(EMLXS_CONTEXT,
1182                                             &emlxs_vpd_msg, "Model: %s",
1183                                             vpd->model);
1184                                 }
1185                                 /*
1186                                  * Look for program type (V3)
1187                                  */
1188 
1189                                 else if (strcmp(tag, "V3") == 0) {
1190                                         (void) strncpy(vpd->prog_types,
1191                                             buffer,
1192                                             (sizeof (vpd->prog_types)-1));
1193                                         EMLXS_MSGF(EMLXS_CONTEXT,
1194                                             &emlxs_vpd_msg, "Prog Types: %s",
1195                                             vpd->prog_types);
1196                                 }
1197                                 /*
1198                                  * Look for port number (V4)
1199                                  */
1200                                 else if (strcmp(tag, "V4") == 0) {
1201                                         (void) strncpy(vpd->port_num, buffer,
1202                                             (sizeof (vpd->port_num)-1));
1203                                         vpd->port_index =
1204                                             emlxs_strtol(vpd->port_num, 10);
1205 
1206                                         EMLXS_MSGF(EMLXS_CONTEXT,
1207                                             &emlxs_vpd_msg, "Port: %s",
1208                                             (vpd->port_num[0]) ? vpd->
1209                                             port_num : "not applicable");
1210                                 }
1211                                 /*
1212                                  * Look for checksum (RV)
1213                                  */
1214                                 else if (strcmp(tag, "RV") == 0) {
1215                                         /* Not used */
1216                                         EMLXS_MSGF(EMLXS_CONTEXT,
1217                                             &emlxs_vpd_msg, "Checksum: 0x%x",
1218                                             buffer[0]);
1219                                 }
1220 
1221                                 else {
1222                                         /* Generic */
1223                                         EMLXS_MSGF(EMLXS_CONTEXT,
1224                                             &emlxs_vpd_msg, "Tag: %s: %s",
1225                                             tag, buffer);
1226                                 }
1227                         }
1228 
1229                         break;
1230 
1231                 case 0x78:
1232                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "End Tag.");
1233                         finished = 1;
1234                         break;
1235 
1236                 default:
1237                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1238                             "Unknown block: %x %x %x %x %x %x %x %x",
1239                             vpd_buf[index], vpd_buf[index + 1],
1240                             vpd_buf[index + 2], vpd_buf[index + 3],
1241                             vpd_buf[index + 4], vpd_buf[index + 5],
1242                             vpd_buf[index + 6], vpd_buf[index + 7]);
1243                         return (0);
1244                 }
1245         }
1246 
1247         return (1);
1248 
1249 } /* emlxs_parse_vpd */
1250 
1251 
1252 /*
1253  * emlxs_parse_fcoe()
1254  *
1255  * This routine will parse the VPD data
1256  */
1257 extern int
1258 emlxs_parse_fcoe(emlxs_hba_t *hba, uint8_t *fcoep, uint32_t size)
1259 {
1260         emlxs_port_t *port = &PPORT;
1261         tlv_fcoe_t *fcoelist;
1262         tlv_fcfconnectlist_t *fcflist;
1263         int i;
1264         uint32_t flags;
1265         uint32_t entry_count;
1266         char FabricName[32];
1267         char SwitchName[32];
1268 
1269         /* Validate the config region 23 signature */
1270         if ((*fcoep != 'R') || (*(fcoep+1) != 'G') ||
1271             (*(fcoep+2) != '2') || (*(fcoep+3) != '3')) {
1272                 return (0);
1273         }
1274 
1275         /* Search the config region 23, for FCOE Parameters record */
1276         i = 4;
1277         while ((i < size) && (*(fcoep+i) != 0xA0) && (*(fcoep+i) != 0xff)) {
1278                 i += fcoep[i+1] * sizeof (uint32_t) + 2;
1279         }
1280 
1281         if (*(fcoep+i) == 0xA0) {
1282                 fcoelist = (tlv_fcoe_t *)(fcoep+i);
1283                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1284                     "Found FCOE Params (A0):%d  x%x",
1285                     fcoelist->length, fcoelist->fip_flags);
1286                 bcopy((uint8_t *)fcoelist, (uint8_t *)&hba->sli.sli4.cfgFCOE,
1287                     sizeof (tlv_fcoe_t));
1288         }
1289 
1290 
1291         /* Search the config region 23, for FCF record */
1292         i = 4;
1293         while ((i < size) && (*(fcoep+i) != 0xA1) && (*(fcoep+i) != 0xff)) {
1294                 i += fcoep[i+1] * sizeof (uint32_t) + 2;
1295         }
1296 
1297         if (*(fcoep+i) == 0xA1) {
1298                 fcflist = (tlv_fcfconnectlist_t *)(fcoep+i);
1299                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1300                     "Found FCF ConnectList (A1):%d", fcflist->length);
1301 
1302                 bcopy((uint8_t *)fcflist, (uint8_t *)&hba->sli.sli4.cfgFCF,
1303                     sizeof (tlv_fcfconnectlist_t));
1304 
1305                 /* Display the list */
1306                 entry_count = (hba->sli.sli4.cfgFCF.length *
1307                     sizeof (uint32_t)) / sizeof (tlv_fcfconnectentry_t);
1308 
1309                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1310                     "FCF List: %d entries", entry_count);
1311 
1312                 for (i = 0; i < entry_count; i++) {
1313                         flags = *(uint32_t *)&hba->sli.sli4.cfgFCF.entry[i];
1314                         (void) emlxs_wwn_xlate(FabricName, sizeof (FabricName),
1315                             hba->sli.sli4.cfgFCF.entry[i].FabricName);
1316                         (void) emlxs_wwn_xlate(SwitchName, sizeof (SwitchName),
1317                             hba->sli.sli4.cfgFCF.entry[i].SwitchName);
1318 
1319                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1320                             "FCF List:%02d %08x %s %s",
1321                             i, flags, FabricName, SwitchName);
1322                 }
1323         }
1324 
1325         return (1);
1326 
1327 } /* emlxs_parse_fcoe */
1328 
1329 
1330 extern void
1331 emlxs_decode_firmware_rev(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1332 {
1333         if (vpd->rBit) {
1334                 switch (hba->sli_mode) {
1335                 case EMLXS_HBA_SLI4_MODE:
1336                         (void) strncpy(vpd->fw_version, vpd->sli4FwName,
1337                             (sizeof (vpd->fw_version)-1));
1338                         (void) strncpy(vpd->fw_label, vpd->sli4FwLabel,
1339                             (sizeof (vpd->fw_label)-1));
1340                         break;
1341                 case EMLXS_HBA_SLI3_MODE:
1342                         (void) strncpy(vpd->fw_version, vpd->sli3FwName,
1343                             (sizeof (vpd->fw_version)-1));
1344                         (void) strncpy(vpd->fw_label, vpd->sli3FwLabel,
1345                             (sizeof (vpd->fw_label)-1));
1346                         break;
1347                 case EMLXS_HBA_SLI2_MODE:
1348                         (void) strncpy(vpd->fw_version, vpd->sli2FwName,
1349                             (sizeof (vpd->fw_version)-1));
1350                         (void) strncpy(vpd->fw_label, vpd->sli2FwLabel,
1351                             (sizeof (vpd->fw_label)-1));
1352                         break;
1353                 case EMLXS_HBA_SLI1_MODE:
1354                         (void) strncpy(vpd->fw_version, vpd->sli1FwName,
1355                             (sizeof (vpd->fw_version)-1));
1356                         (void) strncpy(vpd->fw_label, vpd->sli1FwLabel,
1357                             (sizeof (vpd->fw_label)-1));
1358                         break;
1359                 default:
1360                         (void) strncpy(vpd->fw_version, "unknown",
1361                             (sizeof (vpd->fw_version)-1));
1362                         (void) strncpy(vpd->fw_label, vpd->fw_version,
1363                             (sizeof (vpd->fw_label)-1));
1364                 }
1365         } else {
1366                 emlxs_decode_version(vpd->smFwRev, vpd->fw_version,
1367                     sizeof (vpd->fw_version));
1368                 (void) strncpy(vpd->fw_label, vpd->fw_version,
1369                     (sizeof (vpd->fw_label)-1));
1370         }
1371 
1372         return;
1373 
1374 } /* emlxs_decode_firmware_rev() */
1375 
1376 
1377 
1378 extern void
1379 emlxs_decode_version(uint32_t version, char *buffer, size_t len)
1380 {
1381         uint32_t b1, b2, b3, b4;
1382         char c;
1383 
1384         b1 = (version & 0x0000f000) >> 12;
1385         b2 = (version & 0x00000f00) >> 8;
1386         b3 = (version & 0x000000c0) >> 6;
1387         b4 = (version & 0x00000030) >> 4;
1388 
1389         if (b1 == 0 && b2 == 0) {
1390                 (void) snprintf(buffer, len, "none");
1391                 return;
1392         }
1393 
1394         c = 0;
1395         switch (b4) {
1396         case 0:
1397                 c = 'n';
1398                 break;
1399         case 1:
1400                 c = 'a';
1401                 break;
1402         case 2:
1403                 c = 'b';
1404                 break;
1405         case 3:
1406                 if ((version & 0x0000000f)) {
1407                         c = 'x';
1408                 }
1409                 break;
1410 
1411         }
1412         b4 = (version & 0x0000000f);
1413 
1414         if (c == 0) {
1415                 (void) snprintf(buffer, len, "%d.%d%d", b1, b2, b3);
1416         } else {
1417                 (void) snprintf(buffer, len, "%d.%d%d%c%d", b1, b2, b3, c, b4);
1418         }
1419 
1420         return;
1421 
1422 } /* emlxs_decode_version() */
1423 
1424 
1425 extern void
1426 emlxs_decode_label(char *label, char *buffer, int bige, size_t len)
1427 {
1428         uint32_t i;
1429         char name[16];
1430 
1431         bzero(name, sizeof (name));
1432         bcopy(label, name, MIN(sizeof (name), len));
1433         /* bige is TRUE if the data format is big endian */
1434 
1435         if (bige) {
1436                 /* Data format big Endian */
1437                 LE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
1438 
1439                 for (i = 0; i < sizeof (name); i++) {
1440                         if (name[i] == 0x20) {
1441                                 name[i] = 0;
1442                         }
1443                 }
1444         } else {
1445                 /* Data format little Endian */
1446                 BE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
1447 
1448                 for (i = 0; i < sizeof (name); i++) {
1449                         if (name[i] == 0x20) {
1450                                 name[i] = 0;
1451                         }
1452                 }
1453         }
1454 
1455         (void) strlcpy(buffer, name, len);
1456 
1457         return;
1458 
1459 } /* emlxs_decode_label() */
1460 
1461 
1462 extern uint32_t
1463 emlxs_strtol(char *str, uint32_t base)
1464 {
1465         uint32_t value = 0;
1466         char *ptr;
1467         uint32_t factor = 1;
1468         uint32_t digits;
1469 
1470         if (*str == 0) {
1471                 return (0);
1472         }
1473 
1474         if (base != 10 && base != 16) {
1475                 return (0);
1476         }
1477 
1478         /* Get max digits of value */
1479         digits = (base == 10) ? 9 : 8;
1480 
1481         /* Position pointer to end of string */
1482         ptr = str + strlen(str);
1483 
1484         /* Process string backwards */
1485         while ((ptr-- > str) && digits) {
1486                 /* check for base 10 numbers */
1487                 if (*ptr >= '0' && *ptr <= '9') {
1488                         value += ((uint32_t)(*ptr - '0')) * factor;
1489                         factor *= base;
1490                         digits--;
1491                 } else if (base == 16) {
1492                         /* Check for base 16 numbers */
1493                         if (*ptr >= 'a' && *ptr <= 'f') {
1494                                 value +=
1495                                     ((uint32_t)(*ptr - 'a') + 10) * factor;
1496                                 factor *= base;
1497                                 digits--;
1498                         } else if (*ptr >= 'A' && *ptr <= 'F') {
1499                                 value +=
1500                                     ((uint32_t)(*ptr - 'A') + 10) * factor;
1501                                 factor *= base;
1502                                 digits--;
1503                         } else if (factor > 1) {
1504                                 break;
1505                         }
1506                 } else if (factor > 1) {
1507                         break;
1508                 }
1509         }
1510 
1511         return (value);
1512 
1513 } /* emlxs_strtol() */
1514 
1515 
1516 extern uint64_t
1517 emlxs_strtoll(char *str, uint32_t base)
1518 {
1519         uint64_t value = 0;
1520         char *ptr;
1521         uint32_t factor = 1;
1522         uint32_t digits;
1523 
1524         if (*str == 0) {
1525                 return (0);
1526         }
1527 
1528         if (base != 10 && base != 16) {
1529                 return (0);
1530         }
1531 
1532         /* Get max digits of value */
1533         digits = (base == 10) ? 19 : 16;
1534 
1535         /* Position pointer to end of string */
1536         ptr = str + strlen(str);
1537 
1538         /* Process string backwards */
1539         while ((ptr-- > str) && digits) {
1540                 /* check for base 10 numbers */
1541                 if (*ptr >= '0' && *ptr <= '9') {
1542                         value += ((uint32_t)(*ptr - '0')) * factor;
1543                         factor *= base;
1544                         digits--;
1545                 } else if (base == 16) {
1546                         /* Check for base 16 numbers */
1547                         if (*ptr >= 'a' && *ptr <= 'f') {
1548                                 value +=
1549                                     ((uint32_t)(*ptr - 'a') + 10) * factor;
1550                                 factor *= base;
1551                                 digits--;
1552                         } else if (*ptr >= 'A' && *ptr <= 'F') {
1553                                 value +=
1554                                     ((uint32_t)(*ptr - 'A') + 10) * factor;
1555                                 factor *= base;
1556                                 digits--;
1557                         } else if (factor > 1) {
1558                                 break;
1559                         }
1560                 } else if (factor > 1) {
1561                         break;
1562                 }
1563         }
1564 
1565         return (value);
1566 
1567 } /* emlxs_strtoll() */
1568 
1569 extern void
1570 emlxs_parse_prog_types(emlxs_hba_t *hba, char *prog_types)
1571 {
1572         emlxs_port_t *port = &PPORT;
1573         uint32_t i;
1574         char *ptr;
1575         emlxs_model_t *model;
1576         char types_buffer[256];
1577         char *types;
1578 
1579         bcopy(prog_types, types_buffer, 256);
1580         types = types_buffer;
1581 
1582         model = &hba->model_info;
1583 
1584         while (*types) {
1585                 if (strncmp(types, "T2:", 3) == 0) {
1586                         bzero(model->pt_2, sizeof (model->pt_2));
1587                         types += 3;
1588 
1589                         i = 0;
1590                         while (*types && *types != 'T') {
1591                                 /* Null terminate the next value */
1592                                 ptr = types;
1593                                 while (*ptr && (*ptr != ','))
1594                                         ptr++;
1595                                 *ptr = 0;
1596 
1597                                 /* Save the value */
1598                                 model->pt_2[i++] =
1599                                     (uint8_t)emlxs_strtol(types, 16);
1600 
1601                                 /*
1602                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1603                                  * "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
1604                                  */
1605 
1606                                 /* Move the str pointer */
1607                                 types = ptr + 1;
1608                         }
1609 
1610                 } else if (strncmp(types, "T3:", 3) == 0) {
1611                         bzero(model->pt_3, sizeof (model->pt_3));
1612                         types += 3;
1613 
1614                         i = 0;
1615                         while (*types && *types != 'T') {
1616                                 /* Null terminate the next value */
1617                                 ptr = types;
1618                                 while (*ptr && (*ptr != ','))
1619                                         ptr++;
1620                                 *ptr = 0;
1621 
1622                                 /* Save the value */
1623                                 model->pt_3[i++] =
1624                                     (uint8_t)emlxs_strtol(types, 16);
1625 
1626                                 /*
1627                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1628                                  * "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
1629                                  */
1630 
1631                                 /* Move the str pointer */
1632                                 types = ptr + 1;
1633                         }
1634                 } else if (strncmp(types, "T6:", 3) == 0) {
1635                         bzero(model->pt_6, sizeof (model->pt_6));
1636                         types += 3;
1637 
1638                         i = 0;
1639                         while (*types && *types != 'T') {
1640                                 /* Null terminate the next value */
1641                                 ptr = types;
1642                                 while (*ptr && (*ptr != ','))
1643                                         ptr++;
1644                                 *ptr = 0;
1645 
1646                                 /* Save the value */
1647                                 model->pt_6[i++] =
1648                                     (uint8_t)emlxs_strtol(types, 16);
1649                                 model->pt_6[i] = 0;
1650 
1651                                 /*
1652                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1653                                  * "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
1654                                  */
1655 
1656                                 /* Move the str pointer */
1657                                 types = ptr + 1;
1658                         }
1659                 } else if (strncmp(types, "T7:", 3) == 0) {
1660                         bzero(model->pt_7, sizeof (model->pt_7));
1661                         types += 3;
1662 
1663                         i = 0;
1664                         while (*types && *types != 'T') {
1665                                 /* Null terminate the next value */
1666                                 ptr = types;
1667                                 while (*ptr && (*ptr != ','))
1668                                         ptr++;
1669                                 *ptr = 0;
1670 
1671                                 /* Save the value */
1672                                 model->pt_7[i++] =
1673                                     (uint8_t)emlxs_strtol(types, 16);
1674                                 model->pt_7[i] = 0;
1675 
1676                                 /*
1677                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1678                                  * "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
1679                                  */
1680 
1681                                 /* Move the str pointer */
1682                                 types = ptr + 1;
1683                         }
1684                 } else if (strncmp(types, "TA:", 3) == 0) {
1685                         bzero(model->pt_A, sizeof (model->pt_A));
1686                         types += 3;
1687 
1688                         i = 0;
1689                         while (*types && *types != 'T') {
1690                                 /* Null terminate the next value */
1691                                 ptr = types;
1692                                 while (*ptr && (*ptr != ','))
1693                                         ptr++;
1694                                 *ptr = 0;
1695 
1696                                 /* Save the value */
1697                                 model->pt_A[i++] =
1698                                     (uint8_t)emlxs_strtol(types, 16);
1699 
1700                                 /*
1701                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1702                                  * "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
1703                                  */
1704 
1705                                 /* Move the str pointer */
1706                                 types = ptr + 1;
1707                         }
1708                 } else if (strncmp(types, "TB:", 3) == 0) {
1709                         bzero(model->pt_B, sizeof (model->pt_B));
1710                         types += 3;
1711 
1712                         i = 0;
1713                         while (*types && *types != 'T') {
1714                                 /* Null terminate the next value */
1715                                 ptr = types;
1716                                 while (*ptr && (*ptr != ','))
1717                                         ptr++;
1718                                 *ptr = 0;
1719 
1720                                 /* Save the value */
1721                                 model->pt_B[i++] =
1722                                     (uint8_t)emlxs_strtol(types, 16);
1723 
1724                                 /*
1725                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1726                                  * "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
1727                                  */
1728 
1729                                 /* Move the str pointer */
1730                                 types = ptr + 1;
1731                         }
1732                 } else if (strncmp(types, "TFF:", 4) == 0) {
1733                         bzero(model->pt_FF, sizeof (model->pt_FF));
1734                         types += 4;
1735 
1736                         i = 0;
1737                         while (*types && *types != 'T') {
1738                                 /* Null terminate the next value */
1739                                 ptr = types;
1740                                 while (*ptr && (*ptr != ','))
1741                                         ptr++;
1742                                 *ptr = 0;
1743 
1744                                 /* Save the value */
1745                                 model->pt_FF[i++] =
1746                                     (uint8_t)emlxs_strtol(types, 16);
1747 
1748                                 /*
1749                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1750                                  * "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
1751                                  */
1752 
1753                                 /* Move the str pointer */
1754                                 types = ptr + 1;
1755                         }
1756                 } else if (strncmp(types, "T20:", 4) == 0) {
1757                         bzero(model->pt_20, sizeof (model->pt_20));
1758                         types += 4;
1759 
1760                         i = 0;
1761                         while (*types && *types != 'T') {
1762                                 /* Null terminate the next value */
1763                                 ptr = types;
1764                                 while (*ptr && (*ptr != ','))
1765                                         ptr++;
1766                                 *ptr = 0;
1767 
1768                                 /* Save the value */
1769                                 model->pt_20[i++] =
1770                                     (uint8_t)emlxs_strtol(types, 16);
1771                                 model->pt_20[i] = 0;
1772 
1773                                 /*
1774                                  * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1775                                  * "T20[%d]: 0x%x", i-1, model->pt_20[i-1]);
1776                                  */
1777 
1778                                 /* Move the str pointer */
1779                                 types = ptr + 1;
1780                         }
1781                 } else {
1782                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
1783                             "Unknown prog type string = %s", types);
1784                         break;
1785                 }
1786         }
1787 
1788         return;
1789 
1790 } /* emlxs_parse_prog_types() */
1791 
1792 
1793 extern void
1794 emlxs_build_prog_types(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
1795 {
1796         uint32_t i;
1797         uint32_t found = 0;
1798         char buffer[256];
1799 
1800         bzero(vpd->prog_types, sizeof (vpd->prog_types));
1801 
1802         /* Rebuild the prog type string */
1803         if (hba->model_info.pt_2[0]) {
1804                 (void) strlcat(vpd->prog_types, "T2:",
1805                     sizeof (vpd->prog_types));
1806                 found = 1;
1807 
1808                 i = 0;
1809                 while ((i < 8) && (hba->model_info.pt_2[i])) {
1810                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1811                             hba->model_info.pt_2[i]);
1812                         (void) strlcat(vpd->prog_types, buffer,
1813                             sizeof (vpd->prog_types));
1814                         i++;
1815                 }
1816         }
1817 
1818         if (hba->model_info.pt_3[0]) {
1819                 (void) strlcat(vpd->prog_types, "T3:",
1820                     sizeof (vpd->prog_types));
1821                 found = 1;
1822 
1823                 i = 0;
1824                 while ((i < 8) && (hba->model_info.pt_3[i])) {
1825                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1826                             hba->model_info.pt_3[i]);
1827                         (void) strlcat(vpd->prog_types, buffer,
1828                             sizeof (vpd->prog_types));
1829                         i++;
1830 
1831                 }
1832         }
1833 
1834         if (hba->model_info.pt_6[0]) {
1835                 (void) strlcat(vpd->prog_types, "T6:",
1836                     sizeof (vpd->prog_types));
1837                 found = 1;
1838 
1839                 i = 0;
1840                 while ((i < 8) && (hba->model_info.pt_6[i])) {
1841                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1842                             hba->model_info.pt_6[i]);
1843                         (void) strlcat(vpd->prog_types, buffer,
1844                             sizeof (vpd->prog_types));
1845                         i++;
1846                 }
1847         }
1848 
1849         if (hba->model_info.pt_7[0]) {
1850                 (void) strlcat(vpd->prog_types, "T7:",
1851                     sizeof (vpd->prog_types));
1852                 found = 1;
1853 
1854                 i = 0;
1855                 while ((i < 8) && (hba->model_info.pt_7[i])) {
1856                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1857                             hba->model_info.pt_7[i]);
1858                         (void) strlcat(vpd->prog_types, buffer,
1859                             sizeof (vpd->prog_types));
1860                         i++;
1861                 }
1862         }
1863 
1864         if (hba->model_info.pt_A[0]) {
1865                 (void) strlcat(vpd->prog_types, "TA:",
1866                     sizeof (vpd->prog_types));
1867                 found = 1;
1868 
1869                 i = 0;
1870                 while ((i < 8) && (hba->model_info.pt_A[i])) {
1871                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1872                             hba->model_info.pt_A[i]);
1873                         (void) strlcat(vpd->prog_types, buffer,
1874                             sizeof (vpd->prog_types));
1875                         i++;
1876                 }
1877         }
1878 
1879 
1880         if (hba->model_info.pt_B[0]) {
1881                 (void) strlcat(vpd->prog_types, "TB:",
1882                     sizeof (vpd->prog_types));
1883                 found = 1;
1884 
1885                 i = 0;
1886                 while ((i < 8) && (hba->model_info.pt_B[i])) {
1887                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1888                             hba->model_info.pt_B[i]);
1889                         (void) strlcat(vpd->prog_types, buffer,
1890                             sizeof (vpd->prog_types));
1891                         i++;
1892                 }
1893         }
1894 
1895         if (hba->model_info.pt_20[0]) {
1896                 (void) strlcat(vpd->prog_types, "T20:",
1897                     sizeof (vpd->prog_types));
1898                 found = 1;
1899 
1900                 i = 0;
1901                 while ((i < 8) && (hba->model_info.pt_20[i])) {
1902                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1903                             hba->model_info.pt_20[i]);
1904                         (void) strlcat(vpd->prog_types, buffer,
1905                             sizeof (vpd->prog_types));
1906                         i++;
1907                 }
1908         }
1909 
1910         if (hba->model_info.pt_FF[0]) {
1911                 (void) strlcat(vpd->prog_types, "TFF:",
1912                     sizeof (vpd->prog_types));
1913                 found = 1;
1914 
1915                 i = 0;
1916                 while ((i < 8) && (hba->model_info.pt_FF[i])) {
1917                         (void) snprintf(buffer, sizeof (buffer), "%X,",
1918                             hba->model_info.pt_FF[i]);
1919                         (void) strlcat(vpd->prog_types, buffer,
1920                             sizeof (vpd->prog_types));
1921                         i++;
1922                 }
1923         }
1924 
1925         if (found) {
1926                 /* Terminate at the last comma in string */
1927                 vpd->prog_types[(strlen(vpd->prog_types) - 1)] = 0;
1928         }
1929 
1930         return;
1931 
1932 } /* emlxs_build_prog_types() */
1933 
1934 
1935 extern uint32_t
1936 emlxs_init_adapter_info(emlxs_hba_t *hba)
1937 {
1938         emlxs_port_t *port = &PPORT;
1939         uint32_t pci_id;
1940         uint32_t cache_line;
1941         uint32_t channels;
1942         uint16_t device_id;
1943         uint16_t ssdid;
1944         uint32_t i;
1945         uint32_t found = 0;
1946         int32_t *prop;
1947         uint32_t num_prop;
1948 
1949         if (hba->bus_type == SBUS_FC) {
1950                 if (hba->pci_acc_handle == NULL) {
1951                         bcopy(&emlxs_sbus_model[0], &hba->model_info,
1952                             sizeof (emlxs_model_t));
1953 
1954                         hba->model_info.device_id = 0;
1955 
1956                         return (0);
1957                 }
1958 
1959                 /* Read the PCI device id */
1960                 pci_id =
1961                     ddi_get32(hba->pci_acc_handle,
1962                     (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
1963                 device_id = (uint16_t)(pci_id >> 16);
1964 
1965                 /* Find matching adapter model */
1966                 for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
1967                         if (emlxs_sbus_model[i].device_id == device_id) {
1968                                 bcopy(&emlxs_sbus_model[i], &hba->model_info,
1969                                     sizeof (emlxs_model_t));
1970                                 found = 1;
1971                                 break;
1972                         }
1973                 }
1974 
1975                 /* If not found then use the unknown model */
1976                 if (!found) {
1977                         bcopy(&emlxs_sbus_model[0], &hba->model_info,
1978                             sizeof (emlxs_model_t));
1979 
1980                         hba->model_info.device_id = device_id;
1981 
1982                         return (0);
1983                 }
1984         } else {        /* PCI model */
1985 
1986                 if (hba->pci_acc_handle == NULL) {
1987                         bcopy(&emlxs_pci_model[0], &hba->model_info,
1988                             sizeof (emlxs_model_t));
1989 
1990                         hba->model_info.device_id = 0;
1991 
1992                         return (0);
1993                 }
1994 
1995                 /* Read the PCI device id */
1996                 device_id =
1997                     ddi_get16(hba->pci_acc_handle,
1998                     (uint16_t *)(hba->pci_addr + PCI_DEVICE_ID_REGISTER));
1999 
2000                 /* Read the PCI Subsystem id */
2001                 ssdid =
2002                     ddi_get16(hba->pci_acc_handle,
2003                     (uint16_t *)(hba->pci_addr + PCI_SSDID_REGISTER));
2004 
2005                 if (ssdid == 0 || ssdid == 0xffff) {
2006                         ssdid = device_id;
2007                 }
2008 
2009                 /* Read the Cache Line reg */
2010                 cache_line =
2011                     ddi_get32(hba->pci_acc_handle,
2012                     (uint32_t *)(hba->pci_addr + PCI_CACHE_LINE_REGISTER));
2013 
2014                 EMLXS_MSGF(EMLXS_CONTEXT,
2015                     &emlxs_init_debug_msg, "Device IDs: %x/%x/%x",
2016                     device_id, ssdid, cache_line);
2017 
2018                 /* Check for the multifunction bit being set */
2019                 if ((cache_line & 0x00ff0000) == 0x00800000) {
2020                         channels = EMLXS_MULTI_CHANNEL;
2021                 } else {
2022                         channels = EMLXS_SINGLE_CHANNEL;
2023                 }
2024 
2025                 /* If device ids are unique, then use them for search */
2026                 if (device_id != ssdid) {
2027                         /*
2028                          * Find matching adapter model using
2029                          * device_id, ssdid, and channels
2030                          */
2031                         for (i = 1; i < emlxs_pci_model_count; i++) {
2032                                 if (emlxs_pci_model[i].device_id ==
2033                                     device_id &&
2034                                     emlxs_pci_model[i].ssdid == ssdid &&
2035                                     emlxs_pci_model[i].channels ==
2036                                     channels) {
2037                                         bcopy(&emlxs_pci_model[i],
2038                                             &hba->model_info,
2039                                             sizeof (emlxs_model_t));
2040                                         found = 1;
2041                                         break;
2042                                 }
2043                         }
2044                 }
2045 
2046                 /* If adapter not found, try again */
2047                 if (!found) {
2048                         /*
2049                          * Find matching adapter model using
2050                          * device_id and channels
2051                          */
2052                         for (i = 1; i < emlxs_pci_model_count; i++) {
2053                                 if (emlxs_pci_model[i].device_id == device_id &&
2054                                     emlxs_pci_model[i].channels == channels) {
2055                                         bcopy(&emlxs_pci_model[i],
2056                                             &hba->model_info,
2057                                             sizeof (emlxs_model_t));
2058                                         found = 1;
2059                                         break;
2060                                 }
2061                         }
2062                 }
2063 
2064                 /* If adapter not found, try one last time */
2065                 if (!found) {
2066                         /*
2067                          * Find matching adapter model using
2068                          * device_id only
2069                          */
2070                         for (i = 1; i < emlxs_pci_model_count; i++) {
2071                                 if (emlxs_pci_model[i].device_id == device_id) {
2072                                         bcopy(&emlxs_pci_model[i],
2073                                             &hba->model_info,
2074                                             sizeof (emlxs_model_t));
2075                                         found = 1;
2076                                         break;
2077                                 }
2078                         }
2079                 }
2080 
2081                 /* If not found, set adapter to unknown */
2082                 if (!found) {
2083                         bcopy(&emlxs_pci_model[0], &hba->model_info,
2084                             sizeof (emlxs_model_t));
2085 
2086                         hba->model_info.device_id = device_id;
2087                         hba->model_info.ssdid = ssdid;
2088 
2089                         return (0);
2090                 }
2091 
2092 #ifndef SATURN_MSI_SUPPORT
2093                 /*
2094                  * This will disable MSI support for Saturn adapter's
2095                  * due to a PCI bus issue
2096                  */
2097                 if (hba->model_info.chip == EMLXS_SATURN_CHIP) {
2098                         hba->model_info.flags &=
2099                             ~(EMLXS_MSI_SUPPORTED | EMLXS_MSIX_SUPPORTED);
2100                 }
2101 #endif /* !SATURN_MSI_SUPPORT */
2102 
2103                 /* Scan the PCI capabilities */
2104                 emlxs_pci_cap_offsets(hba);
2105 
2106 #ifdef MSI_SUPPORT
2107                 /* Verify MSI support */
2108                 if ((hba->model_info.flags & EMLXS_MSI_SUPPORTED) &&
2109                     !hba->pci_cap_offset[PCI_CAP_ID_MSI]) {
2110                         hba->model_info.flags &= ~EMLXS_MSI_SUPPORTED;
2111                 }
2112 
2113                 /* Verify MSI-X support */
2114                 if ((hba->model_info.flags & EMLXS_MSIX_SUPPORTED) &&
2115                     !hba->pci_cap_offset[PCI_CAP_ID_MSI_X]) {
2116                         hba->model_info.flags &= ~EMLXS_MSIX_SUPPORTED;
2117                 }
2118 #endif /* MSI_SUPPORT */
2119 
2120                 /* Set the sli_intf value */
2121                 if (hba->pci_cap_offset[PCI_CAP_ID_VS]) {
2122                         /* Save the SLI_INTF register, this contains */
2123                         /* information about the BAR register layout */
2124                         /* and other HBA information. */
2125                         hba->sli_intf =
2126                             ddi_get32(hba->pci_acc_handle,
2127                             (uint32_t *)(hba->pci_addr +
2128                             hba->pci_cap_offset[PCI_CAP_ID_VS] +
2129                             PCI_VS_SLI_INTF_OFFSET));
2130 
2131                         EMLXS_MSGF(EMLXS_CONTEXT,
2132                             &emlxs_init_debug_msg, "PCI_CAP_ID_VS: "
2133                             "SLI_INTF:%08x",
2134                             hba->sli_intf);
2135 
2136                         /* Check validity */
2137                         if ((hba->sli_intf & SLI_INTF_VALID_MASK) !=
2138                             SLI_INTF_VALID) {
2139                                 hba->sli_intf = 0;
2140                         }
2141                 }
2142         }
2143 
2144         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba->dip, 0,
2145             "reg", &prop, &num_prop) == DDI_PROP_SUCCESS) {
2146                 /* Parse the property for PCI function, device and bus no. */
2147                 hba->pci_function_number =
2148                     (uint8_t)((prop[0] & 0x00000700) >> 8);
2149                 hba->pci_device_number =
2150                     (uint8_t)((prop[0] & 0x0000f800) >> 11);
2151                 hba->pci_bus_number = (uint8_t)((prop[0] & 0x00ff0000) >> 16);
2152                 ddi_prop_free((void *)prop);
2153         }
2154 
2155         switch (hba->sli_intf & SLI_INTF_SLI_REV_MASK) {
2156         case SLI_INTF_SLI_REV_NONE: /* Legacy support */
2157                 if (hba->model_info.sli_mask & EMLXS_SLI4_MASK) {
2158                         hba->sli_api = emlxs_sli4_api;
2159                 } else {
2160                         hba->sli_api = emlxs_sli3_api;
2161                 }
2162                 break;
2163 
2164         case SLI_INTF_SLI_REV_3:
2165                 if (!(hba->model_info.sli_mask & EMLXS_SLI3_MASK)) {
2166                         EMLXS_MSGF(EMLXS_CONTEXT,
2167                             &emlxs_init_failed_msg,
2168                             "Adapter does not support SLI3 interface. "
2169                             "sli_intf=%08x sli_mask=%08x",
2170                             hba->sli_intf, hba->model_info.sli_mask);
2171                         return (0);
2172                 }
2173                 hba->sli_api = emlxs_sli3_api;
2174                 break;
2175 
2176         case SLI_INTF_SLI_REV_4:
2177                 if (!(hba->model_info.sli_mask & EMLXS_SLI4_MASK)) {
2178                         EMLXS_MSGF(EMLXS_CONTEXT,
2179                             &emlxs_init_failed_msg,
2180                             "Adapter does not support SLI4 interface. "
2181                             "sli_intf=%08x sli_mask=%08x",
2182                             hba->sli_intf, hba->model_info.sli_mask);
2183                         return (0);
2184                 }
2185                 hba->sli_api = emlxs_sli4_api;
2186                 break;
2187 
2188         default:
2189                 EMLXS_MSGF(EMLXS_CONTEXT,
2190                     &emlxs_init_failed_msg,
2191                     "Invalid SLI interface specified. "
2192                     "sli_intf=%08x sli_mask=%08x",
2193                     hba->sli_intf, hba->model_info.sli_mask);
2194                 return (0);
2195         }
2196 
2197 #ifdef FMA_SUPPORT
2198         if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
2199             != DDI_FM_OK) {
2200                 EMLXS_MSGF(EMLXS_CONTEXT,
2201                     &emlxs_invalid_access_handle_msg, NULL);
2202                 return (0);
2203         }
2204 #endif  /* FMA_SUPPORT */
2205 
2206         return (1);
2207 
2208 } /* emlxs_init_adapter_info()  */
2209 
2210 
2211 /* ARGSUSED */
2212 static void
2213 emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2214 {
2215         emlxs_port_t *port = &PPORT;
2216         IOCB *iocb;
2217         uint32_t *w;
2218         int i, j;
2219 
2220         iocb = &iocbq->iocb;
2221 
2222         if (iocb->ULPSTATUS != 0) {
2223                 return;
2224         }
2225 
2226         switch (iocb->un.astat.EventCode) {
2227         case 0x0100:    /* Temp Warning */
2228 
2229                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_warning_msg,
2230                     "Adapter is very hot (%d °C). Take corrective action.",
2231                     iocb->ULPCONTEXT);
2232 
2233                 hba->temperature = iocb->ULPCONTEXT;
2234                 emlxs_log_temp_event(port, 0x02, iocb->ULPCONTEXT);
2235 
2236 
2237                 break;
2238 
2239 
2240         case 0x0101:    /* Temp Safe */
2241 
2242                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_msg,
2243                     "Adapter temperature now safe (%d °C).",
2244                     iocb->ULPCONTEXT);
2245 
2246                 hba->temperature = iocb->ULPCONTEXT;
2247                 emlxs_log_temp_event(port, 0x03, iocb->ULPCONTEXT);
2248 
2249                 break;
2250 
2251         default:
2252 
2253                 w = (uint32_t *)iocb;
2254                 for (i = 0, j = 0; i < 8; i++, j += 2) {
2255                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_async_msg,
2256                             "(Word[%d]=%x Word[%d]=%x)", j, w[j], j + 1,
2257                             w[j + 1]);
2258                 }
2259 
2260                 emlxs_log_async_event(port, iocb);
2261         }
2262 
2263         return;
2264 
2265 } /* emlxs_handle_async_event() */
2266 
2267 
2268 /* ARGSUSED */
2269 extern void
2270 emlxs_reset_link_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2271 {
2272         emlxs_port_t *port = &PPORT;
2273 
2274         /* Attempt a link reset to recover */
2275         (void) emlxs_reset(port, FC_FCA_LINK_RESET);
2276 
2277         return;
2278 
2279 } /* emlxs_reset_link_thread() */
2280 
2281 
2282 /* ARGSUSED */
2283 extern void
2284 emlxs_restart_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2285 {
2286         emlxs_port_t *port = &PPORT;
2287 
2288         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Restarting...");
2289 
2290         /* Attempt a full hardware reset to recover */
2291         if (emlxs_reset(port, FC_FCA_RESET) != FC_SUCCESS) {
2292                 EMLXS_STATE_CHANGE(hba, FC_ERROR);
2293 
2294                 emlxs_shutdown_thread(hba, arg1, arg2);
2295         }
2296 
2297         return;
2298 
2299 } /* emlxs_restart_thread() */
2300 
2301 
2302 /* ARGSUSED */
2303 extern void
2304 emlxs_shutdown_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
2305 {
2306         emlxs_port_t *port = &PPORT;
2307 
2308         mutex_enter(&EMLXS_PORT_LOCK);
2309         if (hba->flag & FC_SHUTDOWN) {
2310                 mutex_exit(&EMLXS_PORT_LOCK);
2311                 return;
2312         }
2313         hba->flag |= FC_SHUTDOWN;
2314         mutex_exit(&EMLXS_PORT_LOCK);
2315 
2316         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
2317             "Shutting down...");
2318 
2319         /* Take adapter offline and leave it there */
2320         (void) emlxs_offline(hba, 0);
2321 
2322         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2323                 /*
2324                  * Dump is not defined for SLI4, so just
2325                  * reset the HBA for now.
2326                  */
2327                 EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
2328 
2329         } else {
2330                 if (hba->flag & FC_OVERTEMP_EVENT) {
2331                         emlxs_log_temp_event(port, 0x01,
2332                             hba->temperature);
2333                 } else {
2334                         emlxs_log_dump_event(port, NULL, 0);
2335                 }
2336         }
2337 
2338         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_shutdown_msg, "Reboot required.");
2339 
2340         return;
2341 
2342 } /* emlxs_shutdown_thread() */
2343 
2344 
2345 /* ARGSUSED */
2346 extern void
2347 emlxs_proc_channel(emlxs_hba_t *hba, CHANNEL *cp, void *arg2)
2348 {
2349         IOCBQ *iocbq;
2350         IOCBQ *rsp_head;
2351 
2352         /*
2353          * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
2354          * "proc_channel: channel=%d", cp->channelno);
2355          */
2356 
2357         mutex_enter(&cp->rsp_lock);
2358 
2359         while ((rsp_head = cp->rsp_head) != NULL) {
2360                 cp->rsp_head = NULL;
2361                 cp->rsp_tail = NULL;
2362 
2363                 mutex_exit(&cp->rsp_lock);
2364 
2365                 while ((iocbq = rsp_head) != NULL) {
2366                         rsp_head = (IOCBQ *) iocbq->next;
2367 
2368                         emlxs_proc_channel_event(hba, cp, iocbq);
2369                 }
2370 
2371                 mutex_enter(&cp->rsp_lock);
2372         }
2373 
2374         mutex_exit(&cp->rsp_lock);
2375 
2376         EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0);
2377 
2378         return;
2379 
2380 } /* emlxs_proc_channel() */
2381 
2382 
2383 /*
2384  * Called from SLI ring event routines to process a rsp ring IOCB.
2385  */
2386 void
2387 emlxs_proc_channel_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2388 {
2389         emlxs_port_t *port = &PPORT;
2390         char buffer[MAX_MSG_DATA + 1];
2391         IOCB *iocb;
2392         emlxs_buf_t *sbp;
2393         fc_packet_t *pkt;
2394 
2395         iocb = &iocbq->iocb;
2396 
2397 #ifdef DEBUG_CMPL_IOCB
2398         emlxs_data_dump(port, "CMPL_IOCB", (uint32_t *)iocb, 8, 0);
2399 #endif
2400 
2401         sbp = (emlxs_buf_t *)iocbq->sbp;
2402         if (sbp) {
2403                 if (!(sbp->pkt_flags & PACKET_VALID) ||
2404                     (sbp->pkt_flags & (PACKET_ULP_OWNED |
2405                     PACKET_IN_COMPLETION))) {
2406                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_stale_msg,
2407                             "Duplicate: iocb=%p cmd=%x status=%x "
2408                             "error=%x iotag=%d context=%x info=%x",
2409                             iocbq, (uint8_t)iocbq->iocb.ULPCOMMAND,
2410                             iocbq->iocb.ULPSTATUS,
2411                             (uint8_t)iocbq->iocb.un.grsp.perr.statLocalError,
2412                             (uint16_t)iocbq->iocb.ULPIOTAG,
2413                             (uint16_t)iocbq->iocb.ULPCONTEXT,
2414                             (uint8_t)iocbq->iocb.ULPRSVDBYTE);
2415 
2416                         /* Drop this IO immediately */
2417                         return;
2418                 }
2419 
2420                 if (sbp->pkt_flags & PACKET_IN_TIMEOUT) {
2421                         /*
2422                          * If the packet is tagged for timeout then set the
2423                          * return codes appropriately
2424                          */
2425                         iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
2426                         iocb->un.grsp.perr.statLocalError = IOERR_ABORT_TIMEOUT;
2427                 } else if (sbp->pkt_flags &
2428                     (PACKET_IN_FLUSH | PACKET_IN_ABORT)) {
2429                         /*
2430                          * If the packet is tagged for abort then set the
2431                          * return codes appropriately
2432                          */
2433                         iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
2434                         iocb->un.grsp.perr.statLocalError =
2435                             IOERR_ABORT_REQUESTED;
2436                 }
2437         }
2438 
2439         /* Check for IOCB local error */
2440         if (iocb->ULPSTATUS == IOSTAT_LOCAL_REJECT) {
2441                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_event_msg,
2442                     "Local reject. ringno=%d iocb=%p cmd=%x "
2443                     "iotag=%d context=%x info=%x error=%x",
2444                     cp->channelno, iocb, (uint8_t)iocb->ULPCOMMAND,
2445                     (uint16_t)iocb->ULPIOTAG, (uint16_t)iocb->ULPCONTEXT,
2446                     (uint8_t)iocb->ULPRSVDBYTE,
2447                     (uint8_t)iocb->un.grsp.perr.statLocalError);
2448         }
2449 
2450         switch (iocb->ULPCOMMAND) {
2451                 /* RING 0 FCP commands */
2452         case CMD_FCP_ICMND_CR:
2453         case CMD_FCP_ICMND_CX:
2454         case CMD_FCP_IREAD_CR:
2455         case CMD_FCP_IREAD_CX:
2456         case CMD_FCP_IWRITE_CR:
2457         case CMD_FCP_IWRITE_CX:
2458         case CMD_FCP_ICMND64_CR:
2459         case CMD_FCP_ICMND64_CX:
2460         case CMD_FCP_IREAD64_CR:
2461         case CMD_FCP_IREAD64_CX:
2462         case CMD_FCP_IWRITE64_CR:
2463         case CMD_FCP_IWRITE64_CX:
2464                 emlxs_handle_fcp_event(hba, cp, iocbq);
2465                 break;
2466 
2467 #ifdef SFCT_SUPPORT
2468         case CMD_FCP_TSEND_CX:          /* FCP_TARGET IOCB command */
2469         case CMD_FCP_TSEND64_CX:        /* FCP_TARGET IOCB command */
2470         case CMD_FCP_TRECEIVE_CX:       /* FCP_TARGET IOCB command */
2471         case CMD_FCP_TRECEIVE64_CX:     /* FCP_TARGET IOCB command */
2472         case CMD_FCP_TRSP_CX:           /* FCP_TARGET IOCB command */
2473         case CMD_FCP_TRSP64_CX:         /* FCP_TARGET IOCB command */
2474                 if (port->mode == MODE_TARGET) {
2475                         (void) emlxs_fct_handle_fcp_event(hba, cp, iocbq);
2476                 }
2477                 break;
2478 #endif /* SFCT_SUPPORT */
2479 
2480                 /* RING 1 IP commands */
2481         case CMD_XMIT_BCAST_CN:
2482         case CMD_XMIT_BCAST_CX:
2483         case CMD_XMIT_BCAST64_CN:
2484         case CMD_XMIT_BCAST64_CX:
2485                 (void) emlxs_ip_handle_event(hba, cp, iocbq);
2486                 break;
2487 
2488         case CMD_XMIT_SEQUENCE_CX:
2489         case CMD_XMIT_SEQUENCE_CR:
2490         case CMD_XMIT_SEQUENCE64_CX:
2491         case CMD_XMIT_SEQUENCE64_CR:
2492                 switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2493                 case FC_TYPE_IS8802_SNAP:
2494                         (void) emlxs_ip_handle_event(hba, cp, iocbq);
2495                         break;
2496 
2497                 case FC_TYPE_FC_SERVICES:
2498                         (void) emlxs_ct_handle_event(hba, cp, iocbq);
2499                         break;
2500 
2501                 default:
2502                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2503                             "cmd=%x type=%x status=%x iotag=%d context=%x ",
2504                             iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
2505                             iocb->ULPSTATUS, iocb->ULPIOTAG,
2506                             iocb->ULPCONTEXT);
2507                 }
2508                 break;
2509 
2510         case CMD_RCV_SEQUENCE_CX:
2511         case CMD_RCV_SEQUENCE64_CX:
2512         case CMD_RCV_SEQ64_CX:
2513         case CMD_RCV_ELS_REQ_CX:        /* Unsolicited ELS frame  */
2514         case CMD_RCV_ELS_REQ64_CX:      /* Unsolicited ELS frame  */
2515         case CMD_RCV_ELS64_CX:          /* Unsolicited ELS frame  */
2516                 if (hba->sli_mode <= EMLXS_HBA_SLI3_MODE) {
2517                         (void) emlxs_handle_rcv_seq(hba, cp, iocbq);
2518                 }
2519                 break;
2520 
2521         case CMD_RCV_SEQ_LIST64_CX:
2522                 (void) emlxs_ip_handle_rcv_seq_list(hba, cp, iocbq);
2523                 break;
2524 
2525         case CMD_CREATE_XRI_CR:
2526         case CMD_CREATE_XRI_CX:
2527                 (void) emlxs_handle_create_xri(hba, cp, iocbq);
2528                 break;
2529 
2530                 /* RING 2 ELS commands */
2531         case CMD_ELS_REQUEST_CR:
2532         case CMD_ELS_REQUEST_CX:
2533         case CMD_XMIT_ELS_RSP_CX:
2534         case CMD_ELS_REQUEST64_CR:
2535         case CMD_ELS_REQUEST64_CX:
2536         case CMD_XMIT_ELS_RSP64_CX:
2537                 (void) emlxs_els_handle_event(hba, cp, iocbq);
2538                 break;
2539 
2540                 /* RING 3 CT commands */
2541         case CMD_GEN_REQUEST64_CR:
2542         case CMD_GEN_REQUEST64_CX:
2543                 switch (iocb->un.rcvseq64.w5.hcsw.Type) {
2544 #ifdef MENLO_SUPPORT
2545                 case EMLXS_MENLO_TYPE:
2546                         (void) emlxs_menlo_handle_event(hba, cp, iocbq);
2547                         break;
2548 #endif /* MENLO_SUPPORT */
2549 
2550                 case FC_TYPE_FC_SERVICES:
2551                         (void) emlxs_ct_handle_event(hba, cp, iocbq);
2552                         break;
2553 
2554                 default:
2555                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2556                             "cmd=%x type=%x status=%x iotag=%d context=%x ",
2557                             iocb->ULPCOMMAND, iocb->un.rcvseq64.w5.hcsw.Type,
2558                             iocb->ULPSTATUS, iocb->ULPIOTAG,
2559                             iocb->ULPCONTEXT);
2560                 }
2561                 break;
2562 
2563         case CMD_ABORT_XRI_CN:  /* Abort fcp command */
2564 
2565                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2566                     "ABORT_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2567                     (uint32_t)iocb->un.acxri.abortContextTag,
2568                     (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2569                     iocb->un.acxri.parm);
2570 
2571 #ifdef SFCT_SUPPORT
2572                 if (port->mode == MODE_TARGET) {
2573                         (void) emlxs_fct_handle_abort(hba, cp, iocbq);
2574                 }
2575 #endif /* SFCT_SUPPORT */
2576                 break;
2577 
2578         case CMD_ABORT_XRI_CX:  /* Abort command */
2579 
2580                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2581                     "ABORT_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2582                     (uint32_t)iocb->un.acxri.abortContextTag,
2583                     (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2584                     iocb->un.acxri.parm, iocbq->sbp);
2585 
2586 #ifdef SFCT_SUPPORT
2587                 if (port->mode == MODE_TARGET) {
2588                         (void) emlxs_fct_handle_abort(hba, cp, iocbq);
2589                 }
2590 #endif /* SFCT_SUPPORT */
2591                 break;
2592 
2593         case CMD_XRI_ABORTED_CX:        /* Handle ABORT condition */
2594 
2595                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2596                     "XRI_ABORTED_CX: rpi=%d iotag=%d status=%x parm=%x",
2597                     (uint32_t)iocb->un.acxri.abortContextTag,
2598                     (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2599                     iocb->un.acxri.parm);
2600 
2601 #ifdef SFCT_SUPPORT
2602                 if (port->mode == MODE_TARGET) {
2603                         (void) emlxs_fct_handle_abort(hba, cp, iocbq);
2604                 }
2605 #endif /* SFCT_SUPPORT */
2606                 break;
2607 
2608         case CMD_CLOSE_XRI_CN:  /* Handle CLOSE condition */
2609 
2610                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2611                     "CLOSE_XRI_CN: rpi=%d iotag=%d status=%x parm=%x",
2612                     (uint32_t)iocb->un.acxri.abortContextTag,
2613                     (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2614                     iocb->un.acxri.parm);
2615 
2616 #ifdef SFCT_SUPPORT
2617                 if (port->mode == MODE_TARGET) {
2618                         (void) emlxs_fct_handle_abort(hba, cp, iocbq);
2619                 }
2620 #endif /* SFCT_SUPPORT */
2621                 break;
2622 
2623         case CMD_CLOSE_XRI_CX:  /* Handle CLOSE condition */
2624 
2625                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2626                     "CLOSE_XRI_CX: rpi=%d iotag=%d status=%x parm=%x sbp=%p",
2627                     (uint32_t)iocb->un.acxri.abortContextTag,
2628                     (uint32_t)iocb->un.acxri.abortIoTag, iocb->ULPSTATUS,
2629                     iocb->un.acxri.parm, iocbq->sbp);
2630 
2631 #ifdef SFCT_SUPPORT
2632                 if (port->mode == MODE_TARGET) {
2633                         (void) emlxs_fct_handle_abort(hba, cp, iocbq);
2634                 }
2635 #endif /* SFCT_SUPPORT */
2636                 break;
2637 
2638         case CMD_ADAPTER_MSG:
2639                 /* Allows debug adapter firmware messages to print on host */
2640                 bzero(buffer, sizeof (buffer));
2641                 bcopy((uint8_t *)iocb, buffer, MAX_MSG_DATA);
2642 
2643                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_msg, "%s", buffer);
2644 
2645                 break;
2646 
2647         case CMD_QUE_RING_LIST64_CN:
2648         case CMD_QUE_RING_BUF64_CN:
2649                 break;
2650 
2651         case CMD_ASYNC_STATUS:
2652                 emlxs_handle_async_event(hba, cp, iocbq);
2653                 break;
2654 
2655         case CMD_XMIT_BLS_RSP64_CX:
2656                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flushed_msg,
2657                     "CMD_XMIT_BLS_RSP64_CX: sbp = %p", sbp);
2658 
2659                 /*
2660                  * The exchange should have been already freed in the wqe_cmpl
2661                  * so just free up the pkt here.
2662                  */
2663                 pkt = PRIV2PKT(sbp);
2664                 emlxs_pkt_free(pkt);
2665                 break;
2666 
2667         default:
2668                 if (iocb->ULPCOMMAND == 0) {
2669                         break;
2670                 }
2671 
2672                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_iocb_invalid_msg,
2673                     "cmd=%x status=%x iotag=%d context=%x", iocb->ULPCOMMAND,
2674                     iocb->ULPSTATUS, iocb->ULPIOTAG, iocb->ULPCONTEXT);
2675 
2676                 break;
2677         }       /* switch(entry->ULPCOMMAND) */
2678 
2679         return;
2680 
2681 } /* emlxs_proc_channel_event() */
2682 
2683 
2684 extern char *
2685 emlxs_ffstate_xlate(uint32_t state)
2686 {
2687         static char buffer[32];
2688         uint32_t i;
2689         uint32_t count;
2690 
2691         count = sizeof (emlxs_ffstate_table) / sizeof (emlxs_table_t);
2692         for (i = 0; i < count; i++) {
2693                 if (state == emlxs_ffstate_table[i].code) {
2694                         return (emlxs_ffstate_table[i].string);
2695                 }
2696         }
2697 
2698         (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state);
2699         return (buffer);
2700 
2701 } /* emlxs_ffstate_xlate() */
2702 
2703 
2704 extern char *
2705 emlxs_ring_xlate(uint32_t ringno)
2706 {
2707         static char buffer[32];
2708         uint32_t i;
2709         uint32_t count;
2710 
2711         count = sizeof (emlxs_ring_table) / sizeof (emlxs_table_t);
2712         for (i = 0; i < count; i++) {
2713                 if (ringno == emlxs_ring_table[i].code) {
2714                         return (emlxs_ring_table[i].string);
2715                 }
2716         }
2717 
2718         (void) snprintf(buffer, sizeof (buffer), "ring=0x%x", ringno);
2719         return (buffer);
2720 
2721 } /* emlxs_ring_xlate() */
2722 
2723 
2724 extern char *
2725 emlxs_pci_cap_xlate(uint32_t id)
2726 {
2727         static char buffer[32];
2728         uint32_t i;
2729         uint32_t count;
2730 
2731         count = sizeof (emlxs_pci_cap) / sizeof (emlxs_table_t);
2732         for (i = 0; i < count; i++) {
2733                 if (id == emlxs_pci_cap[i].code) {
2734                         return (emlxs_pci_cap[i].string);
2735                 }
2736         }
2737 
2738         (void) snprintf(buffer, sizeof (buffer), "PCI_CAP_ID_%02X", id);
2739         return (buffer);
2740 
2741 } /* emlxs_pci_cap_xlate() */
2742 
2743 
2744 extern char *
2745 emlxs_pci_ecap_xlate(uint32_t id)
2746 {
2747         static char buffer[32];
2748         uint32_t i;
2749         uint32_t count;
2750 
2751         count = sizeof (emlxs_pci_ecap) / sizeof (emlxs_table_t);
2752         for (i = 0; i < count; i++) {
2753                 if (id == emlxs_pci_ecap[i].code) {
2754                         return (emlxs_pci_ecap[i].string);
2755                 }
2756         }
2757 
2758         (void) snprintf(buffer, sizeof (buffer), "PCI_EXT_CAP_ID_%02X", id);
2759         return (buffer);
2760 
2761 } /* emlxs_pci_ecap_xlate() */
2762 
2763 
2764 extern void
2765 emlxs_pcix_mxr_update(emlxs_hba_t *hba, uint32_t verbose)
2766 {
2767         emlxs_port_t *port = &PPORT;
2768         MAILBOXQ *mbq;
2769         MAILBOX *mb;
2770         emlxs_config_t *cfg;
2771         uint32_t value;
2772 
2773         cfg = &CFG;
2774 
2775 xlate:
2776 
2777         switch (cfg[CFG_PCI_MAX_READ].current) {
2778         case 512:
2779                 value = 0;
2780                 break;
2781 
2782         case 1024:
2783                 value = 1;
2784                 break;
2785 
2786         case 2048:
2787                 value = 2;
2788                 break;
2789 
2790         case 4096:
2791                 value = 3;
2792                 break;
2793 
2794         default:
2795                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2796                     "PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
2797                     cfg[CFG_PCI_MAX_READ].current, cfg[CFG_PCI_MAX_READ].def);
2798 
2799                 cfg[CFG_PCI_MAX_READ].current = cfg[CFG_PCI_MAX_READ].def;
2800                 goto xlate;
2801         }
2802 
2803         if ((mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)),
2804             KM_SLEEP)) == 0) {
2805                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2806                     "PCI_MAX_READ: Unable to allocate mailbox buffer.");
2807                 return;
2808         }
2809         mb = (MAILBOX *)mbq;
2810 
2811         emlxs_mb_set_var(hba, mbq, 0x00100506, value);
2812 
2813         if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2814                 if (verbose || (mb->mbxStatus != 0x12)) {
2815                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2816                             "PCI_MAX_READ: Unable to update. "
2817                             "status=%x value=%d (%d bytes)",
2818                             mb->mbxStatus, value,
2819                             cfg[CFG_PCI_MAX_READ].current);
2820                 }
2821         } else {
2822                 if (verbose &&
2823                     (cfg[CFG_PCI_MAX_READ].current !=
2824                     cfg[CFG_PCI_MAX_READ].def)) {
2825                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2826                             "PCI_MAX_READ: Updated. %d bytes",
2827                             cfg[CFG_PCI_MAX_READ].current);
2828                 }
2829         }
2830 
2831         (void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
2832 
2833         return;
2834 
2835 } /* emlxs_pcix_mxr_update */
2836 
2837 
2838 
2839 extern uint32_t
2840 emlxs_get_key(emlxs_hba_t *hba, MAILBOXQ *mbq)
2841 {
2842         emlxs_port_t *port = &PPORT;
2843         MAILBOX *mb = (MAILBOX *)mbq;
2844         uint32_t npname0, npname1;
2845         uint32_t tmpkey, theKey;
2846         uint16_t key850;
2847         uint32_t t1, t2, t3, t4;
2848         uint32_t ts;
2849 
2850 #define SEED 0x876EDC21
2851 
2852         /* This key is only used currently for SBUS adapters */
2853         if (hba->bus_type != SBUS_FC) {
2854                 return (0);
2855         }
2856 
2857         tmpkey = mb->un.varWords[30];
2858         EMLXS_STATE_CHANGE(hba, FC_INIT_NVPARAMS);
2859 
2860         emlxs_mb_read_nv(hba, mbq);
2861         if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
2862                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
2863                     "Unable to read nvram. cmd=%x status=%x", mb->mbxCommand,
2864                     mb->mbxStatus);
2865 
2866                 return (0);
2867         }
2868         npname0 = mb->un.varRDnvp.portname[0];
2869         npname1 = mb->un.varRDnvp.portname[1];
2870 
2871         key850 = (uint16_t)((tmpkey & 0x00FFFF00) >> 8);
2872         ts = (uint16_t)(npname1 + 1);
2873         t1 = ts * key850;
2874         ts = (uint16_t)((npname1 >> 16) + 1);
2875         t2 = ts * key850;
2876         ts = (uint16_t)(npname0 + 1);
2877         t3 = ts * key850;
2878         ts = (uint16_t)((npname0 >> 16) + 1);
2879         t4 = ts * key850;
2880         theKey = SEED + t1 + t2 + t3 + t4;
2881 
2882         return (theKey);
2883 
2884 } /* emlxs_get_key() */
2885 
2886 
2887 extern void
2888 emlxs_fw_show(emlxs_hba_t *hba)
2889 {
2890         emlxs_port_t *port = &PPORT;
2891         uint32_t i;
2892 
2893         /* Display firmware library one time */
2894         for (i = 0; i < emlxs_fw_count; i++) {
2895                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_library_msg, "%s",
2896                     emlxs_fw_table[i].label);
2897         }
2898 
2899         return;
2900 
2901 } /* emlxs_fw_show() */
2902 
2903 
2904 #ifdef MODFW_SUPPORT
2905 extern void
2906 emlxs_fw_load(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2907 {
2908         emlxs_port_t *port = &PPORT;
2909         int (*emlxs_fw_get)(emlxs_firmware_t *);
2910         int err;
2911         char name[64];
2912 
2913         /* Make sure image is unloaded and image buffer pointer is clear */
2914         emlxs_fw_unload(hba, fw);
2915 
2916         err = 0;
2917         hba->fw_modhandle =
2918             ddi_modopen(EMLXS_FW_MODULE, KRTLD_MODE_FIRST, &err);
2919         if (!hba->fw_modhandle) {
2920                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2921                     "Unable to load firmware module. error=%d", err);
2922 
2923                 return;
2924         } else {
2925                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2926                     "Firmware module loaded.");
2927         }
2928 
2929         (void) snprintf(name, sizeof (name), "%s_fw_get", DRIVER_NAME);
2930         err = 0;
2931         emlxs_fw_get =
2932             (int (*)())ddi_modsym(hba->fw_modhandle, name, &err);
2933         if ((void *)emlxs_fw_get == NULL) {
2934                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2935                     "%s not present. error=%d", name, err);
2936 
2937                 emlxs_fw_unload(hba, fw);
2938                 return;
2939         }
2940 
2941         if (emlxs_fw_get(fw)) {
2942                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
2943                     "Invalid firmware image module found. %s", fw->label);
2944 
2945                 emlxs_fw_unload(hba, fw);
2946                 return;
2947         }
2948 
2949         return;
2950 
2951 } /* emlxs_fw_load() */
2952 
2953 
2954 extern void
2955 emlxs_fw_unload(emlxs_hba_t *hba, emlxs_firmware_t *fw)
2956 {
2957         emlxs_port_t *port = &PPORT;
2958 
2959         /* Clear the firmware image */
2960         fw->image = NULL;
2961         fw->size = 0;
2962 
2963         if (hba->fw_modhandle) {
2964                 /* Close the module */
2965                 (void) ddi_modclose(hba->fw_modhandle);
2966                 hba->fw_modhandle = NULL;
2967 
2968                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
2969                     "Firmware module unloaded.");
2970         }
2971 
2972         return;
2973 
2974 } /* emlxs_fw_unload() */
2975 #endif /* MODFW_SUPPORT */
2976 
2977 
2978 static void
2979 emlxs_pci_cap_offsets(emlxs_hba_t *hba)
2980 {
2981         emlxs_port_t *port = &PPORT;
2982         uint32_t reg;
2983         uint8_t offset;
2984         uint8_t next;
2985         uint8_t id;
2986         uint16_t eoffset;
2987         uint16_t enext;
2988         uint8_t eversion;
2989         uint16_t eid;
2990 
2991         /* Read PCI capbabilities */
2992 
2993         bzero(hba->pci_cap_offset, sizeof (hba->pci_cap_offset));
2994 
2995         /* Read first offset */
2996         offset = PCI_CAP_POINTER;
2997         offset = ddi_get8(hba->pci_acc_handle,
2998             (uint8_t *)(hba->pci_addr + offset));
2999 
3000         while (offset >= PCI_CAP_PTR_OFF) {
3001                 /* Read the cap */
3002                 reg = ddi_get32(hba->pci_acc_handle,
3003                     (uint32_t *)(hba->pci_addr + offset));
3004 
3005                 id = ((reg >> PCI_CAP_ID_SHIFT) & PCI_CAP_ID_MASK);
3006                 next = ((reg >> PCI_CAP_NEXT_PTR_SHIFT) &
3007                     PCI_CAP_NEXT_PTR_MASK);
3008 
3009                 if ((id < PCI_CAP_MAX_PTR) &&
3010                     (hba->pci_cap_offset[id] == 0)) {
3011                         hba->pci_cap_offset[id] = offset;
3012                 }
3013 
3014                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3015                     "%s: offset=0x%x next=0x%x",
3016                     emlxs_pci_cap_xlate(id), offset, next);
3017 
3018                 offset = next;
3019         }
3020 
3021         /* Workaround for BE adapters */
3022         if ((hba->pci_cap_offset[PCI_CAP_ID_VS] == 0) &&
3023             (hba->model_info.chip & EMLXS_BE_CHIPS)) {
3024                 hba->pci_cap_offset[PCI_CAP_ID_VS] = 0x54;
3025 
3026                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3027                     "%s: offset=0x%x  Added.",
3028                     emlxs_pci_cap_xlate(PCI_CAP_ID_VS),
3029                     hba->pci_cap_offset[PCI_CAP_ID_VS]);
3030         }
3031 
3032         if (! hba->pci_cap_offset[PCI_CAP_ID_PCI_E]) {
3033                 /* It's not a PCIE adapter. */
3034                 return;
3035         }
3036 
3037         /* Read PCI Extended capbabilities */
3038 
3039         bzero(hba->pci_ecap_offset, sizeof (hba->pci_ecap_offset));
3040 
3041         /* Set first offset */
3042         eoffset = PCIE_EXT_CAP;
3043 
3044         while (eoffset >= PCIE_EXT_CAP) {
3045                 /* Read the cap */
3046                 reg = ddi_get32(hba->pci_acc_handle,
3047                     (uint32_t *)(hba->pci_addr + eoffset));
3048 
3049                 eid = ((reg >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK);
3050                 eversion = ((reg >> PCIE_EXT_CAP_VER_SHIFT) &
3051                     PCIE_EXT_CAP_VER_MASK);
3052                 enext = ((reg >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
3053                     PCIE_EXT_CAP_NEXT_PTR_MASK);
3054 
3055                 if ((eid < PCI_EXT_CAP_MAX_PTR) &&
3056                     (hba->pci_ecap_offset[eid] == 0)) {
3057                         hba->pci_ecap_offset[eid] = eoffset;
3058                 }
3059 
3060                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
3061                     "%s: offset=0x%x version=0x%x next=0x%x",
3062                     emlxs_pci_ecap_xlate(eid),
3063                     eoffset, eversion, enext);
3064 
3065                 eoffset = enext;
3066         }
3067 
3068         return;
3069 
3070 } /* emlxs_pci_cap_offsets() */