/*
* 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
* 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 (c) 2004-2012 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#include <emlxs.h>
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
#ifdef SFCT_SUPPORT
#endif /* SFCT_SUPPORT */
emlxs_buf_t *sbp);
emlxs_buf_t *sbp);
emlxs_buf_t *sbp);
emlxs_buf_t *sbp);
#ifdef SFCT_SUPPORT
#endif /* SFCT_SUPPORT */
emlxs_buf_t *sbp);
emlxs_buf_t *sbp);
emlxs_buf_t *sbp);
#ifdef MSI_SUPPORT
#endif /* MSI_SUPPORT */
/* static int emlxs_handle_rcv_seq(emlxs_hba_t *hba, */
/* CHANNEL *cp, IOCBQ *iocbq); */
/* static void emlxs_update_HBQ_index(emlxs_hba_t *hba, */
/* uint32_t hbq_id); */
/* static void emlxs_hbq_free_all(emlxs_hba_t *hba, */
/* uint32_t hbq_id); */
/* Define SLI3 API functions */
#ifdef SFCT_SUPPORT
#else
NULL,
#endif /* SFCT_SUPPORT */
};
/*
* emlxs_sli3_online()
*
* This routine will start initialization of the SLI2/3 HBA.
*/
static int32_t
{
uint16_t i;
uint32_t j;
MaxRbusSize = 0;
MaxIbusSize = 0;
read_rev_reset = 0;
}
/* Set the fw_check flag */
if ((fw_check & 0x04) ||
kern_update = 1;
}
hba->mbox_queue_flag = 0;
/*
* Get a buffer which will be used repeatedly for mailbox commands
*/
/* Initialize sli mode based on configuration parameter */
case 2: /* SLI2 mode */
break;
case 3: /* SLI3 mode */
break;
case 0: /* Best available */
case 1: /* Best available */
default:
} else {
"No SLI mode available.");
goto failed;
}
break;
}
/* SBUS adapters only available in SLI2 */
}
/* Reset & Initialize the adapter */
if (emlxs_sli3_hba_init(hba)) {
"Unable to init hba.");
goto failed;
}
#ifdef FMA_SUPPORT
/* Access handle validation */
!= DDI_FM_OK) ||
!= DDI_FM_OK) ||
!= DDI_FM_OK)) {
goto failed;
}
#endif /* FMA_SUPPORT */
/* Check for PEGASUS (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;
/* Sanity check */
"Adapter / SLI mode mismatch mask:x%x",
goto failed;
}
"Unable to read rev. Mailbox cmd=%x status=%x",
goto failed;
}
/* Old firmware */
if (read_rev_reset == 0) {
read_rev_reset = 1;
goto reset;
} else {
"Outdated firmware detected.");
}
} else {
if (read_rev_reset == 0) {
read_rev_reset = 1;
goto reset;
} else {
"Non-operational firmware detected. "
"type=%x",
}
}
16);
16);
/*
* Lets try to read the SLI3 version
* Setup and issue mailbox READ REV(v3) command
*/
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"Unable to read rev (v3). Mailbox cmd=%x status=%x",
goto failed;
}
/*
* vpd->sli2FwRev = mb->un.varRdRev.sliFwRev1;
* Not needed
*/
}
}
} else {
sli_mode = 0;
sli_mode_mask = 0;
}
}
} else {
sli_mode = 0;
sli_mode_mask = 0;
}
}
"Firmware not available. sli-mode=%d",
goto failed;
}
/* Save information as VPD data */
/* Decode FW names */
sizeof (vpd->postKernName));
sizeof (vpd->sli1FwName));
sizeof (vpd->sli2FwName));
sizeof (vpd->sli3FwName));
sizeof (vpd->sli4FwName));
/* Decode FW labels */
sizeof (vpd->sli1FwLabel));
sizeof (vpd->sli2FwLabel));
sizeof (vpd->sli3FwLabel));
sizeof (vpd->sli4FwLabel));
/* Reuse mbq from previous mbox */
/* Get adapter VPD information */
offset = 0;
while (offset < DMP_VPD_SIZE) {
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
/*
* 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", offset,
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]) {
/*
* If there is a VPD part number, and it does not
* match the current default HBA model info,
* replace the default data with an entry that
* does match.
*
* After emlxs_parse_vpd model holds the VPD value
* for V2 and part_num hold the value for PN. These
* 2 values are NOT necessarily the same.
*/
rval = 0;
/* First scan for a V2 match */
for (i = 1; i < emlxs_pci_model_count; i++) {
emlxs_pci_model[i].model) == 0) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
rval = 1;
break;
}
}
}
/* Next scan for a PN match */
for (i = 1; i < emlxs_pci_model_count; i++) {
emlxs_pci_model[i].model) == 0) {
bcopy(&emlxs_pci_model[i],
&hba->model_info,
sizeof (emlxs_model_t));
break;
}
}
}
/*
* Now lets update hba->model_info with the real
* VPD data, if any.
*/
/*
* Replace the default model description with vpd data
*/
if (vpd->model_desc[0] != 0) {
}
/* 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 SSDID:0x%x Model:%s",
goto failed;
}
/* Read the adapter's wakeup parms */
/* Get fcode version property */
/*
* If firmware checking is enabled and the adapter model indicates
* a firmware image, then perform firmware version check
*/
if (((fw_check & 0x1) &&
/* Find firmware image indicated by adapter model */
for (i = 0; i < emlxs_fw_count; i++) {
fw = &emlxs_fw_table[i];
break;
}
}
/*
* If the image was found, then verify current firmware
* versions of adapter
*/
if (fw) {
if (!kern_update &&
"Firmware update needed. "
"Updating. id=%d fw=%d",
#ifdef MODFW_SUPPORT
/*
* Load the firmware image now
* If MODFW_SUPPORT is not defined, the
* firmware image will already be defined
* in the emlxs_fw_table
*/
#endif /* MODFW_SUPPORT */
if ((rc != FC_SUCCESS) &&
(rc != EMLXS_REBOOT_REQUIRED)) {
"Firmware update failed.");
}
#ifdef MODFW_SUPPORT
/*
* Unload the firmware image from
* kernel memory
*/
#endif /* MODFW_SUPPORT */
fw_check = 0;
goto reset;
}
"Firmware image unavailable.");
} else {
"Firmware update not needed.");
}
} else {
/* This should not happen */
/*
* This means either the adapter database is not
* correct or a firmware image is missing from the
* compile
*/
"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).");
goto failed;
}
/* Reuse mbq from previous mbox */
"Unable to configure port. "
"Mailbox cmd=%x status=%x slimode=%d key=%x",
/* Check if sli_mode is supported by this adapter */
break;
}
}
if (sli_mode) {
fw_check = 0;
goto reset;
}
goto failed;
}
/* Check if SLI3 mode was achieved */
MAX_VPORTS - 1);
} else {
MAX_VPORTS_LIMITED - 1);
}
}
#if (EMLXS_MODREV >= EMLXS_MODREV5)
#endif /* >= EMLXS_MODREV5 */
}
} else {
#if (EMLXS_MODREV >= EMLXS_MODREV5)
#endif /* >= EMLXS_MODREV5 */
}
/* Get and save the current firmware version (based on sli_mode) */
emlxs_pcix_mxr_update(hba, 0);
/* Reuse mbq from previous mbox */
"Unable to read configuration. Mailbox cmd=%x status=%x",
goto failed;
}
/* Save the link speed capabilities */
/* Set the max node count */
} else {
}
/* Set the io throttle */
/* Set max_iotag */
} else {
}
/* Set out-of-range iotag base */
/*
* Allocate some memory for buffers
*/
if (emlxs_mem_alloc_buffer(hba) == 0) {
"Unable to allocate memory buffers.");
return (ENOMEM);
}
/*
* Setup and issue mailbox RUN BIU DIAG command Setup test buffers
*/
"Unable to allocate diag buffers.");
goto failed;
}
/* Reuse mbq from previous mbox */
"Unable to run BIU diag. Mailbox cmd=%x status=%x",
goto failed;
}
#ifdef FMA_SUPPORT
if (mp->dma_handle) {
!= DDI_FM_OK) {
"sli3_online: hdl=%p",
mp->dma_handle);
goto failed;
}
}
if (mp1->dma_handle) {
!= DDI_FM_OK) {
"sli3_online: hdl=%p",
mp1->dma_handle);
goto failed;
}
}
#endif /* FMA_SUPPORT */
for (i = 0; i < MEM_ELSBUF_SIZE; i++) {
outptr--;
inptr--;
"BIU diagnostic failed. "
"offset %x value %x should be %x.",
goto failed;
}
}
/* Free the buffers since we were polling */
hba->channel_tx_count = 0;
for (i = 0; i < hba->chan_count; i++) {
/* 1 to 1 mapping between ring and channel */
}
/*
* Setup and issue mailbox CONFIGURE RING command
*/
/*
*/
/* 1 to 1 mapping between ring and channel */
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"Unable to configure ring. "
"Mailbox cmd=%x status=%x",
goto failed;
}
}
/*
* Setup link timers
*/
/* Reuse mbq from previous mbox */
"Unable to configure link. Mailbox cmd=%x status=%x",
goto failed;
}
#ifdef MAX_RRDY_SUPPORT
/* Set MAX_RRDY if one is provided */
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"MAX_RRDY: Unable to set. status=%x " \
"value=%d",
} else {
}
}
#endif /* MAX_RRDY_SUPPORT */
/* Reuse mbq from previous mbox */
/*
* We need to get login parameters for NID
*/
"Unable to read parameters. Mailbox cmd=%x status=%x",
goto failed;
}
/* 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 %s FV%s DV%s %s",
"Emulex PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
"WWPN doesn't conform to IP profile: "
"nameType=%x. Disabling networking.",
}
}
/* Reuse mbq from previous mbox */
/* Issue CONFIG FARP */
MBX_SUCCESS) {
/*
* Let it go through even if failed.
*/
"Unable to configure FARP. "
"Mailbox cmd=%x status=%x",
}
}
#ifdef MSI_SUPPORT
/* Configure MSI map if required */
/* always start from 0 */
hba->last_msiid = 0;
}
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
goto msi_configured;
}
"Unable to config MSIX. Mailbox cmd=0x%x status=0x%x",
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
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);
goto failed;
}
/*
* 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;
}
/* intr_count is a sequence of msi id */
/* Setup msi2chan[msi_id] */
for (i = 0; i < hba->intr_count; i ++) {
if (i >= hba->chan_count)
}
}
#endif /* MSI_SUPPORT */
/*
* We always disable the firmware traffic cop feature
*/
if (emlxs_disable_traffic_cop) {
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"Unable to disable traffic cop. "
"Mailbox cmd=%x status=%x",
goto failed;
}
}
/* Reuse mbq from previous mbox */
/* Register for async events */
"Async events disabled. Mailbox status=%x",
} else {
"Async events enabled.");
}
"Unable to setup FCT HBQ.");
#ifdef SFCT_SUPPORT
/* Check if we can fall back to just */
/* initiator mode */
"Disabling dynamic target mode. "
"Enabling initiator mode only.");
/* This will trigger the driver to */
/* reattach */
}
#endif /* SFCT_SUPPORT */
goto failed;
}
"FCT Ring: Posted %d buffers.", MEM_FCTBUF_COUNT);
}
"Unable to setup IP HBQ.");
goto failed;
}
"IP Ring: Posted %d buffers.", MEM_IPBUF_COUNT);
}
"Unable to setup ELS HBQ.");
goto failed;
}
"ELS Ring: Posted %d buffers.", MEM_ELSBUF_COUNT);
"Unable to setup CT HBQ.");
goto failed;
}
"CT Ring: Posted %d buffers.", MEM_CTBUF_COUNT);
} else {
/* 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);
}
/* Check persist-linkdown */
return (0);
}
#ifdef SFCT_SUPPORT
return (0);
}
#endif /* SFCT_SUPPORT */
/*
* Setup and issue mailbox INITIALIZE LINK command
* At this point, the interrupt will be generated by the HW
*/
"Unable to allocate mailbox buffer.");
goto failed;
}
"Unable to initialize link. " \
"Mailbox cmd=%x status=%x",
goto failed;
}
/*
* Enable link attention interrupt
*/
/* Wait for link to come up */
/* Check for hardware error */
"Adapter error.");
goto failed;
}
BUSYWAIT_MS(1000);
i--;
}
/*
* The leadvile driver will now handle the FLOGI at the driver level
*/
return (0);
(void) EMLXS_INTR_REMOVE(hba);
}
if (mp) {
}
if (mp1) {
}
(void) emlxs_mem_free_buffer(hba);
if (mbq) {
}
if (rval == 0) {
}
return (rval);
} /* emlxs_sli3_online() */
/*ARGSUSED*/
static void
{
/* Reverse emlxs_sli3_online */
/* Kill the adapter */
/* Free driver shared memory */
(void) emlxs_mem_free_buffer(hba);
} /* emlxs_sli3_offline() */
static int
{
int status;
if (status != DDI_SUCCESS) {
"(SBUS) ddi_regs_map_setup SLIM failed. "
"status=%x", status);
goto failed;
}
}
if (status != DDI_SUCCESS) {
"(SBUS) ddi_regs_map_setup DFLY CSR "
"failed. status=%x", status);
goto failed;
}
}
if (status != DDI_SUCCESS) {
"(SBUS) ddi_regs_map_setup Fcode Flash "
"failed. status=%x", status);
goto failed;
}
}
if (status != DDI_SUCCESS) {
"(SBUS) ddi_regs_map_setup TITAN CORE "
"failed. status=%x", status);
goto failed;
}
}
if (status != DDI_SUCCESS) {
"(SBUS) ddi_regs_map_setup TITAN CSR "
"failed. status=%x", status);
goto failed;
}
}
} else { /* ****** PCI ****** */
if (status != DDI_SUCCESS) {
"(PCI) ddi_regs_map_setup SLIM failed. "
"stat=%d mem=%p attr=%p hdl=%p",
goto failed;
}
}
/*
* Map in control registers, using memory-mapped version of
* the registers rather than the I/O space-mapped registers.
*/
if (status != DDI_SUCCESS) {
"ddi_regs_map_setup CSR failed. status=%x",
status);
goto failed;
}
}
}
goto failed;
}
}
/* offset from beginning of register space */
(sizeof (uint32_t) * HA_REG_OFFSET));
(sizeof (uint32_t) * CA_REG_OFFSET));
(sizeof (uint32_t) * HS_REG_OFFSET));
(sizeof (uint32_t) * HC_REG_OFFSET));
(sizeof (uint32_t) * BC_REG_OFFSET));
/* offset from beginning of register space */
/* for TITAN registers */
(sizeof (uint32_t) * SBUS_CTRL_REG_OFFSET));
(sizeof (uint32_t) * SBUS_STAT_REG_OFFSET));
(sizeof (uint32_t) * SBUS_UPDATE_REG_OFFSET));
}
return (0);
return (ENOMEM);
} /* emlxs_sli3_map_hdw() */
static void
{
}
}
}
}
}
}
}
return;
} /* emlxs_sli3_unmap_hdw() */
static uint32_t
{
uint16_t i;
i = 0;
/* Restart the adapter */
return (1);
}
/*
* WARNING: There is a max of 6 ring masks allowed
*/
/* RING 0 - FCP */
} else {
}
/* RING 1 - IP */
} else {
}
/* RING 2 - ELS */
/* RING 3 - CT */
if (i > 6) {
"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_sli3_hba_init() */
/*
* 0: quiesce indicates the call is not from quiesce routine.
* 1: quiesce indicates the call is from quiesce routine.
*/
static uint32_t
{
uint32_t i;
"Adapter reset disabled.");
return (1);
}
/* Kill the adapter first */
if (quiesce == 0) {
} else {
}
if (restart) {
"Restarting.");
} else {
"Resetting.");
}
i = 0;
/* Save reset time */
if (restart) {
/* First put restart command in mailbox */
word0 = 0;
/* Only skip post after emlxs_sli3_online is completed */
if (skip_post) {
1);
} else {
0);
}
}
/*
* Turn off SERR, PERR in PCI cmd register
*/
/* Wait 1 msec before restoring PCI config */
BUSYWAIT_MS(1);
/* Restore PCI cmd register */
/* Wait 3 seconds before checking */
BUSYWAIT_MS(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
*/
BUSYWAIT_MS(1000);
i++;
if (i == 15) {
"Reset failed. Retrying...");
goto reset;
}
}
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
/* Timeout occurred */
"Timeout: status=0x%x", status);
/* Log a dump event */
return (1);
done:
/* Initialize hc_copy */
#ifdef FMA_SUPPORT
/* Access handle validation */
!= DDI_FM_OK) ||
!= DDI_FM_OK) ||
!= DDI_FM_OK)) {
goto reset_fail;
}
#endif /* FMA_SUPPORT */
/* Reset the hba structure */
hba->channel_tx_count = 0;
hba->iodone_count = 0;
hba->heartbeat_active = 0;
hba->discovery_timer = 0;
hba->linkup_timer = 0;
hba->loopback_tics = 0;
/* 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_sli3_hba_reset */
#define BPL_CMD 0
static ULP_BDE64 *
{
uint_t i;
#if (EMLXS_MODREV >= EMLXS_MODREV3)
switch (bpl_type) {
case BPL_CMD:
bdeFlags = 0;
break;
case BPL_RESP:
break;
case BPL_DATA:
BUFF_USE_RCV : 0;
break;
default:
return (NULL);
}
#else
switch (bpl_type) {
case BPL_CMD:
cookie_cnt = 1;
bdeFlags = 0;
break;
case BPL_RESP:
cookie_cnt = 1;
break;
case BPL_DATA:
cookie_cnt = 1;
BUFF_USE_RCV : 0;
break;
default:
return (NULL);
}
#endif /* >= EMLXS_MODREV3 */
bpl++;
}
return (bpl);
} /* emlxs_pkt_to_bpl */
static uint32_t
{
} else {
}
if (!bmp) {
return (1);
}
#if (EMLXS_MODREV >= EMLXS_MODREV3)
#else
data_cookie_cnt = 1;
#endif /* >= EMLXS_MODREV3 */
switch (channelno) {
case FC_FCP_RING:
/* CMD payload */
if (! bpl) {
return (1);
}
/* Check if response & data payloads are needed */
break;
}
/* RSP payload */
if (! bpl) {
return (1);
}
/* Check if data payload is needed */
if ((pkt->pkt_datalen == 0) ||
(data_cookie_cnt == 0)) {
break;
}
/* DATA payload */
if (! bpl) {
return (1);
}
break;
case FC_IP_RING:
/* CMD payload */
if (! bpl) {
return (1);
}
break;
case FC_ELS_RING:
/* CMD payload */
if (! bpl) {
return (1);
}
/* Check if response payload is needed */
break;
}
/* RSP payload */
if (! bpl) {
return (1);
}
break;
case FC_CT_RING:
/* CMD payload */
if (! bpl) {
return (1);
}
/* Check if response payload is needed */
break;
}
/* RSP payload */
if (! bpl) {
return (1);
}
break;
}
return (0);
} /* emlxs_sli2_bde_setup */
static uint32_t
{
int data_cookie_cnt;
uint32_t i;
#if (EMLXS_MODREV >= EMLXS_MODREV3)
return (i);
}
#else
data_cookie_cnt = 1;
#endif /* >= EMLXS_MODREV3 */
switch (channelno) {
case FC_FCP_RING:
/* CMD payload */
/* Check if a response & data payload are needed */
break;
}
/* RSP payload */
/* Check if a data payload is needed */
if ((pkt->pkt_datalen == 0) ||
(data_cookie_cnt == 0)) {
break;
}
/* DATA payload */
for (i = 0; i < data_cookie_cnt; i++) {
cp_data++;
bde++;
}
break;
case FC_IP_RING:
/* CMD payload */
break;
case FC_ELS_RING:
/* CMD payload */
/* Check if a response payload is needed */
break;
}
/* RSP payload */
break;
case FC_CT_RING:
/* CMD payload */
/* Check if a response payload is needed */
break;
}
/* RSP payload */
break;
}
iocb->ULPBDECOUNT = 0;
return (0);
} /* emlxs_sli3_bde_setup */
/* Only used for FCP Data xfers */
#ifdef SFCT_SUPPORT
/*ARGSUSED*/
static uint32_t
{
iocb->ULPBDECOUNT = 0;
return (0);
}
} else {
}
if (!bmp) {
"fct_sli2_bde_setup: Unable to BPL buffer. iotag=%d",
iocb->ULPBDECOUNT = 0;
return (1);
}
/* Init the buffer list */
/* Init the IOCB */
return (0);
} /* emlxs_sli2_fct_bde_setup */
#endif /* SFCT_SUPPORT */
#ifdef SFCT_SUPPORT
/*ARGSUSED*/
static uint32_t
{
iocb->ULPBDECOUNT = 0;
return (0);
}
/* Init first BDE */
iocb->ULPBDECOUNT = 0;
return (0);
} /* emlxs_sli3_fct_bde_setup */
#endif /* SFCT_SUPPORT */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
void *ioa2;
#ifdef NODE_THROTTLE_SUPPORT
#endif /* NODE_THROTTLE_SUPPORT */
throttle = 0;
/* Check if FCP ring and adapter is not ready */
/* We may use any ring for FCP_CMD */
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(channelno),
* rp->fc_cmdidx, rp->fc_port_cmdidx,
* hba->channel_tx_count,
* hba->io_count);
*/
}
} else {
return;
}
}
/* CMD_RING_LOCK acquired */
/* Throttle check only applies to non special iocb */
/* 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 */
offset =
/* Calculate the next put index */
nextIdx =
/* 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 NODE_THROTTLE_SUPPORT
if (node_throttle <= 0) {
/* Node is busy */
/* Queue this iocb and get next iocb from */
/* channel */
if (!marked_node) {
}
emlxs_tx_put(iocbq, 0);
goto busy;
}
continue;
}
}
marked_node = 0;
#endif /* NODE_THROTTLE_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 */
((uint64_t)
} else {
ioa2 = (void *)
((channelno * 2) *
sizeof (uint32_t)));
}
}
/* Perform delay */
if ((channelno == FC_ELS_RING) &&
drv_usecwait(100000);
} else {
drv_usecwait(20000);
}
}
/*
* At this point, we have a command ring slot available
* and an iocb to send
*/
/* Send the iocb */
/*
* After this, the sbp / iocb should not be
* accessed in the xmit path.
*/
count++;
/* Check if HBA is full */
if (throttle <= 0) {
goto busy;
}
}
/* Calculate the next put index */
nextIdx =
/* 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 {
ioa2 =
}
/* 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(channelno),
* rp->fc_cmdidx, rp->fc_port_cmdidx);
*/
goto sendit;
}
}
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
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 {
ioa2 =
}
}
if (throttle <= 0) {
} else {
}
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return;
} /* emlxs_sli3_issue_iocb_cmd() */
/* MBX_NOWAIT - returns MBX_BUSY or MBX_SUCCESS or MBX_HARDWARE_ERROR */
/* MBX_WAIT - returns MBX_TIMEOUT or mailbox_status */
/* MBX_SLEEP - returns MBX_TIMEOUT or mailbox_status */
/* MBX_POLL - returns MBX_TIMEOUT or mailbox_status */
static uint32_t
{
}
/* Check for minimum timeouts */
switch (mb->mbxCommand) {
case MBX_DOWN_LOAD:
case MBX_UPDATE_CFG:
case MBX_LOAD_AREA:
case MBX_LOAD_EXP_ROM:
case MBX_WRITE_NV:
case MBX_FLASH_WR_ULA:
case MBX_DEL_LD_ENTRY:
case MBX_LOAD_SM:
if (tmo < 300) {
tmo = 300;
}
break;
default:
if (tmo < 30) {
tmo = 30;
}
break;
}
/* Convert tmo seconds to 10 millisecond tics */
/* Adjust wait flag */
if (flag != MBX_NOWAIT) {
/* If interrupt is enabled, use sleep, otherwise poll */
} else {
}
}
/* Check for hardware error */
"Hardware error reported. %s failed. status=%x mb=%p",
return (MBX_HARDWARE_ERROR);
}
if (hba->mbox_queue_flag) {
/* If we are not polling, then queue it for later */
if (flag == MBX_NOWAIT) {
"Busy. %s: mb=%p NoWait.",
return (MBX_BUSY);
}
while (hba->mbox_queue_flag) {
if (tmo_local-- == 0) {
"Timeout. %s: mb=%p tmo=%d Waiting.",
tmo);
/* Non-lethalStatus mailbox timeout */
/* Does not indicate a hardware error */
return (MBX_TIMEOUT);
}
BUSYWAIT_MS(10);
/* Check for hardware error */
"Hardware error reported. %s failed. "
"status=%x mb=%p",
return (MBX_HARDWARE_ERROR);
}
}
}
/* Initialize mailbox area */
switch (flag) {
case MBX_NOWAIT:
"Sending. %s: mb=%p NoWait.",
}
}
break;
case MBX_SLEEP:
"Sending. %s: mb=%p Sleep.",
}
break;
case MBX_POLL:
"Sending. %s: mb=%p Polled.",
}
break;
}
/* Clear the attention bit */
/* First copy command data */
offset =
#ifdef MBOX_EXT_SUPPORT
}
#endif /* MBOX_EXT_SUPPORT */
} else { /* SLIM 1 */
#ifdef MBOX_EXT_SUPPORT
}
#endif /* MBOX_EXT_SUPPORT */
/* First copy command data */
(MAILBOX_CMD_WSIZE - 1));
/* copy over last word, with mbxOwner set */
}
/* Interrupt board to do it right away */
#ifdef FMA_SUPPORT
/* Access handle validation */
!= DDI_FM_OK) ||
!= DDI_FM_OK)) {
return (MBX_HARDWARE_ERROR);
}
#endif /* FMA_SUPPORT */
switch (flag) {
case MBX_NOWAIT:
return (MBX_SUCCESS);
case MBX_SLEEP:
/* Wait for completion */
/* The driver clock is timing the mailbox. */
/* emlxs_mb_fini() will be called externally. */
}
"Timeout. %s: mb=%p tmo=%d. Sleep.",
} else {
"Completed. %s: mb=%p status=%x Sleep.",
}
}
break;
case MBX_POLL:
/* Convert tmo seconds to 500 usec tics */
/* Get first word of mailbox */
} else {
word0 =
}
/* Wait for command to complete */
/* self time */
"%s: mb=%p tmo=%d Polled.",
break;
}
BUSYWAIT_US(500);
/* Get first word of mailbox */
sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
} else {
word0 =
}
} /* while */
"Timeout. %s: mb=%p tmo=%d. Polled.",
break;
}
/* Check for config port command */
/* Setup host mbox for cmpl */
}
/* copy results back to user */
} else {
}
#ifdef MBOX_EXT_SUPPORT
} else {
}
}
#endif /* MBOX_EXT_SUPPORT */
/* Sync the memory buffer */
}
"Completed. %s: mb=%p status=%x Polled.",
}
/* Process the result */
}
}
/* Clear the attention bit */
/* Clean up the mailbox area */
break;
} /* switch (flag) */
} /* emlxs_sli3_issue_mbox_cmd() */
#ifdef SFCT_SUPPORT
/*ARGSUSED*/
static uint32_t
int channel)
{
/* Get the iotag by registering the packet */
if (!iotag) {
/* No more command slots available, retry later */
"Adapter Busy. Unable to allocate iotag. did=0x%x",
return (IOERR_NO_RESOURCES);
}
/* Point of no return */
cp->ulpSendCmd++;
/* Initalize iocbq */
/*
* Don't give the abort priority, we want the IOCB
* we are aborting to be processed first.
*/
/* Create the abort IOCB */
} else {
/* Create the close IOCB */
}
iocb->ULPRSVDBYTE =
/* Set the pkt timer */
return (IOERR_SUCCESS);
cp->ulpSendCmd++;
/* Initalize iocbq */
#if (EMLXS_MODREV >= EMLXS_MODREV3)
#else
#endif /* >= EMLXS_MODREV3 */
} else { /* SLI3 */
iocb->ULPBDECOUNT = 0;
}
/* Initalize iocb */
iocb->ULPRSVDBYTE =
/* Set the pkt timer */
if (pkt->pkt_cmdlen) {
}
return (IOERR_SUCCESS);
}
/* Unregister the packet */
"Adapter Busy. Unable to setup buffer list. did=%x", did);
return (IOERR_INTERNAL_ERROR);
}
timeout =
} else {
timeout = 0x80000000;
}
/* Initalize iocbq */
/* Initalize iocb */
} else { /* TF_READ_DATA */
(dbuf->db_data_size >=
/* enable auto-rsp AP feature */
}
}
return (IOERR_SUCCESS);
} /* emlxs_sli3_prep_fct_iocb() */
#endif /* SFCT_SUPPORT */
/* ARGSUSED */
static uint32_t
{
/* Find target node object */
/* Get the iotag by registering the packet */
if (!iotag) {
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to allocate iotag: did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* Initalize iocbq */
/* Indicate this is a FCP cmd */
/* Unregister the packet */
"Adapter Busy. Unable to setup buffer list. did=%x", did);
return (FC_TRAN_BUSY);
}
/* Point of no return */
/* Initalize iocb */
iocb->ULPRSVDBYTE =
case FC_TRAN_CLASS1:
break;
case FC_TRAN_CLASS2:
/* iocb->ULPCLASS = CLASS3; */
break;
case FC_TRAN_CLASS3:
default:
break;
}
/* if device is FCP-2 device, set the following bit */
/* that says to run the FC-TAPE protocol. */
}
if (pkt->pkt_datalen == 0) {
} else {
}
return (FC_SUCCESS);
} /* emlxs_sli3_prep_fcp_iocb() */
static uint32_t
{
/* Get the iotag by registering the packet */
if (!iotag) {
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to allocate iotag: did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* Initalize iocbq */
/* Unregister the packet */
"Adapter Busy. Unable to setup buffer list. did=%x", did);
return (FC_TRAN_BUSY);
}
/* Point of no return */
/* Initalize iocb */
}
}
/* network headers */
iocb->ULPRSVDBYTE =
iocb->ULPCONTEXT = 0;
}
}
} else {
}
case FC_TRAN_CLASS1:
break;
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli3_prep_ip_iocb() */
static uint32_t
{
/* Get the iotag by registering the packet */
if (!iotag) {
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to allocate iotag. did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* Initalize iocbq */
/* Unregister the packet */
"Adapter Busy. Unable to setup buffer list. did=%x", did);
return (FC_TRAN_BUSY);
}
/* Point of no return */
/* Initalize iocb */
/* ELS Response */
} else {
/* ELS Request */
iocb->ULPCONTEXT =
cmd &= ELS_CMD_MASK;
if ((cmd == ELS_CMD_FLOGI) ||
(cmd == ELS_CMD_FDISC)) {
} else {
}
}
}
}
iocb->ULPRSVDBYTE =
case FC_TRAN_CLASS1:
break;
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli3_prep_els_iocb() */
static uint32_t
{
/* Get the iotag by registering the packet */
if (!iotag) {
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to allocate iotag. did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* Unregister the packet */
"Adapter Busy. Unable to setup buffer list. did=%x", did);
return (FC_TRAN_BUSY);
}
/* Point of no return */
/* Initalize iocbq */
/* Fill in rest of iocb */
}
}
/* Initalize iocb */
/* CT Response */
} else {
/* CT Request */
}
iocb->ULPRSVDBYTE =
case FC_TRAN_CLASS1:
break;
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli3_prep_ct_iocb() */
#ifdef SFCT_SUPPORT
static uint32_t
{
"fct_bde_setup: Only 1 sglist entry supported: %d",
return (1);
}
} else {
}
return (rval);
} /* emlxs_fct_bde_setup() */
#endif /* SFCT_SUPPORT */
static uint32_t
{
} else {
}
return (rval);
} /* emlxs_bde_setup() */
static void
{
/* Check attention bits once and process if required */
if (ha_copy == 0) {
return;
}
return;
} /* emlxs_sli3_poll_intr() */
#ifdef MSI_SUPPORT
static uint32_t
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
* "sli3_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) {
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
}
return (DDI_INTR_CLAIMED);
} /* emlxs_sli3_msi_intr() */
#endif /* MSI_SUPPORT */
static int
{
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_sli3_intx_intr() */
/* EMLXS_PORT_LOCK must be held when call this routine */
static uint32_t
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
#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) {
}
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return (ha_copy);
} /* emlxs_get_attention() */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
/* ha_copy should be pre-filtered */
/*
* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
* "proc_attention: ha_copy=%x", ha_copy);
*/
return;
}
if (!ha_copy) {
return;
}
}
/* 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 */
#ifdef FMA_SUPPORT
/* Access handle validation */
}
#endif /* FMA_SUPPORT */
return;
} /* emlxs_proc_attention() */
/*
* emlxs_handle_ff_error()
*
* Description: Processes a FireFly error
* Runs at Interrupt level
*/
static void
{
int i = 0;
/* do what needs to be done, get error from STATUS REGISTER */
/* Clear Chip error bit */
/* If HS_FFER1 is set, then wait until the HS_FFER1 bit clears */
"HS_FFER1 received");
status =
BUSYWAIT_MS(1000);
i++;
}
}
if (i == 300) {
/* 5 minutes is up, shutdown HBA */
"HS_FFER1 clear timeout");
goto done;
}
"HS_FFER1 cleared");
if (status & HS_OVERTEMP) {
status1 =
"Maximum adapter temperature exceeded (%d �C).", status1);
} else {
status1 =
status2 =
"Host Error Attention: "
"status=0x%x status1=0x%x status2=0x%x",
} else {
}
}
done:
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return;
} /* emlxs_handle_ff_error() */
/*
* emlxs_sli3_handle_link_event()
*
* Description: Process a Link Attention.
*/
static void
{
int rc;
/* Make sure link is declared down */
/* Get a buffer which will be used for mailbox commands */
/* Get link attention message */
MBX_NOWAIT, 0);
(void *)mbq);
}
/*
* Clear Link Attention in HA REG
*/
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
} else {
}
}
} /* emlxs_sli3_handle_link_event() */
/*
* emlxs_sli3_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.
*/
offset =
/* While ring is not empty */
/* Get the next response ring iocb */
entry =
/* 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=%d cmd=%x status=%x",
goto next;
}
#ifdef SFCT_SUPPORT
case CMD_CLOSE_XRI_CX:
case CMD_CLOSE_XRI_CN:
case CMD_ABORT_XRI_CX:
}
break;
#endif /* SFCT_SUPPORT */
/* 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:
sbp =
break;
}
/* If packet is stale, then drop it. */
if (sbp == STALE_PACKET) {
cp->hbaCmplCmd_sbp++;
/* Copy entry to the local iocbq */
"channelno=%d iocb=%p cmd=%x status=%x "
"error=%x iotag=%d context=%x info=%x",
goto next;
}
/*
* If a packet was found, then queue the packet's
* iocb for deferred processing
*/
else if (sbp) {
#ifdef SFCT_SUPPORT
if (fct_cmd) {
cmd_sbp =
}
#endif /* SFCT_SUPPORT */
cp->hbaCmplCmd_sbp++;
#ifdef NODE_THROTTLE_SUPPORT
}
#endif /* NODE_THROTTLE_SUPPORT */
/* Copy entry to sbp's iocbq */
/*
* If this is NOT a polled command completion
* or a driver allocated pkt, then defer pkt
* completion.
*/
(PACKET_POLLED | PACKET_ALLOCATED))) {
/* Add the IOCB to the local list */
if (!rsp_head) {
} else {
}
goto next;
}
} else {
cp->hbaCmplCmd++;
/* Copy entry to the local iocbq */
}
/* process the channel 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 */
} else {
ioa2 =
1) * sizeof (uint32_t)));
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
}
if (reg & HA_R0RE_REQ) {
/* HBASTATS.chipRingFree++; */
/* Tell the adapter we serviced the ring */
(channel_no * 4));
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
}
}
/* HBASTATS.hostRingFree++; */
/* Cmd ring may be available. Try sending more iocbs */
}
/* HBASTATS.ringEvent++; */
return;
} /* emlxs_sli3_handle_ring_event() */
extern int
{
switch (channelno) {
#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:
"channel=%d cmd=%x %s %x %x %x %x",
return (1);
}
sizeof (error_str));
iocb->ULPBDECOUNT = 0;
sizeof (error_str));
iocb->ULPBDECOUNT = 0;
goto done;
sizeof (error_str));
iocb->ULPBDECOUNT = 0;
goto done;
} else {
sizeof (error_str));
}
goto failed;
}
(*UbPosted)--;
"Invalid HBQE iotag=%d:", hbqe_tag);
goto dropped;
}
} else {
bdeAddr =
/* Check for invalid buffer */
sizeof (error_str));
goto dropped;
}
}
if (!mp) {
sizeof (error_str));
goto dropped;
}
#ifdef FMA_SUPPORT
if (mp->dma_handle) {
!= DDI_FM_OK) {
"handle_rcv_seq: hdl=%p",
mp->dma_handle);
goto dropped;
}
}
#endif /* FMA_SUPPORT */
if (!size) {
goto dropped;
}
/* To avoid we drop the broadcast packets */
if (channelno != FC_IP_RING) {
/* Get virtual port */
"Invalid VPI=%d:", vpi);
goto dropped;
}
}
}
/* Process request */
switch (channelno) {
case FC_FCT_RING:
sizeof (error_str));
goto dropped;
#ifdef SFCT_SUPPORT
size);
#endif /* SFCT_SUPPORT */
} else {
goto dropped;
}
break;
case FC_IP_RING:
#ifdef SFCT_SUPPORT
sizeof (error_str));
goto dropped;
#endif /* SFCT_SUPPORT */
} else {
goto dropped;
}
break;
case FC_ELS_RING:
size);
#ifdef SFCT_SUPPORT
size);
#endif /* SFCT_SUPPORT */
} else {
goto dropped;
}
break;
case FC_CT_RING:
break;
}
goto done;
(*RcvDropped)++;
"%s: cmd=%x %s %x %x %x %x",
if (channelno == FC_FCT_RING) {
if (! ndlp) {
goto done;
}
} else {
}
}
goto done;
(*RcvError)++;
"%s: cmd=%x %s %x %x %x %x hba:%x %x",
done:
if (iocb->ULPBDECOUNT) {
}
} else {
if (mp) {
}
if (iocb->ULPBDECOUNT) {
}
}
return (0);
} /* emlxs_handle_rcv_seq() */
/* 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 */
}
#ifdef NODE_THROTTLE_SUPPORT
}
#endif /* NODE_THROTTLE_SUPPORT */
#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
icmd->ULPCOMMAND);
}
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */
} else {
}
/* get the next available command ring iocb */
iocb =
/* Copy the local iocb to the command ring iocb */
/* DMA sync the command ring iocb for the adapter */
/*
* After this, the sbp / iocb should not be
* accessed in the xmit path.
*/
/* Free the local iocb if there is no sbp tracking it */
if (!sbp) {
}
/* update local ring index to next available ring index */
return;
} /* emlxs_sli3_issue_iocb() */
static void
{
uint32_t j;
/* Perform adapter interlock to kill adapter */
interlock_failed = 0;
return;
}
j = 0;
while (j++ < 10000) {
if (hba->mbox_queue_flag == 0) {
break;
}
BUSYWAIT_US(100);
}
if (hba->mbox_queue_flag != 0) {
"Interlock failed. Mailbox busy.");
return;
}
/* Disable all host interrupts */
goto mode_B;
}
"Attempting SLIM2 Interlock...");
value = 0x55555555;
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 == 0xAAAAAAAA) {
break;
}
BUSYWAIT_US(50);
}
if (value == 0xAAAAAAAA) {
/* Now wait for mailbox ownership to clear */
while (j++ < 10000) {
word0 =
break;
}
BUSYWAIT_US(50);
}
"Interlock succeeded.");
goto done;
}
/* Interlock failed !!! */
interlock_failed = 1;
"Attempting SLIM1 Interlock...");
value = 0x55555555;
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 == 0xAAAAAAAA) {
break;
}
BUSYWAIT_US(50);
}
if (value == 0xAAAAAAAA) {
/* Now wait for mailbox ownership to clear */
while (j++ < 10000) {
word0 =
break;
}
BUSYWAIT_US(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;
}
BUSYWAIT_US(50);
}
"Interlock failed. Board killed.");
} else {
"Interlock failed. Board not killed.");
}
done:
hba->mbox_queue_flag = 0;
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return;
} /* emlxs_sli3_hba_kill() */
static void
{
uint32_t j;
/* Disable all host interrupts */
value = 0x55555555;
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 == 0xAAAAAAAA) {
break;
}
BUSYWAIT_US(50);
}
if (value == 0xAAAAAAAA) {
/* Now wait for mailbox ownership to clear */
while (j++ < 10000) {
word0 =
break;
}
BUSYWAIT_US(50);
}
goto done;
}
done:
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return;
} /* emlxs_sli3_hba_kill4quiesce */
/*
* emlxs_handle_mb_event
*
* Description: Process a Mailbox Attention.
* Called from host_interrupt to process MBATT
*
* Returns:
*
*/
static uint32_t
{
uint32_t i;
int rc;
switch (hba->mbox_queue_flag) {
case 0:
"No mailbox active.");
return (0);
case MBX_POLL:
/* Mark mailbox complete, this should wake up any polling */
/* threads. This can happen if interrupts are enabled while */
/* a polled mailbox command is outstanding. If we don't set */
/* MBQ_COMPLETED here, the polling thread may wait until */
/* timeout error occurs */
if (mbq) {
"Mailbox event. Completing Polled command.");
}
return (0);
case MBX_SLEEP:
case MBX_NOWAIT:
/* Check mbox_timer, it acts as a service flag too */
/* The first to service the mbox queue will clear the timer */
if (hba->mbox_timer) {
hba->mbox_timer = 0;
}
if (!mbq) {
"Mailbox event. No service required.");
return (0);
}
break;
default:
"Invalid Mailbox flag (%x).");
return (0);
}
/* Set port context */
/* Get first word of mailbox */
sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
} else {
}
i = 0;
if (i++ > 10000) {
"OWN_CHIP: %s: status=%x",
return (1);
}
/* Get first word of mailbox */
} else {
word0 =
}
}
/* Now that we are the owner, DMA Sync entire mailbox if needed */
} else {
}
#ifdef MBOX_EXT_SUPPORT
} else {
}
}
#endif /* MBOX_EXT_SUPPORT */
#ifdef FMA_SUPPORT
/* Access handle validation */
}
#endif /* FMA_SUPPORT */
/* Now sync the memory buffer if one was used */
}
/* Mailbox has been completely received at this point */
hba->heartbeat_active = 0;
goto done;
}
"Received. %s: status=%x Sleep.",
}
} else {
"Completed. %s: status=%x",
}
}
/* Filter out passthru mailbox */
goto done;
}
}
/* If mbox was retried, return immediately */
if (rc) {
return (0);
}
}
done:
/* Clean up the mailbox area */
if (mbq) {
/* Attempt to send pending mailboxes */
}
}
return (0);
} /* emlxs_handle_mb_event() */
static void
{
/* Perform SLI3 level timer checks */
} /* emlxs_sli3_timer() */
static void
{
return;
}
/* Return if timer hasn't expired */
return;
}
/* Mailbox timed out, first check for error attention */
hba->mbox_timer = 0;
return;
}
if (hba->mbox_queue_flag) {
/* Get first word of mailbox */
offset =
} else {
word0 =
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
}
/* Check if mailbox has actually completed */
/* Read host attention register to determine */
/* interrupt source */
"Mailbox attention missed: %s. Forcing event. "
(void) emlxs_handle_mb_event(hba);
return;
}
/* The first to service the mbox queue will clear the timer */
/* We will service the mailbox here */
hba->mbox_timer = 0;
}
if (mb) {
switch (hba->mbox_queue_flag) {
case MBX_NOWAIT:
"%s: Nowait.",
break;
case MBX_SLEEP:
"%s: mb=%p Sleep.",
mb);
break;
case MBX_POLL:
"%s: mb=%p Polled.",
mb);
break;
default:
"%s: mb=%p (%d).",
break;
}
} else {
}
/* Perform mailbox cleanup */
/* This will wake any sleeping or polling threads */
/* Trigger adapter shutdown */
return;
} /* emlxs_sli3_timer_check_mbox() */
/*
* emlxs_mb_config_port Issue a CONFIG_PORT mailbox command
*/
static uint32_t
{
uint32_t i;
/* Set Host pointers in SLIM flag */
/* Initialize hba structure for assumed default SLI2 mode */
/* If config port succeeds, then we will update it then */
if (sli_mode == EMLXS_HBA_SLI3_MODE) {
MAX_VPORTS - 1;
} else {
MAX_VPORTS_LIMITED - 1;
}
} else {
"CFGPORT: Firmware does not support NPIV. "
}
}
}
/*
* Now setup pcb
*/
sizeof (MAILBOX) + MBOX_EXTENSION_SIZE;
/*
* Set up HGP - Port Memory
*
* CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
* RR0Get 0xc4 0x84
* CR1Put 0xc8 0x88
* RR1Get 0xcc 0x8c
* CR2Put 0xd0 0x90
* RR2Get 0xd4 0x94
* CR3Put 0xd8 0x98
* RR3Get 0xdc 0x9c
*
* Reserved 0xa0-0xbf
*
* If HBQs configured:
* HBQ 0 Put ptr 0xc0
* HBQ 1 Put ptr 0xc4
* HBQ 2 Put ptr 0xc8
* ...
* HBQ(M-1)Put Pointer 0xc0+(M-1)*4
*/
if (sli_mode >= EMLXS_HBA_SLI3_MODE) {
/* ERBM is enabled */
} else { /* SLI2 */
/* ERBM is disabled */
}
/* The Sbus card uses Host Memory. The PCI card uses SLIM POINTER */
} else {
Laddr =
Laddr &= ~0x4;
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
}
offset = 0;
for (i = 0; i < 4; i++) {
/* Setup command ring */
rp->fc_cmdringaddr =
/* Setup response ring */
rp->fc_rspringaddr =
}
sizeof (PCB));
sizeof (PCB), DDI_DMA_SYNC_FORDEV);
return (0);
} /* emlxs_mb_config_port() */
static uint32_t
{
void *ioa2;
uint32_t j;
switch (hbq_id) {
case EMLXS_ELS_HBQ_ID:
seg = MEM_ELSBUF;
break;
case EMLXS_IP_HBQ_ID:
ringno = FC_IP_RING;
break;
case EMLXS_CT_HBQ_ID:
ringno = FC_CT_RING;
break;
#ifdef SFCT_SUPPORT
case EMLXS_FCT_HBQ_ID:
seg = MEM_FCTBUF;
break;
#endif /* SFCT_SUPPORT */
default:
"hbq_setup: Invalid HBQ id. (%x)", hbq_id);
return (1);
}
/* Configure HBQ */
/* Get a Mailbox buffer to setup mailbox commands for CONFIG_HBQ */
"hbq_setup: Unable to get mailbox.");
return (1);
}
/* Allocate HBQ Host buffer and Initialize the HBQEs */
"hbq_setup: Unable to allocate HBQ.");
return (1);
}
/* 0=all, 7=logentry */
/* HBQ to a ring */
/* Ring0=b0001, Ring1=b0010, */
/* Ring2=b0100 */
/* be used for */
hbq->HBQ_PutIdx_next = 0;
hbq->HBQ_GetIdx = 0;
/* Fill in POST BUFFERs in HBQE */
/* Allocate buffer to post */
seg)) == 0) {
"hbq_setup: Unable to allocate HBQ buffer. "
"cnt=%d", j);
return (1);
}
}
/* Issue CONFIG_HBQ */
"hbq_setup: Unable to config HBQ. cmd=%x status=%x",
return (1);
}
#ifdef FMA_SUPPORT
/* Access handle validation */
!= DDI_FM_OK) {
return (1);
}
#endif /* FMA_SUPPORT */
return (0);
} /* emlxs_hbq_setup() */
extern void
{
uint32_t j;
switch (hbq_id) {
case EMLXS_ELS_HBQ_ID:
seg = MEM_ELSBUF;
HBASTATS.ElsUbPosted = 0;
break;
case EMLXS_IP_HBQ_ID:
HBASTATS.IpUbPosted = 0;
break;
case EMLXS_CT_HBQ_ID:
HBASTATS.CtUbPosted = 0;
break;
#ifdef SFCT_SUPPORT
case EMLXS_FCT_HBQ_ID:
seg = MEM_FCTBUF;
HBASTATS.FctUbPosted = 0;
break;
#endif /* SFCT_SUPPORT */
default:
return;
}
for (j = 0; j < hbq->HBQ_PostBufCnt; j++) {
(void *)hbq->HBQ_PostBufs[j]);
}
hbq->HBQ_PostBufCnt = 0;
}
return;
} /* emlxs_hbq_free_all() */
extern void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
void *ioa2;
switch (hbq_id) {
case EMLXS_ELS_HBQ_ID:
break;
case EMLXS_IP_HBQ_ID:
break;
case EMLXS_CT_HBQ_ID:
break;
#ifdef SFCT_SUPPORT
case EMLXS_FCT_HBQ_ID:
break;
#endif /* SFCT_SUPPORT */
default:
return;
}
hbq->HBQ_PutIdx =
return;
}
}
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return;
} /* emlxs_update_HBQ_index() */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
/* Enable mailbox, error attention interrupts */
/* Enable ring interrupts */
status |=
status |= (HC_R0INT_ENA);
}
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
} /* emlxs_sli3_enable_intr() */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
} /* emlxs_enable_latt() */
static void
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
/* Disable all adapter interrupts */
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
} /* emlxs_sli3_disable_intr() */
static uint32_t
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return (ha_copy);
} /* emlxs_check_attention() */
static void
{
/* Adapter error */
}
} /* emlxs_sli3_poll_erratt() */
static uint32_t
{
int32_t i;
if (control == 0) {
/* Special handle for vport PLOGI */
}
return (0);
}
return (1);
}
}
/* Special handle for vport PLOGI */
}
return (0);
}
if (!mp) {
return (0);
}
/* First copy command data */
/* Create or update the node */
/*
* Fake a mailbox error, so the mbox_fini
* can take appropriate action
*/
}
/* This must be (0xFFFFFE) which was registered by vport */
if (lrpi == 0) {
return (0);
}
"reg_did_mbcmpl:failed. Unable to allocate mbox");
return (0);
}
"reg_did_mbcmpl:failed. Unable to send request.");
return (0);
}
return (0);
}
/* If CLEAR_LA has been sent, then attempt to */
/* register the vpi now */
}
/*
* If NPIV Fabric support has just been established on
* the physical port, then notify the vports of the
* link up
*/
if ((lvpi == 0) &&
/* Skip the physical port */
for (i = 1; i < MAX_VPORTS; i++) {
continue;
}
}
}
}
/* Check for special restricted login flag */
return (0);
}
/* Needed for FCT trigger in emlxs_mb_deferred_cmpl */
}
#ifdef DHCHAP_SUPPORT
/* Auth started - auth completion will */
/* handle sbp and ubp now */
}
}
#endif /* DHCHAP_SUPPORT */
return (0);
} /* emlxs_sli3_reg_did_mbcmpl() */
static uint32_t
{
/* Check for invalid node ids to register */
return (1);
}
if (did & 0xff000000) {
return (1);
}
"Invalid service parameters. did=%06x rval=%d", did,
rval);
return (1);
}
/* Check if the node limit has been reached */
"Limit reached. did=%06x count=%d", did,
port->node_count);
return (1);
}
"Unable to allocate mailbox. did=%x", did);
return (1);
}
/* Build login request */
"Unable to allocate buffer. did=%x", did);
return (1);
}
"Unable to send mbox. did=%x", did);
return (1);
}
return (0);
} /* emlxs_sli3_reg_did() */
/*ARGSUSED*/
static uint32_t
{
"unreg_node_mbcmpl:failed. node=%p rpi=%d status=%x",
return (0);
}
"unreg_node_mbcmpl: node=%p rpi=%d",
if (node) {
} else { /* All nodes */
}
return (0);
} /* emlxs_sli3_unreg_node_mbcmpl */
static uint32_t
{
if (node) {
/* Check for base node */
/* just flush base node */
0, 0, 0);
(void) emlxs_chipq_node_flush(port, 0,
/* Return now */
return (1);
}
/* This node must be (0xFFFFFE) which registered by vport */
if (rpi == 0) {
return (0);
}
} else { /* Unreg all nodes */
rpi = 0xffff;
"unreg_node: All");
}
"unreg_node:failed. Unable to allocate mbox");
return (1);
}
"unreg_node:failed. Unable to send request.");
return (1);
}
return (0);
} /* emlxs_sli3_unreg_node() */