/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_hba.c
C | 2838 lines | 1935 code | 556 blank | 347 comment | 472 complexity | 1a0264f2a4fca20c3eef54eb84eaf7fe MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, LGPL-2.0, 0BSD, AGPL-3.0, GPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
- /*
- * Copyright 2010 Emulex. All rights reserved.
- * Use is subject to license terms.
- */
- #define EMLXS_FW_TABLE_DEF
- #define EMLXS_MODEL_DEF
- #include <emlxs.h>
- /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
- EMLXS_MSG_DEF(EMLXS_HBA_C);
- static void emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp,
- IOCBQ *iocbq);
- static void emlxs_pci_cap_offsets(emlxs_hba_t *hba);
- #ifdef MSI_SUPPORT
- uint32_t emlxs_msi_map[EMLXS_MSI_MODES][EMLXS_MSI_MAX_INTRS] =
- {EMLXS_MSI_MAP1, EMLXS_MSI_MAP2, EMLXS_MSI_MAP4, EMLXS_MSI_MAP8};
- uint32_t emlxs_msi_mask[EMLXS_MSI_MODES] =
- {EMLXS_MSI0_MASK1, EMLXS_MSI0_MASK2, EMLXS_MSI0_MASK4,
- EMLXS_MSI0_MASK8};
- #endif /* MSI_SUPPORT */
- emlxs_firmware_t emlxs_fw_table[] = EMLXS_FW_TABLE;
- int emlxs_fw_count = sizeof (emlxs_fw_table) / sizeof (emlxs_firmware_t);
- emlxs_table_t emlxs_pci_cap[] = {
- {PCI_CAP_ID_PM, "PCI_CAP_ID_PM"},
- {PCI_CAP_ID_AGP, "PCI_CAP_ID_AGP"},
- {PCI_CAP_ID_VPD, "PCI_CAP_ID_VPD"},
- {PCI_CAP_ID_SLOT_ID, "PCI_CAP_ID_SLOT_ID"},
- {PCI_CAP_ID_MSI, "PCI_CAP_ID_MSI"},
- {PCI_CAP_ID_cPCI_HS, "PCI_CAP_ID_cPCI_HS"},
- {PCI_CAP_ID_PCIX, "PCI_CAP_ID_PCIX"},
- {PCI_CAP_ID_HT, "PCI_CAP_ID_HT"},
- {PCI_CAP_ID_VS, "PCI_CAP_ID_VS"},
- {PCI_CAP_ID_DEBUG_PORT, "PCI_CAP_ID_DEBUG_PORT"},
- {PCI_CAP_ID_cPCI_CRC, "PCI_CAP_ID_cPCI_CRC"},
- {PCI_CAP_ID_PCI_HOTPLUG, "PCI_CAP_ID_PCI_HOTPLUG"},
- {PCI_CAP_ID_P2P_SUBSYS, "PCI_CAP_ID_P2P_SUBSYS"},
- {PCI_CAP_ID_AGP_8X, "PCI_CAP_ID_AGP_8X"},
- {PCI_CAP_ID_SECURE_DEV, "PCI_CAP_ID_SECURE_DEV"},
- {PCI_CAP_ID_PCI_E, "PCI_CAP_ID_PCI_E"},
- {PCI_CAP_ID_MSI_X, "PCI_CAP_ID_MSI_X"},
- {PCI_CAP_ID_SATA, "PCI_CAP_ID_SATA"},
- {PCI_CAP_ID_FLR, "PCI_CAP_ID_FLR"}
- }; /* emlxs_pci_cap */
- emlxs_table_t emlxs_ring_table[] = {
- {FC_FCP_RING, "FCP Ring"},
- {FC_IP_RING, "IP Ring"},
- {FC_ELS_RING, "ELS Ring"},
- {FC_CT_RING, "CT Ring"}
- }; /* emlxs_ring_table */
- emlxs_table_t emlxs_ffstate_table[] = {
- {0, "NULL"},
- {FC_ERROR, "ERROR"},
- {FC_KILLED, "KILLED"},
- {FC_WARM_START, "WARM_START"},
- {FC_INIT_START, "INIT_START"},
- {FC_INIT_NVPARAMS, "INIT_NVPARAMS"},
- {FC_INIT_REV, "INIT_REV"},
- {FC_INIT_CFGPORT, "INIT_CFGPORT"},
- {FC_INIT_CFGRING, "INIT_CFGRING"},
- {FC_INIT_INITLINK, "INIT_INITLINK"},
- {FC_LINK_DOWN, "LINK_DOWN"},
- {FC_LINK_UP, "LINK_UP"},
- {FC_CLEAR_LA, "CLEAR_LA"},
- {FC_READY, "READY"}
- }; /* emlxs_ffstate_table */
- #ifdef MSI_SUPPORT
- /* EMLXS_INTR_INIT */
- int32_t
- emlxs_msi_init(emlxs_hba_t *hba, uint32_t max)
- {
- emlxs_port_t *port = &PPORT;
- int32_t pass = 0;
- int32_t type = 0;
- char s_type[16];
- int32_t types;
- int32_t count;
- int32_t nintrs;
- int32_t mode;
- int32_t actual;
- int32_t new_actual;
- int32_t i;
- int32_t ret;
- ddi_intr_handle_t *htable = NULL;
- ddi_intr_handle_t *new_htable = NULL;
- uint32_t *intr_pri = NULL;
- int32_t *intr_cap = NULL;
- int32_t hilevel_pri;
- emlxs_config_t *cfg = &CFG;
- char buf[64];
- if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
- return (emlxs_intx_init(hba, max));
- }
- if (hba->intr_flags & EMLXS_MSI_INITED) {
- return (DDI_SUCCESS);
- }
- /* Set max interrupt count if not specified */
- if (max == 0) {
- if ((cfg[CFG_MSI_MODE].current == 2) ||
- (cfg[CFG_MSI_MODE].current == 3)) {
- max = EMLXS_MSI_MAX_INTRS;
- } else {
- max = 1;
- }
- }
- /* Filter max interrupt count with adapter model specification */
- if (hba->model_info.intr_limit && (max > hba->model_info.intr_limit)) {
- max = hba->model_info.intr_limit;
- }
- /* Get the available interrupt types from the kernel */
- types = 0;
- ret = ddi_intr_get_supported_types(hba->dip, &types);
- if ((ret != DDI_SUCCESS)) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
- /* Default to fixed type */
- types = DDI_INTR_TYPE_FIXED;
- }
- /* Check if fixed interrupts are being forced */
- if (cfg[CFG_MSI_MODE].current == 0) {
- types &= DDI_INTR_TYPE_FIXED;
- }
- /* Check if MSI interrupts are being forced */
- else if ((cfg[CFG_MSI_MODE].current == 1) ||
- (cfg[CFG_MSI_MODE].current == 2)) {
- types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
- }
- begin:
- /* Set interrupt type and interrupt count */
- type = 0;
- /* Check if MSIX is fully supported */
- if ((types & DDI_INTR_TYPE_MSIX) &&
- (hba->model_info.flags & EMLXS_MSIX_SUPPORTED)) {
- /* Get the max interrupt count from the adapter */
- nintrs = 0;
- ret =
- ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSIX,
- &nintrs);
- if (ret == DDI_SUCCESS && nintrs) {
- type = DDI_INTR_TYPE_MSIX;
- (void) strcpy(s_type, "TYPE_MSIX");
- goto initialize;
- }
- }
- /* Check if MSI is fully supported */
- if ((types & DDI_INTR_TYPE_MSI) &&
- (hba->model_info.flags & EMLXS_MSI_SUPPORTED)) {
- /* Get the max interrupt count from the adapter */
- nintrs = 0;
- ret =
- ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_MSI, &nintrs);
- if (ret == DDI_SUCCESS && nintrs) {
- type = DDI_INTR_TYPE_MSI;
- (void) strcpy(s_type, "TYPE_MSI");
- goto initialize;
- }
- }
- /* Check if fixed interrupts are fully supported */
- if ((types & DDI_INTR_TYPE_FIXED) &&
- (hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
- /* Get the max interrupt count from the adapter */
- nintrs = 0;
- ret =
- ddi_intr_get_nintrs(hba->dip, DDI_INTR_TYPE_FIXED,
- &nintrs);
- if (ret == DDI_SUCCESS) {
- type = DDI_INTR_TYPE_FIXED;
- (void) strcpy(s_type, "TYPE_FIXED");
- goto initialize;
- }
- }
- goto init_failed;
- initialize:
- pass++;
- mode = 0;
- actual = 0;
- htable = NULL;
- intr_pri = NULL;
- intr_cap = NULL;
- hilevel_pri = 0;
- if (pass == 1) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: %s: mode=%d types=0x%x nintrs=%d", s_type,
- cfg[CFG_MSI_MODE].current, types, nintrs);
- }
- /* Validate interrupt count */
- count = min(nintrs, max);
- if (count >= 8) {
- count = 8;
- } else if (count >= 4) {
- count = 4;
- } else if (count >= 2) {
- count = 2;
- } else {
- count = 1;
- }
- /* Allocate an array of interrupt handles */
- htable =
- kmem_alloc((size_t)(count * sizeof (ddi_intr_handle_t)),
- KM_SLEEP);
- /* Allocate 'count' interrupts */
- ret =
- ddi_intr_alloc(hba->dip, htable, type, EMLXS_MSI_INUMBER, count,
- &actual, DDI_INTR_ALLOC_NORMAL);
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: %s: count=%d actual=%d ret=%d", s_type, count, actual, ret);
- if ((ret != DDI_SUCCESS) || (actual == 0)) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: Unable to allocate interrupts. error=%d", ret);
- actual = 0;
- goto init_failed;
- }
- if (actual != count) {
- /* Validate actual count */
- if (actual >= 8) {
- new_actual = 8;
- } else if (actual >= 4) {
- new_actual = 4;
- } else if (actual >= 2) {
- new_actual = 2;
- } else {
- new_actual = 1;
- }
- if (new_actual < actual) {
- /* Free extra handles */
- for (i = new_actual; i < actual; i++) {
- (void) ddi_intr_free(htable[i]);
- }
- actual = new_actual;
- }
- /* Allocate a new array of interrupt handles */
- new_htable =
- kmem_alloc((size_t)(actual * sizeof (ddi_intr_handle_t)),
- KM_SLEEP);
- /* Copy old array to new array */
- bcopy((uint8_t *)htable, (uint8_t *)new_htable,
- (actual * sizeof (ddi_intr_handle_t)));
- /* Free the old array */
- kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
- htable = new_htable;
- count = actual;
- }
- /* Allocate interrupt priority table */
- intr_pri =
- (uint32_t *)kmem_alloc((size_t)(count * sizeof (uint32_t)),
- KM_SLEEP);
- /* Allocate interrupt capability table */
- intr_cap = kmem_alloc((size_t)(count * sizeof (uint32_t)), KM_SLEEP);
- /* Get minimum hilevel priority */
- hilevel_pri = ddi_intr_get_hilevel_pri();
- /* Fill the priority and capability tables */
- for (i = 0; i < count; ++i) {
- ret = ddi_intr_get_pri(htable[i], &intr_pri[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: ddi_intr_get_pri(%d) failed. "
- "handle=%p ret=%d",
- i, &htable[i], ret);
- /* Clean up the interrupts */
- goto init_failed;
- }
- if (intr_pri[i] >= hilevel_pri) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: Interrupt(%d) level too high. "
- "pri=0x%x hilevel=0x%x",
- i, intr_pri[i], hilevel_pri);
- /* Clean up the interrupts */
- goto init_failed;
- }
- ret = ddi_intr_get_cap(htable[i], &intr_cap[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: ddi_intr_get_cap(%d) failed. "
- "handle=%p ret=%d",
- i, &htable[i], ret);
- /* Clean up the interrupts */
- goto init_failed;
- }
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x", s_type, i,
- intr_cap[i], intr_pri[i], hilevel_pri);
- }
- /* Set mode */
- switch (count) {
- case 8:
- mode = EMLXS_MSI_MODE8;
- break;
- case 4:
- mode = EMLXS_MSI_MODE4;
- break;
- case 2:
- mode = EMLXS_MSI_MODE2;
- break;
- default:
- mode = EMLXS_MSI_MODE1;
- }
- /* Save the info */
- hba->intr_htable = htable;
- hba->intr_count = count;
- hba->intr_pri = intr_pri;
- hba->intr_cap = intr_cap;
- hba->intr_type = type;
- hba->intr_arg = (void *)((unsigned long)intr_pri[0]);
- hba->intr_mask = emlxs_msi_mask[mode];
- hba->intr_cond = 0;
- /* Adjust number of channels based on intr_count */
- if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
- hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
- }
- for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
- hba->intr_map[i] = emlxs_msi_map[mode][i];
- hba->intr_cond |= emlxs_msi_map[mode][i];
- (void) sprintf(buf, "%s%d_msi%d mutex", DRIVER_NAME,
- hba->ddiinst, i);
- mutex_init(&hba->intr_lock[i], buf, MUTEX_DRIVER,
- DDI_INTR_PRI(hba->intr_arg));
- }
- /* Set flag to indicate support */
- hba->intr_flags |= EMLXS_MSI_INITED;
- /* Create the interrupt threads */
- for (i = 0; i < hba->chan_count; i++) {
- (void) sprintf(buf, "%s%d_channel%d mutex", DRIVER_NAME,
- hba->ddiinst, i);
- mutex_init(&hba->chan[i].rsp_lock, buf, MUTEX_DRIVER,
- DDI_INTR_PRI(hba->intr_arg));
- emlxs_thread_create(hba, &hba->chan[i].intr_thread);
- }
- return (DDI_SUCCESS);
- init_failed:
- if (intr_cap) {
- kmem_free(intr_cap, (count * sizeof (int32_t)));
- }
- if (intr_pri) {
- kmem_free(intr_pri, (count * sizeof (int32_t)));
- }
- if (htable) {
- /* Process the interrupt handlers */
- for (i = 0; i < actual; i++) {
- /* Free the handle[i] */
- (void) ddi_intr_free(htable[i]);
- }
- kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
- }
- /* Initialize */
- hba->intr_htable = NULL;
- hba->intr_count = 0;
- hba->intr_pri = NULL;
- hba->intr_cap = NULL;
- hba->intr_type = 0;
- hba->intr_arg = NULL;
- hba->intr_cond = 0;
- bzero(hba->intr_map, sizeof (hba->intr_map));
- bzero(hba->intr_lock, sizeof (hba->intr_lock));
- if (type == DDI_INTR_TYPE_MSIX) {
- types &= (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
- goto begin;
- } else if (type == DDI_INTR_TYPE_MSI) {
- types &= DDI_INTR_TYPE_FIXED;
- goto begin;
- }
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
- "MSI: Unable to initialize interrupts");
- return (DDI_FAILURE);
- } /* emlxs_msi_init() */
- /* EMLXS_INTR_UNINIT */
- int32_t
- emlxs_msi_uninit(emlxs_hba_t *hba)
- {
- uint32_t count;
- int32_t i;
- ddi_intr_handle_t *htable;
- uint32_t *intr_pri;
- int32_t *intr_cap;
- int32_t ret;
- if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
- return (emlxs_intx_uninit(hba));
- }
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- * "MSI: emlxs_msi_uninit called. flags=%x",
- * hba->intr_flags);
- */
- /* Make sure interrupts have been removed first */
- if ((hba->intr_flags & EMLXS_MSI_ADDED)) {
- ret = emlxs_msi_remove(hba);
- if (ret != DDI_SUCCESS) {
- return (ret);
- }
- }
- /* Check if the interrupts are still initialized */
- if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
- return (DDI_SUCCESS);
- }
- hba->intr_flags &= ~EMLXS_MSI_INITED;
- /* Get handle table parameters */
- htable = hba->intr_htable;
- count = hba->intr_count;
- intr_pri = hba->intr_pri;
- intr_cap = hba->intr_cap;
- /* Clean up */
- hba->intr_count = 0;
- hba->intr_htable = NULL;
- hba->intr_pri = NULL;
- hba->intr_cap = NULL;
- hba->intr_type = 0;
- hba->intr_arg = NULL;
- hba->intr_cond = 0;
- bzero(hba->intr_map, sizeof (hba->intr_map));
- if (intr_cap) {
- kmem_free(intr_cap, (count * sizeof (int32_t)));
- }
- if (intr_pri) {
- kmem_free(intr_pri, (count * sizeof (int32_t)));
- }
- if (htable) {
- /* Process the interrupt handlers */
- for (i = 0; i < count; ++i) {
- /* Free the handle[i] */
- ret = ddi_intr_free(htable[i]);
- }
- kmem_free(htable, (count * sizeof (ddi_intr_handle_t)));
- }
- /* Destroy the intr locks */
- for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
- mutex_destroy(&hba->intr_lock[i]);
- }
- /* Destroy the interrupt threads */
- for (i = 0; i < hba->chan_count; i++) {
- emlxs_thread_destroy(&hba->chan[i].intr_thread);
- mutex_destroy(&hba->chan[i].rsp_lock);
- }
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- * "MSI: emlxs_msi_uninit done. flags=%x",
- * hba->intr_flags);
- */
- return (DDI_SUCCESS);
- } /* emlxs_msi_uninit() */
- /* EMLXS_INTR_ADD */
- int32_t
- emlxs_msi_add(emlxs_hba_t *hba)
- {
- emlxs_port_t *port = &PPORT;
- int32_t count;
- int32_t i;
- int32_t ret;
- ddi_intr_handle_t *htable = NULL;
- int32_t *intr_cap = NULL;
- if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
- return (emlxs_intx_add(hba));
- }
- /* Check if interrupts have already been added */
- if (hba->intr_flags & EMLXS_MSI_ADDED) {
- return (DDI_SUCCESS);
- }
- /* Check if interrupts have been initialized */
- if (!(hba->intr_flags & EMLXS_MSI_INITED)) {
- ret = emlxs_msi_init(hba, 0);
- if (ret != DDI_SUCCESS) {
- return (ret);
- }
- }
- /* Get handle table parameters */
- htable = hba->intr_htable;
- count = hba->intr_count;
- intr_cap = hba->intr_cap;
- /* Add the interrupt handlers */
- for (i = 0; i < count; ++i) {
- /* add handler for handle[i] */
- ret =
- ddi_intr_add_handler(htable[i], EMLXS_SLI_MSI_INTR,
- (char *)hba, (char *)((unsigned long)i));
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
- "MSI: ddi_intr_add_handler(%d) failed. "
- "handle=%p ret=%d",
- i, &htable[i], ret);
- /* Process the remaining interrupt handlers */
- while (i) {
- /* Decrement i */
- i--;
- /* Remove the handler */
- ret = ddi_intr_remove_handler(htable[i]);
- }
- return (DDI_FAILURE);
- }
- }
- /* Enable the interrupts */
- if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
- ret = ddi_intr_block_enable(htable, count);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: ddi_intr_block_enable(%d) failed. ret=%d",
- count, ret);
- for (i = 0; i < count; ++i) {
- ret = ddi_intr_enable(htable[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_init_debug_msg,
- "MSI: ddi_intr_enable(%d) failed. "
- "ret=%d",
- i, ret);
- }
- }
- }
- } else {
- for (i = 0; i < count; ++i) {
- ret = ddi_intr_enable(htable[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_init_debug_msg,
- "MSI: ddi_intr_enable(%d) failed. ret=%d",
- i, ret);
- }
- }
- }
- /* Set flag to indicate support */
- hba->intr_flags |= EMLXS_MSI_ADDED;
- return (DDI_SUCCESS);
- } /* emlxs_msi_add() */
- /* EMLXS_INTR_REMOVE */
- int32_t
- emlxs_msi_remove(emlxs_hba_t *hba)
- {
- emlxs_port_t *port = &PPORT;
- uint32_t count;
- int32_t i;
- ddi_intr_handle_t *htable;
- int32_t *intr_cap;
- int32_t ret;
- if (!(hba->intr_flags & EMLXS_MSI_ENABLED)) {
- return (emlxs_intx_remove(hba));
- }
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- * "MSI: emlxs_msi_remove called. flags=%x",
- * hba->intr_flags);
- */
- /* Check if interrupts have already been removed */
- if (!(hba->intr_flags & EMLXS_MSI_ADDED)) {
- return (DDI_SUCCESS);
- }
- hba->intr_flags &= ~EMLXS_MSI_ADDED;
- /* Disable all adapter interrupts */
- EMLXS_SLI_DISABLE_INTR(hba, 0);
- /* Get handle table parameters */
- htable = hba->intr_htable;
- count = hba->intr_count;
- intr_cap = hba->intr_cap;
- /* Disable the interrupts */
- if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
- ret = ddi_intr_block_disable(htable, count);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
- "MSI: ddi_intr_block_disable(%d) failed. ret=%d",
- count, ret);
- for (i = 0; i < count; i++) {
- ret = ddi_intr_disable(htable[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_init_debug_msg,
- "MSI: ddi_intr_disable(%d) failed. "
- "ret=%d",
- i, ret);
- }
- }
- }
- } else {
- for (i = 0; i < count; i++) {
- ret = ddi_intr_disable(htable[i]);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_init_debug_msg,
- "MSI: ddi_intr_disable(%d) failed. ret=%d",
- i, ret);
- }
- }
- }
- /* Process the interrupt handlers */
- for (i = 0; i < count; i++) {
- /* Remove the handler */
- ret = ddi_intr_remove_handler(htable[i]);
- }
- return (DDI_SUCCESS);
- } /* emlxs_msi_remove() */
- #endif /* MSI_SUPPORT */
- /* EMLXS_INTR_INIT */
- /* ARGSUSED */
- int32_t
- emlxs_intx_init(emlxs_hba_t *hba, uint32_t max)
- {
- emlxs_port_t *port = &PPORT;
- emlxs_config_t *cfg = &CFG;
- int32_t ret;
- uint32_t i;
- char buf[64];
- /* Check if interrupts have already been initialized */
- if (hba->intr_flags & EMLXS_INTX_INITED) {
- return (DDI_SUCCESS);
- }
- /* Check if adapter is flagged for INTX support */
- if (!(hba->model_info.flags & EMLXS_INTX_SUPPORTED)) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
- "INTX: %s does not support INTX. flags=0x%x",
- hba->model_info.model, hba->model_info.flags);
- return (DDI_FAILURE);
- }
- /*
- * Interrupt number '0' is a high-level interrupt. This driver
- * does not support having its interrupts mapped above scheduler
- * priority; i.e., we always expect to be able to call general
- * kernel routines that may invoke the scheduler.
- */
- if (ddi_intr_hilevel(hba->dip, EMLXS_INUMBER) != 0) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
- "INTX: High-level interrupt not supported.");
- return (DDI_FAILURE);
- }
- /* Get an iblock cookie */
- ret =
- ddi_get_iblock_cookie(hba->dip, (uint32_t)EMLXS_INUMBER,
- (ddi_iblock_cookie_t *)&hba->intr_arg);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
- "INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
- return (ret);
- }
- hba->intr_flags |= EMLXS_INTX_INITED;
- hba->intr_count = 1;
- /* Adjust number of channels based on intr_count */
- if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
- hba->chan_count = cfg[CFG_NUM_WQ].current;
- }
- /* Create the interrupt threads */
- for (i = 0; i < hba->chan_count; i++) {
- (void) sprintf(buf, "%s%d_channel%d mutex", DRIVER_NAME,
- hba->ddiinst, i);
- mutex_init(&hba->chan[i].rsp_lock, buf, MUTEX_DRIVER,
- DDI_INTR_PRI(hba->intr_arg));
- emlxs_thread_create(hba, &hba->chan[i].intr_thread);
- }
- return (DDI_SUCCESS);
- } /* emlxs_intx_init() */
- /* EMLXS_INTR_UNINIT */
- int32_t
- emlxs_intx_uninit(emlxs_hba_t *hba)
- {
- int32_t ret;
- uint32_t i;
- /* Make sure interrupts have been removed */
- if ((hba->intr_flags & EMLXS_INTX_ADDED)) {
- ret = emlxs_intx_remove(hba);
- if (ret != DDI_SUCCESS) {
- return (ret);
- }
- }
- /* Check if the interrupts are still initialized */
- if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
- return (DDI_SUCCESS);
- }
- hba->intr_flags &= ~EMLXS_INTX_INITED;
- hba->intr_arg = NULL;
- /* Create the interrupt threads */
- for (i = 0; i < hba->chan_count; i++) {
- emlxs_thread_destroy(&hba->chan[i].intr_thread);
- mutex_destroy(&hba->chan[i].rsp_lock);
- }
- return (DDI_SUCCESS);
- } /* emlxs_intx_uninit() */
- /*
- * This is the legacy method for adding interrupts in Solaris
- * EMLXS_INTR_ADD
- */
- int32_t
- emlxs_intx_add(emlxs_hba_t *hba)
- {
- emlxs_port_t *port = &PPORT;
- int32_t ret;
- /* Check if interrupts have already been added */
- if (hba->intr_flags & EMLXS_INTX_ADDED) {
- return (DDI_SUCCESS);
- }
- /* Check if interrupts have been initialized */
- if (!(hba->intr_flags & EMLXS_INTX_INITED)) {
- ret = emlxs_intx_init(hba, 0);
- if (ret != DDI_SUCCESS) {
- return (ret);
- }
- }
- /* add intrrupt handler routine */
- ret = ddi_add_intr((void *)hba->dip,
- (uint_t)EMLXS_INUMBER,
- (ddi_iblock_cookie_t *)&hba->intr_arg,
- (ddi_idevice_cookie_t *)0,
- (uint_t(*)())EMLXS_SLI_INTX_INTR, (caddr_t)hba);
- if (ret != DDI_SUCCESS) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_failed_msg,
- "INTX: ddi_add_intr failed. ret=%d", ret);
- return (ret);
- }
- hba->intr_flags |= EMLXS_INTX_ADDED;
- return (DDI_SUCCESS);
- } /* emlxs_intx_add() */
- /* EMLXS_INTR_REMOVE */
- int32_t
- emlxs_intx_remove(emlxs_hba_t *hba)
- {
- /* Check if interrupts have already been removed */
- if (!(hba->intr_flags & EMLXS_INTX_ADDED)) {
- return (DDI_SUCCESS);
- }
- hba->intr_flags &= ~EMLXS_INTX_ADDED;
- /* Diable all adapter interrupts */
- EMLXS_SLI_DISABLE_INTR(hba, 0);
- /* Remove the interrupt */
- (void) ddi_remove_intr((void *)hba->dip, (uint_t)EMLXS_INUMBER,
- hba->intr_arg);
- return (DDI_SUCCESS);
- } /* emlxs_intx_remove() */
- extern void
- emlxs_process_link_speed(emlxs_hba_t *hba)
- {
- emlxs_vpd_t *vpd;
- emlxs_config_t *cfg;
- char *cptr;
- uint32_t hi;
- /*
- * This routine modifies the link-speed config parameter entry
- * based on adapter capabilities
- */
- vpd = &VPD;
- cfg = &hba->config[CFG_LINK_SPEED];
- cptr = cfg->help;
- (void) strcpy(cptr, "Select link speed. [0=Auto");
- cptr += 26;
- hi = 0;
- if (vpd->link_speed & LMT_1GB_CAPABLE) {
- (void) strcpy(cptr, ", 1=1Gb");
- cptr += 7;
- hi = 1;
- }
- if (vpd->link_speed & LMT_2GB_CAPABLE) {
- (void) strcpy(cptr, ", 2=2Gb");
- cptr += 7;
- hi = 2;
- }
- if (vpd->link_speed & LMT_4GB_CAPABLE) {
- (void) strcpy(cptr, ", 4=4Gb");
- cptr += 7;
- hi = 4;
- }
- if (vpd->link_speed & LMT_8GB_CAPABLE) {
- (void) strcpy(cptr, ", 8=8Gb");
- cptr += 7;
- hi = 8;
- }
- if (vpd->link_speed & LMT_10GB_CAPABLE) {
- (void) strcpy(cptr, ", 10=10Gb");
- cptr += 9;
- hi = 10;
- }
- (void) strcpy(cptr, "]");
- cfg->hi = hi;
- /* Now revalidate the current parameter setting */
- cfg->current = emlxs_check_parm(hba, CFG_LINK_SPEED, cfg->current);
- return;
- } /* emlxs_process_link_speed() */
- /*
- * emlxs_parse_vpd()
- *
- * This routine will parse the VPD data
- */
- extern int
- emlxs_parse_vpd(emlxs_hba_t *hba, uint8_t *vpd_buf, uint32_t size)
- {
- emlxs_port_t *port = &PPORT;
- char tag[3];
- uint8_t lenlo, lenhi;
- uint32_t n;
- uint16_t block_size;
- uint32_t block_index = 0;
- uint8_t sub_size;
- uint32_t sub_index;
- int32_t finished = 0;
- int32_t index = 0;
- char buffer[128];
- emlxs_vpd_t *vpd;
- vpd = &VPD;
- while (!finished && (block_index < size)) {
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "block_index = %x", block_index);
- */
- switch (vpd_buf[block_index]) {
- case 0x82:
- index = block_index;
- index += 1;
- lenlo = vpd_buf[index];
- index += 1;
- lenhi = vpd_buf[index];
- index += 1;
- block_index = index;
- block_size = ((((uint16_t)lenhi) << 8) + lenlo);
- block_index += block_size;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "block_size = %x", block_size);
- */
- n = sizeof (buffer);
- bzero(buffer, n);
- bcopy(&vpd_buf[index], buffer,
- (block_size < (n - 1)) ? block_size : (n - 1));
- (void) strcpy(vpd->id, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "ID: %s",
- vpd->id);
- break;
- case 0x90:
- index = block_index;
- index += 1;
- lenlo = vpd_buf[index];
- index += 1;
- lenhi = vpd_buf[index];
- index += 1;
- block_index = index;
- sub_index = index;
- block_size = ((((uint16_t)lenhi) << 8) + lenlo);
- block_index += block_size;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "block_size = %x", block_size);
- */
- /* Scan for sub-blocks */
- while ((sub_index < block_index) &&
- (sub_index < size)) {
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "sub_index = %x", sub_index);
- */
- index = sub_index;
- tag[0] = vpd_buf[index++];
- tag[1] = vpd_buf[index++];
- tag[2] = 0;
- sub_size = vpd_buf[index++];
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "sub_size = %x", sub_size);
- */
- sub_index = (index + sub_size);
- n = sizeof (buffer);
- bzero(buffer, n);
- bcopy(&vpd_buf[index], buffer,
- (sub_size < (n - 1)) ? sub_size : (n - 1));
- /*
- * Look for Engineering Change (EC)
- */
- if (strcmp(tag, "EC") == 0) {
- (void) strcpy(vpd->eng_change, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "EC: %s",
- vpd->eng_change);
- }
- /*
- * Look for Manufacturer (MN)
- */
- else if (strcmp(tag, "MN") == 0) {
- (void) strcpy(vpd->manufacturer,
- buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "MN: %s",
- vpd->manufacturer);
- }
- /*
- * Look for Serial Number (SN)
- */
- else if (strcmp(tag, "SN") == 0) {
- (void) strcpy(vpd->serial_num, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "SN: %s",
- vpd->serial_num);
- /* Validate the serial number */
- if (strncmp(buffer, "FFFFFFFFFF", 10) ==
- 0 ||
- strncmp(buffer, "0000000000", 10) ==
- 0) {
- vpd->serial_num[0] = 0;
- }
- }
- /*
- * Look for Part Number (PN)
- */
- else if (strcmp(tag, "PN") == 0) {
- (void) strcpy(vpd->part_num, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "PN: %s",
- vpd->part_num);
- }
- /*
- * Look for (V0)
- */
- else if (strcmp(tag, "V0") == 0) {
- /* Not used */
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "V0: %s", buffer);
- }
- /*
- * Look for model description (V1)
- */
- else if (strcmp(tag, "V1") == 0) {
- (void) strcpy(vpd->model_desc, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Desc: %s",
- vpd->model_desc);
- }
- /*
- * Look for model (V2)
- */
- else if (strcmp(tag, "V2") == 0) {
- (void) strcpy(vpd->model, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Model: %s",
- vpd->model);
- }
- /*
- * Look for program type (V3)
- */
- else if (strcmp(tag, "V3") == 0) {
- (void) strcpy(vpd->prog_types, buffer);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Prog Types: %s",
- vpd->prog_types);
- }
- /*
- * Look for port number (V4)
- */
- else if (strcmp(tag, "V4") == 0) {
- (void) strcpy(vpd->port_num, buffer);
- vpd->port_index =
- emlxs_strtol(vpd->port_num, 10);
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Port: %s",
- (vpd->port_num[0]) ? vpd->
- port_num : "not applicable");
- }
- /*
- * Look for checksum (RV)
- */
- else if (strcmp(tag, "RV") == 0) {
- /* Not used */
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Checksum: 0x%x",
- buffer[0]);
- }
- else {
- /* Generic */
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_vpd_msg, "Tag: %s: %s",
- tag, buffer);
- }
- }
- break;
- case 0x78:
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "End Tag.");
- finished = 1;
- break;
- default:
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- "Unknown block: %x %x %x %x %x %x %x %x",
- vpd_buf[index], vpd_buf[index + 1],
- vpd_buf[index + 2], vpd_buf[index + 3],
- vpd_buf[index + 4], vpd_buf[index + 5],
- vpd_buf[index + 6], vpd_buf[index + 7]);
- return (0);
- }
- }
- return (1);
- } /* emlxs_parse_vpd */
- /*
- * emlxs_parse_fcoe()
- *
- * This routine will parse the VPD data
- */
- extern int
- emlxs_parse_fcoe(emlxs_hba_t *hba, uint8_t *fcoep, uint32_t size)
- {
- emlxs_port_t *port = &PPORT;
- tlv_fcoe_t *fcoelist;
- tlv_fcfconnectlist_t *fcflist;
- int i;
- /* Validate the config region 23 signature */
- if ((*fcoep != 'R') || (*(fcoep+1) != 'G') ||
- (*(fcoep+2) != '2') || (*(fcoep+3) != '3')) {
- return (0);
- }
- /* Search the config region 23, for FCOE Parameters record */
- i = 4;
- while ((i < size) && (*(fcoep+i) != 0xA0) && (*(fcoep+i) != 0xff)) {
- i += fcoep[i+1] * sizeof (uint32_t) + 2;
- }
- if (*(fcoep+i) == 0xA0) {
- fcoelist = (tlv_fcoe_t *)(fcoep+i);
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- "Found FCOE Params (A0):%d x%x",
- fcoelist->length, fcoelist->fip_flags);
- bcopy((uint8_t *)fcoelist, (uint8_t *)&hba->sli.sli4.cfgFCOE,
- sizeof (tlv_fcoe_t));
- }
- /* Search the config region 23, for FCF record */
- i = 4;
- while ((i < size) && (*(fcoep+i) != 0xA1) && (*(fcoep+i) != 0xff)) {
- i += fcoep[i+1] * sizeof (uint32_t) + 2;
- }
- if (*(fcoep+i) == 0xA1) {
- fcflist = (tlv_fcfconnectlist_t *)(fcoep+i);
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- "Found FCF ConnectList (A1):%d", fcflist->length);
- bcopy((uint8_t *)fcflist, (uint8_t *)&hba->sli.sli4.cfgFCF,
- sizeof (tlv_fcfconnectlist_t));
- }
- return (1);
- } /* emlxs_parse_fcoe */
- extern void
- emlxs_decode_firmware_rev(emlxs_hba_t *hba, emlxs_vpd_t *vpd)
- {
- if (vpd->rBit) {
- switch (hba->sli_mode) {
- case EMLXS_HBA_SLI4_MODE:
- (void) strcpy(vpd->fw_version, vpd->sli4FwName);
- (void) strcpy(vpd->fw_label, vpd->sli4FwLabel);
- break;
- case EMLXS_HBA_SLI3_MODE:
- (void) strcpy(vpd->fw_version, vpd->sli3FwName);
- (void) strcpy(vpd->fw_label, vpd->sli3FwLabel);
- break;
- case EMLXS_HBA_SLI2_MODE:
- (void) strcpy(vpd->fw_version, vpd->sli2FwName);
- (void) strcpy(vpd->fw_label, vpd->sli2FwLabel);
- break;
- case EMLXS_HBA_SLI1_MODE:
- (void) strcpy(vpd->fw_version, vpd->sli1FwName);
- (void) strcpy(vpd->fw_label, vpd->sli1FwLabel);
- break;
- default:
- (void) strcpy(vpd->fw_version, "unknown");
- (void) strcpy(vpd->fw_label, vpd->fw_version);
- }
- } else {
- emlxs_decode_version(vpd->smFwRev, vpd->fw_version);
- (void) strcpy(vpd->fw_label, vpd->fw_version);
- }
- return;
- } /* emlxs_decode_firmware_rev() */
- extern void
- emlxs_decode_version(uint32_t version, char *buffer)
- {
- uint32_t b1, b2, b3, b4;
- char c;
- b1 = (version & 0x0000f000) >> 12;
- b2 = (version & 0x00000f00) >> 8;
- b3 = (version & 0x000000c0) >> 6;
- b4 = (version & 0x00000030) >> 4;
- if (b1 == 0 && b2 == 0) {
- (void) sprintf(buffer, "none");
- return;
- }
- c = 0;
- switch (b4) {
- case 0:
- c = 'n';
- break;
- case 1:
- c = 'a';
- break;
- case 2:
- c = 'b';
- break;
- case 3:
- if ((version & 0x0000000f)) {
- c = 'x';
- }
- break;
- }
- b4 = (version & 0x0000000f);
- if (c == 0) {
- (void) sprintf(buffer, "%d.%d%d", b1, b2, b3);
- } else {
- (void) sprintf(buffer, "%d.%d%d%c%d", b1, b2, b3, c, b4);
- }
- return;
- } /* emlxs_decode_version() */
- extern void
- emlxs_decode_label(char *label, char *buffer, int bige)
- {
- uint32_t i;
- char name[16];
- bcopy(label, name, sizeof (name));
- /* bige is TRUE if the data format is big endian */
- if (bige) {
- /* Data format big Endian */
- LE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
- for (i = 0; i < sizeof (name); i++) {
- if (name[i] == 0x20) {
- name[i] = 0;
- }
- }
- } else {
- /* Data format little Endian */
- BE_SWAP32_BUFFER((uint8_t *)name, sizeof (name));
- for (i = 0; i < sizeof (name); i++) {
- if (name[i] == 0x20) {
- name[i] = 0;
- }
- }
- }
- (void) strcpy(buffer, name);
- return;
- } /* emlxs_decode_label() */
- extern uint32_t
- emlxs_strtol(char *str, uint32_t base)
- {
- uint32_t value = 0;
- char *ptr;
- uint32_t factor = 1;
- uint32_t digits;
- if (*str == 0) {
- return (0);
- }
- if (base != 10 && base != 16) {
- return (0);
- }
- /* Get max digits of value */
- digits = (base == 10) ? 9 : 8;
- /* Position pointer to end of string */
- ptr = str + strlen(str);
- /* Process string backwards */
- while ((ptr-- > str) && digits) {
- /* check for base 10 numbers */
- if (*ptr >= '0' && *ptr <= '9') {
- value += ((uint32_t)(*ptr - '0')) * factor;
- factor *= base;
- digits--;
- } else if (base == 16) {
- /* Check for base 16 numbers */
- if (*ptr >= 'a' && *ptr <= 'f') {
- value +=
- ((uint32_t)(*ptr - 'a') + 10) * factor;
- factor *= base;
- digits--;
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- value +=
- ((uint32_t)(*ptr - 'A') + 10) * factor;
- factor *= base;
- digits--;
- } else if (factor > 1) {
- break;
- }
- } else if (factor > 1) {
- break;
- }
- }
- return (value);
- } /* emlxs_strtol() */
- extern uint64_t
- emlxs_strtoll(char *str, uint32_t base)
- {
- uint64_t value = 0;
- char *ptr;
- uint32_t factor = 1;
- uint32_t digits;
- if (*str == 0) {
- return (0);
- }
- if (base != 10 && base != 16) {
- return (0);
- }
- /* Get max digits of value */
- digits = (base == 10) ? 19 : 16;
- /* Position pointer to end of string */
- ptr = str + strlen(str);
- /* Process string backwards */
- while ((ptr-- > str) && digits) {
- /* check for base 10 numbers */
- if (*ptr >= '0' && *ptr <= '9') {
- value += ((uint32_t)(*ptr - '0')) * factor;
- factor *= base;
- digits--;
- } else if (base == 16) {
- /* Check for base 16 numbers */
- if (*ptr >= 'a' && *ptr <= 'f') {
- value +=
- ((uint32_t)(*ptr - 'a') + 10) * factor;
- factor *= base;
- digits--;
- } else if (*ptr >= 'A' && *ptr <= 'F') {
- value +=
- ((uint32_t)(*ptr - 'A') + 10) * factor;
- factor *= base;
- digits--;
- } else if (factor > 1) {
- break;
- }
- } else if (factor > 1) {
- break;
- }
- }
- return (value);
- } /* emlxs_strtoll() */
- extern void
- emlxs_parse_prog_types(emlxs_hba_t *hba, char *prog_types)
- {
- emlxs_port_t *port = &PPORT;
- uint32_t i;
- char *ptr;
- emlxs_model_t *model;
- char types_buffer[256];
- char *types;
- bcopy(prog_types, types_buffer, 256);
- types = types_buffer;
- model = &hba->model_info;
- while (*types) {
- if (strncmp(types, "T2:", 3) == 0) {
- bzero(model->pt_2, sizeof (model->pt_2));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_2[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "T3:", 3) == 0) {
- bzero(model->pt_3, sizeof (model->pt_3));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_3[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "T6:", 3) == 0) {
- bzero(model->pt_6, sizeof (model->pt_6));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_6[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- model->pt_6[i] = 0;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "T7:", 3) == 0) {
- bzero(model->pt_7, sizeof (model->pt_7));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_7[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- model->pt_7[i] = 0;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "TA:", 3) == 0) {
- bzero(model->pt_A, sizeof (model->pt_A));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_A[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "TB:", 3) == 0) {
- bzero(model->pt_B, sizeof (model->pt_B));
- types += 3;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_B[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "TFF:", 4) == 0) {
- bzero(model->pt_FF, sizeof (model->pt_FF));
- types += 4;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_FF[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else if (strncmp(types, "T20:", 4) == 0) {
- bzero(model->pt_20, sizeof (model->pt_20));
- types += 4;
- i = 0;
- while (*types && *types != 'T') {
- /* Null terminate the next value */
- ptr = types;
- while (*ptr && (*ptr != ','))
- ptr++;
- *ptr = 0;
- /* Save the value */
- model->pt_20[i++] =
- (uint8_t)emlxs_strtol(types, 16);
- model->pt_20[i] = 0;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- * "T20[%d]: 0x%x", i-1, model->pt_20[i-1]);
- */
- /* Move the str pointer */
- types = ptr + 1;
- }
- } else {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
- "Unknown prog type string = %s", types);
- break;
- }
- }
- return;
- } /* emlxs_parse_prog_types() */
- extern void
- emlxs_build_prog_types(emlxs_hba_t *hba, char *prog_types)
- {
- uint32_t i;
- uint32_t found = 0;
- char buffer[256];
- bzero(prog_types, 256);
- /* Rebuild the prog type string */
- if (hba->model_info.pt_2[0]) {
- (void) strcat(prog_types, "T2:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_2[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_2[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_3[0]) {
- (void) strcat(prog_types, "T3:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_3[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_3[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_6[0]) {
- (void) strcat(prog_types, "T6:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_6[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_6[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_7[0]) {
- (void) strcat(prog_types, "T7:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_7[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_7[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_A[0]) {
- (void) strcat(prog_types, "TA:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_A[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_A[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_B[0]) {
- (void) strcat(prog_types, "TB:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_B[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_B[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_20[0]) {
- (void) strcat(prog_types, "T20:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_20[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_20[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (hba->model_info.pt_FF[0]) {
- (void) strcat(prog_types, "TFF:");
- found = 1;
- i = 0;
- while (hba->model_info.pt_FF[i] && i < 8) {
- (void) sprintf(buffer, "%X,", hba->model_info.pt_FF[i]);
- (void) strcat(prog_types, buffer);
- i++;
- }
- }
- if (found) {
- /* Terminate at the last comma in string */
- prog_types[(strlen(prog_types) - 1)] = 0;
- }
- return;
- } /* emlxs_build_prog_types() */
- extern uint32_t
- emlxs_init_adapter_info(emlxs_hba_t *hba)
- {
- emlxs_port_t *port = &PPORT;
- uint32_t pci_id;
- uint32_t cache_line;
- uint32_t channels;
- uint16_t device_id;
- uint16_t ssdid;
- uint32_t i;
- uint32_t found = 0;
- int32_t *prop;
- uint32_t num_prop;
- if (hba->bus_type == SBUS_FC) {
- if (hba->pci_acc_handle == NULL) {
- bcopy(&emlxs_sbus_model[0], &hba->model_info,
- sizeof (emlxs_model_t));
- hba->model_info.device_id = 0;
- return (0);
- }
- /* Read the PCI device id */
- pci_id =
- ddi_get32(hba->pci_acc_handle,
- (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER));
- device_id = (uint16_t)(pci_id >> 16);
- /* Find matching adapter model */
- for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
- if (emlxs_sbus_model[i].device_id == device_id) {
- bcopy(&emlxs_sbus_model[i], &hba->model_info,
- sizeof (emlxs_model_t));
- found = 1;
- break;
- }
- }
- /* If not found then use the unknown model */
- if (!found) {
- bcopy(&emlxs_sbus_model[0], &hba->model_info,
- sizeof (emlxs_model_t));
- hba->model_info.device_id = device_id;
- return (0);
- }
- } else { /* PCI model */
- if (hba->pci_acc_handle == NULL) {
- bcopy(&emlxs_pci_model[0], &hba->model_info,
- sizeof (emlxs_model_t));
- hba->model_info.device_id = 0;
- return (0);
- }
- /* Read the PCI device id */
- device_id =
- ddi_get16(hba->pci_acc_handle,
- (uint16_t *)(hba->pci_addr + PCI_DEVICE_ID_REGISTER));
- /* Read the PCI Subsystem id */
- ssdid =
- ddi_get16(hba->pci_acc_handle,
- (uint16_t *)(hba->pci_addr + PCI_SSDID_REGISTER));
- if (ssdid == 0 || ssdid == 0xffff) {
- ssdid = device_id;
- }
- /* Read the Cache Line reg */
- cache_line =
- ddi_get32(hba->pci_acc_handle,
- (uint32_t *)(hba->pci_addr + PCI_CACHE_LINE_REGISTER));
- /* Check for the multifunction bit being set */
- if ((cache_line & 0x00ff0000) == 0x00800000) {
- channels = 2;
- } else {
- channels = 1;
- }
- /* If device ids are unique, then use them for search */
- if (device_id != ssdid) {
- if (channels > 1) {
- /*
- * Find matching adapter model using
- * device_id, ssdid and channels
- */
- for (i = 1; i < emlxs_pci_model_count; i++) {
- if (emlxs_pci_model[i].device_id ==
- device_id &&
- emlxs_pci_model[i].ssdid == ssdid &&
- emlxs_pci_model[i].channels ==
- channels) {
- bcopy(&emlxs_pci_model[i],
- &hba->model_info,
- sizeof (emlxs_model_t));
- found = 1;
- break;
- }
- }
- } else {
- /*
- * Find matching adapter model using
- * device_id and ssdid
- */
- for (i = 1; i < emlxs_pci_model_count; i++) {
- if (emlxs_pci_model[i].device_id ==
- device_id &&
- emlxs_pci_model[i].ssdid == ssdid) {
- bcopy(&emlxs_pci_model[i],
- &hba->model_info,
- sizeof (emlxs_model_t));
- found = 1;
- break;
- }
- }
- }
- }
- /* If adapter not found, try again */
- if (!found) {
- /* Find matching adapter model */
- for (i = 1; i < emlxs_pci_model_count; i++) {
- if (emlxs_pci_model[i].device_id == device_id &&
- emlxs_pci_model[i].channels == channels) {
- bcopy(&emlxs_pci_model[i],
- &hba->model_info,
- sizeof (emlxs_model_t));
- found = 1;
- break;
- }
- }
- }
- /* If adapter not found, try one last time */
- if (!found) {
- /* Find matching adapter model */
- for (i = 1; i < emlxs_pci_model_count; i++) {
- if (emlxs_pci_model[i].device_id == device_id) {
- bcopy(&emlxs_pci_model[i],
- &hba->model_info,
- sizeof (emlxs_model_t));
- found = 1;
- break;
- }
- }
- }
- /* If not found, set adapter to unknown */
- if (!found) {
- bcopy(&emlxs_pci_model[0], &hba->model_info,
- sizeof (emlxs_model_t));
- hba->model_info.device_id = device_id;
- hba->model_info.ssdid = ssdid;
- return (0);
- }
- #ifndef SATURN_MSI_SUPPORT
- /*
- * This will disable MSI support for Saturn adapter's
- * due to a PCI bus issue
- */
- if (hba->model_info.chip == EMLXS_SATURN_CHIP) {
- hba->model_info.flags &=
- ~(EMLXS_MSI_SUPPORTED | EMLXS_MSIX_SUPPORTED);
- }
- #endif /* !SATURN_MSI_SUPPORT */
- /* Scan the PCI capabilities */
- emlxs_pci_cap_offsets(hba);
- #ifdef MSI_SUPPORT
- /* Verify MSI support */
- if ((hba->model_info.flags & EMLXS_MSI_SUPPORTED) &&
- !hba->pci_cap_offset[PCI_CAP_ID_MSI]) {
- hba->model_info.flags &= ~EMLXS_MSI_SUPPORTED;
- }
- /* Verify MSI-X support */
- if ((hba->model_info.flags & EMLXS_MSIX_SUPPORTED) &&
- !hba->pci_cap_offset[PCI_CAP_ID_MSI_X]) {
- hba->model_info.flags &= ~EMLXS_MSIX_SUPPORTED;
- }
- #endif /* MSI_SUPPORT */
- }
- if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba->dip, 0,
- "reg", &prop, &num_prop) == DDI_PROP_SUCCESS) {
- /* Parse the property for PCI function, device and bus no. */
- hba->pci_function_number =
- (uint8_t)((prop[0] & 0x00000700) >> 8);
- hba->pci_device_number = (uint8_t)((prop[0] & 0x00008100) >> 8);
- hba->pci_bus_number = (uint8_t)((prop[0] & 0x00ff0000) >> 16);
- ddi_prop_free((void *)prop);
- }
- if (hba->model_info.sli_mask & EMLXS_SLI4_MASK) {
- hba->sli_api = emlxs_sli4_api;
- } else {
- hba->sli_api = emlxs_sli3_api;
- }
- #ifdef FMA_SUPPORT
- if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
- != DDI_FM_OK) {
- EMLXS_MSGF(EMLXS_CONTEXT,
- &emlxs_invalid_access_handle_msg, NULL);
- return (0);
- }
- #endif /* FMA_SUPPORT */
- return (1);
- } /* emlxs_init_adapter_info() */
- /* ARGSUSED */
- static void
- emlxs_handle_async_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
- {
- emlxs_port_t *port = &PPORT;
- IOCB *iocb;
- uint32_t *w;
- int i, j;
- iocb = &iocbq->iocb;
- if (iocb->ULPSTATUS != 0) {
- return;
- }
- switch (iocb->un.astat.EventCode) {
- case 0x0100: /* Temp Warning */
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_warning_msg,
- "Adapter is very hot (%d °C). Take corrective action.",
- iocb->ULPCONTEXT);
- hba->temperature = iocb->ULPCONTEXT;
- emlxs_log_temp_event(port, 0x02, iocb->ULPCONTEXT);
- break;
- case 0x0101: /* Temp Safe */
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_temp_msg,
- "Adapter temperature now safe (%d °C).",
- iocb->ULPCONTEXT);
- hba->temperature = iocb->ULPCONTEXT;
- emlxs_log_temp_event(port, 0x03, iocb->ULPCONTEXT);
- break;
- default:
- w = (uint32_t *)iocb;
- for (i = 0, j = 0; i < 8; i++, j += 2) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_async_msg,
- "(Word[%d]=%x Word[%d]=%x)", j, w[j], j + 1,
- w[j + 1]);
- }
- emlxs_log_async_event(port, iocb);
- }
- return;
- } /* emlxs_handle_async_event() */
- /* ARGSUSED */
- extern void
- emlxs_reset_link_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
- {
- emlxs_port_t *port = &PPORT;
- /* Attempt a link reset to recover */
- (void) emlxs_reset(port, FC_FCA_LINK_RESET);
- return;
- } /* emlxs_reset_link_thread() */
- /* ARGSUSED */
- extern void
- emlxs_restart_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
- {
- emlxs_port_t *port = &PPORT;
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Restarting...");
- /* Attempt a full hardware reset to recover */
- if (emlxs_reset(port, FC_FCA_RESET) != FC_SUCCESS) {
- EMLXS_STATE_CHANGE(hba, FC_ERROR);
- emlxs_shutdown_thread(hba, arg1, arg2);
- }
- return;
- } /* emlxs_restart_thread() */
- /* ARGSUSED */
- extern void
- emlxs_shutdown_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
- {
- emlxs_port_t *port = &PPORT;
- mutex_enter(&EMLXS_PORT_LOCK);
- if (hba->flag & FC_SHUTDOWN) {
- mutex_exit(&EMLXS_PORT_LOCK);
- return;
- }
- hba->flag |= FC_SHUTDOWN;
- mutex_exit(&EMLXS_PORT_LOCK);
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
- "Shutting down...");
- /* Take adapter offline and leave it there */
- (void) emlxs_offline(hba);
- if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
- /*
- * Dump is not defined for SLI4, so just
- * reset the HBA for now.
- */
- EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
- } else {
- if (hba->flag & FC_OVERTEMP_EVENT) {
- emlxs_log_temp_event(port, 0x01,
- hba->temperature);
- } else {
- emlxs_log_dump_event(port, NULL, 0);
- }
- }
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_shutdown_msg, "Reboot required.");
- return;
- } /* emlxs_shutdown_thread() */
- /* ARGSUSED */
- extern void
- emlxs_proc_channel(emlxs_hba_t *hba, CHANNEL *cp, void *arg2)
- {
- IOCBQ *iocbq;
- IOCBQ *rsp_head;
- /*
- * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
- * "emlxs_proc_channel: channel=%d", cp->channelno);
- */
- mutex_enter(&cp->rsp_lock);
- while ((rsp_head = cp->rsp_head) != NULL) {
- cp->rsp_head = NULL;
- cp->rsp_tail = NULL;
- mutex_exit(&cp->rsp_lock);
- while ((iocbq = rsp_head) != NULL) {
- rsp_head = (IOCBQ *) iocbq->next;
- emlxs_proc_channel_event(hba, cp, iocbq);
- }
- mutex_enter(&cp->rsp_lock);
- }
- mutex_exit(&cp->rsp_lock);
- EMLXS_SLI_ISSUE_I…
Large files files are truncated, but you can click here to view the full file