emlxs_sli4.c revision e2ca2865a6870e9c6cbef6becbcc68cafde64537
/*
* 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 2009 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#include <emlxs.h>
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
char *prog_types);
extern int emlxs_pci_model_count;
extern emlxs_model_t emlxs_pci_model[];
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_check_hdw_ready(emlxs_hba_t *);
/* Define SLI4 API functions */
#ifdef SFCT_SUPPORT
#else
NULL,
#endif /* SFCT_SUPPORT */
};
/* ************************************************************************** */
/*
* emlxs_sli4_online()
*
* This routine will start initialization of the SLI4 HBA.
*/
static int32_t
{
uint32_t i;
uint32_t j;
/* Set the fw_check flag */
hba->mbox_queue_flag = 0;
/* Target mode not supported */
"Target mode not supported in SLI4.");
return (ENOMEM);
}
/* Networking not supported */
"Networking not supported in SLI4, turning it off");
}
"Max channels exceeded, dropping num-wq from %d to 1",
}
/* Default channel for everything else is the last channel */
hba->channel_tx_count = 0;
/* Initialize the local dump region buffer */
"Unable to allocate dump region buffer.");
return (ENOMEM);
}
/*
* Get a buffer which will be used repeatedly for mailbox commands
*/
/* Reset & Initialize the adapter */
if (emlxs_sli4_hba_init(hba)) {
"Unable to init hba.");
goto failed1;
}
#ifdef FMA_SUPPORT
/* Access handle validation */
!= DDI_FM_OK) ||
!= DDI_FM_OK) ||
!= DDI_FM_OK)) {
goto failed1;
}
#endif /* FMA_SUPPORT */
/*
* 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",
goto failed1;
}
"Invalid read rev Version for SLI4: 0x%x",
goto failed1;
}
case EMLXS_DCBX_MODE_CIN: /* Mapped to nonFIP mode */
break;
case EMLXS_DCBX_MODE_CEE: /* Mapped to FIP mode */
break;
default:
"Invalid read rev dcbx mode for SLI4: 0x%x",
goto failed1;
}
/* Save information as VPD data */
/* Decode FW labels */
} else {
}
"VPD ULP:%08x %s ARM:%08x %s f:%d %d %d %d : dcbx %d",
/* No key information is needed for SLI4 products */
/* Get adapter VPD information */
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
} else {
"VPD dumped. rsp_cnt=%d status=%x",
}
}
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) {
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 SSDID:0x%x Model:%s",
goto failed1;
}
/* Get fcode version property */
/*
* 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_fw_count; i++) {
fw = &emlxs_fw_table[i];
break;
}
}
/*
* If the image was found, then verify current firmware
* versions of adapter
*/
if (fw) {
/* Obtain current firmware version info */
} else {
}
"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 (emlxs_fw_download(hba,
"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 means either the adapter database is not
* correct or a firmware image is missing from the
* compile
*/
"Firmware image unavailable. id=%d fw=%d",
}
}
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
} else {
"FCOE info dumped. rsp_cnt=%d status=%x",
(void) emlxs_parse_fcoe(hba,
}
/* Reuse mbq from previous mbox */
"Unable to REQUEST_FEATURES. Mailbox cmd=%x status=%x",
goto failed1;
}
/* Make sure we get the features we requested */
"Unable to get REQUESTed_FEATURES. want:x%x got:x%x",
goto failed1;
}
}
/* Check enable-npiv driver parameter for now */
}
/* Reuse mbq from previous mbox */
"Unable to READ_CONFIG. Mailbox cmd=%x status=%x",
goto failed1;
}
}
/* Set the max node count */
} else {
}
/* Set the io throttle */
/* Save the link speed capabilities */
/*
* Allocate some memory for buffers
*/
if (emlxs_mem_alloc_buffer(hba) == 0) {
"Unable to allocate memory buffers.");
goto failed1;
}
/*
* OutOfRange (oor) iotags are used for abort or close
* XRI commands or any WQE that does not require a SGL
*/
if (emlxs_sli4_resource_alloc(hba)) {
"Unable to allocate resources.");
goto failed2;
}
#if (EMLXS_MODREV >= EMLXS_MODREV5)
}
#endif /* >= EMLXS_MODREV5 */
/* Reuse mbq from previous mbox */
"Unable to post sgl pages.");
goto failed3;
}
/* Reuse mbq from previous mbox */
"Unable to post header templates.");
goto failed3;
}
/*
* 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 failed3;
}
/* Reuse mbq from previous mbox */
/* This MUST be done after EMLXS_INTR_ADD */
"Unable to create queues.");
goto failed3;
}
/* Get and save the current firmware version (based on sli_mode) */
/*
* Setup and issue mailbox RUN BIU DIAG command Setup test buffers
*/
"Unable to allocate diag buffers.");
goto failed3;
}
/* Reuse mbq from previous mbox */
/*
* We need to get login parameters for NID
*/
"Unable to read parameters. Mailbox cmd=%x status=%x",
goto failed3;
}
/* 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 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",
/* Reuse mbq from previous mbox */
/*
* Setup and issue mailbox INITIALIZE LINK command
* At this point, the interrupt will be generated by the HW
* Do this only if persist-linkdown is not set
*/
!= MBX_SUCCESS) {
"Unable to initialize link. " \
"Mailbox cmd=%x status=%x",
goto failed3;
}
/* Wait for link to come up */
/* Check for hardware error */
goto failed3;
}
DELAYMS(1000);
i--;
}
}
/*
* The leadvile driver will now handle the FLOGI at the driver level
*/
return (0);
if (mp) {
}
if (mp1) {
}
(void) EMLXS_INTR_REMOVE(hba);
}
(void) emlxs_mem_free_buffer(hba);
if (mbq) {
}
}
if (rval == 0) {
}
return (rval);
} /* emlxs_sli4_online() */
static void
{
/* Reverse emlxs_sli4_online */
/* This is the only way to disable interupts */
MBX_WAIT, 0) != MBX_SUCCESS) {
/* Timeout occurred */
"Timeout: Offline RESET");
}
(void) emlxs_check_hdw_ready(hba);
} else {
}
/* Shutdown the adapter interface */
/* Free SLI shared memory */
/* Free driver shared memory */
(void) emlxs_mem_free_buffer(hba);
/* Free the host dump region buffer */
} /* emlxs_sli4_offline() */
/*ARGSUSED*/
static int
{
int status;
/*
* Map in Hardware BAR pages that will be used for
* communication with HBA.
*/
if (status != DDI_SUCCESS) {
"(PCI) ddi_regs_map_setup BAR1 failed. "
"stat=%d mem=%p attr=%p hdl=%p",
goto failed;
}
}
if (status != DDI_SUCCESS) {
"ddi_regs_map_setup BAR2 failed. status=%x",
status);
goto failed;
}
}
goto failed;
}
}
/* offset from beginning of register space */
return (0);
return (ENOMEM);
} /* emlxs_sli4_map_hdw() */
/*ARGSUSED*/
static void
{
/*
* Free map for Hardware BAR pages that were used for
* communication with HBA.
*/
}
}
}
}
return;
} /* emlxs_sli4_unmap_hdw() */
static int
{
uint32_t i = 0;
/* Wait for reset completion */
while (i < 30) {
/* Check Semaphore register to see what the ARM state is */
/* Check to see if any errors occurred during init */
if (status & ARM_POST_FATAL) {
"SEMA Error: status=0x%x", status);
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return (1);
}
/* ARM Ready !! */
"ARM Ready: status=0x%x", status);
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return (0);
}
DELAYMS(1000);
i++;
}
/* Timeout occurred */
"Timeout waiting for READY: status=0x%x", status);
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
/* Log a dump event - not supported */
return (2);
} /* emlxs_check_hdw_ready() */
static uint32_t
{
/* Wait for reset completion, tmo is in 10ms ticks */
while (tmo) {
/* Check Semaphore register to see what the ARM state is */
/* Check to see if any errors occurred during init */
if (status & BMBX_READY) {
"BMBX Ready: status=0x%x", status);
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
return (tmo);
}
DELAYMS(10);
tmo--;
}
/* Timeout occurred */
"Timeout waiting for BMailbox: status=0x%x", status);
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
/* Log a dump event - not supported */
return (0);
} /* emlxs_check_bootstrap_ready() */
static uint32_t
{
/*
* This routine assumes the bootstrap mbox is loaded
* with the mailbox command to be executed.
*
* First, load the high 30 bits of bootstrap mailbox
*/
addr30 |= BMBX_ADDR_HI;
if (tmo == 0) {
return (0);
}
/* Load the low 30 bits of bootstrap mailbox */
if (tmo == 0) {
return (0);
}
"BootstrapMB: %p Completed %08x %08x %08x",
return (tmo);
} /* emlxs_issue_bootstrap_mb() */
static int
{
#ifdef FMA_SUPPORT
#endif /* FMA_SUPPORT */
if (emlxs_check_hdw_ready(hba)) {
return (1);
}
return (0); /* Already initialized */
}
/* NOTE: tmo is in 10ms ticks */
if (tmo == 0) {
return (1);
}
/* Special words to initialize bootstrap mbox MUST be little endian */
return (1);
}
return (0);
} /* emlxs_init_bootstrap_mb() */
static uint32_t
{
int rc;
uint32_t i;
/* Restart the adapter */
return (1);
}
for (i = 0; i < hba->chan_count; i++) {
}
/* Initialize all the port objects */
for (i = 0; i < MAX_VPORTS; i++) {
}
/* Set the max node count */
} else {
}
}
if (rc) {
return (rc);
}
return (0);
} /* emlxs_sli4_hba_init() */
/*ARGSUSED*/
static uint32_t
{
uint32_t i;
"Adapter reset disabled.");
return (1);
}
if (quiesce == 0) {
/*
* Initalize Hardware that will be used to bring
* SLI4 online.
*/
if (rc) {
return (rc);
}
}
if (quiesce == 0) {
MBX_POLL, 0) != MBX_SUCCESS) {
/* Timeout occurred */
"Timeout: RESET");
/* Log a dump event - not supported */
return (1);
}
} else {
MBX_POLL, 0) != MBX_SUCCESS) {
/* Log a dump event - not supported */
return (1);
}
}
/* 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 port objects */
for (i = 0; i < MAX_VPORTS; i++) {
vport->node_count = 0;
}
}
if (emlxs_check_hdw_ready(hba)) {
return (1);
}
return (0);
} /* emlxs_sli4_hba_reset */
#define SGL_CMD 0
#define SGL_RESP 1
#define SGL_DATA 2
#define SGL_LAST 0x80
/*ARGSUSED*/
{
#ifdef DEBUG_SGE
#endif
uint_t i;
#if (EMLXS_MODREV >= EMLXS_MODREV3)
switch (sgl_type) {
case SGL_CMD:
break;
case SGL_RESP:
break;
case SGL_DATA:
break;
}
#else
switch (sgl_type) {
case SGL_CMD:
cookie_cnt = 1;
break;
case SGL_RESP:
cookie_cnt = 1;
break;
case SGL_DATA:
cookie_cnt = 1;
break;
}
#endif /* >= EMLXS_MODREV3 */
cnt = 0;
if (cnt) {
/* Copy staged SGE before we build next one */
sge++;
}
}
#ifdef DEBUG_SGE
4, 0);
#endif
}
}
if (last) {
}
sizeof (ULP_SGE64));
sge++;
return (sge);
} /* emlxs_pkt_to_sgl */
/*ARGSUSED*/
{
#if (EMLXS_MODREV >= EMLXS_MODREV3)
#else
#endif /* >= EMLXS_MODREV3 */
return (1);
}
/* CMD payload */
/* DATA payload */
if (pkt->pkt_datalen != 0) {
/* RSP payload */
/* Data portion */
} else {
/* RSP payload */
}
} else {
/* CMD payload */
} else {
/* CMD payload */
/* RSP payload */
}
}
return (0);
} /* emlxs_sli4_bde_setup */
/*ARGSUSED*/
static uint32_t
{
return (0);
} /* emlxs_sli4_fct_bde_setup */
static void
{
#ifdef SLI4_FASTPATH_DEBUG
#endif
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 {
}
} 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;
}
}
/* Check to see if we have room for this WQE */
next_wqe = 0;
}
/* 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 {
}
/* Process each iocbq */
while (iocbq) {
#ifdef SLI4_FASTPATH_DEBUG
#endif
if (sbp) {
/* If exchange removed after wqe was prep'ed, drop it */
"Xmit WQE iotag: %x xri: %x aborted",
/* Get next iocb from the tx queue */
continue;
}
/* Perform delay */
drv_usecwait(100000);
} else {
drv_usecwait(20000);
}
}
}
/*
* At this point, we have a command ring slot available
* and an iocb to send
*/
wq->release_depth--;
if (wq->release_depth == 0) {
}
/* Check for ULP pkt request */
if (sbp) {
/* Set node to base node by default */
}
}
/* Free the local iocb if there is no sbp tracking it */
if (sbp) {
#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
icmd->ULPCOMMAND);
}
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */
cp->hbaSendCmd_sbp++;
} else {
cp->hbaSendCmd++;
}
/* Send the iocb */
sizeof (emlxs_wqe_t));
#ifdef DEBUG_WQE
#endif
4096, DDI_DMA_SYNC_FORDEV);
/* Ring the WQ Doorbell */
#ifdef SLI4_FASTPATH_DEBUG
"WQ RING: %08x", wqdb);
#endif
/*
* After this, the sbp / iocb / wqe should not be
* accessed in the xmit path.
*/
if (!sbp) {
}
/* Check if HBA is full */
if (throttle <= 0) {
goto busy;
}
}
/* Check to see if we have room for another WQE */
next_wqe++;
next_wqe = 0;
}
/* Queue it for later */
goto busy;
}
/* Get the next iocb from the tx queue if there is one */
}
return;
busy:
if (throttle <= 0) {
} else {
}
return;
} /* emlxs_sli4_issue_iocb_cmd() */
/*ARGSUSED*/
static uint32_t
{
/*
* If this is an embedded mbox, everything should fit
* into the mailbox area.
*/
4096, DDI_DMA_SYNC_FORDEV);
} else {
/* SLI_CONFIG and non-embedded */
/*
* If this is not embedded, the MQ area
* MUST contain a SGE pointer to a larger area for the
* non-embedded mailbox command.
* mp will point to the actual mailbox command which
* should be copied into the non-embedded area.
*/
4096, DDI_DMA_SYNC_FORDEV);
}
/* Ring the MQ Doorbell */
"MQ RING: %08x", mqdb);
return (MBX_SUCCESS);
} /* emlxs_sli4_issue_mq() */
/*ARGSUSED*/
static uint32_t
{
/*
* If this is an embedded mbox, everything should fit
* into the bootstrap mailbox area.
*/
} else {
/*
* If this is not embedded, the bootstrap mailbox area
* MUST contain a SGE pointer to a larger area for the
* non-embedded mailbox command.
* mp will point to the actual mailbox command which
* should be copied into the non-embedded area.
*/
}
/* NOTE: tmo is in 10ms ticks */
return (MBX_TIMEOUT);
}
} else {
}
return (MBX_SUCCESS);
} /* emlxs_sli4_issue_bootstrap() */
/*ARGSUSED*/
static uint32_t
{
uint32_t i;
rc = MBX_SUCCESS;
/* 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) {
} else {
}
} else {
/* Must have interrupts enabled to perform MBX_NOWAIT */
"Mailbox Queue missing %s failed",
return (MBX_HARDWARE_ERROR);
}
}
/* 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);
}
DELAYMS(10);
}
}
/* Initialize mailbox area */
switch (flag) {
case MBX_NOWAIT:
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Sending. %s: mb=%p NoWait. embedded %d",
}
}
}
"BDE virt %p phys %p size x%x",
}
break;
case MBX_POLL:
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Sending. %s: mb=%p Poll. embedded %d",
}
/* Clean up the mailbox area */
if (rc == MBX_TIMEOUT) {
"Timeout. %s: mb=%p tmo=%x Poll. embedded %d",
} else {
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Completed. %s: mb=%p status=%x Poll. " \
"embedded %d",
}
/* Process the result */
}
}
}
if (mp) {
}
}
/* Attempt to send pending mailboxes */
if (mbq) {
/* Attempt to send pending mailboxes */
if ((i != MBX_BUSY) && (i != MBX_SUCCESS)) {
}
}
break;
case MBX_SLEEP:
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Sending. %s: mb=%p Sleep. embedded %d",
}
}
if (rc != MBX_SUCCESS) {
break;
}
/* Wait for completion */
/* The driver clock is timing the mailbox. */
}
if (mp) {
}
}
if (rc == MBX_TIMEOUT) {
"Timeout. %s: mb=%p tmo=%x Sleep. embedded %d",
} else {
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Completed. %s: mb=%p status=%x Sleep. " \
"embedded %d",
}
}
break;
}
return (rc);
} /* emlxs_sli4_issue_mbox_cmd() */
/*ARGSUSED*/
static uint32_t
{
rc = MBX_SUCCESS;
if (tmo < 30) {
tmo = 30;
}
/* Convert tmo seconds to 10 millisecond tics */
/* Check for hardware error */
return (MBX_HARDWARE_ERROR);
}
/* Initialize mailbox area */
switch (flag) {
case MBX_POLL:
/* Clean up the mailbox area */
if (rc == MBX_TIMEOUT) {
} else {
/* Process the result */
}
}
}
if (mp) {
}
}
break;
}
return (rc);
} /* emlxs_sli4_issue_mbox_cmd4quiesce() */
#ifdef SFCT_SUPPORT
/*ARGSUSED*/
static uint32_t
{
return (IOERR_NO_RESOURCES);
} /* emlxs_sli4_prep_fct_iocb() */
#endif /* SFCT_SUPPORT */
/*ARGSUSED*/
extern uint32_t
{
/* Find target node object */
if (!rp) {
"Unable to find rpi. did=0x%x", did);
IOERR_INVALID_RPI, 0);
return (0xff);
}
/* Next allocate an Exchange for this command */
if (!xp) {
"Adapter Busy. Unable to allocate exchange. did=0x%x", did);
return (FC_TRAN_BUSY);
}
#ifdef SLI4_FASTPATH_DEBUG
#endif
/* Indicate this is a FCP cmd */
"Adapter Busy. Unable to setup SGE. did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* DEBUG */
#ifdef DEBUG_FCP
"CMD virt %p len %d:%d:%d",
#endif
/* if device is FCP-2 device, set the following bit */
/* that says to run the FC-TAPE protocol. */
}
if (pkt->pkt_datalen == 0) {
} else {
}
}
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli4_prep_fcp_iocb() */
/*ARGSUSED*/
static uint32_t
{
return (FC_TRAN_BUSY);
} /* emlxs_sli4_prep_ip_iocb() */
/*ARGSUSED*/
static uint32_t
{
/* Initalize iocbq */
#if (EMLXS_MODREV >= EMLXS_MODREV3)
#else
#endif /* >= EMLXS_MODREV3 */
/* CMD payload */
/* Initalize iocb */
/* ELS Response */
if (!xp) {
"Unable to find XRI. rxid=%x",
IOERR_NO_XRI, 0);
return (0xff);
}
if (!rp) {
/* This means that we had a node registered */
/* when the unsol request came in but the node */
/* has since been unregistered. */
"Unable to find RPI. rxid=%x",
IOERR_INVALID_RPI, 0);
return (0xff);
}
"Prep ELS XRI: xri=%x iotag=%x oxid=%x rpi=%x",
/* Now sge is fully staged */
sizeof (ULP_SGE64));
} else {
/* ELS Request */
if (!rp) {
}
/* Next allocate an Exchange for this command */
if (!xp) {
"Adapter Busy. Unable to allocate exchange. " \
"did=0x%x", did);
return (FC_TRAN_BUSY);
}
/* setup for rsp */
sizeof (ULP_SGE64));
/* RSP payload */
/* Now sge is fully staged */
sge++;
sizeof (ULP_SGE64));
#ifdef DEBUG_ELS
"SGLaddr virt %p phys %p",
"PAYLOAD virt %p phys %p",
#endif
cmd &= ELS_CMD_MASK;
switch (cmd) {
case ELS_CMD_FLOGI:
}
break;
case ELS_CMD_FDISC:
}
break;
case ELS_CMD_LOGO:
(did == FABRIC_DID)) {
}
break;
case ELS_CMD_SCR:
case ELS_CMD_PLOGI:
case ELS_CMD_PRLI:
default:
break;
}
}
}
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli4_prep_els_iocb() */
/*ARGSUSED*/
static uint32_t
{
/* Initalize wqe */
/* CT Response */
if (!xp) {
"Unable to find XRI. rxid=%x",
IOERR_NO_XRI, 0);
return (0xff);
}
if (!rp) {
/* This means that we had a node registered */
/* when the unsol request came in but the node */
/* has since been unregistered. */
"Unable to find RPI. rxid=%x",
IOERR_INVALID_RPI, 0);
return (0xff);
}
"Adapter Busy. Unable to setup SGE. did=0x%x", did);
return (FC_TRAN_BUSY);
}
}
}
} else {
/* CT Request */
if (!rp) {
"Unable to find rpi. did=0x%x", did);
IOERR_INVALID_RPI, 0);
return (0xff);
}
/* Next allocate an Exchange for this command */
if (!xp) {
"Adapter Busy. Unable to allocate exchange. " \
"did=0x%x", did);
return (FC_TRAN_BUSY);
}
"Adapter Busy. Unable to setup SGE. did=0x%x", did);
return (FC_TRAN_BUSY);
}
#ifdef DEBUG_CT
"CMD virt %p len %d:%d",
#endif /* DEBUG_CT */
}
/* Setup for rsp */
}
case FC_TRAN_CLASS2:
break;
case FC_TRAN_CLASS3:
default:
break;
}
return (FC_SUCCESS);
} /* emlxs_sli4_prep_ct_iocb() */
/*ARGSUSED*/
static int
{
int num_entries = 0;
int rc = 0;
/* EMLXS_PORT_LOCK must be held when entering this routine */
4096, DDI_DMA_SYNC_FORKERNEL);
for (;;) {
rc = 1;
break;
}
*ptr = 0;
num_entries++;
host_index++;
host_index = 0;
} else {
ptr++;
}
if (host_index == shost_index) {
/* We donot need to loop forever */
break;
}
}
return (rc);
} /* emlxs_sli4_poll_eq */
/*ARGSUSED*/
static void
{
int rc = 0;
int i;
char arg2;
/*
* Poll the eqe to see if the valid bit is set or not
*/
for (;;) {
/* only poll eqe0 */
if (rc == 1) {
(char *)&arg2, sizeof (char));
break;
}
} else {
/* poll every msi vector */
for (i = 0; i < hba->intr_count; i++) {
if (rc == 1) {
break;
}
}
(char *)&arg2, sizeof (char));
break;
}
}
}
/* process it here */
return;
} /* emlxs_sli4_poll_intr() */
/*ARGSUSED*/
static void
{
"CQ ENTRY: process async event %d stat %d tag %d",
switch (cqe->event_code) {
switch (cqe->link_status) {
case ASYNC_EVENT_PHYS_LINK_UP:
"Physical link up received");
break;
(void) emlxs_fcf_unbind(hba,
}
/* Log the link event */
break;
/* If link not already up then declare it up now */
} else {
}
/*
* This link is not really up till we have
* a valid FCF.
*/
(void) emlxs_fcf_bind(hba);
}
/* Log the link event */
break;
}
break;
case ASYNC_EVENT_NEW_FCF_DISC:
"FCOE Async Event New FCF %d:%d: received ",
(void) emlxs_fcf_bind(hba);
break;
"FCOE Async Event FCF Table Full %d:%d: received ",
break;
case ASYNC_EVENT_FCF_DEAD:
"FCOE Async Event FCF Disappeared %d:%d: received ",
break;
"FCOE Async Event VLINK CLEAR %d: received ",
/*
* Bounce the link to force rediscovery for
* VPI 0. We are ignoring this event for
* all other VPIs for now.
*/
}
break;
}
break;
case ASYNC_EVENT_CODE_DCBX:
"DCBX Async Event Code %d: Not supported ",
cqe->event_code);
break;
default:
break;
}
} /* emlxs_sli4_process_async_event() */
/*ARGSUSED*/
static void
{
int rc;
"CQ ENTRY: process mbox event");
"CQ ENTRY: Entry comsumed but not completed");
return;
}
switch (hba->mbox_queue_flag) {
case 0:
"No mailbox active.");
return;
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;
case MBX_SLEEP:
case MBX_NOWAIT:
break;
default:
"Invalid Mailbox flag (%x).");
return;
}
/* Now that we are the owner, DMA Sync entire MQ if needed */
4096, DDI_DMA_SYNC_FORDEV);
"Mbox sge_cnt: %d length: %d embed: %d",
}
/* Now sync the memory buffer if one was used */
}
/* Now sync the memory buffer if one was used */
}
/* Mailbox has been completely received at this point */
hba->heartbeat_active = 0;
goto done;
}
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Received. %s: status=%x Sleep.",
}
} else {
/* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
"Completed. %s: status=%x",
}
}
/* Filter out passthru mailbox */
goto done;
}
}
/* If mbox was retried, return immediately */
if (rc) {
return;
}
}
done:
/* Clean up the mailbox area */
/* Attempt to send pending mailboxes */
if (mbq) {
/* Attempt to send pending mailboxes */
}
}
return;
} /* emlxs_sli4_process_mbox_event() */
static void
{
#ifdef SLI4_FASTPATH_DEBUG
#endif
case CMD_FCP_ICMND64_CR:
break;
case CMD_FCP_IREAD64_CR:
}
break;
case CMD_FCP_IWRITE64_CR:
break;
case CMD_ELS_REQUEST64_CR:
}
break;
case CMD_GEN_REQUEST64_CR:
break;
case CMD_XMIT_SEQUENCE64_CR:
break;
default:
}
} /* emlxs_CQE_to_IOCB() */
/*ARGSUSED*/
static void
{
uint32_t i;
continue;
}
cqe.RequestTag = i;
cp->hbaCmplCmd_sbp++;
#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
}
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */
/* Copy entry to sbp's iocbq */
/* Exchange is no longer busy on-chip, free it */
(PACKET_POLLED | PACKET_ALLOCATED))) {
/* Add the IOCB to the channel list */
} else {
}
trigger = 1;
} else {
}
}
if (trigger) {
for (i = 0; i < hba->chan_count; i++) {
}
}
}
} /* emlxs_sli4_hba_flush_chipq() */
/*ARGSUSED*/
static void
{
/* 1 to 1 mapping between CQ and channel */
cp->hbaCmplCmd++;
"CQ ENTRY: OOR Cmpl: tag=%x", request_tag);
} /* emlxs_sli4_process_oor_wqe_cmpl() */
/*ARGSUSED*/
static void
{
#ifdef SFCT_SUPPORT
#endif /* SFCT_SUPPORT */
/* 1 to 1 mapping between CQ and channel */
if (sbp == STALE_PACKET) {
cp->hbaCmplCmd_sbp++;
"CQ ENTRY: Stale sbp. tag=%x. Dropping...", request_tag);
return;
}
cp->hbaCmplCmd++;
"CQ ENTRY: NULL sbp %p. tag=%x. Dropping...",
sbp, request_tag);
return;
}
#ifdef SLI4_FASTPATH_DEBUG
"CQ ENTRY: process wqe compl");
#endif
cp->hbaCmplCmd_sbp++;
#ifdef SFCT_SUPPORT
if (fct_cmd) {
}
#endif /* SFCT_SUPPORT */
/* Copy entry to sbp's iocbq */
/* Mark exchange as ABORT in progress */
"CQ ENTRY: ABORT INP: tag=%x xri=%x", request_tag,
} else {
/* Exchange is no longer busy on-chip, free it */
}
/*
* 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 channel list */
} else {
}
/* Delay triggering thread till end of ISR */
} else {
}
} /* emlxs_sli4_process_wqe_cmpl() */
/*ARGSUSED*/
static void
{
uint32_t i;
#ifdef SLI4_FASTPATH_DEBUG
#endif
/* Cmd ring may be available. Try sending more iocbs */
for (i = 0; i < hba->chan_count; i++) {
}
}
} /* emlxs_sli4_process_release_wqe() */
/*ARGSUSED*/
{
emlxs_queue_t *q;
case 1: /* ELS */
break;
case 0x20: /* CT */
break;
default:
return (NULL);
}
while (iocbq) {
/* Remove iocbq */
if (prev) {
}
}
}
q->q_cnt--;
break;
}
}
return (iocbq);
} /* emlxs_sli4_rxq_get() */
/*ARGSUSED*/
void
{
emlxs_queue_t *q;
case 1: /* ELS */
break;
case 0x20: /* CT */
break;
default:
return;
}
if (q->q_last) {
q->q_cnt++;
} else {
q->q_cnt = 1;
}
return;
} /* emlxs_sli4_rxq_put() */
static void
{
"RQ POST: rqid=%d count=1", rqid);
/* Ring the RQ doorbell once to repost the RQ buffer */
} /* emlxs_sli4_rq_post() */
/*ARGSUSED*/
static void
{
uint32_t i;
char label[32];
"CQ ENTRY: Unsol Rcv: RQid=%d,%d index=%d status=%x " \
"hdr_size=%d data_size=%d",
/* Validate the CQE */
/* Check status */
case RQ_STATUS_SUCCESS: /* 0x10 */
break;
case RQ_STATUS_BUFLEN_EXCEEDED: /* 0x11 */
"CQ ENTRY: Unsol Rcv: Payload truncated.");
break;
case RQ_STATUS_NEED_BUFFER: /* 0x12 */
"CQ ENTRY: Unsol Rcv: Payload buffer needed.");
return;
case RQ_STATUS_FRAME_DISCARDED: /* 0x13 */
"CQ ENTRY: Unsol Rcv: Payload buffer discarded.");
return;
default:
"CQ ENTRY: Unsol Rcv: Unknown status=%x.",
break;
}
/* Make sure there is a frame header */
"CQ ENTRY: Unsol Rcv: FC header too small. Dropping...");
return;
}
/* Update host index */
hdr_rq->host_index++;
hdr_rq->host_index = 0;
}
/* Get the next header rqb */
sizeof (fc_frame_hdr_t), DDI_DMA_SYNC_FORKERNEL);
sizeof (fc_frame_hdr_t));
"RQ HDR[%d]: rctl:%x type:%x " \
"sid:%x did:%x oxid:%x rxid:%x",
"RQ HDR[%d]: fctl:%x seq_id:%x seq_cnt:%x df_ctl:%x ro:%x",
/* Verify fc header type */
case 0: /* BLS */
"RQ ENTRY: Unexpected FC rctl (0x%x) " \
"received. Dropping...",
goto done;
}
/* Make sure there is no payload */
"RQ ENTRY: ABTS payload provided. Dropping...");
goto done;
}
buf_type = 0xFFFFFFFF;
break;
case 0x01: /* ELS */
/* Make sure there is a payload */
"RQ ENTRY: Unsol Rcv: No ELS payload provided. " \
"Dropping...");
goto done;
}
break;
case 0x20: /* CT */
/* Make sure there is a payload */
"RQ ENTRY: Unsol Rcv: No CT payload provided. " \
"Dropping...");
goto done;
}
break;
default:
"RQ ENTRY: Unexpected FC type (0x%x) received. Dropping...",
goto done;
}
/* Fc Header is valid */
/* Check if this is an active sequence */
if (!iocbq) {
"RQ ENTRY: %s: First of sequence not" \
" set. Dropping...",
label);
goto done;
}
}
"RQ ENTRY: %s: Sequence count not zero (%d). " \
"Dropping...",
goto done;
}
/* Find vport (defaults to physical port) */
for (i = 0; i < MAX_VPORTS; i++) {
break;
}
}
/* Allocate an IOCBQ */
MEM_IOCB, 1);
if (!iocbq) {
"RQ ENTRY: %s: Out of IOCB " \
"resources. Dropping...",
label);
goto done;
}
/* Allocate a buffer */
if (!seq_mp) {
"RQ ENTRY: %s: Out of buffer " \
"resources. Dropping...",
label);
goto done;
}
}
"RQ ENTRY: %s: Node not found. sid=%x",
}
/* Initialize the iocbq */
seq_len = 0;
seq_cnt = 0;
} else {
/* Check sequence order */
"RQ ENTRY: %s: Out of order frame received " \
"(%d != %d). Dropping...",
goto done;
}
}
/* We now have an iocbq */
/* Save the frame data to our seq buffer */
/* Get the next data rqb */
"RQ DAT[%d]: %08x %08x %08x %08x %08x %08x ...",
/* Check sequence length */
"RQ ENTRY: %s: Sequence buffer overflow. " \
"(%d > %d). Dropping...",
goto done;
}
/* Copy data to local receive buffer */
}
/* If this is not the last frame of sequence, queue it. */
/* Save sequence header */
if (seq_cnt == 0) {
sizeof (fc_frame_hdr_t));
}
/* Update sequence info in iocb */
/* Queue iocbq for next frame */
/* Don't free resources */
/* No need to abort */
abort = 0;
goto done;
}
posted = 1;
/* End of sequence found. Process request now. */
if (seq_cnt > 0) {
/* Retrieve first frame of sequence */
sizeof (fc_frame_hdr_t));
}
/* Build rcv iocb and process it */
case 0: /* BLS */
"RQ ENTRY: %s: xid:%x sid:%x. Sending BLS ACC...",
/* Set up an iotag using special Abort iotags */
}
/* BLS ACC Response */
}
break;
case 1: /* ELS */
cmd &= ELS_CMD_MASK;
if (cmd != ELS_CMD_LOGO) {
}
if (!rp) {
}
if (!xp) {
"RQ ENTRY: %s: Out of exchange " \
"resources. Dropping...",
label);
goto done;
}
/* Build CMD_RCV_ELS64_CX */
}
break;
case 0x20: /* CT */
if (!node) {
"RQ ENTRY: %s: Node not found (did=%x). " \
"Dropping...",
goto done;
}
if (!rp) {
"RQ ENTRY: %s: RPI not found (did=%x rpi=%x). " \
"Dropping...",
goto done;
}
if (!xp) {
"RQ ENTRY: %s: Out of exchange " \
"resources. Dropping...",
label);
goto done;
}
/* Build CMD_RCV_SEQ64_CX */
}
break;
}
/* Sequence handled, no need to abort */
abort = 0;
done:
if (!posted) {
}
if (abort) {
/* Send ABTS for this exchange */
/* !!! Currently, we have no implementation for this !!! */
abort = 0;
}
/* Return memory resources to pools */
if (iocbq) {
}
}
return;
} /* emlxs_sli4_process_unsol_rcv() */
/*ARGSUSED*/
static void
{
"CQ ENTRY: process xri aborted ignored");
return;
}
"CQ ENTRY: process xri x%x aborted: IA %d EO %d BR %d",
"XRI Aborted: Bad state: x%x xri x%x",
return;
}
/* Exchange is no longer busy on-chip, free it */
} /* emlxs_sli4_process_xri_aborted () */
/*ARGSUSED*/
static void
{
int num_entries = 0;
/* EMLXS_PORT_LOCK must be held when entering this routine */
4096, DDI_DMA_SYNC_FORKERNEL);
for (;;) {
break;
#ifdef SLI4_FASTPATH_DEBUG
#endif
num_entries++;
cq->host_index++;
cq->host_index = 0;
} else {
cqe++;
}
/* Now handle specific cq type */
(CQE_ASYNC_t *)&cq_entry);
} else {
(CQE_MBOX_t *)&cq_entry);
}
} else { /* EMLXS_CQ_TYPE_GROUP2 */
case CQE_TYPE_WQ_COMPLETION:
(CQE_CmplWQ_t *)&cq_entry);
} else {
(CQE_CmplWQ_t *)&cq_entry);
}
break;
case CQE_TYPE_RELEASE_WQE:
(CQE_RelWQ_t *)&cq_entry);
break;
case CQE_TYPE_UNSOL_RCV:
(CQE_UnsolRcv_t *)&cq_entry);
break;
case CQE_TYPE_XRI_ABORTED:
(CQE_XRI_Abort_t *)&cq_entry);
break;
default:
"Invalid CQ entry %d: %08x %08x %08x %08x",
break;
}
}
}
cqdb |= CQ_DB_REARM;
if (num_entries != 0) {
}
#ifdef SLI4_FASTPATH_DEBUG
#endif
/* EMLXS_PORT_LOCK must be held when exiting this routine */
} /* emlxs_sli4_process_cq() */
/*ARGSUSED*/
static void
{
uint32_t i;
int num_entries = 0;
/* EMLXS_PORT_LOCK must be held when entering this routine */
4096, DDI_DMA_SYNC_FORKERNEL);
for (;;) {
break;
#ifdef SLI4_FASTPATH_DEBUG
#endif
*ptr = 0;
num_entries++;
eq->host_index++;
eq->host_index = 0;
} else {
ptr++;
}
#ifdef SLI4_FASTPATH_DEBUG
#endif
}
#ifdef SLI4_FASTPATH_DEBUG
#endif
if (num_entries != 0) {
for (i = 0; i < hba->chan_count; i++) {
}
}
}
/* EMLXS_PORT_LOCK must be held when exiting this routine */
} /* emlxs_sli4_process_eq() */
#ifdef MSI_SUPPORT
/*ARGSUSED*/
static uint32_t
{
int rc;
#ifdef SLI4_FASTPATH_DEBUG
#endif
/* Check for legacy interrupt handling */
return (rc);
}
/* Get MSI message id */
/* Validate the message id */
msgid = 0;
}
return (DDI_INTR_UNCLAIMED);
}
/* The eq[] index == the MSI vector number */
return (DDI_INTR_CLAIMED);
} /* emlxs_sli4_msi_intr() */
#endif /* MSI_SUPPORT */
/*ARGSUSED*/
static int
emlxs_sli4_intx_intr(char *arg)
{
#ifdef SLI4_FASTPATH_DEBUG
"intxINTR arg:%p", arg);
#endif
return (DDI_INTR_UNCLAIMED);
}
return (DDI_INTR_CLAIMED);
} /* emlxs_sli4_intx_intr() */
static void
{
uint32_t j;
return;
}
j = 0;
while (j++ < 10000) {
if (hba->mbox_queue_flag == 0) {
break;
}
DELAYUS(100);
}
if (hba->mbox_queue_flag != 0) {
"Board kill failed. Mailbox busy.");
return;
}
} /* emlxs_sli4_hba_kill() */
static void
{
int i;
int num_cq;
/* ARM EQ / CQs */
for (i = 0; i < num_cq; i++) {
data |= CQ_DB_REARM;
}
for (i = 0; i < hba->intr_count; i++) {
}
} /* emlxs_sli4_enable_intr() */
static void
{
if (att) {
return;
}
/* Short of reset, we cannot disable interrupts */
} /* emlxs_sli4_disable_intr() */
static void
{
uint32_t i;
}
}
}
}
"XRIs inuse during free!: %p %p != %p\n",
}
}
xp++;
}
}
for (i = 0; i < EMLXS_MAX_EQS; i++) {
}
}
for (i = 0; i < EMLXS_MAX_CQS; i++) {
}
}
for (i = 0; i < EMLXS_MAX_WQS; i++) {
}
}
for (i = 0; i < EMLXS_MAX_RQS; i++) {
/* Free the RQ */
/* Free the RQB pool */
/* Free the associated RXQ */
}
}
/* Free the MQ */
}
/* Cleanup queue ordinal mapping */
for (i = 0; i < EMLXS_MAX_EQ_IDS; i++) {
}
for (i = 0; i < EMLXS_MAX_CQ_IDS; i++) {
}
for (i = 0; i < EMLXS_MAX_WQ_IDS; i++) {
}
} /* emlxs_sli4_resource_free() */
static int
{
int num_eq;
int num_wq;
uint32_t i;
uint32_t j;
uint32_t k;
char buf[64];
index = 0; /* Start FCFIs at 0 */
fp++;
index++;
}
}
vp++;
index++;
}
}
rp++;
index++;
}
}
index++; /* Skip XRI 0 or IOTag 0 */
xp++;
continue;
}
/* Add xp to end of single linked free list */
} else {
}
}
/* Allocate SGL for this xp */
"Unable to allocate XRI SGL area: %d",
goto failed;
}
xp++;
index++;
}
/* Initialize double linked list */
}
"Unable to allocate Header Tmplate area: %d",
(sizeof (RPIHdrTmplate_t) *
goto failed;
}
}
/* Allocate space for queues */
/* EQs - 1 per Interrupt vector */
for (i = 0; i < num_eq; i++) {
"Unable to allocate EQ %d area", i);
goto failed;
}
}
DRIVER_NAME, i);
MUTEX_DRIVER, NULL);
}
for (i = 0; i < (num_wq + EMLXS_CQ_OFFSET_WQ); i++) {
"Unable to allocate CQ %d area", i);
goto failed;
}
}
}
/* WQs - NUM_WQ config parameter * number of EQs */
for (i = 0; i < num_wq; i++) {
"Unable to allocate WQ %d area", i);
goto failed;
}
}
}
/* RXQs */
for (i = 0; i < EMLXS_MAX_RXQS; i++) {
}
/* RQs */
for (i = 0; i < EMLXS_MAX_RQS; i++) {
continue;
}
"Unable to allocate RQ %d area", i);
goto failed;
}
/* RQBs */
if ((i & 0x1)) {
/* Odd == Data pool */
} else {
/* Even == Header pool */
}
/* Allocate the pool */
"Unable to allocate RQ %d pool", i);
goto failed;
}
/* Initialize the RQEs */
for (k = 0; k < RQB_COUNT; k++) {
if (j == 0) {
}
#ifdef RQ_DEBUG
"RQ_ALLOC: rq[%d] rqb[%d,%d]=%p tag=%08x",
#endif
rqe++;
rqb++;
}
}
/* Sync the RQ buffer list */
}
/* MQ */
"Unable to allocate MQ area");
goto failed;
}
}
return (0);
(void) emlxs_sli4_resource_free(hba);
return (ENOMEM);
} /* emlxs_sli4_resource_alloc */
static FCFIobj_t *
{
uint32_t i;
return (fp);
}
fp++;
}
"Unable to Alloc FCFI");
return (NULL);
} /* emlxs_sli4_alloc_fcfi() */
static FCFIobj_t *
{
uint32_t i;
/* Check for BOTH a matching FCF index and mac address */
return (fp);
}
}
fp++;
}
return (0);
} /* emlxs_sli4_find_fcfi_fcfrec() */
extern VFIobj_t *
{
uint32_t i;
fp->outstandingVFIs++;
return (vp);
}
vp++;
}
"Unable to Alloc VFI");
return (NULL);
} /* emlxs_sli4_alloc_vfi() */
extern RPIobj_t *
{
uint32_t i;
/* To be consistent with SLI3, the RPI assignment */
/* starts with 1. ONLY one SLI4 HBA in the entire */
/* system will be sacrificed by one RPI and that */
/* is the one having RPI base equal 0. */
port->outstandingRPIs++;
return (rp);
}
rp++;
}
"Unable to Alloc RPI");
return (NULL);
} /* emlxs_sli4_alloc_rpi() */
extern RPIobj_t *
{
int index;
"RPI %d out of range: Count = %d",
return (NULL);
}
"Unable to find RPI %d", index);
return (NULL);
}
return (rp);
} /* emlxs_sli4_find_rpi() */
static XRIobj_t *
{
"Unable to reserve XRI");
return (NULL);
}
if ((!iotag) ||
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to reserve iotag");
return (NULL);
}
if (rp) {
rp->outstandingXRIs++;
}
/* Take it off free list */
/* Add it to end of inuse list */
return (xp);
} /* emlxs_sli4_reserve_xri() */
extern uint32_t
{
return (0);
}
return (1);
}
}
}
/* Take it off inuse list */
/* Add it to end of free list */
return (0);
} /* emlxs_sli4_unreserve_xri() */
static XRIobj_t *
{
if (!xp) {
"emlxs_sli4_register_xri: XRI not found.");
return (NULL);
}
"emlxs_sli4_register_xri: Invalid XRI. xp=%p state=%x",
return (NULL);
}
if ((!iotag) ||
"emlxs_sli4_register_xri: Invalid fc_table entry. " \
"iotag=%x entry=%p",
return (NULL);
}
return (xp);
} /* emlxs_sli4_register_xri() */
/* Performs both reserve and register functions for XRI */
static XRIobj_t *
{
"Unable to allocate XRI");
return (NULL);
}
/* Get the iotag by registering the packet */
if ((!iotag) ||
/*
* No more command slots available, retry later
*/
"Adapter Busy. Unable to allocate iotag");
return (NULL);
}
if (rp) {
rp->outstandingXRIs++;
}
/* Take it off free list */
/* Add it to end of inuse list */
return (xp);
} /* emlxs_sli4_alloc_xri() */
extern XRIobj_t *
{
break;
}
}
"Unable to find XRI x%x", xri);
return (NULL);
}
return (xp);
} /* emlxs_sli4_find_xri() */
extern void
{
"Free FCFI:%d idx:%d, Already freed",
return;
}
if (fp->outstandingVFIs) {
}
} /* emlxs_sli4_free_fcfi() */
extern void
{
return;
}
if (fp->outstandingVPIs) {
}
/* No more VPIs so unreg the VFI */
}
} /* emlxs_sli4_free_vfi() */
static void
{
return;
}
if (pp->outstandingRPIs) {
}
/* No more VPIs so unreg the VFI */
}
} /* emlxs_sli4_free_vpi() */
static void
{
/*
* 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 channel list */
} else {
}
/* Delay triggering thread till end of ISR */
} else {
}
} /* emlxs_sli4_cmpl_io() */
extern void
{
return;
}
if (rp->outstandingXRIs) {
}
}
/* Remove all XRIs under this RPI */
}
}
} /* emlxs_sli4_free_rpi() */
extern void
{
if (xp) {
return;
}
}
}
/* Take it off inuse list */
/* Add it to end of free list */
}
if (sbp) {
"sbp / iotag mismatch %p iotag:%d %d", sbp,
}
}
}
/* Clean up the sbp */
hba->channel_tx_count--;
}
}
} else {
}
} /* emlxs_sli4_free_xri() */
static int
{
"Unable to POST_SGL. Mailbox cmd=%x ",
mb->mbxCommand);
return (EIO);
}
/*
* Signifies a non embedded command
*/
post_sgl =
while (cnt) {
sizeof (FCOE_SGL_PAGES);
for (i = 0; i < xri_cnt; i++) {
cnt--;
xp++;
if (cnt == 0) {
break;
}
}
MBX_SUCCESS) {
"Unable to POST_SGL. Mailbox cmd=%x status=%x "
"XRI cnt:%d start:%d",
return (EIO);
}
}
return (0);
} /* emlxs_sli4_post_sgl_pages() */
static int
{
int i, cnt;
/*
* Signifies an embedded command
*/
sizeof (IOCTL_FCOE_POST_HDR_TEMPLATES) + IOCTL_HEADER_SZ;
sizeof (IOCTL_FCOE_POST_HDR_TEMPLATES);
post_hdr =
i = 0;
while (cnt > 0) {
i++;
addr += 4096;
cnt -= 4096;
}
MBX_SUCCESS) {
"Unable to POST_HDR_TEMPLATES. Mailbox cmd=%x status=%x ",
return (EIO);
}
return (0);
} /* emlxs_sli4_post_hdr_tmplates() */
static int
{
int i, j;
/*
* The first CQ is reserved for ASYNC events,
* the second is reserved for unsol rcv, the rest
* correspond to WQs. (WQ0 -> CQ2, WQ1 -> CQ3, ...)
*/
/* First initialize queue ordinal mapping */
for (i = 0; i < EMLXS_MAX_EQ_IDS; i++) {
}
for (i = 0; i < EMLXS_MAX_CQ_IDS; i++) {
}
for (i = 0; i < EMLXS_MAX_WQ_IDS; i++) {
}
for (i = 0; i < EMLXS_MAX_RQ_IDS; i++) {
}
total_cq = 0;
total_wq = 0;
/* Create EQ's */
for (i = 0; i < hba->intr_count; i++) {
MBX_SUCCESS) {
"Unable to Create EQ %d: Mailbox cmd=%x status=%x ",
return (EIO);
}
if (i == 0) {
}
for (j = 0; j < num_cq; j++) {
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
&emlxs_init_failed_msg, "Unable to Create "
"CQ %d: Mailbox cmd=%x status=%x ",
return (EIO);
}
cq = (IOCTL_COMMON_CQ_CREATE *)
switch (total_cq) {
case EMLXS_CQ_MBOX:
/* First CQ is for async event handling */
break;
case EMLXS_CQ_RCV:
/* Second CQ is for unsol receive handling */
break;
default:
/* Setup CQ to channel mapping */
break;
}
total_cq++;
}
for (j = 0; j < num_wq; j++) {
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
&emlxs_init_failed_msg, "Unable to Create "
"WQ %d: Mailbox cmd=%x status=%x ",
return (EIO);
}
wq = (IOCTL_FCOE_WQ_CREATE *)
total_wq++;
}
}
/* We assume 1 RQ pair will handle ALL incoming data */
/* Create RQs */
for (i = 0; i < EMLXS_MAX_RQS; i++) {
/* Personalize the RQ */
switch (i) {
case 0:
break;
case 1:
break;
default:
}
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"Unable to Create RQ %d: Mailbox cmd=%x status=%x ",
return (EIO);
}
"RQ CREATE: rq[%d].qid=%d cqid=%d",
/* Initialize the host_index */
/* If Data queue was just created, */
/* then post buffers using the header qid */
if ((i & 0x1)) {
/* Ring the RQ doorbell to post buffers */
"RQ CREATE: Doorbell rang: qid=%d count=%d",
}
}
/* Create MQ */
/* Personalize the MQ */
/* Reuse mbq from previous mbox */
MBX_SUCCESS) {
"Unable to Create MQ %d: Mailbox cmd=%x status=%x ",
return (EIO);
}
return (0);
} /* emlxs_sli4_create_queues() */
static int
{
int rc;
return (0);
}
/*
* If the firmware donesn't support FIP, we must
* build the fcf table manually first.
*/
} else {
}
if (rc == 0) {
return (0);
}
}
return (1);
} /* emlxs_fcf_bind() */
static int
{
int i;
/* Loop thru all FCFIs */
if ((index == MAX_FCFCONNECTLIST_ENTRIES) ||
/* Declare link down here */
}
/* There should only be 1 FCF for now */
return (1);
}
}
}
return (0);
} /* emlxs_fcf_unbind() */
/*ARGSUSED*/
extern int
{
int i;
/* Nothing specified, so everything matches */
/* For nonFIP only use index 0 */
return (1); /* success */
}
return (0);
}
/* Just check FCMap for now */
return (1); /* success */
}
return (0);
}
/* For FIP mode, the FCF record must match Config Region 23 */
/* Nothing specified, so everything matches */
return (1); /* success */
}
/* Just check FabricName for now */
for (i = 0; i < MAX_FCFCONNECTLIST_ENTRIES; i++) {
return (1); /* success */
}
}
return (0);
}
extern FCFIobj_t *
{
int i;
if (!fcfp) {
if (!fcfp) {
"Unable to alloc FCFI for fcf index %d",
return (0);
}
}
for (i = 0; i < 512; i++) {
break;
}
}
"FCFI %d: idx %x av %x val %x ste %x macp %x vid %x "
"addr: %02x:%02x:%02x:%02x:%02x:%02x",
fcfrec->fcf_mac_address_hi[0],
"fabric: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
"switch: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
return (fcfp);
} /* emlxs_sli4_assign_fcfi() */
extern FCFIobj_t *
{
int rc;
uint32_t i;
/* Loop thru all FCFIs */
/*
* Look for one thats valid, available
* and matches our FCF configuration info.
*/
/* Since we only support one FCF */
break;
}
}
fp++;
}
"Not a valid FCF");
return (0);
}
if (!vfip) {
"Fabric VFI alloc failure, fcf index %d",
return (0);
}
}
}
}
return (fp);
}
"Unable to alloc mbox for fcf index %d",
return (0);
}
"Unable to issue mbox for fcf index %d",
}
return (fp);
} /* emlxs_sli4_bind_fcfi() */
extern void
{
/* Perform SLI4 level timer checks */
return;
} /* emlxs_sli4_timer() */
static void
{
return;
}
/* Return if timer hasn't expired */
return;
}
hba->mbox_timer = 0;
if (hba->mbox_queue_flag) {
}
}
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_sli4_timer_check_mbox() */
extern void
{
void *msg;
if (err) {
msg = &emlxs_sli_err_msg;
} else {
}
if (cnt) {
}
if (cnt > 6) {
}
if (cnt > 12) {
}
if (cnt > 18) {
}
if (cnt > 24) {
}
if (cnt > 30) {
}
if (cnt > 36) {
}
} /* emlxs_data_dump() */
extern void
{
"%s: ueLow:%08x ueHigh:%08x on1:%08x on2:%08x", str,
#ifdef FMA_SUPPORT
/* Access handle validation */
#endif /* FMA_SUPPORT */
} /* emlxs_ue_dump() */
void
{
return;
}
/* Unrecoverable error detected */
/* Shut the HBA down */
"Host Error: ueLow:%08x ueHigh:%08x on1:%08x on2:%08x",
}
#ifdef FMA_SUPPORT
/* The PCI(e) driver generates PCI error when PCI read returns */
/* 0xFFFFFFFF value. Since PCICFG_UE_STATUS_ONLINE0 and */
/* PCICFG_UE_STATUS_ONLINE1 registers return 0xFFFFFFFF to */
/* indicate that no internal component has an unrecoverable */
/* error on HBA, no access handle check and just call below */
/* function to clear the access handle error here. */
/* Some S10 versions do not define the ddi_fm_acc_err_clear function */
if ((void *)&ddi_fm_acc_err_clear != NULL) {
}
#endif /* FMA_SUPPORT */
} /* emlxs_sli4_poll_erratt() */
int
{
int i;
for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
(void) emlxs_mb_unreg_rpi(port,
} else {
/* Just free nlp back to the pool */
}
}
}
return (0);
} /* emlxs_sli4_unreg_all_rpi_by_port() */