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