emlxs_hba.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* 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
* 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 2008 Emulex. All rights reserved.
* Use is subject to License terms.
*/
#define EMLXS_MODEL_DEF
#include "emlxs.h"
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
#ifdef MSI_SUPPORT
{
};
{
};
#endif /* MSI_SUPPORT */
{
{FC_FCP_RING, "FCP Ring"},
{FC_IP_RING, "IP Ring"},
{FC_ELS_RING, "ELS Ring"},
{FC_CT_RING, "CT Ring"}
}; /* emlxs_ring_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 */
/*
*
* emlxs_ffinit
* This routine will start initialization of the FireFly Chipset
*
*/
extern int
{
uint32_t i;
uint32_t j;
mb = 0;
MaxRbusSize = 0;
MaxIbusSize = 0;
read_rev_reset = 0;
sli_mode = 2;
#ifdef SLI3_SUPPORT
/* Initialize sli mode based on configuration parameter */
case 2: /* SLI2 mode */
sli_mode = 2;
break;
case 0: /* Best available */
case 1: /* Best available */
case 3: /* SLI3 mode */
default:
/* SBUS adapters only available in SLI2 */
sli_mode = 2;
} else {
sli_mode = 3;
}
break;
}
#endif /* SLI3_SUPPORT */
/* Set the fw_check flag */
hba->mbox_queue_flag = 0;
/* Reset and initialize the adapter */
if (emlxs_hba_init(hba)) {
return (EIO);
}
/*
* Allocate some memory for buffers
*/
if (emlxs_mem_alloc_buffer(hba) == 0) {
"Unable to allocate memory buffers.");
return (ENOMEM);
}
/*
* Get a buffer which will be used repeatedly for mailbox commands
*/
"Unable to allocate mailbox buffer.");
(void) emlxs_mem_free_buffer(hba);
return (ENOMEM);
}
/* Check for the LP9802 (This is a special case) */
/* We need to check for dual channel adapter */
/* Try to determine if this is a DC adapter */
if (MaxRbusSize == REDUCED_SRAM_CFG) {
/* LP9802DC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP9802 */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
}
}
}
/*
* Setup and issue mailbox READ REV command
*/
vpd->postKernRev = 0;
vpd->postKernName[0] = 0;
vpd->sli1FwName[0] = 0;
vpd->sli2FwName[0] = 0;
vpd->sli3FwName[0] = 0;
vpd->sli4FwName[0] = 0;
vpd->sli1FwLabel[0] = 0;
vpd->sli2FwLabel[0] = 0;
vpd->sli3FwLabel[0] = 0;
vpd->sli4FwLabel[0] = 0;
"Unable to read rev. Mailbox cmd=%x status=%x",
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/* Old firmware */
if (read_rev_reset == 0) {
/* Clean up */
(void) emlxs_mem_free_buffer(hba);
read_rev_reset = 1;
goto reset;
} else {
"Outdated firmware detected.");
}
} else {
if (read_rev_reset == 0) {
/* Clean up */
(void) emlxs_mem_free_buffer(hba);
read_rev_reset = 1;
goto reset;
} else {
"Non-operational firmware detected. "
"type=%x",
}
}
/* Lets try to read the SLI3 version */
/* Setup and issue mailbox READ REV(v3) command */
"Unable to read rev (v3). Mailbox cmd=%x status=%x",
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/*
* vpd->sli2FwRev = mb->un.varRdRev.sliFwRev1; Not
* needed
*/
}
}
/* Check sli mode against available firmware levels */
sli_mode = 3;
sli_mode = 2;
} else {
sli_mode = 0;
}
sli_mode = 4;
sli_mode = 2;
} else {
sli_mode = 0;
}
sli_mode = 4;
sli_mode = 3;
} else {
sli_mode = 0;
}
}
if (sli_mode == 0) {
#ifdef SLI3_SUPPORT
"Firmware not available. sli-mode=%d",
#else
"Firmware not available. sli-mode=2");
#endif /* SLI3_SUPPORT */
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/* Save information as VPD data */
/* Decode FW names */
/* Decode FW labels */
/* Get adapter VPD information */
offset = 0;
while (offset < DMP_VPD_SIZE) {
/*
* Let it go through even if failed.*
*/
/*
* Not all adapter's have VPD info and thus will fail
* here
*/
/* This is not a problem */
"No VPD found. offset=%x status=%x",
break;
} else {
/*
* mb->un.varDmp.word_cnt is actually byte
* count for the dump reply
*/
/* Stop if no data was received */
if (bsize == 0) {
break;
}
/* Check limit on byte size */
/*
* Convert size from bytes to words with
* minimum of 1 word
*/
/*
* Transfer data into vpd_data buffer one
* word at a time
*/
for (i = 0; i < wsize; i++) {
}
/* Increment total byte count saved */
/*
* Stop if less than a full transfer was
* received
*/
if (wsize < DMP_VPD_DUMP_WCOUNT) {
break;
}
} else {
"No VPD acknowledgment. offset=%x", offset);
break;
}
}
}
if (vpd_data[0]) {
/*
* Some adapter models require the vpd data to identify the
* exact model
*/
/*
* Check if vpd->part_num is now defined and the LP8000
* adapter (This is a special case)
*/
/* We need to look for LP8000DC */
/* LP8000DC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP8000 */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
}
}
/* PCI_DEVICE_ID_LP8000 */
/*
* Check if vpd->part_num is now defined and the LP9002L
* adapter (This is a special case)
*/
/*
* We need to look for LP9002C, LP9002DC, and the LP9402DC
* adapters
*/
/* LP9002C */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP9002DC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP9402DC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP9002 */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
}
}
/* PCI_DEVICE_ID_LP9002 */
/*
* We need the vpd->part_num to decern between the LP10000DC
* and LP10000ExDC
*/
/* LP10000DC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
if (emlxs_pci_model[i].id ==
LP10000DC) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
== 0) {
/* LP10000ExDC */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
if (emlxs_pci_model[i].id ==
LP10000ExDC) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
/* LP10000 */
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
}
} /* PCI_DEVICE_ID_LP10000 */
/* Replace the default model description with vpd data */
if (vpd->model_desc[0] != 0) {
vpd->model_desc);
}
/* Replace the default model with vpd data */
}
/* Replace the default program types with vpd data */
if (vpd->prog_types[0] != 0) {
}
}
/* Since the adapter model may have changed with the vpd data */
/* lets double check if adapter is not supported */
"Unsupported adapter found. Id:%d Device id:0x%x "
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/* Read the adapter's wakeup parms */
vpd->boot_version);
/* Get fcode version property */
"Firmware: kern=%08x stub=%08x sli1=%08x",
"Firmware: sli2=%08x sli3=%08x sli4=%08x fl=%x",
/*
* If firmware checking is enabled and the adapter model indicates a
* firmware image,
*/
/* then perform firmware version check */
/* Find firmware image indicated by adapter model */
for (i = 0; i < EMLXS_IMAGE_COUNT; i++) {
image = &emlxs_fw_image[i];
break;
}
}
/*
* If the image was found, then verify current firmware
* versions of adapter
*/
if (image) {
"Firmware update needed. Updating... "
if (emlxs_fw_download(hba,
"Firmware update failed.");
}
/* Clean up */
(void) emlxs_mem_free_buffer(hba);
fw_check = 0;
goto reset;
}
} else {
/* This should not happen */
/*
* This means either the adapter database is not
* correct or a firmware image is missing from the
* compile
*/
"Driver firmware image unavailable. (id=%d fw=%d)",
}
}
/* Add our interrupt routine to kernel's interrupt chain & enable it */
/*
* If MSI is enabled this will cause Solaris to program the MSI
* address
*/
/* and data registers in PCI config space */
"Unable to add interrupt(s).");
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/*
*/
/* Used for pkt io */
/* Used for abort or close XRI iotags */
}
"Unable to configure port. Mailbox cmd=%x status=%x "
#ifdef SLI3_SUPPORT
/* Try to fall back to SLI2 if possible */
if (sli_mode >= 3) {
sli_mode = 2;
/* Clean up */
(void) emlxs_mem_free_buffer(hba);
fw_check = 0;
goto reset;
}
#endif /* SLI3_SUPPORT */
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
#ifdef SLI3_SUPPORT
/* Check if SLI3 mode was achieved */
#ifdef NPIV_SUPPORT
MAX_VPORTS - 1);
} else {
MAX_VPORTS_LIMITED - 1);
}
}
#endif /* NPIV_SUPPORT */
}
} else {
}
#endif /* SLI3_SUPPORT */
/* Get and save the current firmware version (based on sli_mode) */
emlxs_pcix_mxr_update(hba, 0);
/*
* Setup and issue mailbox RUN BIU DIAG command Setup test buffers
*/
mp = 0;
mp1 = 0;
"Unable to allocate diag buffers.");
if (mp) {
}
if (mp1) {
}
(void) emlxs_mem_free_buffer(hba);
return (ENOMEM);
}
"Unable to run BIU diag. Mailbox cmd=%x status=%x",
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
for (i = 0; i < MEM_ELSBUF_SIZE; i++) {
outptr--;
inptr--;
"BIU diagnostic failed. offset %x value %x "
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
}
/*
* Setup and issue mailbox CONFIGURE RING command
*/
"Unable to configure ring. Mailbox cmd=%x "
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
}
/*
* Setup link timers
*/
"Unable to configure link. Mailbox cmd=%x status=%x",
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
#ifdef MAX_RRDY_PATCH
/* Set MAX_RRDY if one is provided */
"MAX_RRDY: Unable to set. status=%x value=%d",
} else {
}
}
#endif /* MAX_RRDY_PATCH */
/*
* We need to get login parameters for NID
*/
"Unable to read parameters. Mailbox cmd=%x status=%x",
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/* Free the buffer since we were polling */
/* If no serial number in VPD data, then use the WWPN */
if (vpd->serial_num[0] == 0) {
for (i = 0; i < 12; i++) {
if (j <= 9) {
vpd->serial_num[i] =
} else {
vpd->serial_num[i] =
}
i++;
j = (status & 0xf);
if (j <= 9) {
vpd->serial_num[i] =
} else {
vpd->serial_num[i] =
}
}
/* Set port number and port index to zero */
/*
* The WWN's are unique to each port and therefore port_num
* must equal zero
*/
/*
* This effects the hba_fru_details structure in
* fca_bind_port()
*/
vpd->port_index = 0;
}
/* Make first attempt to set a port index */
/* Check if this is a multifunction adapter */
char *buffer;
int32_t i;
/* The port address looks like this: */
/* 1 - for port index 0 */
/* 1,1 - for port index 1 */
/* 1,2 - for port index 2 */
if (buffer) {
vpd->port_index = 0;
/* Reverse scan for a comma */
if (buffer[i] == ',') {
/* Comma found - set index now */
vpd->port_index =
break;
}
}
}
}
/* Make final attempt to set a port index */
vpd->port_index = 0;
vpd->port_index++;
}
}
}
}
}
if (vpd->manufacturer[0] == 0) {
}
}
if (vpd->model_desc[0] == 0) {
}
}
if (vpd->prog_types[0] == 0) {
}
/* Create the symbolic names */
"Emulex PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
"WWPN doesn't conform to IP profile: nameType=%x",
}
/* Issue CONFIG FARP */
/*
* Let it go through even if failed.
*/
"Unable to configure FARP. Mailbox cmd=%x "
}
}
#ifdef MSI_SUPPORT
/* Configure MSI map if required */
goto msi_configured;
}
"Unable to config MSIX. Mailbox cmd=0x%x status=0x%x",
goto msi_configured;
}
"Unable to config MSI. Mailbox cmd=0x%x status=0x%x",
"Attempting single interrupt mode...");
/* First cleanup old interrupts */
(void) emlxs_msi_remove(hba);
(void) emlxs_msi_uninit(hba);
if (status != DDI_SUCCESS) {
"Unable to initialize interrupt. status=%d",
status);
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/*
* Reset adapter - The adapter needs to be reset because the
* bus cannot handle the MSI change without handshaking with
* the adapter again
*/
(void) emlxs_mem_free_buffer(hba);
fw_check = 0;
goto reset;
}
#endif /* MSI_SUPPORT */
/*
* We always disable the firmware traffic cop feature
*/
if (emlxs_disable_traffic_cop) {
"Unable to disable traffic cop. Mailbox cmd=%x "
(void) EMLXS_INTR_REMOVE(hba);
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
}
"Unable to read configuration. Mailbox cmd=%x status=%x",
(void) EMLXS_INTR_REMOVE(hba);
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/* Save the link speed capabilities */
/* Set the io throttle */
/* Set the max node count */
} else {
}
/* Enable mailbox, error attention interrupts */
/* Enable ring interrupts */
status |= (HC_R0INT_ENA);
}
#ifdef SLI3_SUPPORT
return (ENOMEM);
}
"FCT Ring: Posted %d buffers.", MEM_FCTBUF_COUNT);
}
return (ENOMEM);
}
"IP Ring: Posted %d buffers.", MEM_IPBUF_COUNT);
}
return (ENOMEM);
}
"ELS Ring: Posted %d buffers.", MEM_ELSBUF_COUNT);
return (ENOMEM);
}
"CT Ring: Posted %d buffers.", MEM_CTBUF_COUNT);
} else
#endif /* SLI3_SUPPORT */
{
/* Post the FCT unsol buffers */
for (j = 0; j < MEM_FCTBUF_COUNT; j += 2) {
}
"FCP Ring: Posted %d buffers.", MEM_FCTBUF_COUNT);
}
/* Post the IP unsol buffers */
for (j = 0; j < MEM_IPBUF_COUNT; j += 2) {
}
"IP Ring: Posted %d buffers.", MEM_IPBUF_COUNT);
}
/* Post the ELS unsol buffers */
for (j = 0; j < MEM_ELSBUF_COUNT; j += 2) {
}
"ELS Ring: Posted %d buffers.", MEM_ELSBUF_COUNT);
/* Post the CT unsol buffers */
for (j = 0; j < MEM_CTBUF_COUNT; j += 2) {
}
"CT Ring: Posted %d buffers.", MEM_CTBUF_COUNT);
}
/* Register for async events */
} else {
"Async events enabled.");
}
/*
* Setup and issue mailbox INITIALIZE LINK command At this point, the
* interrupt will be generated by the HW
*/
"Unable to initialize link. Mailbox cmd=%x status=%x",
(void) EMLXS_INTR_REMOVE(hba);
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
/*
* Enable link attention interrupt
*/
/* Wait for link to come up */
/* Check for hardware error */
(void) EMLXS_INTR_REMOVE(hba);
(void) emlxs_mem_free_buffer(hba);
return (EIO);
}
DELAYMS(1000);
i--;
}
out:
/*
* The leadvile driver will now handle the FLOGI at the driver level
*/
return (0);
} /* emlxs_ffinit() */
#ifdef MSI_SUPPORT
/* EMLXS_INTR_INIT */
{
char s_type[16];
int32_t i;
char buf[64];
}
return (DDI_SUCCESS);
}
/* Set max interrupt count if not specified */
if (max == 0) {
} else {
max = 1;
}
}
/* Filter max interrupt count with adapter model specification */
}
/* Get the available interrupt types from the kernel */
types = 0;
if ((ret != DDI_SUCCESS)) {
"MSI: ddi_intr_get_supported_types failed. ret=%d", ret);
/* Default to fixed type */
}
/* Check if fixed interrupts are being forced */
}
/* Check if MSI interrupts are being forced */
}
/* Set interrupt type and interrupt count */
type = 0;
/* Check if MSIX is fully supported */
if ((types & DDI_INTR_TYPE_MSIX) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
ret =
goto initialize;
}
}
/* Check if MSI is fully supported */
if ((types & DDI_INTR_TYPE_MSI) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
goto initialize;
}
}
/* Check if fixed interrupts are fully supported */
if ((types & DDI_INTR_TYPE_FIXED) &&
/* Get the max interrupt count from the adapter */
nintrs = 0;
ret =
if (ret == DDI_SUCCESS) {
goto initialize;
}
}
goto init_failed;
pass++;
mode = 0;
actual = 0;
hilevel_pri = 0;
if (pass == 1) {
"MSI: %s: mode=%d types=0x%x nintrs=%d",
}
/* Validate interrupt count */
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 =
"MSI: Unable to allocate interrupt handle table");
goto init_failed;
}
/* Allocate 'count' interrupts */
"MSI: Unable to allocate interrupts. error=%d", ret);
goto init_failed;
}
/* 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 */
KM_SLEEP);
if (new_htable == NULL) {
"MSI: Unable to allocate new interrupt handle "
"table");
goto init_failed;
}
/* Copy old array to new array */
(actual * sizeof (ddi_intr_handle_t)));
/* Free the old array */
htable = new_htable;
}
/* Allocate interrupt priority table */
intr_pri =
KM_SLEEP);
"MSI: Unable to allocate interrupt priority table");
goto init_failed;
}
/* Allocate interrupt capability table */
"MSI: Unable to allocate interrupt capability table");
goto init_failed;
}
/* Get minimum hilevel priority */
/* Fill the priority and capability tables */
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_get_pri(%d) failed. "
/* Clean up the interrupts */
goto init_failed;
}
if (intr_pri[i] >= hilevel_pri) {
"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;
}
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_get_cap(%d) failed. handle=%p "
/* Clean up the interrupts */
goto init_failed;
}
"MSI: %s: %d: cap=0x%x pri=0x%x hilevel=0x%x",
}
/* Set mode */
switch (count) {
case 8:
break;
case 4:
break;
case 2:
break;
default:
}
/* Save the info */
for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
}
/* Set flag to indicate support */
/* Create the interrupt threads */
for (i = 0; i < MAX_RINGS; i++) {
}
return (DDI_SUCCESS);
if (intr_cap) {
}
if (intr_pri) {
}
if (htable) {
/* Process the interrupt handlers */
for (i = 0; i < actual; i++) {
/* Free the handle[i] */
(void) ddi_intr_free(htable[i]);
}
}
/* Initialize */
hba->intr_count = 0;
if (type == DDI_INTR_TYPE_MSIX) {
goto begin;
} else if (type == DDI_INTR_TYPE_MSI) {
goto begin;
}
"MSI: Unable to initialize interrupts");
return (DDI_FAILURE);
} /* emlxs_msi_init() */
/* EMLXS_INTR_UNINIT */
{
int32_t i;
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 (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Check if the interrupts are still initialized */
return (DDI_SUCCESS);
}
/* Get handle table parameters */
/* Clean up */
hba->intr_count = 0;
if (intr_cap) {
}
if (intr_pri) {
}
if (htable) {
/* Process the interrupt handlers */
for (i = 0; i < count; ++i) {
/* Free the handle[i] */
(void) ddi_intr_free(htable[i]);
}
}
/* Destroy the intr locks */
for (i = 0; i < EMLXS_MSI_MAX_INTRS; i++) {
}
/* Destroy the interrupt threads */
for (i = 0; i < MAX_RINGS; i++) {
}
/*
* 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 i;
return (emlxs_intx_add(hba));
}
/* Check if interrupts have already been added */
return (DDI_SUCCESS);
}
/* Check if interrupts have been initialized */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Get handle table parameters */
/* Add the interrupt handlers */
for (i = 0; i < count; ++i) {
/* add handler for handle[i] */
(char *)hba, (char *)(unsigned long)i);
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_add_handler(%d) failed. handle=%p "
/* Process the remaining interrupt handlers */
while (i) {
/* Decrement i */
i--;
/* Remove the handler */
}
return (DDI_FAILURE);
}
}
/* Enable the interrupts */
if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_block_enable(%d) failed. ret=%d",
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_enable(%d) failed. "
"ret=%d", i, ret);
}
}
}
} else {
for (i = 0; i < count; ++i) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_enable(%d) failed. ret=%d",
i, ret);
}
}
}
/* Set flag to indicate support */
return (DDI_SUCCESS);
} /* emlxs_msi_add() */
/* EMLXS_INTR_REMOVE */
{
int32_t i;
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 */
return (DDI_SUCCESS);
}
/* Disable all adapter interrupts */
/* Get handle table parameters */
/* Disable the interrupts */
if (intr_cap[0] & DDI_INTR_FLAG_BLOCK) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_block_disable(%d) failed. ret=%d",
for (i = 0; i < count; i++) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_disable(%d) failed. "
"ret=%d", i, ret);
}
}
}
} else {
for (i = 0; i < count; i++) {
if (ret != DDI_SUCCESS) {
"MSI: ddi_intr_disable(%d) failed. ret=%d",
i, ret);
}
}
}
/* Process the interrupt handlers */
for (i = 0; i < count; i++) {
/* Remove the handler */
}
return (DDI_SUCCESS);
} /* emlxs_msi_remove() */
#endif /* MSI_SUPPORT */
/* EMLXS_INTR_INIT */
/* ARGSUSED */
{
uint32_t i;
char buf[64];
/* Check if interrupts have already been initialized */
return (DDI_SUCCESS);
}
/* Check if adapter is flagged for INTX support */
"INTX: %s does not support INTX. flags=0x%x",
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.
*/
"INTX: High-level interrupt not supported.");
return (DDI_FAILURE);
}
/* Get an iblock cookie */
if (ret != DDI_SUCCESS) {
"INTX: ddi_get_iblock_cookie failed. ret=%d", ret);
return (ret);
}
/* Create the interrupt threads */
for (i = 0; i < MAX_RINGS; i++) {
}
return (DDI_SUCCESS);
} /* emlxs_intx_init() */
/* EMLXS_INTR_UNINIT */
{
uint32_t i;
/* Make sure interrupts have been removed */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* Check if the interrupts are still initialized */
return (DDI_SUCCESS);
}
/* Create the interrupt threads */
for (i = 0; i < MAX_RINGS; i++) {
}
return (DDI_SUCCESS);
} /* emlxs_intx_uninit() */
/* This is the legacy method for adding interrupts in Solaris */
/* EMLXS_INTR_ADD */
{
/* Check if interrupts have already been added */
return (DDI_SUCCESS);
}
/* Check if interrupts have been initialized */
if (ret != DDI_SUCCESS) {
return (ret);
}
}
/* add intrrupt handler routine */
if (ret != DDI_SUCCESS) {
"INTX: ddi_add_intr failed. ret=%d", ret);
return (ret);
}
return (DDI_SUCCESS);
} /* emlxs_intx_add() */
/* EMLXS_INTR_REMOVE */
{
/* Check if interrupts have already been removed */
return (DDI_SUCCESS);
}
/* Diable all adapter interrupts */
/* Remove the interrupt */
return (DDI_SUCCESS);
} /* emlxs_intx_remove() */
extern int
{
int32_t i;
i = 0;
/* Restart the adapter */
return (1);
}
/* WARNING: There is a max of 6 ring masks allowed */
/*
* RING 0 - FCP
*/
hba->ring_rmask[i] = 0;
} else {
}
/*
* RING 1 - IP
*/
} else {
}
/*
* RING 2 - ELS
*/
/*
* RING 3 - CT
*/
if (i > 6) {
"emlxs_hba_init: Too many ring masks defined. cnt=%d", i);
return (1);
}
/* Initialize all the port objects */
for (i = 0; i < MAX_VPORTS; i++) {
}
/*
* Initialize the max_node count to a default value if needed
* This determines how many node objects we preallocate in the pool
* The actual max_nodes will be set later based on adapter info
*/
} else {
}
}
return (0);
} /* emlxs_hba_init() */
static void
{
char *cptr;
/*
* This routine modifies the link-speed config parameter entry based
* on adapter capabilities
*/
cptr += 26;
hi = 0;
cptr += 7;
hi = 1;
}
cptr += 7;
hi = 2;
}
cptr += 7;
hi = 4;
}
cptr += 7;
hi = 8;
}
cptr += 9;
hi = 10;
}
/* Now revalidate the current parameter setting */
return;
} /* emlxs_process_link_speed() */
/*
*
* emlxs_parse_vpd
* This routine will parse the VPD data
*
*/
extern int
{
char tag[3];
uint32_t n;
uint32_t block_index = 0;
char buffer[128];
#ifdef MENLO_TEST
/* Check if VPD is disabled Hornet adapters */
return (1);
}
#endif /* MENLO_TEST */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg, "block_index =
* %x", block_index);
*/
switch (vpd_buf[block_index]) {
case 0x82:
index = block_index;
index += 1;
index += 1;
index += 1;
block_index = index;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "block_size = %x", block_size);
*/
n = sizeof (buffer);
break;
case 0x90:
index = block_index;
index += 1;
index += 1;
index += 1;
block_index = index;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "block_size = %x", block_size);
*/
/* Scan for sub-blocks */
while ((sub_index < block_index) &&
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "sub_index = %x", sub_index);
*/
tag[2] = 0;
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "sub_size = %x", sub_size);
*/
n = sizeof (buffer);
/*
* Look for Engineering Change (EC)
*/
}
/*
* Look for Manufacturer (MN)
*/
buffer);
}
/*
* Look for Serial Number (SN)
*/
/* Validate the serial number */
10) == 0) ||
10) == 0)) {
vpd->serial_num[0] = 0;
}
}
/*
* Look for Part Number (PN)
*/
}
/*
* Look for (V0)
*/
/* Not used */
"V0: %s", buffer);
}
/*
* Look for model description (V1)
*/
}
/*
* Look for model (V2)
*/
}
/*
* Look for program type (V3)
*/
}
/*
* Look for port number (V4)
*/
vpd->port_index =
"Port: %s",
}
/*
* Look for checksum (RV)
*/
/* Not used */
"Checksum: 0x%x", buffer[0]);
} else {
/* Generic */
}
}
break;
case 0x78:
finished = 1;
break;
default:
"Unknown block: %x %x %x %x %x %x %x %x",
return (0);
}
}
return (1);
} /* emlxs_parse_vpd */
static uint32_t
{
return (rev & 0xf);
} /* End emlxs_decode_biu_rev */
static uint32_t
{
} /* End emlxs_decode_endec_rev */
extern void
{
case 4:
break;
case 3:
break;
case 2:
break;
case 1:
break;
default:
}
} else {
}
return;
} /* emlxs_decode_firmware_rev() */
extern void
{
char c;
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;
}
if (c == 0) {
} else {
}
return;
} /* emlxs_decode_version() */
static void
{
uint32_t i;
char name[16];
#ifdef EMLXS_LITTLE_ENDIAN
#endif /* EMLXS_LITTLE_ENDIAN */
#ifdef EMLXS_LITTLE_ENDIAN
for (i = 0; i < 3; i++) {
}
#endif /* EMLXS_LITTLE_ENDIAN */
for (i = 0; i < 16; i++) {
if (name[i] == 0x20) {
name[i] = 0;
}
}
return;
} /* emlxs_decode_label() */
extern uint32_t
{
char *ptr;
if (*str == 0) {
return (0);
}
return (0);
}
/* Get max digits of value */
/* Position pointer to end of string */
/* Process string backwards */
/* check for base 10 numbers */
digits--;
} else if (base == 16) {
/* Check for base 16 numbers */
digits--;
digits--;
} else if (factor > 1) {
break;
}
} else if (factor > 1) {
break;
}
}
return (value);
} /* emlxs_strtol() */
extern uint64_t
{
char *ptr;
if (*str == 0) {
return (0);
}
return (0);
}
/* Get max digits of value */
/* Position pointer to end of string */
/* Process string backwards */
/* check for base 10 numbers */
digits--;
} else if (base == 16) {
/* Check for base 16 numbers */
digits--;
digits--;
} else if (factor > 1) {
break;
}
} else if (factor > 1) {
break;
}
}
return (value);
} /* emlxs_strtoll() */
static void
{
uint32_t i;
char *ptr;
char types_buffer[256];
char *types;
while (*types) {
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T2[%d]: 0x%x", i-1, model->pt_2[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T3[%d]: 0x%x", i-1, model->pt_3[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T6[%d]: 0x%x", i-1, model->pt_6[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "T7[%d]: 0x%x", i-1, model->pt_7[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TA[%d]: 0x%x", i-1, model->pt_A[i-1]);
*/
/* Move the str pointer */
}
types += 3;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TB[%d]: 0x%x", i-1, model->pt_B[i-1]);
*/
/* Move the str pointer */
}
types += 4;
i = 0;
/* Null terminate the next value */
ptr++;
*ptr = 0;
/* Save the value */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_vpd_msg,
* "TF[%d]: 0x%x", i-1, model->pt_FF[i-1]);
*/
/* Move the str pointer */
}
} else {
"Unknown prog type string = %s", types);
break;
}
}
return;
} /* emlxs_parse_prog_types() */
static void
{
uint32_t i;
char buffer[256];
/* Rebuild the prog type string */
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
found = 1;
i = 0;
i++;
}
}
if (found) {
/* Terminate at the last comma in string */
}
return;
} /* emlxs_build_prog_types() */
extern uint32_t
{
uint32_t i;
sizeof (emlxs_model_t));
return (0);
}
/* Read the PCI device id */
/* Find matching adapter model */
for (i = 1; i < EMLXS_SBUS_MODEL_COUNT; i++) {
sizeof (emlxs_model_t));
found = 1;
break;
}
}
/* If not found then use the unknown model */
if (!found) {
sizeof (emlxs_model_t));
return (0);
}
} else { /* PCI model */
sizeof (emlxs_model_t));
return (0);
}
/* Read the PCI device id */
/* Read the PCI Subsystem id */
}
/* Read the Cache Line reg */
/* Check for the multifunction bit being set */
channels = 2;
} else {
channels = 1;
}
#ifdef MENLO_TEST
/* Convert Zephyr adapters to Hornet adapters */
if ((device_id == PCI_DEVICE_ID_LPe11000_M4) &&
}
#endif /* MENLO_TEST */
/* If device ids are unique, then use them for search */
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++) {
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++) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
found = 1;
break;
}
}
}
/* If not found, set adapter to unknown */
if (!found) {
sizeof (emlxs_model_t));
return (0);
}
#ifdef MENLO_TEST
/* Convert Hornet program types to Zephyr program types */
/*
* Find matching Zephyr card and copy Zephyr program
* types
*/
for (i = 1; i < EMLXS_PCI_MODEL_COUNT; i++) {
if ((emlxs_pci_model[i].device_id ==
(emlxs_pci_model[i].ssdid ==
break;
}
}
}
#endif /* MENLO_TEST */
#ifndef SATURN_MSI_SUPPORT
/*
* This will disable MSI support for Saturn adapter's due to
* a PCI bus issue
*/
}
#endif /* !SATURN_MSI_SUPPORT */
#ifdef MSI_SUPPORT
/* Verify MSI support */
/* Scan for MSI capabilities register */
offset &= 0xff;
while (offset) {
break;
}
}
if (offset) {
} else {
hba->msi_cap_offset = 0;
"MSI: control_reg capability not found!");
}
}
/* Verify MSI-X support */
/* Scan for MSI capabilities register */
offset &= 0xff;
while (offset) {
break;
}
}
if (offset) {
} else {
hba->msix_cap_offset = 0;
"MSIX: control_reg capability not found!");
}
}
#endif /* MSI_SUPPORT */
}
return (1);
} /* emlxs_init_adapter_info() */
/* EMLXS_PORT_LOCK must be held when call this routine */
static uint32_t
{
#ifdef MSI_SUPPORT
/* Check for default MSI interrupt */
if (msgid == 0) {
/* Read host attention register to determine interrupt source */
/* Filter out MSI non-default attention bits */
}
/* Check for polled or fixed type interrupt */
else if (msgid == -1) {
/* Read host attention register to determine interrupt source */
}
/* Otherwise, assume a mapped MSI interrupt */
else {
/* Convert MSI msgid to mapped attention bits */
}
#else /* !MSI_SUPPORT */
/* Read host attention register to determine interrupt source */
#endif /* MSI_SUPPORT */
/* Check if Hardware error interrupt is enabled */
}
/* Check if link interrupt is enabled */
}
/* Check if Mailbox interrupt is enabled */
}
/* Check if ring0 interrupt is enabled */
}
/* Check if ring1 interrupt is enabled */
}
/* Check if ring2 interrupt is enabled */
}
/* Check if ring3 interrupt is enabled */
}
/* Accumulate attention bits */
/* Clear attentions except for error, link, and autoclear(MSIX) */
if (ha_copy2) {
}
return (ha_copy);
} /* emlxs_get_attention() */
static void
{
/* ha_copy should be pre-filtered */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
* "emlxs_proc_attention: ha_copy=%x", ha_copy);
*/
return;
}
if (!ha_copy) {
return;
}
hba->sbus_csr_addr));
}
/* Adapter error */
return;
}
/* Mailbox interrupt */
(void) emlxs_handle_mb_event(hba);
}
/* Link Attention interrupt */
}
/* event on ring 0 - FCP Ring */
}
/* event on ring 1 - IP Ring */
}
/* event on ring 2 - ELS Ring */
}
/* event on ring 3 - CT Ring */
}
}
/* Set heartbeat flag to show activity */
return;
} /* emlxs_proc_attention() */
#ifdef MSI_SUPPORT
static uint32_t
{
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg, "emlxs_msi_intr:
* arg1=%p arg2=%p", arg1, arg2);
*/
/* Check for legacy interrupt handling */
return (DDI_INTR_CLAIMED);
} else {
return (DDI_INTR_UNCLAIMED);
}
}
/* Get host attention bits */
if (ha_copy == 0) {
if (hba->intr_unclaimed) {
return (DDI_INTR_UNCLAIMED);
}
} else {
hba->intr_unclaimed = 0;
}
/* Process the interrupt */
return (DDI_INTR_CLAIMED);
}
/* DDI_INTR_TYPE_MSI */
/* DDI_INTR_TYPE_MSIX */
/* Get MSI message id */
/* Validate the message id */
msgid = 0;
}
/* Check if adapter is offline */
/* Always claim an MSI interrupt */
return (DDI_INTR_CLAIMED);
}
/* Disable interrupts associated with this msgid */
restore = 1;
}
/* Get host attention bits */
/* Process the interrupt */
/* Restore interrupts */
if (restore) {
}
return (DDI_INTR_CLAIMED);
} /* emlxs_msi_intr() */
#endif /* MSI_SUPPORT */
static int
emlxs_intx_intr(char *arg)
{
return (DDI_INTR_CLAIMED);
} else {
return (DDI_INTR_UNCLAIMED);
}
}
/* Get host attention bits */
if (ha_copy == 0) {
if (hba->intr_unclaimed) {
return (DDI_INTR_UNCLAIMED);
}
} else {
hba->intr_unclaimed = 0;
}
/* Process the interrupt */
return (DDI_INTR_CLAIMED);
} /* emlxs_intx_intr() */
/* ARGSUSED */
static void
{
return;
}
case 0x0100: /* Temp Warning */
"Adapter is very hot (%d �C). Take corrective action.",
iocb->ulpContext);
break;
case 0x0101: /* Temp Safe */
"Adapter temperature now safe (%d �C).",
iocb->ulpContext);
break;
}
return;
} /* emlxs_handle_async_event() */
/*
* emlxs_handle_ff_error
*
* Description: Processes a FireFly error
* Runs at Interrupt level
*
*/
extern void
{
/* do what needs to be done, get error from STATUS REGISTER */
/* Clear Chip error bit */
if (status & HS_OVERTEMP) {
"Maximum adapter temperature exceeded (%d �C).",
status1);
} else {
"Host Error Attention: status=0x%x status1=0x%x "
}
} else {
}
} /* emlxs_handle_ff_error() */
extern void
emlxs_reset_link_thread(void *arg)
{
/* Attempt a link reset to recover */
(void) thread_exit();
} /* emlxs_reset_link_thread() */
extern void
emlxs_restart_thread(void *arg)
{
/* Attempt a full hardware reset to recover */
}
(void) thread_exit();
} /* emlxs_restart_thread() */
extern void
emlxs_shutdown_thread(void *arg)
{
(void) thread_exit();
}
/* Take adapter offline and leave it there */
(void) emlxs_offline(hba);
/* Log a dump event */
(void) thread_exit();
} /* emlxs_shutdown_thread() */
/*
* emlxs_handle_link_event
*
* Description: Process a Link Attention.
*
*/
static void
{
/* Get a buffer which will be used for mailbox commands */
/* Get link attention message */
MBX_BUSY) {
}
/*
* Clear Link Attention in HA REG
*/
} else {
}
}
} /* emlxs_handle_link_event() */
/*
* emlxs_handle_ring_event
*
* Description: Process a Ring Attention.
*
*/
static void
{
void *ioa2;
count = 0;
/* Isolate this ring's host attention bits */
/* This makes all ring attention bits equal to Ring0 attention bits */
/*
* Gather iocb entries off response ring. Ensure entry is owned by
* the host.
*/
/* While ring is not empty */
/* Get the next response ring iocb */
/* DMA sync the response ring iocb for the adapter */
count++;
/* Copy word6 and word7 to local iocb for now */
iocbq = &local_iocbq;
(sizeof (uint32_t) * 2));
/* when LE is not set, entire Command has not been received */
/* This should never happen */
"ulpLE is not set. ring=%d iotag=%x cmd=%x "
goto next;
}
/* Ring 0 registered commands */
case CMD_FCP_ICMND_CR:
case CMD_FCP_ICMND_CX:
case CMD_FCP_IREAD_CR:
case CMD_FCP_IREAD_CX:
case CMD_FCP_IWRITE_CR:
case CMD_FCP_IWRITE_CX:
case CMD_FCP_ICMND64_CR:
case CMD_FCP_ICMND64_CX:
case CMD_FCP_IREAD64_CR:
case CMD_FCP_IREAD64_CX:
case CMD_FCP_IWRITE64_CR:
case CMD_FCP_IWRITE64_CX:
#ifdef SFCT_SUPPORT
case CMD_FCP_TSEND_CX:
case CMD_FCP_TSEND64_CX:
case CMD_FCP_TRECEIVE_CX:
case CMD_FCP_TRECEIVE64_CX:
case CMD_FCP_TRSP_CX:
case CMD_FCP_TRSP64_CX:
#endif /* SFCT_SUPPORT */
/* Ring 1 registered commands */
case CMD_XMIT_BCAST_CN:
case CMD_XMIT_BCAST_CX:
case CMD_XMIT_SEQUENCE_CX:
case CMD_XMIT_SEQUENCE_CR:
case CMD_XMIT_BCAST64_CN:
case CMD_XMIT_BCAST64_CX:
case CMD_XMIT_SEQUENCE64_CX:
case CMD_XMIT_SEQUENCE64_CR:
case CMD_CREATE_XRI_CR:
case CMD_CREATE_XRI_CX:
/* Ring 2 registered commands */
case CMD_ELS_REQUEST_CR:
case CMD_ELS_REQUEST_CX:
case CMD_XMIT_ELS_RSP_CX:
case CMD_ELS_REQUEST64_CR:
case CMD_ELS_REQUEST64_CX:
case CMD_XMIT_ELS_RSP64_CX:
/* Ring 3 registered commands */
case CMD_GEN_REQUEST64_CR:
case CMD_GEN_REQUEST64_CX:
break;
default:
}
/* If packet is stale, then drop it. */
if (sbp == STALE_PACKET) {
/* Copy entry to the local iocbq */
hba->iocb_rsp_size);
"ringno=%d iocb=%p cmd=%x status=%x error=%x "
goto next;
}
/*
* If a packet was found, then queue the packet's iocb for
* deferred processing
*/
else if (sbp) {
/* Copy entry to sbp's iocbq */
hba->iocb_rsp_size);
/*
* If this is NOT a polled command completion or a
* driver allocated pkt, then defer pkt completion.
*/
PACKET_ALLOCATED)) {
/* Add the IOCB to the local list */
if (!rsp_head) {
} else {
}
goto next;
}
} else {
/* Copy entry to the local iocbq */
hba->iocb_rsp_size);
}
/* process the ring event now */
next:
/* Increment the driver's local response get index */
}
} /* while(TRUE) */
if (rsp_head) {
} else {
}
}
/* Check if at least one response entry was processed */
if (count) {
/* Update response get index for the adapter */
/* DMA sync the index for the adapter */
rspGetInx) -
} else {
sizeof (uint32_t)));
}
if (reg & HA_R0RE_REQ) {
/* HBASTATS.chipRingFree++; */
/* Tell the adapter we serviced the ring */
(ring_no * 4));
chipatt);
}
}
if (reg & HA_R0CE_RSP) {
/* HBASTATS.hostRingFree++; */
/* Cmd ring may be available. Try sending more iocbs */
}
/* HBASTATS.ringEvent++; */
return;
} /* emlxs_handle_ring_event() */
/* ARGSUSED */
extern void
{
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, "emlxs_proc_ring:
* ringo=%d", rp->ringno);
*/
}
}
return;
} /* emlxs_proc_ring() */
/*
* Called from SLI-1 and SLI-2 ring event routines to process a rsp ring IOCB.
*/
static void
{
/* Check for IOCB local error */
"Local reject. ringno=%d iocb=%p cmd=%x iotag=%x "
"context=%x info=%x error=%x",
"Illegal frame. ringno=%d iocb=%p cmd=%x iotag=%x "
"context=%x info=%x error=%x",
}
switch (iocb->ulpCommand) {
/* RING 0 FCP commands */
case CMD_FCP_ICMND_CR:
case CMD_FCP_ICMND_CX:
case CMD_FCP_IREAD_CR:
case CMD_FCP_IREAD_CX:
case CMD_FCP_IWRITE_CR:
case CMD_FCP_IWRITE_CX:
case CMD_FCP_ICMND64_CR:
case CMD_FCP_ICMND64_CX:
case CMD_FCP_IREAD64_CR:
case CMD_FCP_IREAD64_CX:
case CMD_FCP_IWRITE64_CR:
case CMD_FCP_IWRITE64_CX:
break;
#ifdef SFCT_SUPPORT
case CMD_FCP_TSEND_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TSEND64_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRECEIVE_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRECEIVE64_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRSP_CX: /* FCP_TARGET IOCB command */
case CMD_FCP_TRSP64_CX: /* FCP_TARGET IOCB command */
break;
#endif /* SFCT_SUPPORT */
/* RING 1 IP commands */
case CMD_XMIT_BCAST_CN:
case CMD_XMIT_BCAST_CX:
case CMD_XMIT_BCAST64_CN:
case CMD_XMIT_BCAST64_CX:
break;
case CMD_XMIT_SEQUENCE_CX:
case CMD_XMIT_SEQUENCE_CR:
case CMD_XMIT_SEQUENCE64_CX:
case CMD_XMIT_SEQUENCE64_CR:
case FC_TYPE_IS8802_SNAP:
break;
case FC_TYPE_FC_SERVICES:
break;
default:
"cmd=%x type=%x status=%x iotag=%x context=%x ",
}
break;
case CMD_RCV_SEQUENCE_CX:
case CMD_RCV_SEQUENCE64_CX:
case CMD_RCV_SEQ64_CX:
case CMD_RCV_ELS_REQ_CX: /* Unsolicited ELS frame */
case CMD_RCV_ELS_REQ64_CX: /* Unsolicited ELS frame */
case CMD_RCV_ELS64_CX: /* Unsolicited ELS frame */
break;
case CMD_RCV_SEQ_LIST64_CX:
break;
case CMD_CREATE_XRI_CR:
case CMD_CREATE_XRI_CX:
break;
/* RING 2 ELS commands */
case CMD_ELS_REQUEST_CR:
case CMD_ELS_REQUEST_CX:
case CMD_XMIT_ELS_RSP_CX:
case CMD_ELS_REQUEST64_CR:
case CMD_ELS_REQUEST64_CX:
case CMD_XMIT_ELS_RSP64_CX:
break;
/* RING 3 CT commands */
case CMD_GEN_REQUEST64_CR:
case CMD_GEN_REQUEST64_CX:
#ifdef MENLO_SUPPORT
case EMLXS_MENLO_TYPE:
break;
#endif /* MENLO_SUPPORT */
case FC_TYPE_FC_SERVICES:
break;
default:
"cmd=%x type=%x status=%x iotag=%x context=%x ",
}
break;
case CMD_ABORT_XRI_CN: /* Abort fcp command */
"ABORT_XRI_CN: rpi=%d iotag=%x status=%x parm=%x",
break;
case CMD_ABORT_XRI_CX: /* Abort command */
"ABORT_XRI_CX: rpi=%d iotag=%x status=%x parm=%x",
break;
case CMD_XRI_ABORTED_CX: /* Handle ABORT condition */
"XRI_ABORTED_CX: rpi=%d iotag=%x status=%x parm=%x",
break;
case CMD_CLOSE_XRI_CN: /* Handle CLOSE condition */
"CLOSE_XRI_CR: rpi=%d iotag=%x status=%x parm=%x",
break;
case CMD_CLOSE_XRI_CX: /* Handle CLOSE condition */
"CLOSE_XRI_CX: rpi=%d iotag=%x status=%x parm=%x",
break;
case CMD_ADAPTER_MSG:
/* Allows debug adapter firmware messages to print on host */
break;
case CMD_QUE_RING_LIST64_CN:
case CMD_QUE_RING_BUF64_CN:
break;
case CMD_ASYNC_STATUS:
break;
default:
"cmd=%x status=%x iotag=%x context=%x",
iocb->ulpContext);
break;
} /* switch(entry->ulpCommand) */
return;
} /* emlxs_proc_ring_event() */
static int
{
char error_str[64];
#ifdef SLI3_SUPPORT
#endif /* SLI3_SUPPORT */
switch (ringno) {
#ifdef SFCT_SUPPORT
case FC_FCT_RING:
break;
#endif /* SFCT_SUPPORT */
case FC_IP_RING:
break;
case FC_ELS_RING:
break;
case FC_CT_RING:
break;
default:
"ring=%d cmd=%x %s %x %x %x %x",
return (1);
}
goto done;
} else {
}
goto failed;
}
#ifdef SLI3_SUPPORT
*UbPosted -= 1;
hbqe_tag);
goto dropped;
}
} else
#endif /* SLI3_SUPPORT */
{
/* Check for invalid buffer */
goto dropped;
}
}
if (!mp) {
goto dropped;
}
if (!size) {
goto dropped;
}
#ifdef SLI3_SUPPORT
/* To avoid we drop the broadcast packets */
if (ringno != FC_IP_RING) {
/* Get virtual port */
vpi);
goto dropped;
}
}
}
#endif /* SLI3_SUPPORT */
/* Process request */
switch (ringno) {
#ifdef SFCT_SUPPORT
case FC_FCT_RING:
break;
#endif /* SFCT_SUPPORT */
case FC_IP_RING:
break;
case FC_ELS_RING:
/* If this is a target port, then let fct handle this */
#ifdef SFCT_SUPPORT
} else {
}
#else
#endif /* SFCT_SUPPORT */
break;
case FC_CT_RING:
break;
}
goto done;
*RcvDropped += 1;
"%s: cmd=%x %s %x %x %x %x",
if (ringno == FC_FCT_RING) {
#ifdef SLI3_SUPPORT
} else
#endif /* SLI3_SUPPORT */
{
}
}
goto done;
*RcvError += 1;
"%s: cmd=%x %s %x %x %x %x hba:%x %x",
done:
#ifdef SLI3_SUPPORT
} else
#endif /* SLI3_SUPPORT */
{
if (mp) {
}
}
return (0);
} /* emlxs_handle_rcv_seq() */
extern void
{
void *ioa2;
throttle = 0;
/* Check if FCP ring and adapter is not ready */
if (!iocbq) {
return;
}
return;
}
}
/* Attempt to acquire CMD_RING lock */
/* Queue it for later */
if (iocbq) {
return;
} else {
/*
* EMLXS_MSGF(EMLXS_CONTEXT,
* &emlxs_ring_watchdog_msg, "%s host=%d
* port=%d cnt=%d,%d RACE CONDITION3
* DETECTED.", emlxs_ring_xlate(ringno),
* rp->fc_cmdidx, rp->fc_port_cmdidx,
* hba->ring_tx_count[ringno],
* hba->io_count[ringno]);
*/
}
} else {
return;
}
}
/* CMD_RING_LOCK acquired */
/* Check if HBA is full */
if (throttle <= 0) {
/* Hitting adapter throttle limit */
/* Queue it for later */
if (iocbq) {
}
goto busy;
}
/* Read adapter's get index */
/* Calculate the next put index */
/* Check if ring is full */
/* Try one more time */
/* Queue it for later */
if (iocbq) {
}
goto busy;
}
}
/* We have a command ring slot available */
/* Make sure we have an iocb to send */
if (iocbq) {
/* Check if the ring already has iocb's waiting */
/* Put the current iocbq on the tx queue */
emlxs_tx_put(iocbq, 0);
/*
* Attempt to replace it with the next iocbq in the
* tx queue
*/
}
} else {
/* Try to get the next iocb on the tx queue */
}
count = 0;
/* Process each iocbq */
while (iocbq) {
#ifdef NPIV_SUPPORT
/*
* Update adapter if needed, since we are about to
* delay here
*/
if (count) {
count = 0;
/* Update the adapter's cmd put index */
/* DMA sync the index for the adapter */
offset =
(off_t)
} else {
}
}
/* Perform delay */
if (ringno == FC_ELS_RING) {
(void) drv_usecwait(100000);
} else {
(void) drv_usecwait(20000);
}
}
#endif /* NPIV_SUPPORT */
/* At this point, we have a command ring slot available */
/* and an iocb to send */
/* Send the iocb */
count++;
/* Check if HBA is full */
if (throttle <= 0) {
goto busy;
}
/* Calculate the next put index */
/* Check if ring is full */
/* Try one more time */
goto busy;
}
}
/* Get the next iocb from the tx queue if there is one */
}
if (count) {
/* Update the adapter's cmd put index */
/* DMA sync the index for the adapter */
} else {
sizeof (uint32_t)));
}
/* Check tx queue one more time before releasing */
/*
* EMLXS_MSGF(EMLXS_CONTEXT,
* &emlxs_ring_watchdog_msg, "%s host=%d port=%d
* RACE CONDITION1 DETECTED.",
* emlxs_ring_xlate(ringno), rp->fc_cmdidx,
* rp->fc_port_cmdidx);
*/
goto sendit;
}
}
return;
busy:
/*
* Set ring to SET R0CE_REQ in Chip Att register. Chip will tell us
* when an entry is freed.
*/
if (count) {
/* Update the adapter's cmd put index */
/* DMA sync the index for the adapter */
} else {
sizeof (uint32_t)));
}
}
if (throttle <= 0) {
} else {
}
return;
} /* emlxs_issue_iocb_cmd() */
/* EMLXS_CMD_RING_LOCK must be held when calling this function */
static void
{
/* Check for ULP pkt request */
if (sbp) {
/* Set node to base node by default */
}
}
/* get the next available command ring iocb */
/* Copy the local iocb to the command ring iocb */
hba->iocb_cmd_size);
/* DMA sync the command ring iocb for the adapter */
/* Free the local iocb if there is no sbp tracking it */
if (!sbp) {
}
/* update local ring index to next available ring index */
return;
} /* emlxs_issue_iocb() */
extern uint32_t
{
uint32_t j;
interlock_failed = 0;
return (FC_SUCCESS);
}
j = 0;
while (j++ < 10000) {
if (hba->mbox_queue_flag == 0) {
break;
}
DELAYUS(100);
}
if (hba->mbox_queue_flag != 0) {
"Interlock failed. Mailbox busy.");
return (FC_SUCCESS);
}
/* Disable all host interrupts */
goto mode_B;
}
"Attempting SLIM2 Interlock...");
value = 0xFFFFFFFF;
word0 = 0;
/* Write value to SLIM */
/* Send Kill board request */
/* Sync the memory */
/* interrupt board to do it right away */
/* First wait for command acceptence */
j = 0;
while (j++ < 1000) {
if (value == 0) {
break;
}
DELAYUS(50);
}
if (value == 0) {
/* Now wait for mailbox ownership to clear */
while (j++ < 10000) {
break;
}
DELAYUS(50);
}
"Interlock succeeded.");
goto done;
}
/* Interlock failed !!! */
interlock_failed = 1;
"Interlock failed.");
"Attempting SLIM1 Interlock...");
value = 0xFFFFFFFF;
word0 = 0;
/* Write KILL BOARD to mailbox */
/* interrupt board to do it right away */
/* First wait for command acceptence */
j = 0;
while (j++ < 1000) {
if (value == 0) {
break;
}
DELAYUS(50);
}
if (value == 0) {
/* Now wait for mailbox ownership to clear */
while (j++ < 10000) {
break;
}
DELAYUS(50);
}
"Interlock succeeded.");
goto done;
}
/* Interlock failed !!! */
/* If this is the first time then try again */
if (interlock_failed == 0) {
"Interlock failed. Retrying...");
/* Try again */
interlock_failed = 1;
goto interlock_B;
}
/*
* Now check for error attention to indicate the board has been
* kiilled
*/
j = 0;
while (j++ < 10000) {
break;
}
DELAYUS(50);
}
"Interlock failed. Board killed.");
} else {
"Interlock failed. Board not killed.");
}
done:
hba->mbox_queue_flag = 0;
return (FC_SUCCESS);
} /* emlxs_interlock() */
extern uint32_t
{
uint32_t i;
i = 0;
"Adapter reset disabled.");
return (1);
}
/* Make sure we have called interlock */
(void) emlxs_interlock(hba);
if (restart) {
} else {
}
/* Save reset time */
if (restart) {
/* First put restart command in mailbox */
word0 = 0;
/* Only skip post after emlxs_ffinit is completed */
if (skip_post) {
} else {
}
}
/*
* Turn off SERR, PERR in PCI cmd register
*/
/* Wait 1 msec before restoring PCI config */
DELAYMS(1);
/* Restore PCI cmd register */
/* Wait 3 seconds before checking */
DELAYMS(3000);
i += 3;
/* Wait for reset completion */
while (i < 30) {
/* Check status register to see what current state is */
/* Check to see if any errors occurred during init */
"HS_FFERM: status=0x%x status1=0x%x status2=0x%x",
return (1);
}
/* Reset Done !! */
goto done;
}
/*
* Check every 1 second for 15 seconds, then reset board
*/
DELAYMS(1000);
i++;
if (i == 15) {
"Reset failed. Retrying...");
goto reset;
}
}
/* Timeout occurred */
"Timeout: status=0x%x", status);
/* Log a dump event */
return (1);
done:
/* Reset the hba structure */
hba->iodone_count = 0;
hba->heartbeat_active = 0;
hba->discovery_timer = 0;
hba->linkup_timer = 0;
hba->loopback_tics = 0;
/* Initialize hc_copy */
/* Reset the ring objects */
for (i = 0; i < MAX_RINGS; i++) {
}
/* Reset the port objects */
for (i = 0; i < MAX_VPORTS; i++) {
vport->node_count = 0;
}
}
return (0);
} /* emlxs_hba_reset */
extern void
{
/*
* Polling a specific attention bit.
*/
for (;;) {
break;
}
}
/* Process the attentions */
return;
} /* emlxs_poll_intr() */
extern uint32_t
{
uint32_t i;
"%s: Unable to allocate mailbox buffer.",
return ((uint32_t)FC_FAILURE);
}
"%s: Unable to reset ring. Mailbox cmd=%x status=%x",
return ((uint32_t)FC_FAILURE);
}
/* Free the mailbox */
/* Update the response ring indicies */
/* Update the command ring indicies */
for (i = 0; i < MAX_VPORTS; i++) {
continue;
}
/* Clear all node XRI contexts */
for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
}
}
}
return (FC_SUCCESS);
} /* emlxs_reset_ring() */
extern char *
{
static char buffer[32];
uint32_t i;
for (i = 0; i < count; i++) {
return (emlxs_ffstate_table[i].string);
}
}
return (buffer);
} /* emlxs_ffstate_xlate() */
extern char *
{
static char buffer[32];
uint32_t i;
for (i = 0; i < count; i++) {
return (emlxs_ring_table[i].string);
}
}
return (buffer);
} /* emlxs_ring_xlate() */
extern void
{
case 512:
value = 0;
break;
case 1024:
value = 1;
break;
case 2048:
value = 2;
break;
case 4096:
value = 3;
break;
default:
"PCI_MAX_READ: Invalid parameter value. old=%d new=%d",
goto xlate;
}
"PCI_MAX_READ: Unable to allocate mailbox buffer.");
return;
}
"PCI_MAX_READ: Unable to update. status=%x "
}
} else {
"PCI_MAX_READ: Updated. %d bytes",
}
}
return;
} /* emlxs_pcix_mxr_update */
extern uint32_t
{
#define SEED 0x876EDC21
/* This key is only used currently for SBUS adapters */
return (0);
}
"Unable to read nvram. cmd=%x status=%x",
return (0);
}
return (theKey);
} /* emlxs_get_key() */