root/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_sli4.c
/*
 * 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
 * http://www.opensource.org/licenses/cddl1.txt.
 * 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.
 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
 * Copyright 2020 RackTop Systems, Inc.
 */

#include <emlxs.h>


/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
EMLXS_MSG_DEF(EMLXS_SLI4_C);

static int              emlxs_sli4_init_extents(emlxs_hba_t *hba,
                                MAILBOXQ *mbq);
static uint32_t         emlxs_sli4_read_status(emlxs_hba_t *hba);

static int              emlxs_init_bootstrap_mb(emlxs_hba_t *hba);

static uint32_t         emlxs_sli4_read_sema(emlxs_hba_t *hba);

static uint32_t         emlxs_sli4_read_mbdb(emlxs_hba_t *hba);

static void             emlxs_sli4_write_mbdb(emlxs_hba_t *hba, uint64_t phys,
                                boolean_t high);

static void             emlxs_sli4_write_wqdb(emlxs_hba_t *hba, uint16_t qid,
                                uint_t posted, uint_t index);

static void             emlxs_sli4_write_mqdb(emlxs_hba_t *hba, uint16_t qid,
                                uint_t count);

static void             emlxs_sli4_write_rqdb(emlxs_hba_t *hba, uint16_t qid,
                                uint_t count);

static void             emlxs_sli4_write_eqdb(emlxs_hba_t *hba, uint16_t qid,
                                uint32_t count, boolean_t arm);
static void             emlxs_sli4_write_cqdb(emlxs_hba_t *hba, uint16_t qid,
                                uint32_t count, boolean_t arm);

static int              emlxs_sli4_create_queues(emlxs_hba_t *hba,
                                MAILBOXQ *mbq);
static int              emlxs_sli4_post_hdr_tmplates(emlxs_hba_t *hba,
                                MAILBOXQ *mbq);
static int              emlxs_sli4_post_sgl_pages(emlxs_hba_t *hba,
                                MAILBOXQ *mbq);

static int              emlxs_sli4_read_eq(emlxs_hba_t *hba, EQ_DESC_t *eq);

static int              emlxs_sli4_map_hdw(emlxs_hba_t *hba);

static void             emlxs_sli4_unmap_hdw(emlxs_hba_t *hba);

static int32_t          emlxs_sli4_online(emlxs_hba_t *hba);

static void             emlxs_sli4_offline(emlxs_hba_t *hba,
                                uint32_t reset_requested);

static uint32_t         emlxs_sli4_hba_reset(emlxs_hba_t *hba, uint32_t restart,
                                uint32_t skip_post, uint32_t quiesce);
static void             emlxs_sli4_hba_kill(emlxs_hba_t *hba);

static uint32_t         emlxs_sli4_hba_init(emlxs_hba_t *hba);

static uint32_t         emlxs_sli4_bde_setup(emlxs_port_t *port,
                                emlxs_buf_t *sbp);

static void             emlxs_sli4_issue_iocb_cmd(emlxs_hba_t *hba,
                                CHANNEL *cp, IOCBQ *iocb_cmd);
static uint32_t         emlxs_sli4_issue_mbox_cmd(emlxs_hba_t *hba,
                                MAILBOXQ *mbq, int32_t flg, uint32_t tmo);
static uint32_t         emlxs_sli4_issue_mbox_cmd4quiesce(emlxs_hba_t *hba,
                                MAILBOXQ *mbq, int32_t flg, uint32_t tmo);
#ifdef SFCT_SUPPORT
static uint32_t         emlxs_sli4_prep_fct_iocb(emlxs_port_t *port,
                                emlxs_buf_t *cmd_sbp, int channel);
static uint32_t         emlxs_sli4_fct_bde_setup(emlxs_port_t *port,
                                emlxs_buf_t *sbp);
#endif /* SFCT_SUPPORT */

static uint32_t         emlxs_sli4_prep_fcp_iocb(emlxs_port_t *port,
                                emlxs_buf_t *sbp, int ring);
static uint32_t         emlxs_sli4_prep_ip_iocb(emlxs_port_t *port,
                                emlxs_buf_t *sbp);
static uint32_t         emlxs_sli4_prep_els_iocb(emlxs_port_t *port,
                                emlxs_buf_t *sbp);
static uint32_t         emlxs_sli4_prep_ct_iocb(emlxs_port_t *port,
                                emlxs_buf_t *sbp);
static void             emlxs_sli4_poll_intr(emlxs_hba_t *hba);
static int32_t          emlxs_sli4_intx_intr(char *arg);

#ifdef MSI_SUPPORT
static uint32_t         emlxs_sli4_msi_intr(char *arg1, char *arg2);
#endif /* MSI_SUPPORT */

static void             emlxs_sli4_resource_free(emlxs_hba_t *hba);

static int              emlxs_sli4_resource_alloc(emlxs_hba_t *hba);
extern void             emlxs_sli4_zero_queue_stat(emlxs_hba_t *hba);

static XRIobj_t         *emlxs_sli4_alloc_xri(emlxs_port_t *port,
                                emlxs_buf_t *sbp, RPIobj_t *rpip,
                                uint32_t type);
static void             emlxs_sli4_enable_intr(emlxs_hba_t *hba);

static void             emlxs_sli4_disable_intr(emlxs_hba_t *hba, uint32_t att);

static void             emlxs_sli4_timer(emlxs_hba_t *hba);

static void             emlxs_sli4_timer_check_mbox(emlxs_hba_t *hba);

static void             emlxs_sli4_gpio_timer_start(emlxs_hba_t *hba);

static void             emlxs_sli4_gpio_timer_stop(emlxs_hba_t *hba);

static void             emlxs_sli4_gpio_timer(void *arg);

static void             emlxs_sli4_check_gpio(emlxs_hba_t *hba);

static uint32_t emlxs_sli4_fix_gpio(emlxs_hba_t *hba,
                                        uint8_t *pin, uint8_t *pinval);

static uint32_t emlxs_sli4_fix_gpio_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq);

static void             emlxs_sli4_poll_erratt(emlxs_hba_t *hba);

extern XRIobj_t         *emlxs_sli4_reserve_xri(emlxs_port_t *port,
                                RPIobj_t *rpip, uint32_t type, uint16_t rx_id);
static int              emlxs_check_hdw_ready(emlxs_hba_t *);

static uint32_t         emlxs_sli4_reg_did(emlxs_port_t *port,
                                uint32_t did, SERV_PARM *param,
                                emlxs_buf_t *sbp, fc_unsol_buf_t *ubp,
                                IOCBQ *iocbq);

static uint32_t         emlxs_sli4_unreg_node(emlxs_port_t *port,
                                emlxs_node_t *node, emlxs_buf_t *sbp,
                                fc_unsol_buf_t *ubp, IOCBQ *iocbq);

static void             emlxs_sli4_handle_fc_link_att(emlxs_hba_t *hba,
                                CQE_ASYNC_t *cqe);
static void             emlxs_sli4_handle_fcoe_link_event(emlxs_hba_t *hba,
                                CQE_ASYNC_t *cqe);


static uint16_t         emlxs_sli4_rqid_to_index(emlxs_hba_t *hba,
                                uint16_t rqid);
static uint16_t         emlxs_sli4_wqid_to_index(emlxs_hba_t *hba,
                                uint16_t wqid);
static uint16_t         emlxs_sli4_cqid_to_index(emlxs_hba_t *hba,
                                uint16_t cqid);

/* Define SLI4 API functions */
emlxs_sli_api_t emlxs_sli4_api = {
        emlxs_sli4_map_hdw,
        emlxs_sli4_unmap_hdw,
        emlxs_sli4_online,
        emlxs_sli4_offline,
        emlxs_sli4_hba_reset,
        emlxs_sli4_hba_kill,
        emlxs_sli4_issue_iocb_cmd,
        emlxs_sli4_issue_mbox_cmd,
#ifdef SFCT_SUPPORT
        emlxs_sli4_prep_fct_iocb,
#else
        NULL,
#endif /* SFCT_SUPPORT */
        emlxs_sli4_prep_fcp_iocb,
        emlxs_sli4_prep_ip_iocb,
        emlxs_sli4_prep_els_iocb,
        emlxs_sli4_prep_ct_iocb,
        emlxs_sli4_poll_intr,
        emlxs_sli4_intx_intr,
        emlxs_sli4_msi_intr,
        emlxs_sli4_disable_intr,
        emlxs_sli4_timer,
        emlxs_sli4_poll_erratt,
        emlxs_sli4_reg_did,
        emlxs_sli4_unreg_node
};


/* ************************************************************************** */

static void
emlxs_sli4_set_default_params(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;

        bzero((char *)&hba->sli.sli4.param, sizeof (sli_params_t));

        hba->sli.sli4.param.ProtocolType = 0x3; /* FC/FCoE */

        hba->sli.sli4.param.SliHint2 = 0;
        hba->sli.sli4.param.SliHint1 = 0;
        hba->sli.sli4.param.IfType = 0;
        hba->sli.sli4.param.SliFamily = 0;
        hba->sli.sli4.param.Revision = 0x4; /* SLI4 */
        hba->sli.sli4.param.FT = 0;

        hba->sli.sli4.param.EqeCntMethod = 0x1; /* Bit pattern */
        hba->sli.sli4.param.EqPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.EqeSize = 0x1; /* 4 byte */
        hba->sli.sli4.param.EqPageCnt = 8;
        hba->sli.sli4.param.EqeCntMask = 0x1F; /* 256-4096 elements */

        hba->sli.sli4.param.CqeCntMethod = 0x1; /* Bit pattern */
        hba->sli.sli4.param.CqPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.CQV = 0;
        hba->sli.sli4.param.CqeSize = 0x3; /* 16 byte */
        hba->sli.sli4.param.CqPageCnt = 4;
        hba->sli.sli4.param.CqeCntMask = 0x70; /* 256-1024 elements */

        hba->sli.sli4.param.MqeCntMethod = 0x1; /* Bit pattern */
        hba->sli.sli4.param.MqPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.MQV = 0;
        hba->sli.sli4.param.MqPageCnt = 8;
        hba->sli.sli4.param.MqeCntMask = 0x0F; /* 16-128 elements */

        hba->sli.sli4.param.WqeCntMethod = 0; /* Page Count */
        hba->sli.sli4.param.WqPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.WQV = 0;
        hba->sli.sli4.param.WqeSize = 0x5; /* 64 byte */
        hba->sli.sli4.param.WqPageCnt = 4;
        hba->sli.sli4.param.WqeCntMask = 0x10; /* 256 elements */

        hba->sli.sli4.param.RqeCntMethod = 0; /* Page Count */
        hba->sli.sli4.param.RqPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.RQV = 0;
        hba->sli.sli4.param.RqeSize = 0x2; /* 8 byte */
        hba->sli.sli4.param.RqPageCnt = 8;
        hba->sli.sli4.param.RqDbWin = 1;
        hba->sli.sli4.param.RqeCntMask = 0x100; /* 4096 elements */

        hba->sli.sli4.param.Loopback = 0xf; /* unsupported */
        hba->sli.sli4.param.PHWQ = 0;
        hba->sli.sli4.param.PHON = 0;
        hba->sli.sli4.param.TRIR = 0;
        hba->sli.sli4.param.TRTY = 0;
        hba->sli.sli4.param.TCCA = 0;
        hba->sli.sli4.param.MWQE = 0;
        hba->sli.sli4.param.ASSI = 0;
        hba->sli.sli4.param.TERP = 0;
        hba->sli.sli4.param.TGT  = 0;
        hba->sli.sli4.param.AREG = 0;
        hba->sli.sli4.param.FBRR = 0;
        hba->sli.sli4.param.SGLR = 1;
        hba->sli.sli4.param.HDRR = 1;
        hba->sli.sli4.param.EXT  = 0;
        hba->sli.sli4.param.FCOE = 1;

        hba->sli.sli4.param.SgeLength = (64 * 1024);
        hba->sli.sli4.param.SglAlign = 0x7 /* 4096 */;
        hba->sli.sli4.param.SglPageSize = 0x1; /* 4096 */
        hba->sli.sli4.param.SglPageCnt = 2;

        hba->sli.sli4.param.MinRqSize = 128;
        hba->sli.sli4.param.MaxRqSize = 2048;

        hba->sli.sli4.param.RPIMax = 0x3ff;
        hba->sli.sli4.param.XRIMax = 0x3ff;
        hba->sli.sli4.param.VFIMax = 0xff;
        hba->sli.sli4.param.VPIMax = 0xff;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "Default SLI4 parameters set.");

} /* emlxs_sli4_set_default_params() */


/*
 * emlxs_sli4_online()
 *
 * This routine will start initialization of the SLI4 HBA.
 */
static int32_t
emlxs_sli4_online(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        emlxs_config_t *cfg;
        emlxs_vpd_t *vpd;
        MAILBOXQ *mbq = NULL;
        MAILBOX4 *mb  = NULL;
        MATCHMAP *mp  = NULL;
        uint32_t i;
        uint32_t j;
        uint32_t rval = 0;
        uint8_t *vpd_data;
        uint32_t sli_mode;
        uint8_t *outptr;
        uint32_t status;
        uint32_t fw_check;
        uint32_t kern_update = 0;
        emlxs_firmware_t hba_fw;
        emlxs_firmware_t *fw;
        uint16_t ssvid;
        char buf[64];

        cfg = &CFG;
        vpd = &VPD;

        sli_mode = EMLXS_HBA_SLI4_MODE;
        hba->sli_mode = sli_mode;

        /* Set the fw_check flag */
        fw_check = cfg[CFG_FW_CHECK].current;

        if ((fw_check & 0x04) ||
            (hba->fw_flag & FW_UPDATE_KERNEL)) {
                kern_update = 1;
        }

        hba->mbox_queue_flag = 0;
        hba->fc_edtov = FF_DEF_EDTOV;
        hba->fc_ratov = FF_DEF_RATOV;
        hba->fc_altov = FF_DEF_ALTOV;
        hba->fc_arbtov = FF_DEF_ARBTOV;

        /* Networking not supported */
        if (cfg[CFG_NETWORK_ON].current) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
                    "Networking is not supported in SLI4, turning it off");
                cfg[CFG_NETWORK_ON].current = 0;
        }

        hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
        if (hba->chan_count > MAX_CHANNEL) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Max channels exceeded, dropping num-wq from %d to 1",
                    cfg[CFG_NUM_WQ].current);
                cfg[CFG_NUM_WQ].current = 1;
                hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
        }
        hba->channel_fcp = 0; /* First channel */

        /* Default channel for everything else is the last channel */
        hba->channel_ip = hba->chan_count - 1;
        hba->channel_els = hba->chan_count - 1;
        hba->channel_ct = hba->chan_count - 1;

        hba->fc_iotag = 1;
        hba->io_count = 0;
        hba->channel_tx_count = 0;

        /* Specific to ATTO G5 boards */
        if (hba->model_info.flags & EMLXS_GPIO_LEDS) {
                /* Set hard-coded GPIO pins */
                if (hba->pci_function_number) {
                        hba->gpio_pin[EMLXS_GPIO_PIN_LO] = 27;
                        hba->gpio_pin[EMLXS_GPIO_PIN_HI] = 28;
                        hba->gpio_pin[EMLXS_GPIO_PIN_ACT] = 29;
                        hba->gpio_pin[EMLXS_GPIO_PIN_LASER] = 8;
                } else {
                        hba->gpio_pin[EMLXS_GPIO_PIN_LO] = 13;
                        hba->gpio_pin[EMLXS_GPIO_PIN_HI] = 25;
                        hba->gpio_pin[EMLXS_GPIO_PIN_ACT] = 26;
                        hba->gpio_pin[EMLXS_GPIO_PIN_LASER] = 12;
                }
        }

        /* Initialize the local dump region buffer */
        bzero(&hba->sli.sli4.dump_region, sizeof (MBUF_INFO));
        hba->sli.sli4.dump_region.size = EMLXS_DUMP_REGION_SIZE;
        hba->sli.sli4.dump_region.flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
        hba->sli.sli4.dump_region.align = ddi_ptob(hba->dip, 1L);

        (void) emlxs_mem_alloc(hba, &hba->sli.sli4.dump_region);

        if (hba->sli.sli4.dump_region.virt == NULL) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate dump region buffer.");

                return (ENOMEM);
        }

        /*
         * Get a buffer which will be used repeatedly for mailbox commands
         */
        mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)), KM_SLEEP);

        mb = (MAILBOX4 *)mbq;

reset:
        /* Reset & Initialize the adapter */
        if (emlxs_sli4_hba_init(hba)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to init hba.");

                rval = EIO;
                goto failed1;
        }

#ifdef FMA_SUPPORT
        /* Access handle validation */
        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_6:
                if ((emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
                    != DDI_FM_OK) ||
                    (emlxs_fm_check_acc_handle(hba,
                    hba->sli.sli4.bar0_acc_handle) != DDI_FM_OK) ||
                    (emlxs_fm_check_acc_handle(hba,
                    hba->sli.sli4.bar1_acc_handle) != DDI_FM_OK)) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_access_handle_msg, NULL);

                        rval = EIO;
                        goto failed1;
                }
                break;
        case SLI_INTF_IF_TYPE_2:
                if ((emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
                    != DDI_FM_OK) ||
                    (emlxs_fm_check_acc_handle(hba,
                    hba->sli.sli4.bar0_acc_handle) != DDI_FM_OK)) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_access_handle_msg, NULL);

                        rval = EIO;
                        goto failed1;
                }
                break;
        default :
                if ((emlxs_fm_check_acc_handle(hba,
                    hba->pci_acc_handle) != DDI_FM_OK) ||
                    (emlxs_fm_check_acc_handle(hba,
                    hba->sli.sli4.bar1_acc_handle) != DDI_FM_OK) ||
                    (emlxs_fm_check_acc_handle(hba,
                    hba->sli.sli4.bar2_acc_handle) != DDI_FM_OK)) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_access_handle_msg, NULL);

                        rval = EIO;
                        goto failed1;
                }
                break;
        }
#endif  /* FMA_SUPPORT */

        /*
         * Setup and issue mailbox READ REV command
         */
        vpd->opFwRev = 0;
        vpd->postKernRev = 0;
        vpd->sli1FwRev = 0;
        vpd->sli2FwRev = 0;
        vpd->sli3FwRev = 0;
        vpd->sli4FwRev = 0;

        vpd->postKernName[0] = 0;
        vpd->opFwName[0] = 0;
        vpd->sli1FwName[0] = 0;
        vpd->sli2FwName[0] = 0;
        vpd->sli3FwName[0] = 0;
        vpd->sli4FwName[0] = 0;

        vpd->opFwLabel[0] = 0;
        vpd->sli1FwLabel[0] = 0;
        vpd->sli2FwLabel[0] = 0;
        vpd->sli3FwLabel[0] = 0;
        vpd->sli4FwLabel[0] = 0;

        EMLXS_STATE_CHANGE(hba, FC_INIT_REV);

        emlxs_mb_get_sli4_params(hba, mbq);
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "Unable to read parameters. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                /* Set param defaults */
                emlxs_sli4_set_default_params(hba);

        } else {
                /* Save parameters */
                bcopy((char *)&mb->un.varSLIConfig.payload,
                    (char *)&hba->sli.sli4.param, sizeof (sli_params_t));

                emlxs_data_dump(port, "SLI_PARMS",
                    (uint32_t *)&hba->sli.sli4.param,
                    sizeof (sli_params_t), 0);
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_get_port_name(hba, mbq);
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "Unable to get port names. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                bzero(hba->sli.sli4.port_name,
                    sizeof (hba->sli.sli4.port_name));
        } else {
                /* Save port names */
                bcopy((char *)&mb->un.varSLIConfig.payload,
                    (char *)&hba->sli.sli4.port_name,
                    sizeof (hba->sli.sli4.port_name));
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_read_rev(hba, mbq, 0);
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to read rev. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                rval = EIO;
                goto failed1;

        }

        emlxs_data_dump(port, "RD_REV", (uint32_t *)mb, 18, 0);
        if (mb->un.varRdRev4.sliLevel != 4) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Invalid read rev Version for SLI4: 0x%x",
                    mb->un.varRdRev4.sliLevel);

                rval = EIO;
                goto failed1;
        }

        switch (mb->un.varRdRev4.dcbxMode) {
        case EMLXS_DCBX_MODE_CIN:       /* Mapped to nonFIP mode */
                hba->flag &= ~FC_FIP_SUPPORTED;
                break;

        case EMLXS_DCBX_MODE_CEE:       /* Mapped to FIP mode */
                hba->flag |= FC_FIP_SUPPORTED;
                break;

        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Invalid read rev dcbx mode for SLI4: 0x%x",
                    mb->un.varRdRev4.dcbxMode);

                rval = EIO;
                goto failed1;
        }

        /* Set FC/FCoE mode */
        if (mb->un.varRdRev4.FCoE) {
                hba->sli.sli4.flag |= EMLXS_SLI4_FCOE_MODE;
        } else {
                hba->sli.sli4.flag &= ~EMLXS_SLI4_FCOE_MODE;
        }

        /* Save information as VPD data */
        vpd->rBit = 1;

        vpd->sli4FwRev = (mb->un.varRdRev4.ULPFwId);
        bcopy((char *)mb->un.varRdRev4.ULPFwName, vpd->sli4FwName, 16);

        vpd->opFwRev = (mb->un.varRdRev4.ULPFwId);
        bcopy((char *)mb->un.varRdRev4.ULPFwName, vpd->opFwName, 16);

        vpd->postKernRev = (mb->un.varRdRev4.ARMFwId);
        bcopy((char *)mb->un.varRdRev4.ARMFwName, vpd->postKernName, 16);

        vpd->biuRev = mb->un.varRdRev4.HwRev1;
        vpd->fcphHigh = mb->un.varRdRev4.fcphHigh;
        vpd->fcphLow = mb->un.varRdRev4.fcphLow;
        vpd->feaLevelHigh = mb->un.varRdRev4.feaLevelHigh;
        vpd->feaLevelLow = mb->un.varRdRev4.feaLevelLow;

        /* Decode FW labels */
        if ((hba->model_info.chip & EMLXS_LANCER_CHIPS) != 0) {
                bcopy(vpd->postKernName, vpd->sli4FwName, 16);
        }
        emlxs_decode_label(vpd->sli4FwName, vpd->sli4FwName, 0,
            sizeof (vpd->sli4FwName));
        emlxs_decode_label(vpd->opFwName, vpd->opFwName, 0,
            sizeof (vpd->opFwName));
        emlxs_decode_label(vpd->postKernName, vpd->postKernName, 0,
            sizeof (vpd->postKernName));

        if (hba->model_info.chip == EMLXS_BE2_CHIP) {
                (void) strlcpy(vpd->sli4FwLabel, "be2.ufi",
                    sizeof (vpd->sli4FwLabel));
        } else if (hba->model_info.chip == EMLXS_BE3_CHIP) {
                (void) strlcpy(vpd->sli4FwLabel, "be3.ufi",
                    sizeof (vpd->sli4FwLabel));
        } else if (hba->model_info.chip == EMLXS_LANCER_CHIP) {
                (void) strlcpy(vpd->sli4FwLabel, "xe201.grp",
                    sizeof (vpd->sli4FwLabel));
        } else if (hba->model_info.chip == EMLXS_LANCERG6_CHIP) {
                (void) strlcpy(vpd->sli4FwLabel, "xe501.grp",
                    sizeof (vpd->sli4FwLabel));
        } else if (hba->model_info.chip == EMLXS_PRISMG7_CHIP) {
                (void) strlcpy(vpd->sli4FwLabel, "xe601.grp",
                    sizeof (vpd->sli4FwLabel));
        } else {
                (void) strlcpy(vpd->sli4FwLabel, "sli4.fw",
                    sizeof (vpd->sli4FwLabel));
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "VPD ULP:%08x %s ARM:%08x %s f:%d %d %d %d : dcbx %d",
            vpd->opFwRev, vpd->opFwName, vpd->postKernRev, vpd->postKernName,
            vpd->fcphHigh, vpd->fcphLow, vpd->feaLevelHigh, vpd->feaLevelLow,
            mb->un.varRdRev4.dcbxMode);

        /* No key information is needed for SLI4 products */

        /* Get adapter VPD information */
        vpd->port_index = (uint32_t)-1;

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_dump_vpd(hba, mbq, 0);
        vpd_data = hba->sli.sli4.dump_region.virt;

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
            MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "No VPD found. status=%x", mb->mbxStatus);
        } else {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_debug_msg,
                    "VPD dumped. rsp_cnt=%d status=%x",
                    mb->un.varDmp4.rsp_cnt, mb->mbxStatus);

                if (mb->un.varDmp4.rsp_cnt) {
                        EMLXS_MPDATA_SYNC(hba->sli.sli4.dump_region.dma_handle,
                            0, mb->un.varDmp4.rsp_cnt, DDI_DMA_SYNC_FORKERNEL);

#ifdef FMA_SUPPORT
                        if (hba->sli.sli4.dump_region.dma_handle) {
                                if (emlxs_fm_check_dma_handle(hba,
                                    hba->sli.sli4.dump_region.dma_handle)
                                    != DDI_FM_OK) {
                                        EMLXS_MSGF(EMLXS_CONTEXT,
                                            &emlxs_invalid_dma_handle_msg,
                                            "sli4_online: hdl=%p",
                                            hba->sli.sli4.dump_region.
                                            dma_handle);
                                        rval = EIO;
                                        goto failed1;
                                }
                        }
#endif /* FMA_SUPPORT */

                }
        }

        if (vpd_data[0]) {
                (void) emlxs_parse_vpd(hba, (uint8_t *)vpd_data,
                    mb->un.varDmp4.rsp_cnt);

                /*
                 * 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;
                if ((vpd->model[0] != 0) &&
                    (strcmp(&vpd->model[0], hba->model_info.model) != 0)) {

                        /* First scan for a V2 match */

                        for (i = 1; i < emlxs_pci_model_count; i++) {
                                if (strcmp(&vpd->model[0],
                                    emlxs_pci_model[i].model) == 0) {
                                        bcopy(&emlxs_pci_model[i],
                                            &hba->model_info,
                                            sizeof (emlxs_model_t));
                                        rval = 1;
                                        break;
                                }
                        }
                }

                if (!rval && (vpd->part_num[0] != 0) &&
                    (strcmp(&vpd->part_num[0], hba->model_info.model) != 0)) {

                        /* Next scan for a PN match */

                        for (i = 1; i < emlxs_pci_model_count; i++) {
                                if (strcmp(&vpd->part_num[0],
                                    emlxs_pci_model[i].model) == 0) {
                                        bcopy(&emlxs_pci_model[i],
                                            &hba->model_info,
                                            sizeof (emlxs_model_t));
                                        break;
                                }
                        }
                }

                /* HP CNA port indices start at 1 instead of 0 */
                if (hba->model_info.chip & EMLXS_BE_CHIPS) {
                        ssvid = ddi_get16(hba->pci_acc_handle,
                            (uint16_t *)(hba->pci_addr + PCI_SSVID_REGISTER));

                        if ((ssvid == PCI_SSVID_HP) && (vpd->port_index > 0)) {
                                vpd->port_index--;
                        }
                }

                /*
                 * 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) {
                        (void) strncpy(hba->model_info.model_desc,
                            vpd->model_desc,
                            (sizeof (hba->model_info.model_desc)-1));
                }

                /* Replace the default model with vpd data */
                if (vpd->model[0] != 0) {
                        (void) strncpy(hba->model_info.model, vpd->model,
                            (sizeof (hba->model_info.model)-1));
                }

                /* Replace the default program types with vpd data */
                if (vpd->prog_types[0] != 0) {
                        emlxs_parse_prog_types(hba, vpd->prog_types);
                }
        }

        /*
         * Since the adapter model may have changed with the vpd data
         * lets double check if adapter is not supported
         */
        if (hba->model_info.flags & EMLXS_NOT_SUPPORTED) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unsupported adapter found.  "
                    "Id:%d  Vendor id:0x%x  Device id:0x%x  SSDID:0x%x  "
                    "Model:%s", hba->model_info.id, hba->model_info.vendor_id,
                    hba->model_info.device_id, hba->model_info.ssdid,
                    hba->model_info.model);

                rval = EIO;
                goto failed1;
        }

        (void) strncpy(vpd->boot_version, vpd->sli4FwName,
            (sizeof (vpd->boot_version)-1));

        /* Get fcode version property */
        emlxs_get_fcode_version(hba);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "Firmware: kern=%08x stub=%08x sli1=%08x", vpd->postKernRev,
            vpd->opFwRev, vpd->sli1FwRev);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "Firmware: sli2=%08x sli3=%08x sli4=%08x fl=%x", vpd->sli2FwRev,
            vpd->sli3FwRev, vpd->sli4FwRev, vpd->feaLevelHigh);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "BIOS: boot=%s fcode=%s", vpd->boot_version, vpd->fcode_version);

        /*
         * If firmware checking is enabled and the adapter model indicates
         * a firmware image, then perform firmware version check
         */
        hba->fw_flag = 0;
        hba->fw_timer = 0;

        if (((fw_check & 0x1) &&
            (hba->model_info.flags & EMLXS_ORACLE_BRANDED) &&
            hba->model_info.fwid) ||
            ((fw_check & 0x2) && hba->model_info.fwid)) {

                /* Find firmware image indicated by adapter model */
                fw = NULL;
                for (i = 0; i < emlxs_fw_count; i++) {
                        if (emlxs_fw_table[i].id == hba->model_info.fwid) {
                                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 */
                        if (hba->model_info.chip & EMLXS_BE_CHIPS) {
                                (void) emlxs_be_read_fw_version(hba, &hba_fw);
                        } else {
                                hba_fw.kern = vpd->postKernRev;
                                hba_fw.stub = vpd->opFwRev;
                                hba_fw.sli1 = vpd->sli1FwRev;
                                hba_fw.sli2 = vpd->sli2FwRev;
                                hba_fw.sli3 = vpd->sli3FwRev;
                                hba_fw.sli4 = vpd->sli4FwRev;
                        }

                        if (!kern_update &&
                            ((fw->kern && (hba_fw.kern != fw->kern)) ||
                            (fw->stub && (hba_fw.stub != fw->stub)))) {

                                hba->fw_flag |= FW_UPDATE_NEEDED;

                        } else if ((fw->kern && (hba_fw.kern != fw->kern)) ||
                            (fw->stub && (hba_fw.stub != fw->stub)) ||
                            (fw->sli1 && (hba_fw.sli1 != fw->sli1)) ||
                            (fw->sli2 && (hba_fw.sli2 != fw->sli2)) ||
                            (fw->sli3 && (hba_fw.sli3 != fw->sli3)) ||
                            (fw->sli4 && (hba_fw.sli4 != fw->sli4))) {

                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
                                    "Firmware update needed. "
                                    "Updating. id=%d fw=%d",
                                    hba->model_info.id, hba->model_info.fwid);

#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
                                 */
                                emlxs_fw_load(hba, fw);
#endif /* MODFW_SUPPORT */

                                if (fw->image && fw->size) {
                                        uint32_t rc;

                                        rc = emlxs_fw_download(hba,
                                            (char *)fw->image, fw->size, 0);
                                        if ((rc != FC_SUCCESS) &&
                                            (rc != EMLXS_REBOOT_REQUIRED)) {
                                                EMLXS_MSGF(EMLXS_CONTEXT,
                                                    &emlxs_init_msg,
                                                    "Firmware update failed.");
                                                hba->fw_flag |=
                                                    FW_UPDATE_NEEDED;
                                        }
#ifdef MODFW_SUPPORT
                                        /*
                                         * Unload the firmware image from
                                         * kernel memory
                                         */
                                        emlxs_fw_unload(hba, fw);
#endif /* MODFW_SUPPORT */

                                        fw_check = 0;

                                        goto reset;
                                }

                                hba->fw_flag |= FW_UPDATE_NEEDED;

                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
                                    "Firmware image unavailable.");
                        } else {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
                                    "Firmware update not needed.");
                        }
                } else {
                        /*
                         * This means either the adapter database is not
                         * correct or a firmware image is missing from the
                         * compile
                         */
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
                            "Firmware image unavailable. id=%d fw=%d",
                            hba->model_info.id, hba->model_info.fwid);
                }
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_dump_fcoe(hba, mbq, 0);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
            MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "No FCOE info found. status=%x", mb->mbxStatus);
        } else {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_debug_msg,
                    "FCOE info dumped. rsp_cnt=%d status=%x",
                    mb->un.varDmp4.rsp_cnt, mb->mbxStatus);
                (void) emlxs_parse_fcoe(hba,
                    (uint8_t *)hba->sli.sli4.dump_region.virt,
                    mb->un.varDmp4.rsp_cnt);
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        status = 0;
        if (port->flag & EMLXS_INI_ENABLED) {
                status |= SLI4_FEATURE_FCP_INITIATOR;
        }
        if (port->flag & EMLXS_TGT_ENABLED) {
                status |= SLI4_FEATURE_FCP_TARGET;
        }
        if (cfg[CFG_NPIV_ENABLE].current) {
                status |= SLI4_FEATURE_NPIV;
        }
        if (cfg[CFG_RQD_MODE].current) {
                status |= SLI4_FEATURE_RQD;
        }
        if (cfg[CFG_PERF_HINT].current) {
                if (hba->sli.sli4.param.PHON) {
                        status |= SLI4_FEATURE_PERF_HINT;
                }
        }

        emlxs_mb_request_features(hba, mbq, status);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to REQUEST_FEATURES. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                rval = EIO;
                goto failed1;
        }
        emlxs_data_dump(port, "REQ_FEATURE", (uint32_t *)mb, 6, 0);

        /* Check to see if we get the features we requested */
        if (status != mb->un.varReqFeatures.featuresEnabled) {

                /* Just report descrepencies, don't abort the attach */

                outptr = (uint8_t *)emlxs_request_feature_xlate(
                    mb->un.varReqFeatures.featuresRequested);
                (void) strlcpy(buf, (char *)outptr, sizeof (buf));

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "REQUEST_FEATURES: wanted:%s  got:%s",
                    &buf[0], emlxs_request_feature_xlate(
                    mb->un.varReqFeatures.featuresEnabled));

        }

        if ((port->flag & EMLXS_INI_ENABLED) &&
            !(mb->un.varReqFeatures.featuresEnabled &
            SLI4_FEATURE_FCP_INITIATOR)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Initiator mode not supported by adapter.");

                rval = EIO;

#ifdef SFCT_SUPPORT
                /* Check if we can fall back to just target mode */
                if ((hba->pm_state == EMLXS_PM_IN_ATTACH) &&
                    (mb->un.varReqFeatures.featuresEnabled &
                    SLI4_FEATURE_FCP_TARGET) &&
                    (cfg[CFG_DTM_ENABLE].current == 1) &&
                    (cfg[CFG_TARGET_MODE].current == 1)) {

                        cfg[CFG_DTM_ENABLE].current = 0;

                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_init_failed_msg,
                            "Disabling dynamic target mode. "
                            "Enabling target mode only.");

                        /* This will trigger the driver to reattach */
                        rval = EAGAIN;
                }
#endif /* SFCT_SUPPORT */
                goto failed1;
        }

        if ((port->flag & EMLXS_TGT_ENABLED) &&
            !(mb->un.varReqFeatures.featuresEnabled &
            SLI4_FEATURE_FCP_TARGET)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Target mode not supported by adapter.");

                rval = EIO;

#ifdef SFCT_SUPPORT
                /* Check if we can fall back to just initiator mode */
                if ((hba->pm_state == EMLXS_PM_IN_ATTACH) &&
                    (mb->un.varReqFeatures.featuresEnabled &
                    SLI4_FEATURE_FCP_INITIATOR) &&
                    (cfg[CFG_DTM_ENABLE].current == 1) &&
                    (cfg[CFG_TARGET_MODE].current == 0)) {

                        cfg[CFG_DTM_ENABLE].current = 0;

                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_init_failed_msg,
                            "Disabling dynamic target mode. "
                            "Enabling initiator mode only.");

                        /* This will trigger the driver to reattach */
                        rval = EAGAIN;
                }
#endif /* SFCT_SUPPORT */
                goto failed1;
        }

        if (mb->un.varReqFeatures.featuresEnabled & SLI4_FEATURE_NPIV) {
                hba->flag |= FC_NPIV_ENABLED;
        }

        if (mb->un.varReqFeatures.featuresEnabled & SLI4_FEATURE_PERF_HINT) {
                hba->sli.sli4.flag |= EMLXS_SLI4_PHON;
                if (hba->sli.sli4.param.PHWQ) {
                        hba->sli.sli4.flag |= EMLXS_SLI4_PHWQ;
                }
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_read_config(hba, mbq);
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to READ_CONFIG. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                rval = EIO;
                goto failed1;
        }
        emlxs_data_dump(port, "READ_CONFIG4", (uint32_t *)mb, 18, 0);

        /* Set default extents */
        hba->sli.sli4.XRICount = mb->un.varRdConfig4.XRICount;
        hba->sli.sli4.XRIExtCount = 1;
        hba->sli.sli4.XRIExtSize = hba->sli.sli4.XRICount;
        hba->sli.sli4.XRIBase[0] = mb->un.varRdConfig4.XRIBase;

        hba->sli.sli4.RPICount = mb->un.varRdConfig4.RPICount;
        hba->sli.sli4.RPIExtCount = 1;
        hba->sli.sli4.RPIExtSize = hba->sli.sli4.RPICount;
        hba->sli.sli4.RPIBase[0] = mb->un.varRdConfig4.RPIBase;

        hba->sli.sli4.VPICount = mb->un.varRdConfig4.VPICount;
        hba->sli.sli4.VPIExtCount = 1;
        hba->sli.sli4.VPIExtSize = hba->sli.sli4.VPICount;
        hba->sli.sli4.VPIBase[0] = mb->un.varRdConfig4.VPIBase;

        hba->sli.sli4.VFICount = mb->un.varRdConfig4.VFICount;
        hba->sli.sli4.VFIExtCount = 1;
        hba->sli.sli4.VFIExtSize = hba->sli.sli4.VFICount;
        hba->sli.sli4.VFIBase[0] = mb->un.varRdConfig4.VFIBase;

        hba->sli.sli4.FCFICount = mb->un.varRdConfig4.FCFICount;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "CONFIG: xri:%d rpi:%d vpi:%d vfi:%d fcfi:%d",
            hba->sli.sli4.XRICount,
            hba->sli.sli4.RPICount,
            hba->sli.sli4.VPICount,
            hba->sli.sli4.VFICount,
            hba->sli.sli4.FCFICount);

        if ((hba->sli.sli4.XRICount == 0) ||
            (hba->sli.sli4.RPICount == 0) ||
            (hba->sli.sli4.VPICount == 0) ||
            (hba->sli.sli4.VFICount == 0) ||
            (hba->sli.sli4.FCFICount == 0)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Invalid extent value(s) - xri:%d rpi:%d vpi:%d "
                    "vfi:%d fcfi:%d",
                    hba->sli.sli4.XRICount,
                    hba->sli.sli4.RPICount,
                    hba->sli.sli4.VPICount,
                    hba->sli.sli4.VFICount,
                    hba->sli.sli4.FCFICount);

                rval = EIO;
                goto failed1;
        }

        if (mb->un.varRdConfig4.extents) {
                if (emlxs_sli4_init_extents(hba, mbq)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to initialize extents.");

                        rval = EIO;
                        goto failed1;
                }
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "CONFIG: port_name:%c %c %c %c",
            hba->sli.sli4.port_name[0],
            hba->sli.sli4.port_name[1],
            hba->sli.sli4.port_name[2],
            hba->sli.sli4.port_name[3]);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "CONFIG: ldv:%d link_type:%d link_number:%d",
            mb->un.varRdConfig4.ldv,
            mb->un.varRdConfig4.link_type,
            mb->un.varRdConfig4.link_number);

        if (mb->un.varRdConfig4.ldv) {
                hba->sli.sli4.link_number = mb->un.varRdConfig4.link_number;
        } else {
                hba->sli.sli4.link_number = (uint32_t)-1;
        }

        if (hba->sli.sli4.VPICount) {
                hba->vpi_max = min(hba->sli.sli4.VPICount, MAX_VPORTS) - 1;
        }

        /* Set the max node count */
        if (cfg[CFG_NUM_NODES].current > 0) {
                hba->max_nodes =
                    min(cfg[CFG_NUM_NODES].current,
                    hba->sli.sli4.RPICount);
        } else {
                hba->max_nodes = hba->sli.sli4.RPICount;
        }

        /* Set the io throttle */
        hba->io_throttle = hba->sli.sli4.XRICount - IO_THROTTLE_RESERVE;

        /* Set max_iotag */
        /* We add 1 in case all XRI's are non-zero */
        hba->max_iotag = hba->sli.sli4.XRICount + 1;

        if (cfg[CFG_NUM_IOTAGS].current) {
                hba->max_iotag = min(hba->max_iotag,
                    (uint16_t)cfg[CFG_NUM_IOTAGS].current);
        }

        /* Set out-of-range iotag base */
        hba->fc_oor_iotag = hba->max_iotag;

        /* Save the link speed capabilities */
        vpd->link_speed = (uint16_t)mb->un.varRdConfig4.lmt;
        emlxs_process_link_speed(hba);

        /*
         * Allocate some memory for buffers
         */
        if (emlxs_mem_alloc_buffer(hba) == 0) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate memory buffers.");

                rval = ENOMEM;
                goto failed1;
        }

        if (emlxs_sli4_resource_alloc(hba)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate resources.");

                rval = ENOMEM;
                goto failed2;
        }
        emlxs_data_dump(port, "XRIp", (uint32_t *)hba->sli.sli4.XRIp, 18, 0);
        emlxs_sli4_zero_queue_stat(hba);

#if (EMLXS_MODREV >= EMLXS_MODREV5)
        if ((cfg[CFG_NPIV_ENABLE].current) && (hba->flag & FC_NPIV_ENABLED)) {
                hba->fca_tran->fca_num_npivports = hba->vpi_max;
        }
#endif /* >= EMLXS_MODREV5 */

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        if (emlxs_sli4_post_sgl_pages(hba, mbq)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to post sgl pages.");

                rval = EIO;
                goto failed3;
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        if (emlxs_sli4_post_hdr_tmplates(hba, mbq)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to post header templates.");

                rval = EIO;
                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
         */
        if (EMLXS_INTR_ADD(hba) != DDI_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to add interrupt(s).");

                rval = EIO;
                goto failed3;
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        /* This MUST be done after EMLXS_INTR_ADD */
        if (emlxs_sli4_create_queues(hba, mbq)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to create queues.");

                rval = EIO;
                goto failed3;
        }

        EMLXS_STATE_CHANGE(hba, FC_INIT_CFGPORT);

        /* Get and save the current firmware version (based on sli_mode) */
        emlxs_decode_firmware_rev(hba, vpd);


        EMLXS_STATE_CHANGE(hba, FC_INIT_INITLINK);

        if (SLI4_FC_MODE) {
                /* Reuse mbq from previous mbox */
                bzero(mbq, sizeof (MAILBOXQ));

                emlxs_mb_config_link(hba, mbq);
                if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                    MBX_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to configure link. Mailbox cmd=%x "
                            "status=%x",
                            mb->mbxCommand, mb->mbxStatus);

                        rval = EIO;
                        goto failed3;
                }
        }

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        /*
         * We need to get login parameters for NID
         */
        (void) emlxs_mb_read_sparam(hba, mbq);
        mp = (MATCHMAP *)mbq->bp;
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to read parameters. Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                rval = EIO;
                goto failed3;
        }

        /* Free the buffer since we were polling */
        emlxs_mem_put(hba, MEM_BUF, (void *)mp);
        mp = NULL;

        /* If no serial number in VPD data, then use the WWPN */
        if (vpd->serial_num[0] == 0) {
                outptr = (uint8_t *)&hba->wwpn.IEEE[0];
                for (i = 0; i < 12; i++) {
                        status = *outptr++;
                        j = ((status & 0xf0) >> 4);
                        if (j <= 9) {
                                vpd->serial_num[i] =
                                    (char)((uint8_t)'0' + (uint8_t)j);
                        } else {
                                vpd->serial_num[i] =
                                    (char)((uint8_t)'A' + (uint8_t)(j - 10));
                        }

                        i++;
                        j = (status & 0xf);
                        if (j <= 9) {
                                vpd->serial_num[i] =
                                    (char)((uint8_t)'0' + (uint8_t)j);
                        } else {
                                vpd->serial_num[i] =
                                    (char)((uint8_t)'A' + (uint8_t)(j - 10));
                        }
                }

                /*
                 * 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_num[0] = 0;
                vpd->port_index = 0;

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "CONFIG: WWPN: port_index=0");
        }

        /* Make final attempt to set a port index */
        if (vpd->port_index == (uint32_t)-1) {
                dev_info_t *p_dip;
                dev_info_t *c_dip;

                p_dip = ddi_get_parent(hba->dip);
                c_dip = ddi_get_child(p_dip);

                vpd->port_index = 0;
                while (c_dip && (hba->dip != c_dip)) {
                        c_dip = ddi_get_next_sibling(c_dip);

                        if (strcmp(ddi_get_name(c_dip), "ethernet") == 0) {
                                continue;
                        }

                        vpd->port_index++;
                }

                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_debug_msg,
                    "CONFIG: Device tree: port_index=%d",
                    vpd->port_index);
        }

        if (vpd->port_num[0] == 0) {
                if (hba->model_info.channels == EMLXS_MULTI_CHANNEL) {
                        (void) snprintf(vpd->port_num,
                            (sizeof (vpd->port_num)-1),
                            "%d", vpd->port_index);
                }
        }

        if (vpd->id[0] == 0) {
                (void) snprintf(vpd->id, (sizeof (vpd->id)-1),
                    "%s %d",
                    hba->model_info.model_desc, vpd->port_index);

        }

        if (vpd->manufacturer[0] == 0) {
                (void) strncpy(vpd->manufacturer, hba->model_info.manufacturer,
                    (sizeof (vpd->manufacturer)-1));
        }

        if (vpd->part_num[0] == 0) {
                (void) strncpy(vpd->part_num, hba->model_info.model,
                    (sizeof (vpd->part_num)-1));
        }

        if (vpd->model_desc[0] == 0) {
                (void) snprintf(vpd->model_desc, (sizeof (vpd->model_desc)-1),
                    "%s %d",
                    hba->model_info.model_desc, vpd->port_index);
        }

        if (vpd->model[0] == 0) {
                (void) strncpy(vpd->model, hba->model_info.model,
                    (sizeof (vpd->model)-1));
        }

        if (vpd->prog_types[0] == 0) {
                emlxs_build_prog_types(hba, vpd);
        }

        /* Create the symbolic names */
        (void) snprintf(hba->snn, (sizeof (hba->snn)-1),
            "%s %s FV%s DV%s %s",
            hba->model_info.manufacturer, hba->model_info.model,
            hba->vpd.fw_version, emlxs_version,
            (char *)utsname.nodename);

        (void) snprintf(hba->spn, (sizeof (hba->spn)-1),
            "%s PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
            hba->model_info.manufacturer,
            hba->wwpn.nameType, hba->wwpn.IEEEextMsn, hba->wwpn.IEEEextLsb,
            hba->wwpn.IEEE[0], hba->wwpn.IEEE[1], hba->wwpn.IEEE[2],
            hba->wwpn.IEEE[3], hba->wwpn.IEEE[4], hba->wwpn.IEEE[5]);


        EMLXS_STATE_CHANGE(hba, FC_LINK_DOWN);
        emlxs_sli4_enable_intr(hba);

        /* Check persist-linkdown */
        if (cfg[CFG_PERSIST_LINKDOWN].current) {
                EMLXS_STATE_CHANGE(hba, FC_LINK_DOWN_PERSIST);
                goto done;
        }

#ifdef SFCT_SUPPORT
        if ((port->mode == MODE_TARGET) &&
            !(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
                goto done;
        }
#endif /* SFCT_SUPPORT */

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        /*
         * Interupts are enabled, start the timeout timers now.
         */
        emlxs_timer_start(hba);

        /*
         * Setup and issue mailbox INITIALIZE LINK command
         * At this point, the interrupt will be generated by the HW
         */
        emlxs_mb_init_link(hba, mbq,
            cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);

        rval = emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0);
        if ((rval != MBX_SUCCESS) && (rval != MBX_BUSY)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to initialize link. "
                    "Mailbox cmd=%x status=%x",
                    mb->mbxCommand, mb->mbxStatus);

                rval = EIO;
                goto failed4;
        }

        /* Wait for link to come up */
        i = cfg[CFG_LINKUP_DELAY].current;
        while (i && (hba->state < FC_LINK_UP)) {
                /* Check for hardware error */
                if (hba->state == FC_ERROR) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_init_failed_msg,
                            "Adapter error.");

                        rval = EIO;
                        goto failed4;
                }

                BUSYWAIT_MS(1000);
                i--;
        }
        if (i == 0) {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_msg,
                    "Link up timeout");
        }

done:
        /*
         * The leadville driver will now handle the FLOGI at the driver level
         */

        if (mbq) {
                (void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
                mbq = NULL;
                mb = NULL;
        }

        if (hba->model_info.flags & EMLXS_GPIO_LEDS)
                emlxs_sli4_gpio_timer_start(hba);

        return (0);

failed4:
        emlxs_timer_stop(hba);

failed3:
        EMLXS_STATE_CHANGE(hba, FC_ERROR);

        if (mp) {
                emlxs_mem_put(hba, MEM_BUF, (void *)mp);
                mp = NULL;
        }


        if (hba->intr_flags & EMLXS_MSI_ADDED) {
                (void) EMLXS_INTR_REMOVE(hba);
        }

        emlxs_sli4_resource_free(hba);

failed2:
        (void) emlxs_mem_free_buffer(hba);

failed1:
        if (mbq) {
                (void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
                mbq = NULL;
                mb = NULL;
        }

        if (hba->sli.sli4.dump_region.virt) {
                mutex_enter(&EMLXS_PORT_LOCK);
                (void) emlxs_mem_free(hba, &hba->sli.sli4.dump_region);
                mutex_exit(&EMLXS_PORT_LOCK);
        }

        if (rval == 0) {
                rval = EIO;
        }

        return (rval);

} /* emlxs_sli4_online() */


static void
emlxs_sli4_offline(emlxs_hba_t *hba, uint32_t reset_requested)
{
        /* Reverse emlxs_sli4_online */

        if (hba->model_info.flags & EMLXS_GPIO_LEDS)
                emlxs_sli4_gpio_timer_stop(hba);

        mutex_enter(&EMLXS_PORT_LOCK);
        if (hba->flag & FC_INTERLOCKED) {
                mutex_exit(&EMLXS_PORT_LOCK);
                goto killed;
        }
        mutex_exit(&EMLXS_PORT_LOCK);

        if (reset_requested) {
                (void) emlxs_sli4_hba_reset(hba, 0, 0, 0);
        }

        /* Shutdown the adapter interface */
        emlxs_sli4_hba_kill(hba);

killed:

        /* Free SLI shared memory */
        emlxs_sli4_resource_free(hba);

        /* Free driver shared memory */
        (void) emlxs_mem_free_buffer(hba);

        /* Free the host dump region buffer */
        mutex_enter(&EMLXS_PORT_LOCK);
        (void) emlxs_mem_free(hba, &hba->sli.sli4.dump_region);
        mutex_exit(&EMLXS_PORT_LOCK);

} /* emlxs_sli4_offline() */

static int
emlxs_map_g7_bars(emlxs_hba_t *hba)
{
        emlxs_port_t            *port = &PPORT;
        dev_info_t              *dip;
        ddi_device_acc_attr_t   dev_attr = emlxs_dev_acc_attr;
        uint_t                  num_prop;
        pci_regspec_t           *prop;
        int                     rnum, type, size, rcount, r;

        if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba->dip, 0,
            "reg", (int **)&prop, &num_prop) != DDI_PROP_SUCCESS) {
                return (0);
        }

        dip = (dev_info_t *)hba->dip;
        rcount = num_prop * sizeof (int) / sizeof (pci_regspec_t);
        for (r = 0; r < rcount; r++) {
                rnum = PCI_REG_REG_G(prop[r].pci_phys_hi);
                type = PCI_ADDR_MASK &prop[r].pci_phys_hi;
                size = prop[r].pci_size_low;
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_debug_msg,
                    "PCI_BAR%x regaddr=%x type=%x size=%x",
                    r, rnum, PCI_REG_ADDR_G(type), size);
                if (type < PCI_ADDR_MEM32) {
                        /* config or IO reg address */
                        continue;
                }
                /* MEM reg address */
                caddr_t addr;
                ddi_acc_handle_t handle;
                int status;

                status = ddi_regs_map_setup(dip, r,
                    (caddr_t *)&addr, 0, 0, &dev_attr,
                    &handle);
                if (status != DDI_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_attach_failed_msg,
                            "ddi_regs_map_setup BAR%d failed."
                            "  status=%x",
                            r, status);
                        ddi_prop_free((void *)prop);
                        return (0);
                }
                switch (r-1) {
                case 0:
                        if (hba->sli.sli4.bar0_acc_handle == 0) {
                                hba->sli.sli4.bar0_addr = addr;
                                hba->sli.sli4.bar0_acc_handle =
                                    handle;
                        }
                        break;
                case 1:
                        if (hba->sli.sli4.bar1_acc_handle == 0) {
                                hba->sli.sli4.bar1_addr = addr;
                                hba->sli.sli4.bar1_acc_handle =
                                    handle;
                        }
                        break;
                case 2:
                        if (hba->sli.sli4.bar2_acc_handle == 0) {
                                hba->sli.sli4.bar2_addr = addr;
                                hba->sli.sli4.bar2_acc_handle =
                                    handle;
                        }
                        break;
                }
        }
        ddi_prop_free((void *)prop);
        return (num_prop > 0);
}

/*ARGSUSED*/
static int
emlxs_sli4_map_hdw(emlxs_hba_t *hba)
{
        emlxs_port_t            *port = &PPORT;
        dev_info_t              *dip;
        ddi_device_acc_attr_t   dev_attr;
        int                     status;

        dip = (dev_info_t *)hba->dip;
        dev_attr = emlxs_dev_acc_attr;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:

                /* Map in Hardware BAR pages that will be used for */
                /* communication with HBA. */
                if (hba->sli.sli4.bar1_acc_handle == 0) {
                        status = ddi_regs_map_setup(dip, PCI_BAR1_RINDEX,
                            (caddr_t *)&hba->sli.sli4.bar1_addr,
                            0, 0, &dev_attr, &hba->sli.sli4.bar1_acc_handle);
                        if (status != DDI_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_attach_failed_msg,
                                    "(PCI) ddi_regs_map_setup BAR1 failed. "
                                    "stat=%d mem=%p attr=%p hdl=%p",
                                    status, &hba->sli.sli4.bar1_addr, &dev_attr,
                                    &hba->sli.sli4.bar1_acc_handle);
                                goto failed;
                        }
                }

                if (hba->sli.sli4.bar2_acc_handle == 0) {
                        status = ddi_regs_map_setup(dip, PCI_BAR2_RINDEX,
                            (caddr_t *)&hba->sli.sli4.bar2_addr,
                            0, 0, &dev_attr, &hba->sli.sli4.bar2_acc_handle);
                        if (status != DDI_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_attach_failed_msg,
                                    "ddi_regs_map_setup BAR2 failed. status=%x",
                                    status);
                                goto failed;
                        }
                }

                /* offset from beginning of register space */
                hba->sli.sli4.MPUEPSemaphore_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr +
                    CSR_MPU_EP_SEMAPHORE_OFFSET);
                hba->sli.sli4.MBDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar2_addr + PD_MB_DB_OFFSET);
                hba->sli.sli4.CQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar2_addr + PD_CQ_DB_OFFSET);
                hba->sli.sli4.MQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar2_addr + PD_MQ_DB_OFFSET);
                hba->sli.sli4.WQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar2_addr + PD_WQ_DB_OFFSET);
                hba->sli.sli4.RQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar2_addr + PD_RQ_DB_OFFSET);

                hba->sli.sli4.STATUS_reg_addr = 0;
                hba->sli.sli4.CNTL_reg_addr = 0;

                hba->sli.sli4.ERR1_reg_addr =
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_STATUS_LO_OFFSET);
                hba->sli.sli4.ERR2_reg_addr =
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_STATUS_HI_OFFSET);

                hba->sli.sli4.PHYSDEV_reg_addr = 0;
                break;

        case SLI_INTF_IF_TYPE_2: /* Lancer FC */

                /* Map in Hardware BAR pages that will be used for */
                /* communication with HBA. */
                if (hba->sli.sli4.bar0_acc_handle == 0) {
                        status = ddi_regs_map_setup(dip, PCI_BAR0_RINDEX,
                            (caddr_t *)&hba->sli.sli4.bar0_addr,
                            0, 0, &dev_attr, &hba->sli.sli4.bar0_acc_handle);
                        if (status != DDI_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_attach_failed_msg,
                                    "(PCI) ddi_regs_map_setup BAR0 failed. "
                                    "stat=%d mem=%p attr=%p hdl=%p",
                                    status, &hba->sli.sli4.bar0_addr, &dev_attr,
                                    &hba->sli.sli4.bar0_acc_handle);
                                goto failed;
                        }
                }

                /* offset from beginning of register space */
                hba->sli.sli4.MPUEPSemaphore_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_SEMAPHORE_OFFSET);
                hba->sli.sli4.MBDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_MB_DB_OFFSET);
                hba->sli.sli4.CQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_CQ_DB_OFFSET);
                hba->sli.sli4.MQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_MQ_DB_OFFSET);
                hba->sli.sli4.WQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_WQ_DB_OFFSET);
                hba->sli.sli4.RQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_RQ_DB_OFFSET);

                hba->sli.sli4.STATUS_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_STATUS_OFFSET);
                hba->sli.sli4.CNTL_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_CONTROL_OFFSET);
                hba->sli.sli4.ERR1_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_ERROR1_OFFSET);
                hba->sli.sli4.ERR2_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_ERROR2_OFFSET);
                hba->sli.sli4.PHYSDEV_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    PHYSDEV_CONTROL_OFFSET);

                break;
        case SLI_INTF_IF_TYPE_6:
                /* Map in Hardware BAR pages that will be used for */
                /* communication with HBA. */
                if (!emlxs_map_g7_bars(hba))
                        goto failed;
                /* offset from beginning of register space */
                hba->sli.sli4.MPUEPSemaphore_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_SEMAPHORE_OFFSET);
                hba->sli.sli4.MBDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr + PD_MB_DB_OFFSET);
                hba->sli.sli4.EQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr + PD_IF6_EQ_DB_OFFSET);
                hba->sli.sli4.CQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr + PD_IF6_CQ_DB_OFFSET);
                hba->sli.sli4.MQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr + PD_IF6_MQ_DB_OFFSET);
                hba->sli.sli4.WQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr + PD_IF6_WQ_DB_OFFSET);
                hba->sli.sli4.RQDB_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar1_addr + PD_IF6_RQ_DB_OFFSET);

                hba->sli.sli4.STATUS_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_STATUS_OFFSET);
                hba->sli.sli4.CNTL_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_CONTROL_OFFSET);
                hba->sli.sli4.ERR1_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_ERROR1_OFFSET);
                hba->sli.sli4.ERR2_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    SLIPORT_ERROR2_OFFSET);
                hba->sli.sli4.PHYSDEV_reg_addr =
                    (uint32_t *)(hba->sli.sli4.bar0_addr +
                    PHYSDEV_CONTROL_OFFSET);

                break;
        case SLI_INTF_IF_TYPE_1:
        case SLI_INTF_IF_TYPE_3:
        default:
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_attach_failed_msg,
                    "Map hdw: Unsupported if_type %08x",
                    (hba->sli_intf & SLI_INTF_IF_TYPE_MASK));

                goto failed;
        }

        if (hba->sli.sli4.bootstrapmb.virt == 0) {
                MBUF_INFO       *buf_info;
                MBUF_INFO       bufinfo;

                buf_info = &bufinfo;

                bzero(buf_info, sizeof (MBUF_INFO));
                buf_info->size = EMLXS_BOOTSTRAP_MB_SIZE + MBOX_EXTENSION_SIZE;
                buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                buf_info->align = ddi_ptob(dip, 1L);

                (void) emlxs_mem_alloc(hba, buf_info);

                if (buf_info->virt == NULL) {
                        goto failed;
                }

                hba->sli.sli4.bootstrapmb.virt = buf_info->virt;
                hba->sli.sli4.bootstrapmb.phys = buf_info->phys;
                hba->sli.sli4.bootstrapmb.size = EMLXS_BOOTSTRAP_MB_SIZE +
                    MBOX_EXTENSION_SIZE;
                hba->sli.sli4.bootstrapmb.data_handle = buf_info->data_handle;
                hba->sli.sli4.bootstrapmb.dma_handle = buf_info->dma_handle;
                bzero((char *)hba->sli.sli4.bootstrapmb.virt,
                    EMLXS_BOOTSTRAP_MB_SIZE);
        }

        hba->chan_count = MAX_CHANNEL;

        return (0);

failed:

        emlxs_sli4_unmap_hdw(hba);
        return (ENOMEM);


} /* emlxs_sli4_map_hdw() */


/*ARGSUSED*/
static void
emlxs_sli4_unmap_hdw(emlxs_hba_t *hba)
{
        MBUF_INFO       bufinfo;
        MBUF_INFO       *buf_info = &bufinfo;


        if (hba->sli.sli4.bar0_acc_handle) {
                ddi_regs_map_free(&hba->sli.sli4.bar0_acc_handle);
                hba->sli.sli4.bar0_acc_handle = 0;
        }

        if (hba->sli.sli4.bar1_acc_handle) {
                ddi_regs_map_free(&hba->sli.sli4.bar1_acc_handle);
                hba->sli.sli4.bar1_acc_handle = 0;
        }

        if (hba->sli.sli4.bar2_acc_handle) {
                ddi_regs_map_free(&hba->sli.sli4.bar2_acc_handle);
                hba->sli.sli4.bar2_acc_handle = 0;
        }

        if (hba->sli.sli4.bootstrapmb.virt) {
                bzero(buf_info, sizeof (MBUF_INFO));

                if (hba->sli.sli4.bootstrapmb.phys) {
                        buf_info->phys = hba->sli.sli4.bootstrapmb.phys;
                        buf_info->data_handle =
                            hba->sli.sli4.bootstrapmb.data_handle;
                        buf_info->dma_handle =
                            hba->sli.sli4.bootstrapmb.dma_handle;
                        buf_info->flags = FC_MBUF_DMA;
                }

                buf_info->virt = hba->sli.sli4.bootstrapmb.virt;
                buf_info->size = hba->sli.sli4.bootstrapmb.size;
                emlxs_mem_free(hba, buf_info);

                hba->sli.sli4.bootstrapmb.virt = NULL;
        }

        return;

} /* emlxs_sli4_unmap_hdw() */


static int
emlxs_check_hdw_ready(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        uint32_t status;
        uint32_t i = 0;
        uint32_t err1;
        uint32_t err2;

        /* Wait for reset completion */
        while (i < 30) {

                switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
                case SLI_INTF_IF_TYPE_0:
                        status = emlxs_sli4_read_sema(hba);

                        /* Check to see if any errors occurred during init */
                        if (status & ARM_POST_FATAL) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_reset_failed_msg,
                                    "SEMA Error: status=%x", status);

                                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                                return (1);
                        }

                        if ((status & ARM_UNRECOVERABLE_ERROR) ==
                            ARM_UNRECOVERABLE_ERROR) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_reset_failed_msg,
                                    "Unrecoverable Error: status=%x", status);

                                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                                return (1);
                        }

                        if ((status & ARM_POST_MASK) == ARM_POST_READY) {
                                /* ARM Ready !! */
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_sli_detail_msg,
                                    "ARM Ready: status=%x", status);

                                return (0);
                        }
                        break;

                case SLI_INTF_IF_TYPE_2:
                case SLI_INTF_IF_TYPE_6:
                        status = emlxs_sli4_read_status(hba);

                        if (status & SLI_STATUS_READY) {
                                if (!(status & SLI_STATUS_ERROR)) {
                                        /* ARM Ready !! */
                                        EMLXS_MSGF(EMLXS_CONTEXT,
                                            &emlxs_sli_detail_msg,
                                            "ARM Ready: status=%x", status);

                                        return (0);
                                }

                                err1 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                                    hba->sli.sli4.ERR1_reg_addr);
                                err2 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                                    hba->sli.sli4.ERR2_reg_addr);

                                if (status & SLI_STATUS_RESET_NEEDED) {
                                        EMLXS_MSGF(EMLXS_CONTEXT,
                                            &emlxs_sli_detail_msg,
                                            "ARM Ready (Reset Needed): "
                                            "status=%x err1=%x "
                                            "err2=%x",
                                            status, err1, err2);

                                        return (1);
                                }

                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_reset_failed_msg,
                                    "Unrecoverable Error: status=%x err1=%x "
                                    "err2=%x",
                                    status, err1, err2);

                                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                                return (2);
                        }

                        break;

                default:
                        EMLXS_STATE_CHANGE(hba, FC_ERROR);

                        return (3);
                }

                BUSYWAIT_MS(1000);
                i++;
        }

        /* Timeout occurred */
        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                err1 = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                err2 = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);
                break;

        default:
                err1 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                err2 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);
                break;
        }

        if (status & SLI_STATUS_ERROR) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
                    "Ready Timeout: Port Error: status=%x err1=%x err2=%x",
                    status, err1, err2);
        } else {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
                    "Ready Timeout: status=%x err1=%x err2=%x",
                    status, err1, err2);
        }

        EMLXS_STATE_CHANGE(hba, FC_ERROR);

        return (3);

} /* emlxs_check_hdw_ready() */


static uint32_t
emlxs_sli4_read_status(emlxs_hba_t *hba)
{
#ifdef FMA_SUPPORT
        emlxs_port_t *port = &PPORT;
#endif  /* FMA_SUPPORT */
        uint32_t status;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                status = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.STATUS_reg_addr);
#ifdef FMA_SUPPORT
                /* Access handle validation */
                EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli4.bar0_acc_handle);
#endif  /* FMA_SUPPORT */
                break;
        default:
                status = 0;
                break;
        }

        return (status);

} /* emlxs_sli4_read_status() */


static uint32_t
emlxs_sli4_read_sema(emlxs_hba_t *hba)
{
#ifdef FMA_SUPPORT
        emlxs_port_t *port = &PPORT;
#endif  /* FMA_SUPPORT */
        uint32_t status;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                status = ddi_get32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.MPUEPSemaphore_reg_addr);
#ifdef FMA_SUPPORT
                /* Access handle validation */
                EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli4.bar1_acc_handle);
#endif  /* FMA_SUPPORT */
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                status = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.MPUEPSemaphore_reg_addr);
#ifdef FMA_SUPPORT
                /* Access handle validation */
                EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli4.bar0_acc_handle);
#endif  /* FMA_SUPPORT */
                break;
        default:
                status = 0;
                break;
        }

        return (status);

} /* emlxs_sli4_read_sema() */


static uint32_t
emlxs_sli4_read_mbdb(emlxs_hba_t *hba)
{
#ifdef FMA_SUPPORT
        emlxs_port_t *port = &PPORT;
#endif  /* FMA_SUPPORT */
        uint32_t status;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                status = ddi_get32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.MBDB_reg_addr);

#ifdef FMA_SUPPORT
                /* Access handle validation */
                EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli4.bar2_acc_handle);
#endif  /* FMA_SUPPORT */
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                status = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.MBDB_reg_addr);
#ifdef FMA_SUPPORT
                /* Access handle validation */
                EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli4.bar0_acc_handle);
#endif  /* FMA_SUPPORT */
                break;
        default:
                status = 0;
                break;
        }

        return (status);

} /* emlxs_sli4_read_mbdb() */


static void
emlxs_sli4_write_mbdb(emlxs_hba_t *hba, uint64_t phys, boolean_t high)
{
        uint32_t db;
        uint_t shift;

        /*
         * The bootstrap mailbox is posted as 2 x 30 bit values.
         * It is required to be 16 bit aligned, and the 2 low order
         * bits are used as flags.
         */
        shift = high ? 32 : 2;

        db = (uint32_t)(phys >> shift) & BMBX_ADDR;

        if (high)
                db |= BMBX_ADDR_HI;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.MBDB_reg_addr, db);
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.MBDB_reg_addr, db);
                break;
        }

} /* emlxs_sli4_write_mbdb() */


static void
emlxs_sli4_write_eqdb(emlxs_hba_t *hba, uint16_t qid, uint32_t count,
    boolean_t arm)
{
        emlxs_eqdb_u    db;
        db.word = 0;

        /*
         * Add the qid to the doorbell. It is split into a low and
         * high component.
         */

        if ((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) == SLI_INTF_IF_TYPE_6) {
                db.db6.Qid = qid;
                db.db6.NumPopped = count;
                db.db6.Rearm = arm;
        } else {
                /* Initialize with the low bits */
                db.db2.Qid = qid & EQ_DB_ID_LO_MASK;

                /* Add the high bits */
                db.db2.Qid_hi = (qid >> EQ_ID_LO_BITS) & 0x1f;

                /*
                 * Include the number of entries to be popped.
                 */
                db.db2.NumPopped = count;

                /* The doorbell is for an event queue */
                db.db2.Event = B_TRUE;

                /* Arm if asked to do so */
                if (arm)
                        /* Clear only on not AutoValid EqAV */
                        db.db2.Clear = B_TRUE;
                db.db2.Rearm = arm;
        }

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(&hba->port[0], _FILENO_, __LINE__, &emlxs_sli_detail_msg,
            "EQE: CLEAR db=%08x pops=%d", db, count);
#endif /* DEBUG_FASTPATH */

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                /* The CQDB_reg_addr is also use for EQs */
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.CQDB_reg_addr, db.word);
                break;

        case SLI_INTF_IF_TYPE_2:
                /* The CQDB_reg_addr is also use for EQs */
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.CQDB_reg_addr, db.word);
                break;

        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.EQDB_reg_addr, db.word);
                break;

        }
} /* emlxs_sli4_write_eqdb() */

static void
emlxs_sli4_write_cqdb(emlxs_hba_t *hba, uint16_t qid, uint32_t count,
    boolean_t arm)
{
        emlxs_cqdb_u    db;
        db.word = 0;

        /*
         * Add the qid to the doorbell. It is split into a low and
         * high component.
         */

        if ((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) == SLI_INTF_IF_TYPE_6) {
                db.db6.Qid = qid;
                db.db6.NumPopped = count;
                db.db6.Rearm = arm;
        } else {
                /* Initialize with the low bits */
                db.db2.Qid = qid & CQ_DB_ID_LO_MASK;

                /* Add the high bits */
                db.db2.Qid_hi = (qid >> CQ_ID_LO_BITS) & 0x1f;

                /*
                 * Include the number of entries to be popped.
                 */
                db.db2.NumPopped = count;

                /* Arm if asked to do so */
                db.db2.Rearm = arm;
        }
#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(&hba->port[0], _FILENO_, __LINE__, &emlxs_sli_detail_msg,
            "CQE: db=%08x: pops=%d", db, count);
#endif /* DEBUG_FASTPATH */

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.CQDB_reg_addr, db.word);
                break;

        case SLI_INTF_IF_TYPE_2:
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.CQDB_reg_addr, db.word);
                break;

        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.CQDB_reg_addr, db.word);
                break;
        }
} /* emlxs_sli4_write_cqdb() */


static void
emlxs_sli4_write_rqdb(emlxs_hba_t *hba, uint16_t qid, uint_t count)
{
        emlxs_rqdbu_t rqdb;

        rqdb.word = 0;
        rqdb.db.Qid = qid;
        rqdb.db.NumPosted = count;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.RQDB_reg_addr, rqdb.word);
                break;

        case SLI_INTF_IF_TYPE_2:
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.RQDB_reg_addr, rqdb.word);
                break;

        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.RQDB_reg_addr, rqdb.word);
                break;

        }

} /* emlxs_sli4_write_rqdb() */


static void
emlxs_sli4_write_mqdb(emlxs_hba_t *hba, uint16_t qid, uint_t count)
{
        uint32_t db;

        db = qid;
        db |= (count << MQ_DB_POP_SHIFT) & MQ_DB_POP_MASK;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.MQDB_reg_addr, db);
                break;

        case SLI_INTF_IF_TYPE_2:
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.MQDB_reg_addr, db);
                break;
        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.MQDB_reg_addr, db);
                break;
        }

} /* emlxs_sli4_write_mqdb() */


static void
emlxs_sli4_write_wqdb(emlxs_hba_t *hba, uint16_t qid, uint_t posted,
    uint_t index)
{
        uint32_t db;

        db = qid;
        db |= (posted << WQ_DB_POST_SHIFT) & WQ_DB_POST_MASK;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                db |= (index << WQ_DB_IDX_SHIFT) & WQ_DB_IDX_MASK;
                ddi_put32(hba->sli.sli4.bar2_acc_handle,
                    hba->sli.sli4.WQDB_reg_addr, db);
                break;

        case SLI_INTF_IF_TYPE_2:
                db |= (index << WQ_DB_IDX_SHIFT) & WQ_DB_IDX_MASK;
                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.WQDB_reg_addr, db);
                break;

        case SLI_INTF_IF_TYPE_6:
                ddi_put32(hba->sli.sli4.bar1_acc_handle,
                    hba->sli.sli4.WQDB_reg_addr, db);
                break;

        }

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(&hba->port[0], _FILENO_, __LINE__, &emlxs_sli_detail_msg,
            "WQ RING: %08x", db);
#endif /* DEBUG_FASTPATH */
} /* emlxs_sli4_write_wqdb() */


static uint32_t
emlxs_check_bootstrap_ready(emlxs_hba_t *hba, uint32_t tmo)
{
        emlxs_port_t *port = &PPORT;
        uint32_t status = 0;
        uint32_t err1;
        uint32_t err2;

        /* Wait for reset completion, tmo is in 10ms ticks */
        while (tmo) {
                status = emlxs_sli4_read_mbdb(hba);

                /* Check to see if any errors occurred during init */
                if (status & BMBX_READY) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "BMBX Ready: status=0x%x", status);

                        return (tmo);
                }

                BUSYWAIT_MS(10);
                tmo--;
        }

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                err1 = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                err2 = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);
                break;

        default: /* IF_TYPE_2 and IF_TYPE_6 */
                err1 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                err2 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);
                break;
        }

        /* Timeout occurred */
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
            "Timeout waiting for BMailbox: status=%x err1=%x err2=%x",
            status, err1, err2);

        EMLXS_STATE_CHANGE(hba, FC_ERROR);

        return (0);

} /* emlxs_check_bootstrap_ready() */


static uint32_t
emlxs_issue_bootstrap_mb(emlxs_hba_t *hba, uint32_t tmo)
{
        emlxs_port_t *port = &PPORT;
        uint32_t *iptr;

        /*
         * This routine assumes the bootstrap mbox is loaded
         * with the mailbox command to be executed.
         *
         * First, load the high 30 bits of bootstrap mailbox
         */
        emlxs_sli4_write_mbdb(hba, hba->sli.sli4.bootstrapmb.phys, B_TRUE);

        tmo = emlxs_check_bootstrap_ready(hba, tmo);
        if (tmo == 0) {
                return (0);
        }

        /* Load the low 30 bits of bootstrap mailbox */
        emlxs_sli4_write_mbdb(hba, hba->sli.sli4.bootstrapmb.phys, B_FALSE);

        tmo = emlxs_check_bootstrap_ready(hba, tmo);
        if (tmo == 0) {
                return (0);
        }

        iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "BootstrapMB: %p Completed %08x %08x %08x",
            hba->sli.sli4.bootstrapmb.virt,
            *iptr, *(iptr+1), *(iptr+2));

        return (tmo);

} /* emlxs_issue_bootstrap_mb() */


static int
emlxs_init_bootstrap_mb(emlxs_hba_t *hba)
{
#ifdef FMA_SUPPORT
        emlxs_port_t *port = &PPORT;
#endif /* FMA_SUPPORT */
        uint32_t *iptr;
        uint32_t tmo;

        if (emlxs_check_hdw_ready(hba)) {
                return (1);
        }

        if (hba->flag & FC_BOOTSTRAPMB_INIT) {
                return (0);  /* Already initialized */
        }

        /* NOTE: tmo is in 10ms ticks */
        tmo = emlxs_check_bootstrap_ready(hba, 3000);
        if (tmo == 0) {
                return (1);
        }

        /* Issue FW_INITIALIZE command */

        /* Special words to initialize bootstrap mbox MUST be little endian */
        iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;
        *iptr = LE_SWAP32(FW_INITIALIZE_WORD0);
        *(iptr+1) = LE_SWAP32(FW_INITIALIZE_WORD1);

        EMLXS_MPDATA_SYNC(hba->sli.sli4.bootstrapmb.dma_handle, 0,
            MAILBOX_CMD_BSIZE, DDI_DMA_SYNC_FORDEV);

        emlxs_data_dump(port, "FW_INIT", (uint32_t *)iptr, 6, 0);
        if (!emlxs_issue_bootstrap_mb(hba, tmo)) {
                return (1);
        }

#ifdef FMA_SUPPORT
        if (emlxs_fm_check_dma_handle(hba, hba->sli.sli4.bootstrapmb.dma_handle)
            != DDI_FM_OK) {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_invalid_dma_handle_msg,
                    "init_bootstrap_mb: hdl=%p",
                    hba->sli.sli4.bootstrapmb.dma_handle);
                return (1);
        }
#endif
        hba->flag |= FC_BOOTSTRAPMB_INIT;
        return (0);

} /* emlxs_init_bootstrap_mb() */




static uint32_t
emlxs_sli4_hba_init(emlxs_hba_t *hba)
{
        int rc;
        uint16_t i;
        emlxs_port_t *vport;
        emlxs_config_t *cfg = &CFG;
        CHANNEL *cp;
        VPIobj_t *vpip;

        /* Restart the adapter */
        if (emlxs_sli4_hba_reset(hba, 1, 0, 0)) {
                return (1);
        }

        for (i = 0; i < hba->chan_count; i++) {
                cp = &hba->chan[i];
                cp->iopath = (void *)&hba->sli.sli4.wq[i];
        }

        /* Initialize all the port objects */
        hba->vpi_max  = 0;
        for (i = 0; i < MAX_VPORTS; i++) {
                vport = &VPORT(i);
                vport->hba = hba;
                vport->vpi = i;

                vpip = &vport->VPIobj;
                vpip->index = i;
                vpip->VPI = i;
                vpip->port = vport;
                vpip->state = VPI_STATE_OFFLINE;
                vport->vpip = vpip;
        }

        /* Set the max node count */
        if (hba->max_nodes == 0) {
                if (cfg[CFG_NUM_NODES].current > 0) {
                        hba->max_nodes = cfg[CFG_NUM_NODES].current;
                } else {
                        hba->max_nodes = 4096;
                }
        }

        rc = emlxs_init_bootstrap_mb(hba);
        if (rc) {
                return (rc);
        }

        hba->sli.sli4.cfgFCOE.FCMap[0] = FCOE_FCF_MAP0;
        hba->sli.sli4.cfgFCOE.FCMap[1] = FCOE_FCF_MAP1;
        hba->sli.sli4.cfgFCOE.FCMap[2] = FCOE_FCF_MAP2;

        if ((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) == SLI_INTF_IF_TYPE_0) {
                /* Cache the UE MASK registers value for UE error detection */
                hba->sli.sli4.ue_mask_lo = ddi_get32(hba->pci_acc_handle,
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_MASK_LO_OFFSET));
                hba->sli.sli4.ue_mask_hi = ddi_get32(hba->pci_acc_handle,
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_MASK_HI_OFFSET));
        }

        return (0);

} /* emlxs_sli4_hba_init() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_hba_reset(emlxs_hba_t *hba, uint32_t restart, uint32_t skip_post,
    uint32_t quiesce)
{
        emlxs_port_t *port = &PPORT;
        emlxs_port_t *vport;
        CHANNEL *cp;
        emlxs_config_t *cfg = &CFG;
        MAILBOXQ mboxq;
        uint32_t value;
        uint32_t i;
        uint32_t rc;
        uint16_t channelno;
        uint32_t status;
        uint32_t err1;
        uint32_t err2;
        uint8_t generate_event = 0;

        if (!cfg[CFG_RESET_ENABLE].current) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_reset_failed_msg,
                    "Adapter reset disabled.");
                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                return (1);
        }

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                if (quiesce == 0) {
                        emlxs_sli4_hba_kill(hba);

                        /*
                         * Initalize Hardware that will be used to bring
                         * SLI4 online.
                         */
                        rc = emlxs_init_bootstrap_mb(hba);
                        if (rc) {
                                return (rc);
                        }
                }

                bzero((void *)&mboxq, sizeof (MAILBOXQ));
                emlxs_mb_resetport(hba, &mboxq);

                if (quiesce == 0) {
                        if (emlxs_sli4_issue_mbox_cmd(hba, &mboxq,
                            MBX_POLL, 0) != MBX_SUCCESS) {
                                /* Timeout occurred */
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_reset_failed_msg,
                                    "Timeout: RESET");
                                EMLXS_STATE_CHANGE(hba, FC_ERROR);
                                /* Log a dump event - not supported */
                                return (1);
                        }
                } else {
                        if (emlxs_sli4_issue_mbox_cmd4quiesce(hba, &mboxq,
                            MBX_POLL, 0) != MBX_SUCCESS) {
                                EMLXS_STATE_CHANGE(hba, FC_ERROR);
                                /* Log a dump event - not supported */
                                return (1);
                        }
                }
                emlxs_data_dump(port, "resetPort", (uint32_t *)&mboxq, 12, 0);
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                if (quiesce == 0) {
                        emlxs_sli4_hba_kill(hba);
                }

                rc = emlxs_check_hdw_ready(hba);
                if (rc > 1) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
                            "Adapter not ready for reset.");
                        return (1);
                }

                if (rc == 1) {
                        err1 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                            hba->sli.sli4.ERR1_reg_addr);
                        err2 = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                            hba->sli.sli4.ERR2_reg_addr);

                        /* Don't generate an event if dump was forced */
                        if ((err1 != 0x2) || (err2 != 0x2)) {
                                generate_event = 1;
                        }
                }

                /* Reset the port now */

                mutex_enter(&EMLXS_PORT_LOCK);
                value = SLI_CNTL_INIT_PORT;

                ddi_put32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.CNTL_reg_addr, value);
                mutex_exit(&EMLXS_PORT_LOCK);

                break;
        }

        /* Reset the hba structure */
        hba->flag &= FC_RESET_MASK;

        for (channelno = 0; channelno < hba->chan_count; channelno++) {
                cp = &hba->chan[channelno];
                cp->hba = hba;
                cp->channelno = channelno;
        }

        hba->channel_tx_count = 0;
        hba->io_count = 0;
        hba->iodone_count = 0;
        hba->topology = 0;
        hba->linkspeed = 0;
        hba->heartbeat_active = 0;
        hba->discovery_timer = 0;
        hba->linkup_timer = 0;
        hba->loopback_tics = 0;

        /* Specific to ATTO G5 boards */
        if (hba->model_info.flags & EMLXS_GPIO_LEDS) {
                /* Assume the boot driver enabled all LEDs */
                hba->gpio_current =
                    EMLXS_GPIO_LO | EMLXS_GPIO_HI | EMLXS_GPIO_ACT;
                hba->gpio_desired = 0;
                hba->gpio_bit = 0;
        }

        /* Reset the port objects */
        for (i = 0; i < MAX_VPORTS; i++) {
                vport = &VPORT(i);

                vport->flag &= EMLXS_PORT_RESET_MASK;
                vport->did = 0;
                vport->prev_did = 0;
                vport->lip_type = 0;
                bzero(&vport->fabric_sparam, sizeof (SERV_PARM));
                bzero(&vport->prev_fabric_sparam, sizeof (SERV_PARM));

                bzero((caddr_t)&vport->node_base, sizeof (NODELIST));
                vport->node_base.nlp_Rpi = 0;
                vport->node_base.nlp_DID = 0xffffff;
                vport->node_base.nlp_list_next = NULL;
                vport->node_base.nlp_list_prev = NULL;
                vport->node_base.nlp_active = 1;
                vport->node_count = 0;

                if (vport->ub_count < EMLXS_UB_TOKEN_OFFSET) {
                        vport->ub_count = EMLXS_UB_TOKEN_OFFSET;
                }
        }

        if (emlxs_check_hdw_ready(hba)) {
                return (1);
        }

        if (generate_event) {
                status = emlxs_sli4_read_status(hba);
                if (status & SLI_STATUS_DUMP_IMAGE_PRESENT) {
                        emlxs_log_dump_event(port, NULL, 0);
                }
        }

        return (0);

} /* emlxs_sli4_hba_reset */


#define SGL_CMD         0
#define SGL_RESP        1
#define SGL_DATA        2
#define SGL_LAST        0x80

/*ARGSUSED*/
static ULP_SGE64 *
emlxs_pkt_to_sgl(emlxs_port_t *port, fc_packet_t *pkt, ULP_SGE64 *sge,
    uint32_t sgl_type, uint32_t *pcnt)
{
#ifdef DEBUG_SGE
        emlxs_hba_t *hba = HBA;
#endif /* DEBUG_SGE */
        ddi_dma_cookie_t *cp;
        uint_t i;
        uint_t last;
        int32_t size;
        int32_t sge_size;
        uint64_t sge_addr;
        int32_t len;
        uint32_t cnt;
        uint_t cookie_cnt;
        ULP_SGE64 stage_sge;

        last = sgl_type & SGL_LAST;
        sgl_type &= ~SGL_LAST;

#if (EMLXS_MODREV >= EMLXS_MODREV3)
        switch (sgl_type) {
        case SGL_CMD:
                cp = pkt->pkt_cmd_cookie;
                cookie_cnt = pkt->pkt_cmd_cookie_cnt;
                size = (int32_t)pkt->pkt_cmdlen;
                break;

        case SGL_RESP:
                cp = pkt->pkt_resp_cookie;
                cookie_cnt = pkt->pkt_resp_cookie_cnt;
                size = (int32_t)pkt->pkt_rsplen;
                break;


        case SGL_DATA:
                cp = pkt->pkt_data_cookie;
                cookie_cnt = pkt->pkt_data_cookie_cnt;
                size = (int32_t)pkt->pkt_datalen;
                break;

        default:
                return (NULL);
        }

#else
        switch (sgl_type) {
        case SGL_CMD:
                cp = &pkt->pkt_cmd_cookie;
                cookie_cnt = 1;
                size = (int32_t)pkt->pkt_cmdlen;
                break;

        case SGL_RESP:
                cp = &pkt->pkt_resp_cookie;
                cookie_cnt = 1;
                size = (int32_t)pkt->pkt_rsplen;
                break;


        case SGL_DATA:
                cp = &pkt->pkt_data_cookie;
                cookie_cnt = 1;
                size = (int32_t)pkt->pkt_datalen;
                break;

        default:
                return (NULL);
        }
#endif  /* >= EMLXS_MODREV3 */

        stage_sge.offset = 0;
        stage_sge.type = 0;
        stage_sge.last = 0;
        cnt = 0;
        for (i = 0; i < cookie_cnt && size > 0; i++, cp++) {

                sge_size = cp->dmac_size;
                sge_addr = cp->dmac_laddress;
                while (sge_size && size) {
                        if (cnt) {
                                /* Copy staged SGE before we build next one */
                                BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
                                    (uint8_t *)sge, sizeof (ULP_SGE64));
                                sge++;
                        }
                        len = MIN(EMLXS_MAX_SGE_SIZE, sge_size);
                        len = MIN(size, len);

                        stage_sge.addrHigh =
                            PADDR_HI(sge_addr);
                        stage_sge.addrLow =
                            PADDR_LO(sge_addr);
                        stage_sge.length = len;
                        if (sgl_type == SGL_DATA) {
                                stage_sge.offset = cnt;
                        }
#ifdef DEBUG_SGE
                        emlxs_data_dump(port, "SGE", (uint32_t *)&stage_sge,
                            4, 0);
#endif /* DEBUG_SGE */
                        sge_addr += len;
                        sge_size -= len;

                        cnt += len;
                        size -= len;
                }
        }

        if (last) {
                stage_sge.last = 1;
        }
        BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
            sizeof (ULP_SGE64));

        sge++;

        if (pcnt) {
                *pcnt = cnt;
        }
        return (sge);

} /* emlxs_pkt_to_sgl */


/*ARGSUSED*/
uint32_t
emlxs_sli4_bde_setup(emlxs_port_t *port, emlxs_buf_t *sbp)
{
        emlxs_hba_t *hba = HBA;
        fc_packet_t *pkt;
        XRIobj_t *xrip;
        ULP_SGE64 *sge;
        emlxs_wqe_t *wqe;
        IOCBQ *iocbq;
        ddi_dma_cookie_t *cp_cmd;
        ddi_dma_cookie_t *cp_data;
        uint64_t sge_addr;
        uint32_t cmd_cnt;
        uint32_t resp_cnt;

        iocbq = (IOCBQ *) &sbp->iocbq;
        wqe = &iocbq->wqe;
        pkt = PRIV2PKT(sbp);
        xrip = sbp->xrip;
        sge = xrip->SGList->virt;

#if (EMLXS_MODREV >= EMLXS_MODREV3)
        cp_cmd = pkt->pkt_cmd_cookie;
        cp_data = pkt->pkt_data_cookie;
#else
        cp_cmd  = &pkt->pkt_cmd_cookie;
        cp_data = &pkt->pkt_data_cookie;
#endif  /* >= EMLXS_MODREV3 */

        iocbq = &sbp->iocbq;
        if (iocbq->flag & IOCB_FCP_CMD) {

                if (pkt->pkt_tran_type == FC_PKT_OUTBOUND) {
                        return (1);
                }

                /* CMD payload */
                sge = emlxs_pkt_to_sgl(port, pkt, sge, SGL_CMD, &cmd_cnt);
                if (! sge) {
                        return (1);
                }

                /* DATA payload */
                if (pkt->pkt_datalen != 0) {
                        /* RSP payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_RESP, &resp_cnt);
                        if (! sge) {
                                return (1);
                        }

                        /* Data payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_DATA | SGL_LAST, 0);
                        if (! sge) {
                                return (1);
                        }

                        if (hba->sli.sli4.flag & EMLXS_SLI4_PHON) {
                                sge_addr = cp_data->dmac_laddress;
                                wqe->FirstData.addrHigh = PADDR_HI(sge_addr);
                                wqe->FirstData.addrLow = PADDR_LO(sge_addr);
                                wqe->FirstData.tus.f.bdeSize =
                                    cp_data->dmac_size;
                        }
                } else {
                        /* RSP payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_RESP | SGL_LAST, &resp_cnt);
                        if (! sge) {
                                return (1);
                        }
                }

                wqe->un.FcpCmd.Payload.addrHigh =
                    PADDR_HI(cp_cmd->dmac_laddress);
                wqe->un.FcpCmd.Payload.addrLow =
                    PADDR_LO(cp_cmd->dmac_laddress);
                wqe->un.FcpCmd.Payload.tus.f.bdeSize = cmd_cnt;
                wqe->un.FcpCmd.PayloadLength = cmd_cnt + resp_cnt;

        } else {

                if (pkt->pkt_tran_type == FC_PKT_OUTBOUND) {
                        /* CMD payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_CMD | SGL_LAST, &cmd_cnt);
                        if (! sge) {
                                return (1);
                        }
                } else {
                        /* CMD payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_CMD, &cmd_cnt);
                        if (! sge) {
                                return (1);
                        }

                        /* RSP payload */
                        sge = emlxs_pkt_to_sgl(port, pkt, sge,
                            SGL_RESP | SGL_LAST, &resp_cnt);
                        if (! sge) {
                                return (1);
                        }
                        wqe->un.GenReq.PayloadLength = cmd_cnt;
                }

                wqe->un.GenReq.Payload.addrHigh =
                    PADDR_HI(cp_cmd->dmac_laddress);
                wqe->un.GenReq.Payload.addrLow =
                    PADDR_LO(cp_cmd->dmac_laddress);
                wqe->un.GenReq.Payload.tus.f.bdeSize = cmd_cnt;
        }
        return (0);
} /* emlxs_sli4_bde_setup */




#ifdef SFCT_SUPPORT
/*ARGSUSED*/
static uint32_t
emlxs_sli4_fct_bde_setup(emlxs_port_t *port, emlxs_buf_t *sbp)
{
        emlxs_hba_t *hba = HBA;
        emlxs_wqe_t *wqe;
        ULP_SGE64 stage_sge;
        ULP_SGE64 *sge;
        IOCB *iocb;
        IOCBQ *iocbq;
        MATCHMAP *mp;
        MATCHMAP *fct_mp;
        XRIobj_t *xrip;
        uint64_t sge_addr;
        uint32_t sge_size;
        uint32_t cnt;
        uint32_t len;
        uint32_t size;
        uint32_t *xrdy_vaddr;
        stmf_data_buf_t *dbuf;

        iocbq = &sbp->iocbq;
        iocb = &iocbq->iocb;
        wqe = &iocbq->wqe;
        xrip = sbp->xrip;

        if (!sbp->fct_buf) {
                return (0);
        }

        size = sbp->fct_buf->db_data_size;

        /*
         * The hardware will automaticlly round up
         * to multiple of 4.
         *
         * if (size & 3) {
         *      size = (size + 3) & 0xfffffffc;
         * }
         */
        fct_mp = (MATCHMAP *)sbp->fct_buf->db_port_private;

        if (sbp->fct_buf->db_sglist_length != 1) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
                    "fct_bde_setup: Only 1 sglist entry supported: %d",
                    sbp->fct_buf->db_sglist_length);
                return (1);
        }

        sge = xrip->SGList->virt;

        if (iocb->ULPCOMMAND == CMD_FCP_TRECEIVE64_CX) {

                mp = emlxs_mem_buf_alloc(hba, EMLXS_XFER_RDY_SIZE);
                if (!mp || !mp->virt || !mp->phys) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
                            "fct_bde_setup: Cannot allocate XRDY memory");
                        return (1);
                }
                /* Save the MATCHMAP info to free this memory later */
                iocbq->bp = mp;

                /* Point to XRDY payload */
                xrdy_vaddr = (uint32_t *)(mp->virt);

                /* Fill in burstsize in payload */
                *xrdy_vaddr++ = 0;
                *xrdy_vaddr++ = LE_SWAP32(size);
                *xrdy_vaddr = 0;

                /* First 2 SGEs are XRDY and SKIP */
                stage_sge.addrHigh = PADDR_HI(mp->phys);
                stage_sge.addrLow = PADDR_LO(mp->phys);
                stage_sge.length = EMLXS_XFER_RDY_SIZE;
                stage_sge.offset = 0;
                stage_sge.type = 0;
                stage_sge.last = 0;

                /* Words  0-3 */
                wqe->un.FcpCmd.Payload.addrHigh = stage_sge.addrHigh;
                wqe->un.FcpCmd.Payload.addrLow = stage_sge.addrLow;
                wqe->un.FcpCmd.Payload.tus.f.bdeSize = EMLXS_XFER_RDY_SIZE;
                wqe->un.FcpCmd.PayloadLength = EMLXS_XFER_RDY_SIZE;

        } else {        /* CMD_FCP_TSEND64_CX */
                /* First 2 SGEs are SKIP */
                stage_sge.addrHigh = 0;
                stage_sge.addrLow = 0;
                stage_sge.length = 0;
                stage_sge.offset = 0;
                stage_sge.type = EMLXS_SGE_TYPE_SKIP;
                stage_sge.last = 0;

                /* Words  0-3 */
                wqe->un.FcpCmd.Payload.addrHigh = PADDR_HI(fct_mp->phys);
                wqe->un.FcpCmd.Payload.addrLow = PADDR_LO(fct_mp->phys);

                /* The BDE should match the contents of the first SGE payload */
                len = MIN(EMLXS_MAX_SGE_SIZE, size);
                wqe->un.FcpCmd.Payload.tus.f.bdeSize = len;

                /* The PayloadLength should be set to 0 for TSEND64. */
                wqe->un.FcpCmd.PayloadLength = 0;
        }

        dbuf = sbp->fct_buf;
        /*
         * TotalTransferCount equals to Relative Offset field (Word 4)
         * in both TSEND64 and TRECEIVE64 WQE.
         */
        wqe->un.FcpCmd.TotalTransferCount = dbuf->db_relative_offset;

        /* Copy staged SGE into SGL */
        BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
            (uint8_t *)sge, sizeof (ULP_SGE64));
        sge++;

        stage_sge.addrHigh = 0;
        stage_sge.addrLow = 0;
        stage_sge.length = 0;
        stage_sge.offset = 0;
        stage_sge.type = EMLXS_SGE_TYPE_SKIP;
        stage_sge.last = 0;

        /* Copy staged SGE into SGL */
        BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
            (uint8_t *)sge, sizeof (ULP_SGE64));
        sge++;

        sge_size = size;
        sge_addr = fct_mp->phys;
        cnt = 0;

        /* Build SGEs */
        while (sge_size) {
                if (cnt) {
                        /* Copy staged SGE before we build next one */
                        BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
                            (uint8_t *)sge, sizeof (ULP_SGE64));
                        sge++;
                }

                len = MIN(EMLXS_MAX_SGE_SIZE, sge_size);

                stage_sge.addrHigh = PADDR_HI(sge_addr);
                stage_sge.addrLow = PADDR_LO(sge_addr);
                stage_sge.length = len;
                stage_sge.offset = cnt;
                stage_sge.type = EMLXS_SGE_TYPE_DATA;

                sge_addr += len;
                sge_size -= len;
                cnt += len;
        }

        stage_sge.last = 1;

        if (hba->sli.sli4.flag & EMLXS_SLI4_PHON) {
                wqe->FirstData.addrHigh = stage_sge.addrHigh;
                wqe->FirstData.addrLow = stage_sge.addrLow;
                wqe->FirstData.tus.f.bdeSize = stage_sge.length;
        }
        /* Copy staged SGE into SGL */
        BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
            (uint8_t *)sge, sizeof (ULP_SGE64));

        return (0);

} /* emlxs_sli4_fct_bde_setup */
#endif /* SFCT_SUPPORT */


static void
emlxs_sli4_issue_iocb_cmd(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
{
        emlxs_port_t *port = &PPORT;
        emlxs_buf_t *sbp;
        uint32_t channelno;
        int32_t throttle;
        emlxs_wqe_t *wqe;
        emlxs_wqe_t *wqeslot;
        WQ_DESC_t *wq;
        uint32_t flag;
        uint16_t next_wqe;
        off_t offset;
#ifdef NODE_THROTTLE_SUPPORT
        int32_t node_throttle;
        NODELIST *marked_node = NULL;
#endif /* NODE_THROTTLE_SUPPORT */


        channelno = cp->channelno;
        wq = (WQ_DESC_t *)cp->iopath;

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "ISSUE WQE channel: %x  %p", channelno, wq);
#endif /* DEBUG_FASTPATH */

        throttle = 0;

        /* Check if FCP ring and adapter is not ready */
        /* We may use any ring for FCP_CMD */
        if (iocbq && (iocbq->flag & IOCB_FCP_CMD) && (hba->state != FC_READY)) {
                if (!(iocbq->flag & IOCB_SPECIAL) || !iocbq->port ||
                    (((emlxs_port_t *)iocbq->port)->mode == MODE_INITIATOR)) {
                        emlxs_tx_put(iocbq, 1);
                        return;
                }
        }

        /* Attempt to acquire CMD_RING lock */
        if (mutex_tryenter(&EMLXS_QUE_LOCK(channelno)) == 0) {
                /* Queue it for later */
                if (iocbq) {
                        if ((hba->io_count -
                            hba->channel_tx_count) > 10) {
                                emlxs_tx_put(iocbq, 1);
                                return;
                        } else {

                                mutex_enter(&EMLXS_QUE_LOCK(channelno));
                        }
                } else {
                        return;
                }
        }
        /* EMLXS_QUE_LOCK acquired */

        /* Throttle check only applies to non special iocb */
        if (iocbq && (!(iocbq->flag & IOCB_SPECIAL))) {
                /* Check if HBA is full */
                throttle = hba->io_throttle - hba->io_active;
                if (throttle <= 0) {
                        /* Hitting adapter throttle limit */
                        /* Queue it for later */
                        if (iocbq) {
                                emlxs_tx_put(iocbq, 1);
                        }

                        goto busy;
                }
        }

        /* Check to see if we have room for this WQE */
        next_wqe = wq->host_index + 1;
        if (next_wqe >= wq->max_index) {
                next_wqe = 0;
        }

        if (next_wqe == wq->port_index) {
                /* Queue it for later */
                if (iocbq) {
                        emlxs_tx_put(iocbq, 1);
                }
                goto busy;
        }

        /*
         * We have a command ring slot available
         * Make sure we have an iocb to send
         */
        if (iocbq) {
                mutex_enter(&EMLXS_TX_CHANNEL_LOCK);

                /* Check if the ring already has iocb's waiting */
                if (cp->nodeq.q_first != NULL) {
                        /* 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
                         */
                        iocbq = emlxs_tx_get(cp, 0);
                }

                mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
        } else {
                iocbq = emlxs_tx_get(cp, 1);
        }

        /* Process each iocbq */
        while (iocbq) {
                sbp = iocbq->sbp;

#ifdef NODE_THROTTLE_SUPPORT
                if (sbp && sbp->node && sbp->node->io_throttle) {
                        node_throttle = sbp->node->io_throttle -
                            sbp->node->io_active;
                        if (node_throttle <= 0) {
                                /* Node is busy */
                                /* Queue this iocb and get next iocb from */
                                /* channel */

                                if (!marked_node) {
                                        marked_node = sbp->node;
                                }

                                mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
                                emlxs_tx_put(iocbq, 0);

                                if (cp->nodeq.q_first == marked_node) {
                                        mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
                                        goto busy;
                                }

                                iocbq = emlxs_tx_get(cp, 0);
                                mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
                                continue;
                        }
                }
                marked_node = 0;
#endif /* NODE_THROTTLE_SUPPORT */

                wqe = &iocbq->wqe;
#ifdef DEBUG_FASTPATH
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "ISSUE QID %d WQE iotag:%x xri:%d", wq->qid,
                    wqe->RequestTag, wqe->XRITag);
#endif /* DEBUG_FASTPATH */

                if (sbp) {
                        /* If exchange removed after wqe was prep'ed, drop it */
                        if (!(sbp->xrip)) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "Xmit WQE iotag:%x xri:%d aborted",
                                    wqe->RequestTag, wqe->XRITag);

                                /* Get next iocb from the tx queue */
                                iocbq = emlxs_tx_get(cp, 1);
                                continue;
                        }

                        if (sbp->pkt_flags & PACKET_DELAY_REQUIRED) {

                                /* Perform delay */
                                if ((channelno == hba->channel_els) &&
                                    !(iocbq->flag & IOCB_FCP_CMD)) {
                                        drv_usecwait(100000);
                                } else {
                                        drv_usecwait(20000);
                                }
                        }

                        /* Check for ULP pkt request */
                        mutex_enter(&sbp->mtx);

                        if (sbp->node == NULL) {
                                /* Set node to base node by default */
                                iocbq->node = (void *)&port->node_base;
                                sbp->node = (void *)&port->node_base;
                        }

                        sbp->pkt_flags |= PACKET_IN_CHIPQ;
                        mutex_exit(&sbp->mtx);

                        atomic_inc_32(&hba->io_active);
#ifdef NODE_THROTTLE_SUPPORT
                        if (sbp->node) {
                                atomic_inc_32(&sbp->node->io_active);
                        }
#endif /* NODE_THROTTLE_SUPPORT */

                        sbp->xrip->flag |= EMLXS_XRI_PENDING_IO;
#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
                        if (sbp->fct_cmd) {
                                emlxs_fct_io_trace(port, sbp->fct_cmd,
                                    EMLXS_FCT_IOCB_ISSUED);
                                emlxs_fct_io_trace(port, sbp->fct_cmd,
                                    icmd->ULPCOMMAND);
                        }
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */
                        cp->hbaSendCmd_sbp++;
                        iocbq->channel = cp;
                } else {
                        cp->hbaSendCmd++;
                }

                flag = iocbq->flag;

                /*
                 * At this point, we have a command ring slot available
                 * and an iocb to send
                 */
                wq->release_depth--;
                if (wq->release_depth == 0) {
                        wq->release_depth = WQE_RELEASE_DEPTH;
                        wqe->WQEC = 1;
                }

                HBASTATS.IocbIssued[channelno]++;
                wq->num_proc++;

                /* Send the iocb */
                wqeslot = (emlxs_wqe_t *)wq->addr.virt;
                wqeslot += wq->host_index;

                wqe->CQId = wq->cqid;
                if (hba->sli.sli4.param.PHWQ) {
                        WQE_PHWQ_WQID(wqe, wq->qid);
                }
                BE_SWAP32_BCOPY((uint8_t *)wqe, (uint8_t *)wqeslot,
                    sizeof (emlxs_wqe_t));
#ifdef DEBUG_WQE
                emlxs_data_dump(port, "WQE", (uint32_t *)wqe, 18, 0);
#endif /* DEBUG_WQE */
                offset = (off_t)((uint64_t)((unsigned long)
                    wq->addr.virt) -
                    (uint64_t)((unsigned long)
                    hba->sli.sli4.slim2.virt));

                EMLXS_MPDATA_SYNC(wq->addr.dma_handle, offset,
                    4096, DDI_DMA_SYNC_FORDEV);

                /*
                 * After this, the sbp / iocb / wqe should not be
                 * accessed in the xmit path.
                 */

                /* Ring the WQ Doorbell */
                emlxs_sli4_write_wqdb(hba, wq->qid, 1, wq->host_index);
                wq->host_index = next_wqe;

                if (!sbp) {
                        emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
                }

                if (iocbq && (!(flag & IOCB_SPECIAL))) {
                        /* Check if HBA is full */
                        throttle = hba->io_throttle - hba->io_active;
                        if (throttle <= 0) {
                                goto busy;
                        }
                }

                /* Check to see if we have room for another WQE */
                next_wqe++;
                if (next_wqe >= wq->max_index) {
                        next_wqe = 0;
                }

                if (next_wqe == wq->port_index) {
                        /* Queue it for later */
                        goto busy;
                }

                /* Get the next iocb from the tx queue if there is one */
                iocbq = emlxs_tx_get(cp, 1);
        }

        mutex_exit(&EMLXS_QUE_LOCK(channelno));

        return;

busy:
        wq->num_busy++;
        if (throttle <= 0) {
                HBASTATS.IocbThrottled++;
        } else {
                HBASTATS.IocbRingFull[channelno]++;
        }

        mutex_exit(&EMLXS_QUE_LOCK(channelno));

        return;

} /* emlxs_sli4_issue_iocb_cmd() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_issue_mq(emlxs_port_t *port, MAILBOX4 *mqe, MAILBOX *mb,
    uint32_t tmo)
{
        emlxs_hba_t *hba = HBA;
        MAILBOXQ        *mbq;
        MAILBOX4        *mb4;
        MATCHMAP        *mp;
        uint32_t        *iptr;
        off_t           offset;

        mbq = (MAILBOXQ *)mb;
        mb4 = (MAILBOX4 *)mb;
        mp = (MATCHMAP *) mbq->nonembed;
        hba->mbox_mqe = (void *)mqe;

        if ((mb->mbxCommand != MBX_SLI_CONFIG) ||
            (mb4->un.varSLIConfig.be.embedded)) {
                /*
                 * If this is an embedded mbox, everything should fit
                 * into the mailbox area.
                 */
                BE_SWAP32_BCOPY((uint8_t *)mb, (uint8_t *)mqe,
                    MAILBOX_CMD_SLI4_BSIZE);

                EMLXS_MPDATA_SYNC(hba->sli.sli4.mq.addr.dma_handle, 0,
                    4096, DDI_DMA_SYNC_FORDEV);

                if (mb->mbxCommand != MBX_HEARTBEAT) {
                        emlxs_data_dump(port, "MBOX CMD", (uint32_t *)mqe,
                            18, 0);
                }
        } 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.
                 */
                mb4->un.varSLIConfig.be.sge_cnt = 1;
                mb4->un.varSLIConfig.be.payload_length = mp->size;
                iptr = (uint32_t *)&mb4->un.varSLIConfig.be.un_hdr.hdr_req;
                *iptr++ = (uint32_t)PADDR_LO(mp->phys);
                *iptr++ = (uint32_t)PADDR_HI(mp->phys);
                *iptr = mp->size;

                BE_SWAP32_BUFFER(mp->virt, mp->size);

                EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
                    DDI_DMA_SYNC_FORDEV);

                BE_SWAP32_BCOPY((uint8_t *)mb, (uint8_t *)mqe,
                    MAILBOX_CMD_SLI4_BSIZE);

                offset = (off_t)((uint64_t)((unsigned long)
                    hba->sli.sli4.mq.addr.virt) -
                    (uint64_t)((unsigned long)
                    hba->sli.sli4.slim2.virt));

                EMLXS_MPDATA_SYNC(hba->sli.sli4.mq.addr.dma_handle, offset,
                    4096, DDI_DMA_SYNC_FORDEV);

                emlxs_data_dump(port, "MBOX EXT", (uint32_t *)mqe, 12, 0);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                    "Extension Addr %p %p", mp->phys, (uint32_t *)(mp->virt));
                emlxs_data_dump(port, "EXT AREA", (uint32_t *)mp->virt, 24, 0);
        }

        /* Ring the MQ Doorbell */
        if (mb->mbxCommand != MBX_HEARTBEAT) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "MQ RING: Qid %04x", hba->sli.sli4.mq.qid);
        }

        emlxs_sli4_write_mqdb(hba, hba->sli.sli4.mq.qid, 1);

        return (MBX_SUCCESS);

} /* emlxs_sli4_issue_mq() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_issue_bootstrap(emlxs_hba_t *hba, MAILBOX *mb, uint32_t tmo)
{
        emlxs_port_t    *port = &PPORT;
        MAILBOXQ        *mbq;
        MAILBOX4        *mb4;
        MATCHMAP        *mp = NULL;
        uint32_t        *iptr;
        int             nonembed = 0;

        mbq = (MAILBOXQ *)mb;
        mb4 = (MAILBOX4 *)mb;
        mp = (MATCHMAP *) mbq->nonembed;
        hba->mbox_mqe = hba->sli.sli4.bootstrapmb.virt;

        if ((mb->mbxCommand != MBX_SLI_CONFIG) ||
            (mb4->un.varSLIConfig.be.embedded)) {
                /*
                 * If this is an embedded mbox, everything should fit
                 * into the bootstrap mailbox area.
                 */
                iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;
                BE_SWAP32_BCOPY((uint8_t *)mb, (uint8_t *)iptr,
                    MAILBOX_CMD_SLI4_BSIZE);

                EMLXS_MPDATA_SYNC(hba->sli.sli4.bootstrapmb.dma_handle, 0,
                    MAILBOX_CMD_SLI4_BSIZE, DDI_DMA_SYNC_FORDEV);
                emlxs_data_dump(port, "MBOX CMD", iptr, 18, 0);
        } 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.
                 */
                nonembed = 1;
                mb4->un.varSLIConfig.be.sge_cnt = 1;
                mb4->un.varSLIConfig.be.payload_length = mp->size;
                iptr = (uint32_t *)&mb4->un.varSLIConfig.be.un_hdr.hdr_req;
                *iptr++ = (uint32_t)PADDR_LO(mp->phys);
                *iptr++ = (uint32_t)PADDR_HI(mp->phys);
                *iptr = mp->size;

                BE_SWAP32_BUFFER(mp->virt, mp->size);

                EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
                    DDI_DMA_SYNC_FORDEV);

                iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;
                BE_SWAP32_BCOPY((uint8_t *)mb, (uint8_t *)iptr,
                    MAILBOX_CMD_SLI4_BSIZE);

                EMLXS_MPDATA_SYNC(hba->sli.sli4.bootstrapmb.dma_handle, 0,
                    EMLXS_BOOTSTRAP_MB_SIZE + MBOX_EXTENSION_SIZE,
                    DDI_DMA_SYNC_FORDEV);

                emlxs_data_dump(port, "MBOX EXT", iptr, 12, 0);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                    "Extension Addr %p %p", mp->phys,
                    (uint32_t *)((uint8_t *)mp->virt));
                iptr = (uint32_t *)((uint8_t *)mp->virt);
                emlxs_data_dump(port, "EXT AREA", (uint32_t *)mp->virt, 24, 0);
        }


        /* NOTE: tmo is in 10ms ticks */
        if (!emlxs_issue_bootstrap_mb(hba, tmo)) {
                return (MBX_TIMEOUT);
        }

        if ((mb->mbxCommand != MBX_SLI_CONFIG) ||
            (mb4->un.varSLIConfig.be.embedded)) {
                EMLXS_MPDATA_SYNC(hba->sli.sli4.bootstrapmb.dma_handle, 0,
                    MAILBOX_CMD_SLI4_BSIZE, DDI_DMA_SYNC_FORKERNEL);

                iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;
                BE_SWAP32_BCOPY((uint8_t *)iptr, (uint8_t *)mb,
                    MAILBOX_CMD_SLI4_BSIZE);

                emlxs_data_dump(port, "MBOX CMP", iptr, 18, 0);

        } else {
                EMLXS_MPDATA_SYNC(hba->sli.sli4.bootstrapmb.dma_handle, 0,
                    EMLXS_BOOTSTRAP_MB_SIZE + MBOX_EXTENSION_SIZE,
                    DDI_DMA_SYNC_FORKERNEL);

                EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
                    DDI_DMA_SYNC_FORKERNEL);

                BE_SWAP32_BUFFER(mp->virt, mp->size);

                iptr = (uint32_t *)hba->sli.sli4.bootstrapmb.virt;
                BE_SWAP32_BCOPY((uint8_t *)iptr, (uint8_t *)mb,
                    MAILBOX_CMD_SLI4_BSIZE);

                emlxs_data_dump(port, "MBOX CMP", iptr, 12, 0);
                iptr = (uint32_t *)((uint8_t *)mp->virt);
                emlxs_data_dump(port, "EXT AREA", (uint32_t *)iptr, 24, 0);
        }

#ifdef FMA_SUPPORT
        if (nonembed && mp) {
                if (emlxs_fm_check_dma_handle(hba, mp->dma_handle)
                    != DDI_FM_OK) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_dma_handle_msg,
                            "sli4_issue_bootstrap: mp_hdl=%p",
                            mp->dma_handle);
                        return (MBXERR_DMA_ERROR);
                }
        }

        if (emlxs_fm_check_dma_handle(hba,
            hba->sli.sli4.bootstrapmb.dma_handle)
            != DDI_FM_OK) {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_invalid_dma_handle_msg,
                    "sli4_issue_bootstrap: hdl=%p",
                    hba->sli.sli4.bootstrapmb.dma_handle);
                return (MBXERR_DMA_ERROR);
        }
#endif

        return (MBX_SUCCESS);

} /* emlxs_sli4_issue_bootstrap() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_issue_mbox_cmd(emlxs_hba_t *hba, MAILBOXQ *mbq, int32_t flag,
    uint32_t tmo)
{
        emlxs_port_t    *port;
        MAILBOX4        *mb4;
        MAILBOX         *mb;
        mbox_rsp_hdr_t  *hdr_rsp;
        MATCHMAP        *mp;
        uint32_t        *iptr;
        uint32_t        rc;
        uint32_t        i;
        uint32_t        tmo_local;

        if (!mbq->port) {
                mbq->port = &PPORT;
        }

        port = (emlxs_port_t *)mbq->port;

        mb4 = (MAILBOX4 *)mbq;
        mb = (MAILBOX *)mbq;

        mb->mbxStatus = MBX_SUCCESS;
        rc = MBX_SUCCESS;

        /* Check for minimum timeouts */
        switch (mb->mbxCommand) {
        /* Mailbox commands that erase/write flash */
        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:
        case MBX_DUMP_MEMORY:
        case MBX_WRITE_VPARMS:
        case MBX_ACCESS_VDATA:
                if (tmo < 300) {
                        tmo = 300;
                }
                break;

        case MBX_SLI_CONFIG: {
                mbox_req_hdr_t *hdr_req;

                hdr_req = (mbox_req_hdr_t *)
                    &mb4->un.varSLIConfig.be.un_hdr.hdr_req;

                if (hdr_req->subsystem == IOCTL_SUBSYSTEM_COMMON) {
                        switch (hdr_req->opcode) {
                        case COMMON_OPCODE_WRITE_OBJ:
                        case COMMON_OPCODE_READ_OBJ:
                        case COMMON_OPCODE_READ_OBJ_LIST:
                        case COMMON_OPCODE_DELETE_OBJ:
                        case COMMON_OPCODE_SET_BOOT_CFG:
                        case COMMON_OPCODE_GET_PROFILE_CFG:
                        case COMMON_OPCODE_SET_PROFILE_CFG:
                        case COMMON_OPCODE_GET_PROFILE_LIST:
                        case COMMON_OPCODE_SET_ACTIVE_PROFILE:
                        case COMMON_OPCODE_GET_PROFILE_CAPS:
                        case COMMON_OPCODE_GET_MR_PROFILE_CAPS:
                        case COMMON_OPCODE_SET_MR_PROFILE_CAPS:
                        case COMMON_OPCODE_SET_FACTORY_PROFILE_CFG:
                        case COMMON_OPCODE_SEND_ACTIVATION:
                        case COMMON_OPCODE_RESET_LICENSES:
                        case COMMON_OPCODE_SET_PHYSICAL_LINK_CFG_V1:
                        case COMMON_OPCODE_GET_VPD_DATA:
                                if (tmo < 300) {
                                        tmo = 300;
                                }
                                break;
                        default:
                                if (tmo < 30) {
                                        tmo = 30;
                                }
                        }
                } else if (hdr_req->subsystem == IOCTL_SUBSYSTEM_FCOE) {
                        switch (hdr_req->opcode) {
                        case FCOE_OPCODE_SET_FCLINK_SETTINGS:
                                if (tmo < 300) {
                                        tmo = 300;
                                }
                                break;
                        default:
                                if (tmo < 30) {
                                        tmo = 30;
                                }
                        }
                } else {
                        if (tmo < 30) {
                                tmo = 30;
                        }
                }

                /*
                 * Also: VENDOR_MANAGE_FFV  (0x13, 0x02) (not currently used)
                 */

                break;
        }
        default:
                if (tmo < 30) {
                        tmo = 30;
                }
                break;
        }

        /* Convert tmo seconds to 10 millisecond tics */
        tmo_local = tmo * 100;

        mutex_enter(&EMLXS_PORT_LOCK);

        /* Adjust wait flag */
        if (flag != MBX_NOWAIT) {
                if (hba->sli.sli4.flag & EMLXS_SLI4_INTR_ENABLED) {
                        flag = MBX_SLEEP;
                } else {
                        flag = MBX_POLL;
                }
        } else {
                /* Must have interrupts enabled to perform MBX_NOWAIT */
                if (!(hba->sli.sli4.flag & EMLXS_SLI4_INTR_ENABLED)) {

                        mb->mbxStatus = MBX_HARDWARE_ERROR;
                        mutex_exit(&EMLXS_PORT_LOCK);

                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Interrupts disabled. %s failed.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand));

                        return (MBX_HARDWARE_ERROR);
                }
        }

        /* Check for hardware error ; special case SLI_CONFIG */
        if ((hba->flag & FC_HARDWARE_ERROR) &&
            ! ((mb4->mbxCommand == MBX_SLI_CONFIG) &&
            (mb4->un.varSLIConfig.be.un_hdr.hdr_req.opcode ==
            COMMON_OPCODE_RESET))) {
                mb->mbxStatus = MBX_HARDWARE_ERROR;

                mutex_exit(&EMLXS_PORT_LOCK);

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                    "Hardware error reported. %s failed. status=%x mb=%p",
                    emlxs_mb_cmd_xlate(mb->mbxCommand), mb->mbxStatus, mb);

                return (MBX_HARDWARE_ERROR);
        }

        if (hba->mbox_queue_flag) {
                /* If we are not polling, then queue it for later */
                if (flag == MBX_NOWAIT) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Busy.      %s: mb=%p NoWait.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand), mb);

                        emlxs_mb_put(hba, mbq);

                        HBASTATS.MboxBusy++;

                        mutex_exit(&EMLXS_PORT_LOCK);

                        return (MBX_BUSY);
                }

                while (hba->mbox_queue_flag) {
                        mutex_exit(&EMLXS_PORT_LOCK);

                        if (tmo_local-- == 0) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_event_msg,
                                    "Timeout.   %s: mb=%p tmo=%d Waiting.",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
                                    tmo);

                                /* Non-lethalStatus mailbox timeout */
                                /* Does not indicate a hardware error */
                                mb->mbxStatus = MBX_TIMEOUT;
                                return (MBX_TIMEOUT);
                        }

                        BUSYWAIT_MS(10);
                        mutex_enter(&EMLXS_PORT_LOCK);

                        /* Check for hardware error ; special case SLI_CONFIG */
                        if ((hba->flag & FC_HARDWARE_ERROR) &&
                            ! ((mb4->mbxCommand == MBX_SLI_CONFIG) &&
                            (mb4->un.varSLIConfig.be.un_hdr.hdr_req.opcode ==
                            COMMON_OPCODE_RESET))) {
                                mb->mbxStatus = MBX_HARDWARE_ERROR;

                                mutex_exit(&EMLXS_PORT_LOCK);

                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "Hardware error reported. %s failed. "
                                    "status=%x mb=%p",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand),
                                    mb->mbxStatus, mb);

                                return (MBX_HARDWARE_ERROR);
                        }
                }
        }

        /* Initialize mailbox area */
        emlxs_mb_init(hba, mbq, flag, tmo);

        if (mb->mbxCommand == MBX_DOWN_LINK) {
                hba->sli.sli4.flag |= EMLXS_SLI4_DOWN_LINK;
        }

        mutex_exit(&EMLXS_PORT_LOCK);
        switch (flag) {

        case MBX_NOWAIT:
                if (mb->mbxCommand != MBX_HEARTBEAT) {
                        if (mb->mbxCommand != MBX_DOWN_LOAD
                            /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "Sending.   %s: mb=%p NoWait. embedded %d",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
                                    ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                                    (mb4->un.varSLIConfig.be.embedded)));
                        }
                }

                iptr = hba->sli.sli4.mq.addr.virt;
                iptr += (hba->sli.sli4.mq.host_index * MAILBOX_CMD_SLI4_WSIZE);
                hba->sli.sli4.mq.host_index++;
                if (hba->sli.sli4.mq.host_index >= hba->sli.sli4.mq.max_index) {
                        hba->sli.sli4.mq.host_index = 0;
                }

                if (mbq->bp) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "BDE virt %p phys %p size x%x",
                            ((MATCHMAP *)mbq->bp)->virt,
                            ((MATCHMAP *)mbq->bp)->phys,
                            ((MATCHMAP *)mbq->bp)->size);
                        emlxs_data_dump(port, "DATA",
                            (uint32_t *)(((MATCHMAP *)mbq->bp)->virt), 30, 0);
                }
                rc = emlxs_sli4_issue_mq(port, (MAILBOX4 *)iptr, mb, tmo_local);
                break;

        case MBX_POLL:
                if (mb->mbxCommand != MBX_DOWN_LOAD
                    /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Sending.   %s: mb=%p Poll. embedded %d",
                            emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
                            ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                            (mb4->un.varSLIConfig.be.embedded)));
                }

                rc = emlxs_sli4_issue_bootstrap(hba, mb, tmo_local);

                /* Clean up the mailbox area */
                if (rc == MBX_TIMEOUT) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Timeout.   %s: mb=%p tmo=%x Poll. embedded %d",
                            emlxs_mb_cmd_xlate(mb->mbxCommand), mb, tmo,
                            ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                            (mb4->un.varSLIConfig.be.embedded)));

                        hba->flag |= FC_MBOX_TIMEOUT;
                        EMLXS_STATE_CHANGE(hba, FC_ERROR);
                        emlxs_mb_fini(hba, NULL, MBX_TIMEOUT);

                } else {
                        if (mb->mbxCommand != MBX_DOWN_LOAD
                            /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "Completed.   %s: mb=%p status=%x rc=%x"
                                    " Poll. embedded %d",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
                                    rc, mb->mbxStatus,
                                    ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                                    (mb4->un.varSLIConfig.be.embedded)));
                        }

                        /* Process the result */
                        if (!(mbq->flag & MBQ_PASSTHRU)) {
                                if (mbq->mbox_cmpl) {
                                        (void) (mbq->mbox_cmpl)(hba, mbq);
                                }
                        }

                        emlxs_mb_fini(hba, NULL, mb->mbxStatus);
                }

                mp = (MATCHMAP *)mbq->nonembed;
                if (mp) {
                        hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
                        if (hdr_rsp->status) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "%s: MBX_NONEMBED_ERROR: 0x%x, 0x%x",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand),
                                    hdr_rsp->status, hdr_rsp->extra_status);

                                mb->mbxStatus = MBX_NONEMBED_ERROR;
                        }
                }
                rc = mb->mbxStatus;

                /* Attempt to send pending mailboxes */
                mbq = (MAILBOXQ *)emlxs_mb_get(hba);
                if (mbq) {
                        /* Attempt to send pending mailboxes */
                        i =  emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);
                        if ((i != MBX_BUSY) && (i != MBX_SUCCESS)) {
                                emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
                        }
                }
                break;

        case MBX_SLEEP:
                if (mb->mbxCommand != MBX_DOWN_LOAD
                    /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Sending.   %s: mb=%p Sleep. embedded %d",
                            emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
                            ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                            (mb4->un.varSLIConfig.be.embedded)));
                }

                iptr = hba->sli.sli4.mq.addr.virt;
                iptr += (hba->sli.sli4.mq.host_index * MAILBOX_CMD_SLI4_WSIZE);
                hba->sli.sli4.mq.host_index++;
                if (hba->sli.sli4.mq.host_index >= hba->sli.sli4.mq.max_index) {
                        hba->sli.sli4.mq.host_index = 0;
                }

                rc = emlxs_sli4_issue_mq(port, (MAILBOX4 *)iptr, mb, tmo_local);

                if (rc != MBX_SUCCESS) {
                        break;
                }

                /* Wait for completion */
                /* The driver clock is timing the mailbox. */

                mutex_enter(&EMLXS_MBOX_LOCK);
                while (!(mbq->flag & MBQ_COMPLETED)) {
                        cv_wait(&EMLXS_MBOX_CV, &EMLXS_MBOX_LOCK);
                }
                mutex_exit(&EMLXS_MBOX_LOCK);

                mp = (MATCHMAP *)mbq->nonembed;
                if (mp) {
                        hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
                        if (hdr_rsp->status) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "%s: MBX_NONEMBED_ERROR: 0x%x, 0x%x",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand),
                                    hdr_rsp->status, hdr_rsp->extra_status);

                                mb->mbxStatus = MBX_NONEMBED_ERROR;
                        }
                }
                rc = mb->mbxStatus;

                if (rc == MBX_TIMEOUT) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Timeout.   %s: mb=%p tmo=%x Sleep. embedded %d",
                            emlxs_mb_cmd_xlate(mb->mbxCommand), mb, tmo,
                            ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                            (mb4->un.varSLIConfig.be.embedded)));
                } else {
                        if (mb->mbxCommand != MBX_DOWN_LOAD
                            /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "Completed.   %s: mb=%p status=%x Sleep. "
                                    "embedded %d",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand), mb, rc,
                                    ((mb->mbxCommand != MBX_SLI_CONFIG) ? 1 :
                                    (mb4->un.varSLIConfig.be.embedded)));
                        }
                }
                break;
        }

        return (rc);

} /* emlxs_sli4_issue_mbox_cmd() */



/*ARGSUSED*/
static uint32_t
emlxs_sli4_issue_mbox_cmd4quiesce(emlxs_hba_t *hba, MAILBOXQ *mbq, int32_t flag,
    uint32_t tmo)
{
        emlxs_port_t    *port = &PPORT;
        MAILBOX         *mb;
        mbox_rsp_hdr_t  *hdr_rsp;
        MATCHMAP        *mp;
        uint32_t        rc;
        uint32_t        tmo_local;

        mb = (MAILBOX *)mbq;

        mb->mbxStatus = MBX_SUCCESS;
        rc = MBX_SUCCESS;

        if (tmo < 30) {
                tmo = 30;
        }

        /* Convert tmo seconds to 10 millisecond tics */
        tmo_local = tmo * 100;

        flag = MBX_POLL;

        /* Check for hardware error */
        if (hba->flag & FC_HARDWARE_ERROR) {
                mb->mbxStatus = MBX_HARDWARE_ERROR;
                return (MBX_HARDWARE_ERROR);
        }

        /* Initialize mailbox area */
        emlxs_mb_init(hba, mbq, flag, tmo);

        switch (flag) {

        case MBX_POLL:

                rc = emlxs_sli4_issue_bootstrap(hba, mb, tmo_local);

                /* Clean up the mailbox area */
                if (rc == MBX_TIMEOUT) {
                        hba->flag |= FC_MBOX_TIMEOUT;
                        EMLXS_STATE_CHANGE(hba, FC_ERROR);
                        emlxs_mb_fini(hba, NULL, MBX_TIMEOUT);

                } else {
                        /* Process the result */
                        if (!(mbq->flag & MBQ_PASSTHRU)) {
                                if (mbq->mbox_cmpl) {
                                        (void) (mbq->mbox_cmpl)(hba, mbq);
                                }
                        }

                        emlxs_mb_fini(hba, NULL, mb->mbxStatus);
                }

                mp = (MATCHMAP *)mbq->nonembed;
                if (mp) {
                        hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
                        if (hdr_rsp->status) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_mbox_detail_msg,
                                    "%s: MBX_NONEMBED_ERROR: 0x%x, 0x%x",
                                    emlxs_mb_cmd_xlate(mb->mbxCommand),
                                    hdr_rsp->status, hdr_rsp->extra_status);

                                mb->mbxStatus = MBX_NONEMBED_ERROR;
                        }
                }
                rc = mb->mbxStatus;

                break;
        }

        return (rc);

} /* emlxs_sli4_issue_mbox_cmd4quiesce() */



#ifdef SFCT_SUPPORT
/*ARGSUSED*/
extern uint32_t
emlxs_sli4_prep_fct_iocb(emlxs_port_t *port, emlxs_buf_t *cmd_sbp, int channel)
{
        emlxs_hba_t *hba = HBA;
        emlxs_config_t *cfg = &CFG;
        fct_cmd_t *fct_cmd;
        stmf_data_buf_t *dbuf;
        scsi_task_t *fct_task;
        fc_packet_t *pkt;
        CHANNEL *cp;
        XRIobj_t *xrip;
        emlxs_node_t *ndlp;
        IOCBQ *iocbq;
        IOCB *iocb;
        emlxs_wqe_t *wqe;
        ULP_SGE64 stage_sge;
        ULP_SGE64 *sge;
        RPIobj_t *rpip;
        int32_t sge_size;
        uint64_t sge_addr;
        uint32_t did;
        uint32_t timeout;

        ddi_dma_cookie_t *cp_cmd;

        pkt = PRIV2PKT(cmd_sbp);

        cp = (CHANNEL *)cmd_sbp->channel;

        iocbq = &cmd_sbp->iocbq;
        iocb = &iocbq->iocb;

        did = cmd_sbp->did;
        if (iocb->ULPCOMMAND == CMD_ABORT_XRI_CX) {

                ndlp = cmd_sbp->node;
                rpip = EMLXS_NODE_TO_RPI(port, ndlp);

                if (!rpip) {
                        /* Use the fabric rpi */
                        rpip = port->vpip->fabric_rpip;
                }

                /* Next allocate an Exchange for this command */
                xrip = emlxs_sli4_alloc_xri(port, cmd_sbp, rpip,
                    EMLXS_XRI_SOL_BLS_TYPE);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Adapter Busy. Unable to allocate exchange. "
                            "did=0x%x", did);

                        return (FC_TRAN_BUSY);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "FCT Abort Request: xri=%d iotag=%d sbp=%p rxid=%x",
                    xrip->XRI, xrip->iotag, cmd_sbp, pkt->pkt_cmd_fhdr.rx_id);

                cmd_sbp->xrip = xrip;

                cp->ulpSendCmd++;

                /* Initalize iocbq */
                iocbq->port = (void *)port;
                iocbq->node = (void *)ndlp;
                iocbq->channel = (void *)cp;

                /*
                 * Don't give the abort priority, we want the IOCB
                 * we are aborting to be processed first.
                 */
                iocbq->flag |= IOCB_SPECIAL;

                wqe = &iocbq->wqe;
                bzero((void *)wqe, sizeof (emlxs_wqe_t));

                wqe = &iocbq->wqe;
                wqe->un.Abort.Criteria = ABORT_XRI_TAG;
                wqe->RequestTag = xrip->iotag;
                wqe->AbortTag = pkt->pkt_cmd_fhdr.rx_id;
                wqe->Command = CMD_ABORT_XRI_CX;
                wqe->Class = CLASS3;
                wqe->CQId = 0xffff;
                wqe->CmdType = WQE_TYPE_ABORT;

                if (hba->state >= FC_LINK_UP) {
                        wqe->un.Abort.IA = 0;
                } else {
                        wqe->un.Abort.IA = 1;
                }

                /* Set the pkt timer */
                cmd_sbp->ticks = hba->timer_tics + pkt->pkt_timeout +
                    ((pkt->pkt_timeout > 0xff) ? 0 : 10);

                return (IOERR_SUCCESS);

        } else if (iocb->ULPCOMMAND == CMD_FCP_TRSP64_CX) {

                timeout = pkt->pkt_timeout;
                ndlp = cmd_sbp->node;
                if (!ndlp) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Unable to find rpi. did=0x%x", did);

                        emlxs_set_pkt_state(cmd_sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_INVALID_RPI, 0);
                        return (0xff);
                }

                cp->ulpSendCmd++;

                /* Initalize iocbq */
                iocbq->port = (void *)port;
                iocbq->node = (void *)ndlp;
                iocbq->channel = (void *)cp;

                wqe = &iocbq->wqe;
                bzero((void *)wqe, sizeof (emlxs_wqe_t));

                xrip = emlxs_sli4_register_xri(port, cmd_sbp,
                    pkt->pkt_cmd_fhdr.rx_id, did);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Unable to register xri %x. did=0x%x",
                            pkt->pkt_cmd_fhdr.rx_id, did);

                        emlxs_set_pkt_state(cmd_sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_NO_XRI, 0);
                        return (0xff);
                }

                cmd_sbp->iotag = xrip->iotag;
                cmd_sbp->channel = cp;

#if (EMLXS_MODREV >= EMLXS_MODREV3)
                cp_cmd = pkt->pkt_cmd_cookie;
#else
                cp_cmd  = &pkt->pkt_cmd_cookie;
#endif  /* >= EMLXS_MODREV3 */

                sge_size = pkt->pkt_cmdlen;
                /* Make size a multiple of 4 */
                if (sge_size & 3) {
                        sge_size = (sge_size + 3) & 0xfffffffc;
                }
                sge_addr = cp_cmd->dmac_laddress;
                sge = xrip->SGList->virt;

                stage_sge.addrHigh = PADDR_HI(sge_addr);
                stage_sge.addrLow = PADDR_LO(sge_addr);
                stage_sge.length = sge_size;
                stage_sge.offset = 0;
                stage_sge.type = 0;
                stage_sge.last = 1;

                /* Copy staged SGE into SGL */
                BE_SWAP32_BCOPY((uint8_t *)&stage_sge,
                    (uint8_t *)sge, sizeof (ULP_SGE64));

                /* Words  0-3 */
                wqe->un.FcpCmd.Payload.addrHigh = stage_sge.addrHigh;
                wqe->un.FcpCmd.Payload.addrLow = stage_sge.addrLow;
                wqe->un.FcpCmd.Payload.tus.f.bdeSize = sge_size;
                wqe->un.FcpCmd.PayloadLength = sge_size;

                /*  Word  6 */
                wqe->ContextTag = ndlp->nlp_Rpi;
                wqe->XRITag = xrip->XRI;

                /*  Word  7 */
                wqe->Command  = iocb->ULPCOMMAND;
                wqe->Class = cmd_sbp->class;
                wqe->ContextType = WQE_RPI_CONTEXT;
                wqe->Timer = ((timeout > 0xff) ? 0 : timeout);

                /*  Word  8 */
                wqe->AbortTag = 0;

                /*  Word  9 */
                wqe->RequestTag = xrip->iotag;
                wqe->OXId = (uint16_t)xrip->rx_id;

                /*  Word  10 */
                if (xrip->flag & EMLXS_XRI_BUSY) {
                        wqe->XC = 1;
                }

                if (!(hba->sli.sli4.param.PHWQ)) {
                        wqe->QOSd = 1;
                        wqe->DBDE = 1; /* Data type for BDE 0 */
                }

                /*  Word  11 */
                wqe->CmdType = WQE_TYPE_TRSP;
                wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */

                /* Set the pkt timer */
                cmd_sbp->ticks = hba->timer_tics + timeout +
                    ((timeout > 0xff) ? 0 : 10);

                if (pkt->pkt_cmdlen) {
                        EMLXS_MPDATA_SYNC(pkt->pkt_cmd_dma, 0, pkt->pkt_cmdlen,
                            DDI_DMA_SYNC_FORDEV);
                }

                return (IOERR_SUCCESS);
        }

        fct_cmd = cmd_sbp->fct_cmd;
        did = fct_cmd->cmd_rportid;
        dbuf = cmd_sbp->fct_buf;
        fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
        ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
        if (!ndlp) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Unable to find rpi. did=0x%x", did);

                emlxs_set_pkt_state(cmd_sbp, IOSTAT_LOCAL_REJECT,
                    IOERR_INVALID_RPI, 0);
                return (0xff);
        }


        /* Initalize iocbq */
        iocbq->port = (void *) port;
        iocbq->node = (void *)ndlp;
        iocbq->channel = (void *) cp;

        wqe = &iocbq->wqe;
        bzero((void *)wqe, sizeof (emlxs_wqe_t));

        xrip = cmd_sbp->xrip;
        if (!xrip) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Unable to find xri. did=0x%x", did);

                emlxs_set_pkt_state(cmd_sbp, IOSTAT_LOCAL_REJECT,
                    IOERR_NO_XRI, 0);
                return (0xff);
        }

        if (emlxs_sli4_register_xri(port, cmd_sbp,
            xrip->XRI, ndlp->nlp_DID) == NULL) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Unable to register xri. did=0x%x", did);

                emlxs_set_pkt_state(cmd_sbp, IOSTAT_LOCAL_REJECT,
                    IOERR_NO_XRI, 0);
                return (0xff);
        }
        cmd_sbp->iotag = xrip->iotag;
        cmd_sbp->channel = cp;

        if (cfg[CFG_TIMEOUT_ENABLE].current) {
                timeout =
                    ((2 * hba->fc_ratov) < 60) ? 60 : (2 * hba->fc_ratov);
        } else {
                timeout = 0x80000000;
        }
        cmd_sbp->ticks =
            hba->timer_tics + timeout + ((timeout > 0xff) ? 0 : 10);


        iocb->ULPCT = 0;
        if (fct_task->task_flags & TF_WRITE_DATA) {
                iocb->ULPCOMMAND = CMD_FCP_TRECEIVE64_CX;
                wqe->CmdType = WQE_TYPE_TRECEIVE;               /* Word 11 */

        } else { /* TF_READ_DATA */

                iocb->ULPCOMMAND = CMD_FCP_TSEND64_CX;
                wqe->CmdType = WQE_TYPE_TSEND;                  /* Word 11 */

                if ((dbuf->db_data_size >=
                    fct_task->task_expected_xfer_length)) {
                        /* enable auto-rsp AP feature */
                        wqe->AR = 0x1;
                        iocb->ULPCT = 0x1; /* for cmpl */
                }
        }

        (void) emlxs_sli4_fct_bde_setup(port, cmd_sbp);

        /*  Word  6 */
        wqe->ContextTag = ndlp->nlp_Rpi;
        wqe->XRITag = xrip->XRI;

        /*  Word  7 */
        wqe->Command  = iocb->ULPCOMMAND;
        wqe->Class = cmd_sbp->class;
        wqe->ContextType = WQE_RPI_CONTEXT;
        wqe->Timer = ((timeout > 0xff) ? 0 : timeout);
        wqe->PU = 1;

        /*  Word  8 */
        wqe->AbortTag = 0;

        /*  Word  9 */
        wqe->RequestTag = xrip->iotag;
        wqe->OXId = (uint16_t)fct_cmd->cmd_oxid;

        /*  Word  10 */
        if (xrip->flag & EMLXS_XRI_BUSY) {
                wqe->XC = 1;
        }

        if (!(hba->sli.sli4.param.PHWQ)) {
                wqe->QOSd = 1;
                wqe->DBDE = 1; /* Data type for BDE 0 */
        }

        /*  Word  11 */
        wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */

        /*  Word  12 */
        wqe->CmdSpecific = dbuf->db_data_size;

        return (IOERR_SUCCESS);

} /* emlxs_sli4_prep_fct_iocb() */
#endif /* SFCT_SUPPORT */


/*ARGSUSED*/
extern uint32_t
emlxs_sli4_prep_fcp_iocb(emlxs_port_t *port, emlxs_buf_t *sbp, int channel)
{
        emlxs_hba_t *hba = HBA;
        fc_packet_t *pkt;
        CHANNEL *cp;
        RPIobj_t *rpip;
        XRIobj_t *xrip;
        emlxs_wqe_t *wqe;
        IOCBQ *iocbq;
        IOCB *iocb;
        NODELIST *node;
        uint16_t iotag;
        uint32_t did;

        pkt = PRIV2PKT(sbp);
        did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
        cp = &hba->chan[channel];

        iocbq = &sbp->iocbq;
        iocbq->channel = (void *) cp;
        iocbq->port = (void *) port;

        wqe = &iocbq->wqe;
        iocb = &iocbq->iocb;
        bzero((void *)wqe, sizeof (emlxs_wqe_t));
        bzero((void *)iocb, sizeof (IOCB));

        /* Find target node object */
        node = (NODELIST *)iocbq->node;
        rpip = EMLXS_NODE_TO_RPI(port, node);

        if (!rpip) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Unable to find rpi. did=0x%x", did);

                emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                    IOERR_INVALID_RPI, 0);
                return (0xff);
        }

        sbp->channel = cp;
        /* Next allocate an Exchange for this command */
        xrip = emlxs_sli4_alloc_xri(port, sbp, rpip,
            EMLXS_XRI_SOL_FCP_TYPE);

        if (!xrip) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Adapter Busy. Unable to allocate exchange. did=0x%x", did);

                return (FC_TRAN_BUSY);
        }
        sbp->bmp = NULL;
        iotag = sbp->iotag;

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "FCP: Prep xri=%d iotag=%d oxid=%x rpi=%d",
            xrip->XRI, xrip->iotag, xrip->rx_id, rpip->RPI);
#endif /* DEBUG_FASTPATH */

        /* Indicate this is a FCP cmd */
        iocbq->flag |= IOCB_FCP_CMD;

        if (emlxs_sli4_bde_setup(port, sbp)) {
                emlxs_sli4_free_xri(port, sbp, xrip, 1);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Adapter Busy. Unable to setup SGE. did=0x%x", did);

                return (FC_TRAN_BUSY);
        }

        /* DEBUG */
#ifdef DEBUG_FCP
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "FCP: SGLaddr virt %p phys %p size %d", xrip->SGList->virt,
            xrip->SGList->phys, pkt->pkt_datalen);
        emlxs_data_dump(port, "FCP: SGL",
            (uint32_t *)xrip->SGList->virt, 32, 0);
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "FCP: CMD virt %p len %d:%d:%d",
            pkt->pkt_cmd, pkt->pkt_cmdlen, pkt->pkt_rsplen, pkt->pkt_datalen);
        emlxs_data_dump(port, "FCP: CMD", (uint32_t *)pkt->pkt_cmd, 10, 0);
#endif /* DEBUG_FCP */

        EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
            xrip->SGList->size, DDI_DMA_SYNC_FORDEV);

        /* if device is FCP-2 device, set the following bit */
        /* that says to run the FC-TAPE protocol. */
        if (node->nlp_fcp_info & NLP_FCP_2_DEVICE) {
                wqe->ERP = 1;
        }

        if (pkt->pkt_datalen == 0) {
                iocb->ULPCOMMAND = CMD_FCP_ICMND64_CR;
                wqe->Command = CMD_FCP_ICMND64_CR;
                wqe->CmdType = WQE_TYPE_FCP_DATA_IN;
        } else if (pkt->pkt_tran_type == FC_PKT_FCP_READ) {
                iocb->ULPCOMMAND = CMD_FCP_IREAD64_CR;
                wqe->Command = CMD_FCP_IREAD64_CR;
                wqe->CmdType = WQE_TYPE_FCP_DATA_IN;
                wqe->PU = PARM_XFER_CHECK;
        } else {
                iocb->ULPCOMMAND = CMD_FCP_IWRITE64_CR;
                wqe->Command = CMD_FCP_IWRITE64_CR;
                wqe->CmdType = WQE_TYPE_FCP_DATA_OUT;
        }
        wqe->un.FcpCmd.TotalTransferCount = pkt->pkt_datalen;

        if (!(hba->sli.sli4.param.PHWQ)) {
                wqe->DBDE = 1; /* Data type for BDE 0 */
        }
        wqe->ContextTag = rpip->RPI;
        wqe->ContextType = WQE_RPI_CONTEXT;
        wqe->XRITag = xrip->XRI;
        wqe->Timer =
            ((pkt->pkt_timeout > 0xff) ? 0 : pkt->pkt_timeout);

        if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_CHAINED_SEQ) {
                wqe->CCPE = 1;
                wqe->CCP = pkt->pkt_cmd_fhdr.rsvd;
        }

        switch (FC_TRAN_CLASS(pkt->pkt_tran_flags)) {
        case FC_TRAN_CLASS2:
                wqe->Class = CLASS2;
                break;
        case FC_TRAN_CLASS3:
        default:
                wqe->Class = CLASS3;
                break;
        }
        sbp->class = wqe->Class;
        wqe->RequestTag = iotag;
        wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */

        return (FC_SUCCESS);
} /* emlxs_sli4_prep_fcp_iocb() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_prep_ip_iocb(emlxs_port_t *port, emlxs_buf_t *sbp)
{
        return (FC_TRAN_BUSY);

} /* emlxs_sli4_prep_ip_iocb() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_prep_els_iocb(emlxs_port_t *port, emlxs_buf_t *sbp)
{
        emlxs_hba_t *hba = HBA;
        fc_packet_t *pkt;
        IOCBQ *iocbq;
        IOCB *iocb;
        emlxs_wqe_t *wqe;
        FCFIobj_t *fcfp;
        RPIobj_t *reserved_rpip = NULL;
        RPIobj_t *rpip = NULL;
        XRIobj_t *xrip;
        CHANNEL *cp;
        uint32_t did;
        uint32_t cmd;
        ULP_SGE64 stage_sge;
        ULP_SGE64 *sge;
        ddi_dma_cookie_t *cp_cmd;
        ddi_dma_cookie_t *cp_resp;
        emlxs_node_t *node;

        pkt = PRIV2PKT(sbp);
        did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);

        iocbq = &sbp->iocbq;
        wqe = &iocbq->wqe;
        iocb = &iocbq->iocb;
        bzero((void *)wqe, sizeof (emlxs_wqe_t));
        bzero((void *)iocb, sizeof (IOCB));
        cp = &hba->chan[hba->channel_els];

        /* Initalize iocbq */
        iocbq->port = (void *) port;
        iocbq->channel = (void *) cp;

        sbp->channel = cp;
        sbp->bmp = NULL;

#if (EMLXS_MODREV >= EMLXS_MODREV3)
        cp_cmd = pkt->pkt_cmd_cookie;
        cp_resp = pkt->pkt_resp_cookie;
#else
        cp_cmd  = &pkt->pkt_cmd_cookie;
        cp_resp = &pkt->pkt_resp_cookie;
#endif  /* >= EMLXS_MODREV3 */

        /* CMD payload */
        sge = &stage_sge;
        sge->addrHigh = PADDR_HI(cp_cmd->dmac_laddress);
        sge->addrLow = PADDR_LO(cp_cmd->dmac_laddress);
        sge->length = pkt->pkt_cmdlen;
        sge->offset = 0;
        sge->type = 0;

        cmd = *((uint32_t *)pkt->pkt_cmd);
        cmd &= ELS_CMD_MASK;

        /* Initalize iocb */
        if (pkt->pkt_tran_type == FC_PKT_OUTBOUND) {
                /* ELS Response */

                sbp->xrip = 0;
                xrip = emlxs_sli4_register_xri(port, sbp,
                    pkt->pkt_cmd_fhdr.rx_id, did);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to find XRI. rxid=%x",
                            pkt->pkt_cmd_fhdr.rx_id);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_NO_XRI, 0);
                        return (0xff);
                }

                rpip = xrip->rpip;

                if (!rpip) {
                        /* This means that we had a node registered */
                        /* when the unsol request came in but the node */
                        /* has since been unregistered. */
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to find RPI. rxid=%x",
                            pkt->pkt_cmd_fhdr.rx_id);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_INVALID_RPI, 0);
                        return (0xff);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "ELS: Prep xri=%d iotag=%d oxid=%x rpi=%d",
                    xrip->XRI, xrip->iotag, xrip->rx_id, rpip->RPI);

                iocb->ULPCOMMAND = CMD_XMIT_ELS_RSP64_CX;
                wqe->Command = CMD_XMIT_ELS_RSP64_CX;
                wqe->CmdType = WQE_TYPE_GEN;
                if (!(hba->sli.sli4.param.PHWQ)) {
                        wqe->DBDE = 1; /* Data type for BDE 0 */
                }

                wqe->un.ElsRsp.Payload.addrHigh = sge->addrHigh;
                wqe->un.ElsRsp.Payload.addrLow = sge->addrLow;
                wqe->un.ElsRsp.Payload.tus.f.bdeSize = pkt->pkt_cmdlen;
                wqe->un.ElsCmd.PayloadLength = pkt->pkt_cmdlen;

                wqe->un.ElsRsp.RemoteId = did;
                wqe->PU = 0x3;
                wqe->OXId = xrip->rx_id;

                sge->last = 1;
                /* Now sge is fully staged */

                sge = xrip->SGList->virt;
                BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
                    sizeof (ULP_SGE64));

                if (rpip->RPI == FABRIC_RPI) {
                        wqe->ContextTag = port->vpip->VPI;
                        wqe->ContextType = WQE_VPI_CONTEXT;
                } else {
                        wqe->ContextTag = rpip->RPI;
                        wqe->ContextType = WQE_RPI_CONTEXT;
                }

                if ((cmd == ELS_CMD_ACC) && (sbp->ucmd == ELS_CMD_FLOGI)) {
                        wqe->un.ElsCmd.SP = 1;
                        wqe->un.ElsCmd.LocalId = 0xFFFFFE;
                }

        } else {
                /* ELS Request */

                fcfp = port->vpip->vfip->fcfp;
                node = (emlxs_node_t *)iocbq->node;
                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (!rpip) {
                        /* Use the fabric rpi */
                        rpip = port->vpip->fabric_rpip;
                }

                /* Next allocate an Exchange for this command */
                xrip = emlxs_sli4_alloc_xri(port, sbp, rpip,
                    EMLXS_XRI_SOL_ELS_TYPE);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Adapter Busy. Unable to allocate exchange. "
                            "did=0x%x", did);

                        return (FC_TRAN_BUSY);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "ELS: Prep xri=%d iotag=%d rpi=%d",
                    xrip->XRI, xrip->iotag, rpip->RPI);

                iocb->ULPCOMMAND = CMD_ELS_REQUEST64_CR;
                wqe->Command = CMD_ELS_REQUEST64_CR;
                wqe->CmdType = WQE_TYPE_ELS;
                if (!(hba->sli.sli4.param.PHWQ)) {
                        wqe->DBDE = 1; /* Data type for BDE 0 */
                }

                wqe->un.ElsCmd.Payload.addrHigh = sge->addrHigh;
                wqe->un.ElsCmd.Payload.addrLow = sge->addrLow;
                wqe->un.ElsCmd.Payload.tus.f.bdeSize = pkt->pkt_cmdlen;

                wqe->un.ElsCmd.RemoteId = did;
                wqe->Timer = ((pkt->pkt_timeout > 0xff) ? 0 : pkt->pkt_timeout);

                /* setup for rsp */
                iocb->un.elsreq64.remoteID = (did == BCAST_DID) ? 0 : did;
                iocb->ULPPU = 1;        /* Wd4 is relative offset */

                sge->last = 0;

                sge = xrip->SGList->virt;
                BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
                    sizeof (ULP_SGE64));

                wqe->un.ElsCmd.PayloadLength =
                    pkt->pkt_cmdlen; /* Byte offset of rsp data */

                /* RSP payload */
                sge = &stage_sge;
                sge->addrHigh = PADDR_HI(cp_resp->dmac_laddress);
                sge->addrLow = PADDR_LO(cp_resp->dmac_laddress);
                sge->length = pkt->pkt_rsplen;
                sge->offset = 0;
                sge->last = 1;
                /* Now sge is fully staged */

                sge = xrip->SGList->virt;
                sge++;
                BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
                    sizeof (ULP_SGE64));
#ifdef DEBUG_ELS
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "ELS: SGLaddr virt %p phys %p",
                    xrip->SGList->virt, xrip->SGList->phys);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "ELS: PAYLOAD virt %p phys %p",
                    pkt->pkt_cmd, cp_cmd->dmac_laddress);
                emlxs_data_dump(port, "ELS: SGL",
                    (uint32_t *)xrip->SGList->virt, 12, 0);
#endif /* DEBUG_ELS */

                switch (cmd) {
                case ELS_CMD_FLOGI:
                        wqe->un.ElsCmd.SP = 1;

                        if ((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) ==
                            SLI_INTF_IF_TYPE_0) {
                                wqe->ContextTag = fcfp->FCFI;
                                wqe->ContextType = WQE_FCFI_CONTEXT;
                        } else {
                                wqe->ContextTag = port->vpip->VPI;
                                wqe->ContextType = WQE_VPI_CONTEXT;
                        }

                        if (hba->flag & FC_FIP_SUPPORTED) {
                                wqe->CmdType |= WQE_TYPE_MASK_FIP;
                        }

                        if (hba->topology == TOPOLOGY_LOOP) {
                                wqe->un.ElsCmd.LocalId = port->did;
                        }

                        wqe->ELSId = WQE_ELSID_FLOGI;
                        break;
                case ELS_CMD_FDISC:
                        wqe->un.ElsCmd.SP = 1;
                        wqe->ContextTag = port->vpip->VPI;
                        wqe->ContextType = WQE_VPI_CONTEXT;

                        if (hba->flag & FC_FIP_SUPPORTED) {
                                wqe->CmdType |= WQE_TYPE_MASK_FIP;
                        }

                        wqe->ELSId = WQE_ELSID_FDISC;
                        break;
                case ELS_CMD_LOGO:
                        if ((did == FABRIC_DID) &&
                            (hba->flag & FC_FIP_SUPPORTED)) {
                                wqe->CmdType |= WQE_TYPE_MASK_FIP;
                        }

                        wqe->ContextTag = port->vpip->VPI;
                        wqe->ContextType = WQE_VPI_CONTEXT;
                        wqe->ELSId = WQE_ELSID_LOGO;
                        break;
                case ELS_CMD_PLOGI:
                        if (rpip->RPI == FABRIC_RPI) {
                                if (hba->flag & FC_PT_TO_PT) {
                                        wqe->un.ElsCmd.SP = 1;
                                        wqe->un.ElsCmd.LocalId = port->did;
                                }

                                wqe->ContextTag = port->vpip->VPI;
                                wqe->ContextType = WQE_VPI_CONTEXT;
                        } else {
                                wqe->ContextTag = rpip->RPI;
                                wqe->ContextType = WQE_RPI_CONTEXT;
                        }

                        wqe->ELSId = WQE_ELSID_PLOGI;
                        break;
                default:
                        if (rpip->RPI == FABRIC_RPI) {
                                wqe->ContextTag = port->vpip->VPI;
                                wqe->ContextType = WQE_VPI_CONTEXT;
                        } else {
                                wqe->ContextTag = rpip->RPI;
                                wqe->ContextType = WQE_RPI_CONTEXT;
                        }

                        wqe->ELSId = WQE_ELSID_CMD;
                        break;
                }

#ifdef SFCT_SUPPORT
                /* This allows fct to abort the request */
                if (sbp->fct_cmd) {
                        sbp->fct_cmd->cmd_oxid = xrip->XRI;
                        sbp->fct_cmd->cmd_rxid = 0xFFFF;
                }
#endif /* SFCT_SUPPORT */
        }

        if (wqe->ContextType == WQE_VPI_CONTEXT) {
                reserved_rpip = emlxs_rpi_reserve_notify(port, did, xrip);

                if (!reserved_rpip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to alloc reserved RPI. rxid=%x. Rejecting.",
                            pkt->pkt_cmd_fhdr.rx_id);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_INVALID_RPI, 0);
                        return (0xff);
                }

                /* Store the reserved rpi */
                if (wqe->Command == CMD_ELS_REQUEST64_CR) {
                        wqe->OXId = reserved_rpip->RPI;
                } else {
                        wqe->CmdSpecific = reserved_rpip->RPI;
                }
        }

        EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
            xrip->SGList->size, DDI_DMA_SYNC_FORDEV);

        if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_CHAINED_SEQ) {
                wqe->CCPE = 1;
                wqe->CCP = pkt->pkt_cmd_fhdr.rsvd;
        }

        switch (FC_TRAN_CLASS(pkt->pkt_tran_flags)) {
        case FC_TRAN_CLASS2:
                wqe->Class = CLASS2;
                break;
        case FC_TRAN_CLASS3:
        default:
                wqe->Class = CLASS3;
                break;
        }
        sbp->class = wqe->Class;
        wqe->XRITag = xrip->XRI;
        wqe->RequestTag = xrip->iotag;
        wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
        return (FC_SUCCESS);

} /* emlxs_sli4_prep_els_iocb() */


/*ARGSUSED*/
static uint32_t
emlxs_sli4_prep_ct_iocb(emlxs_port_t *port, emlxs_buf_t *sbp)
{
        emlxs_hba_t *hba = HBA;
        fc_packet_t *pkt;
        IOCBQ *iocbq;
        IOCB *iocb;
        emlxs_wqe_t *wqe;
        NODELIST *node = NULL;
        CHANNEL *cp;
        RPIobj_t *rpip;
        XRIobj_t *xrip;
        uint32_t did;

        pkt = PRIV2PKT(sbp);
        did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);

        iocbq = &sbp->iocbq;
        wqe = &iocbq->wqe;
        iocb = &iocbq->iocb;
        bzero((void *)wqe, sizeof (emlxs_wqe_t));
        bzero((void *)iocb, sizeof (IOCB));

        cp = &hba->chan[hba->channel_ct];

        iocbq->port = (void *) port;
        iocbq->channel = (void *) cp;

        sbp->bmp = NULL;
        sbp->channel = cp;

        /* Initalize wqe */
        if (pkt->pkt_tran_type == FC_PKT_OUTBOUND) {
                /* CT Response */

                sbp->xrip = 0;
                xrip = emlxs_sli4_register_xri(port, sbp,
                    pkt->pkt_cmd_fhdr.rx_id, did);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to find XRI. rxid=%x",
                            pkt->pkt_cmd_fhdr.rx_id);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_NO_XRI, 0);
                        return (0xff);
                }

                rpip = xrip->rpip;

                if (!rpip) {
                        /* This means that we had a node registered */
                        /* when the unsol request came in but the node */
                        /* has since been unregistered. */
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to find RPI. rxid=%x",
                            pkt->pkt_cmd_fhdr.rx_id);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_INVALID_RPI, 0);
                        return (0xff);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CT: Prep xri=%d iotag=%d oxid=%x rpi=%d",
                    xrip->XRI, xrip->iotag, xrip->rx_id, rpip->RPI);

                if (emlxs_sli4_bde_setup(port, sbp)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Adapter Busy. Unable to setup SGE. did=0x%x", did);

                        return (FC_TRAN_BUSY);
                }

                if (!(hba->model_info.chip & EMLXS_BE_CHIPS)) {
                        wqe->un.XmitSeq.Rsvd0 = 0; /* Word3 now reserved */
                }

                if (!(hba->sli.sli4.param.PHWQ)) {
                        wqe->DBDE = 1; /* Data type for BDE 0 */
                }

                iocb->ULPCOMMAND = CMD_XMIT_SEQUENCE64_CR;
                wqe->CmdType = WQE_TYPE_GEN;
                wqe->Command = CMD_XMIT_SEQUENCE64_CR;
                wqe->LenLoc = 2;

                if (((SLI_CT_REQUEST *) pkt->pkt_cmd)->CommandResponse.bits.
                    CmdRsp == (LE_SWAP16(SLI_CT_LOOPBACK))) {
                        wqe->un.XmitSeq.xo = 1;
                } else {
                        wqe->un.XmitSeq.xo = 0;
                }

                if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_LAST_SEQ) {
                        wqe->un.XmitSeq.ls = 1;
                }

                if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_SEQ_INITIATIVE) {
                        wqe->un.XmitSeq.si = 1;
                }

                wqe->un.XmitSeq.DFctl  = pkt->pkt_cmd_fhdr.df_ctl;
                wqe->un.XmitSeq.Rctl  = pkt->pkt_cmd_fhdr.r_ctl;
                wqe->un.XmitSeq.Type  = pkt->pkt_cmd_fhdr.type;
                wqe->OXId = xrip->rx_id;
                wqe->XC = 0; /* xri_tag is a new exchange */
                wqe->CmdSpecific = wqe->un.GenReq.Payload.tus.f.bdeSize;

        } else {
                /* CT Request */

                node = (emlxs_node_t *)iocbq->node;
                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (!rpip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_failed_msg,
                            "Unable to find rpi. did=0x%x rpi=%d",
                            did, node->nlp_Rpi);

                        emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT,
                            IOERR_INVALID_RPI, 0);
                        return (0xff);
                }

                /* Next allocate an Exchange for this command */
                xrip = emlxs_sli4_alloc_xri(port, sbp, rpip,
                    EMLXS_XRI_SOL_CT_TYPE);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Adapter Busy. Unable to allocate exchange. "
                            "did=0x%x", did);

                        return (FC_TRAN_BUSY);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CT: Prep xri=%d iotag=%d oxid=%x rpi=%d",
                    xrip->XRI, xrip->iotag, xrip->rx_id, rpip->RPI);

                if (emlxs_sli4_bde_setup(port, sbp)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "Adapter Busy. Unable to setup SGE. did=0x%x", did);

                        emlxs_sli4_free_xri(port, sbp, xrip, 1);
                        return (FC_TRAN_BUSY);
                }

                if (!(hba->sli.sli4.param.PHWQ)) {
                        wqe->DBDE = 1; /* Data type for BDE 0 */
                }

                iocb->ULPCOMMAND = CMD_GEN_REQUEST64_CR;
                wqe->CmdType = WQE_TYPE_GEN;
                wqe->Command = CMD_GEN_REQUEST64_CR;
                wqe->un.GenReq.la = 1;
                wqe->un.GenReq.DFctl  = pkt->pkt_cmd_fhdr.df_ctl;
                wqe->un.GenReq.Rctl  = pkt->pkt_cmd_fhdr.r_ctl;
                wqe->un.GenReq.Type  = pkt->pkt_cmd_fhdr.type;

#ifdef DEBUG_CT
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CT: SGLaddr virt %p phys %p", xrip->SGList->virt,
                    xrip->SGList->phys);
                emlxs_data_dump(port, "CT: SGL", (uint32_t *)xrip->SGList->virt,
                    12, 0);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CT: CMD virt %p len %d:%d",
                    pkt->pkt_cmd, pkt->pkt_cmdlen, pkt->pkt_rsplen);
                emlxs_data_dump(port, "CT: DATA", (uint32_t *)pkt->pkt_cmd,
                    20, 0);
#endif /* DEBUG_CT */

#ifdef SFCT_SUPPORT
                /* This allows fct to abort the request */
                if (sbp->fct_cmd) {
                        sbp->fct_cmd->cmd_oxid = xrip->XRI;
                        sbp->fct_cmd->cmd_rxid = 0xFFFF;
                }
#endif /* SFCT_SUPPORT */
        }

        /* Setup for rsp */
        iocb->un.genreq64.w5.hcsw.Rctl  = pkt->pkt_cmd_fhdr.r_ctl;
        iocb->un.genreq64.w5.hcsw.Type  = pkt->pkt_cmd_fhdr.type;
        iocb->un.genreq64.w5.hcsw.Dfctl  = pkt->pkt_cmd_fhdr.df_ctl;
        iocb->ULPPU = 1;        /* Wd4 is relative offset */

        EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
            xrip->SGList->size, DDI_DMA_SYNC_FORDEV);

        wqe->ContextTag = rpip->RPI;
        wqe->ContextType = WQE_RPI_CONTEXT;
        wqe->XRITag = xrip->XRI;
        wqe->Timer = ((pkt->pkt_timeout > 0xff) ? 0 : pkt->pkt_timeout);

        if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_CHAINED_SEQ) {
                wqe->CCPE = 1;
                wqe->CCP = pkt->pkt_cmd_fhdr.rsvd;
        }

        switch (FC_TRAN_CLASS(pkt->pkt_tran_flags)) {
        case FC_TRAN_CLASS2:
                wqe->Class = CLASS2;
                break;
        case FC_TRAN_CLASS3:
        default:
                wqe->Class = CLASS3;
                break;
        }
        sbp->class = wqe->Class;
        wqe->RequestTag = xrip->iotag;
        wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
        return (FC_SUCCESS);

} /* emlxs_sli4_prep_ct_iocb() */


/*ARGSUSED*/
static int
emlxs_sli4_read_eq(emlxs_hba_t *hba, EQ_DESC_t *eq)
{
        uint32_t *ptr;
        EQE_u eqe;
        int rc = 0;
        off_t offset;

        mutex_enter(&EMLXS_PORT_LOCK);

        ptr = eq->addr.virt;
        ptr += eq->host_index;

        offset = (off_t)((uint64_t)((unsigned long)
            eq->addr.virt) -
            (uint64_t)((unsigned long)
            hba->sli.sli4.slim2.virt));

        EMLXS_MPDATA_SYNC(eq->addr.dma_handle, offset,
            4096, DDI_DMA_SYNC_FORKERNEL);

        eqe.word = *ptr;
        eqe.word = BE_SWAP32(eqe.word);

        if ((eqe.word & EQE_VALID) == eq->qe_valid) {
                rc = 1;
        }

        mutex_exit(&EMLXS_PORT_LOCK);

        return (rc);

} /* emlxs_sli4_read_eq */


static void
emlxs_sli4_poll_intr(emlxs_hba_t *hba)
{
        int rc = 0;
        int i;
        char arg[] = {0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};

        /* Check attention bits once and process if required */

        for (i = 0; i < hba->intr_count; i++) {
                rc = emlxs_sli4_read_eq(hba, &hba->sli.sli4.eq[i]);
                if (rc == 1) {
                        break;
                }
        }

        if (rc != 1) {
                return;
        }

        (void) emlxs_sli4_msi_intr((char *)hba,
            (char *)(unsigned long)arg[i]);

        return;

} /* emlxs_sli4_poll_intr() */


/*ARGSUSED*/
static void
emlxs_sli4_process_async_event(emlxs_hba_t *hba, CQE_ASYNC_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        uint8_t status;

        /* Save the event tag */
        if (hba->link_event_tag == cqe->un.link.event_tag) {
                HBASTATS.LinkMultiEvent++;
        } else if (hba->link_event_tag + 1 < cqe->un.link.event_tag) {
                HBASTATS.LinkMultiEvent++;
        }
        hba->link_event_tag = cqe->un.link.event_tag;

        switch (cqe->event_code) {
        case ASYNC_EVENT_CODE_FCOE_LINK_STATE:
                HBASTATS.LinkEvent++;

                switch (cqe->un.link.link_status) {
                case ASYNC_EVENT_PHYS_LINK_UP:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Link Async Event: PHYS_LINK_UP. val=%d "
                            "type=%x event=%x",
                            cqe->valid, cqe->event_type, HBASTATS.LinkEvent);
                        break;

                case ASYNC_EVENT_LOGICAL_LINK_UP:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Link Async Event: LOGICAL_LINK_UP. val=%d "
                            "type=%x event=%x",
                            cqe->valid, cqe->event_type, HBASTATS.LinkEvent);

                        emlxs_sli4_handle_fcoe_link_event(hba, cqe);
                        break;

                case ASYNC_EVENT_PHYS_LINK_DOWN:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Link Async Event: PHYS_LINK_DOWN. val=%d "
                            "type=%x event=%x",
                            cqe->valid, cqe->event_type, HBASTATS.LinkEvent);

                        emlxs_sli4_handle_fcoe_link_event(hba, cqe);
                        break;

                case ASYNC_EVENT_LOGICAL_LINK_DOWN:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Link Async Event: LOGICAL_LINK_DOWN. val=%d "
                            "type=%x event=%x",
                            cqe->valid, cqe->event_type, HBASTATS.LinkEvent);

                        emlxs_sli4_handle_fcoe_link_event(hba, cqe);
                        break;
                default:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Link Async Event: Unknown link status=%d event=%x",
                            cqe->un.link.link_status, HBASTATS.LinkEvent);
                        break;
                }
                break;
        case ASYNC_EVENT_CODE_FCOE_FIP:
                switch (cqe->un.fcoe.evt_type) {
                case ASYNC_EVENT_NEW_FCF_DISC:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: FCF_FOUND %d:%d",
                            cqe->un.fcoe.ref_index, cqe->un.fcoe.fcf_count);

                        (void) emlxs_fcf_found_notify(port,
                            cqe->un.fcoe.ref_index);
                        break;
                case ASYNC_EVENT_FCF_TABLE_FULL:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: FCFTAB_FULL %d:%d",
                            cqe->un.fcoe.ref_index, cqe->un.fcoe.fcf_count);

                        (void) emlxs_fcf_full_notify(port);
                        break;
                case ASYNC_EVENT_FCF_DEAD:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: FCF_LOST %d:%d",
                            cqe->un.fcoe.ref_index, cqe->un.fcoe.fcf_count);

                        (void) emlxs_fcf_lost_notify(port,
                            cqe->un.fcoe.ref_index);
                        break;
                case ASYNC_EVENT_VIRT_LINK_CLEAR:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: CVL %d",
                            cqe->un.fcoe.ref_index);

                        (void) emlxs_fcf_cvl_notify(port,
                            emlxs_sli4_vpi_to_index(hba,
                            cqe->un.fcoe.ref_index));
                        break;

                case ASYNC_EVENT_FCF_MODIFIED:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: FCF_CHANGED %d",
                            cqe->un.fcoe.ref_index);

                        (void) emlxs_fcf_changed_notify(port,
                            cqe->un.fcoe.ref_index);
                        break;
                default:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FIP Async Event: Unknown event type=%d",
                            cqe->un.fcoe.evt_type);
                        break;
                }
                break;
        case ASYNC_EVENT_CODE_DCBX:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "DCBX Async Event: type=%d. Not supported.",
                    cqe->event_type);
                break;
        case ASYNC_EVENT_CODE_GRP_5:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "Group 5 Async Event: type=%d.", cqe->event_type);
                if (cqe->event_type == ASYNC_EVENT_QOS_SPEED) {
                        hba->qos_linkspeed = cqe->un.qos.qos_link_speed;
                }
                break;
        case ASYNC_EVENT_CODE_FC_EVENT:
                switch (cqe->event_type) {
                case ASYNC_EVENT_FC_LINK_ATT:
                        HBASTATS.LinkEvent++;

                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FC Async Event: Link Attention. event=%x",
                            HBASTATS.LinkEvent);

                        emlxs_sli4_handle_fc_link_att(hba, cqe);
                        break;
                case ASYNC_EVENT_FC_SHARED_LINK_ATT:
                        HBASTATS.LinkEvent++;

                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FC Async Event: Shared Link Attention. event=%x",
                            HBASTATS.LinkEvent);

                        emlxs_sli4_handle_fc_link_att(hba, cqe);
                        break;
                default:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "FC Async Event: Unknown event. type=%d event=%x",
                            cqe->event_type, HBASTATS.LinkEvent);
                }
                break;
        case ASYNC_EVENT_CODE_PORT:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "SLI Port Async Event: type=%d", cqe->event_type);

                switch (cqe->event_type) {
                case ASYNC_EVENT_PORT_OTEMP:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "SLI Port Async Event: Temperature limit exceeded");
                        cmn_err(CE_WARN,
                            "^%s%d: Temperature limit exceeded. Fibre channel "
                            "controller temperature %u degrees C",
                            DRIVER_NAME, hba->ddiinst,
                            BE_SWAP32(*(uint32_t *)cqe->un.port.link_status));
                        break;

                case ASYNC_EVENT_PORT_NTEMP:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "SLI Port Async Event: Temperature returned to "
                            "normal");
                        cmn_err(CE_WARN,
                            "^%s%d: Temperature returned to normal",
                            DRIVER_NAME, hba->ddiinst);
                        break;

                case ASYNC_EVENT_MISCONFIG_PORT:
                        *((uint32_t *)cqe->un.port.link_status) =
                            BE_SWAP32(*((uint32_t *)cqe->un.port.link_status));
                        status =
                            cqe->un.port.link_status[hba->sli.sli4.link_number];

                        switch (status) {
                                case 0 :
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "SLI Port Async Event: link%d misconfig "
                                    "functional", hba->sli.sli4.link_number);
                                break;

                                case 1 :
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                                    "SLI Port Async Event: Physical media not "
                                    "detected");
                                cmn_err(CE_WARN,
                                    "^%s%d: Optics faulted/incorrectly "
                                    "installed/not installed - Reseat optics, "
                                    "if issue not resolved, replace.",
                                    DRIVER_NAME, hba->ddiinst);
                                break;

                                case 2 :
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                                    "SLI Port Async Event: Wrong physical "
                                    "media detected");
                                cmn_err(CE_WARN,
                                    "^%s%d: Optics of two types installed - "
                                    "Remove one optic or install matching"
                                    "pair of optics.",
                                    DRIVER_NAME, hba->ddiinst);
                                break;

                                case 3 :
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                                    "SLI Port Async Event: Unsupported "
                                    "physical media detected");
                                cmn_err(CE_WARN,
                                    "^%s%d:  Incompatible optics - Replace "
                                    "with compatible optics for card to "
                                    "function.",
                                    DRIVER_NAME, hba->ddiinst);
                                break;

                                default :
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                                    "SLI Port Async Event: Physical media "
                                    "error, status=%x", status);
                                cmn_err(CE_WARN,
                                    "^%s%d: Misconfigured port: status=0x%x - "
                                    "Check optics on card.",
                                    DRIVER_NAME, hba->ddiinst, status);
                                break;
                        }
                        break;
                }

                break;
        case ASYNC_EVENT_CODE_VF:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "VF Async Event: type=%d",
                    cqe->event_type);
                break;
        case ASYNC_EVENT_CODE_MR:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "MR Async Event: type=%d",
                    cqe->event_type);
                break;
        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "Unknown Async Event: code=%d type=%d.",
                    cqe->event_code, cqe->event_type);
                break;
        }

} /* emlxs_sli4_process_async_event() */


/*ARGSUSED*/
static void
emlxs_sli4_process_mbox_event(emlxs_hba_t *hba, CQE_MBOX_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        MAILBOX4 *mb;
        MATCHMAP *mbox_bp;
        MATCHMAP *mbox_nonembed;
        MAILBOXQ *mbq = NULL;
        uint32_t size;
        uint32_t *iptr;
        int rc;
        off_t offset;

        if (cqe->consumed && !cqe->completed) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: Mbox event. Entry consumed but not completed");
                return;
        }

        mutex_enter(&EMLXS_PORT_LOCK);
        switch (hba->mbox_queue_flag) {
        case 0:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_mbox_intr_msg,
                    "CQ ENTRY: Mbox event. No mailbox active.");

                mutex_exit(&EMLXS_PORT_LOCK);
                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 */

                mutex_enter(&EMLXS_MBOX_LOCK);
                mbq = (MAILBOXQ *)hba->mbox_mbq;
                if (mbq) {
                        port = (emlxs_port_t *)mbq->port;
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "CQ ENTRY: Mbox event. Completing Polled command.");
                        mbq->flag |= MBQ_COMPLETED;
                }
                mutex_exit(&EMLXS_MBOX_LOCK);

                mutex_exit(&EMLXS_PORT_LOCK);
                return;

        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;

                        mutex_enter(&EMLXS_MBOX_LOCK);
                        mbq = (MAILBOXQ *)hba->mbox_mbq;
                        mutex_exit(&EMLXS_MBOX_LOCK);
                }

                if (!mbq) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Mailbox event. No service required.");
                        mutex_exit(&EMLXS_PORT_LOCK);
                        return;
                }

                mb = (MAILBOX4 *)mbq;
                mutex_exit(&EMLXS_PORT_LOCK);
                break;

        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_completion_error_msg,
                    "CQ ENTRY: Mbox event. Invalid Mailbox flag (%x).",
                    hba->mbox_queue_flag);

                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        /* Set port context */
        port = (emlxs_port_t *)mbq->port;

        offset = (off_t)((uint64_t)((unsigned long)
            hba->sli.sli4.mq.addr.virt) -
            (uint64_t)((unsigned long)
            hba->sli.sli4.slim2.virt));

        /* Now that we are the owner, DMA Sync entire MQ if needed */
        EMLXS_MPDATA_SYNC(hba->sli.sli4.mq.addr.dma_handle, offset,
            4096, DDI_DMA_SYNC_FORDEV);

        BE_SWAP32_BCOPY((uint8_t *)hba->mbox_mqe, (uint8_t *)mb,
            MAILBOX_CMD_SLI4_BSIZE);

        if (mb->mbxCommand != MBX_HEARTBEAT) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: Mbox event. Mbox complete. status=%x cmd=%x",
                    mb->mbxStatus, mb->mbxCommand);

                emlxs_data_dump(port, "MBOX CMP", (uint32_t *)hba->mbox_mqe,
                    12, 0);
        }

        if (mb->mbxCommand == MBX_SLI_CONFIG) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "Mbox sge_cnt: %d length: %d embed: %d",
                    mb->un.varSLIConfig.be.sge_cnt,
                    mb->un.varSLIConfig.be.payload_length,
                    mb->un.varSLIConfig.be.embedded);
        }

        /* Now sync the memory buffer if one was used */
        if (mbq->bp) {
                mbox_bp = (MATCHMAP *)mbq->bp;
                EMLXS_MPDATA_SYNC(mbox_bp->dma_handle, 0, mbox_bp->size,
                    DDI_DMA_SYNC_FORKERNEL);
#ifdef FMA_SUPPORT
                if (emlxs_fm_check_dma_handle(hba, mbox_bp->dma_handle)
                    != DDI_FM_OK) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_dma_handle_msg,
                            "sli4_process_mbox_event: hdl=%p",
                            mbox_bp->dma_handle);

                        mb->mbxStatus = MBXERR_DMA_ERROR;
}
#endif
        }

        /* Now sync the memory buffer if one was used */
        if (mbq->nonembed) {
                mbox_nonembed = (MATCHMAP *)mbq->nonembed;
                size = mbox_nonembed->size;
                EMLXS_MPDATA_SYNC(mbox_nonembed->dma_handle, 0, size,
                    DDI_DMA_SYNC_FORKERNEL);
                iptr = (uint32_t *)((uint8_t *)mbox_nonembed->virt);
                BE_SWAP32_BCOPY((uint8_t *)iptr, (uint8_t *)iptr, size);

#ifdef FMA_SUPPORT
                if (emlxs_fm_check_dma_handle(hba,
                    mbox_nonembed->dma_handle) != DDI_FM_OK) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_dma_handle_msg,
                            "sli4_process_mbox_event: hdl=%p",
                            mbox_nonembed->dma_handle);

                        mb->mbxStatus = MBXERR_DMA_ERROR;
                }
#endif
                emlxs_data_dump(port, "EXT AREA", (uint32_t *)iptr, 24, 0);
        }

        /* Mailbox has been completely received at this point */

        if (mb->mbxCommand == MBX_HEARTBEAT) {
                hba->heartbeat_active = 0;
                goto done;
        }

        if (hba->mbox_queue_flag == MBX_SLEEP) {
                if (mb->mbxCommand != MBX_DOWN_LOAD
                    /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Received.  %s: status=%x Sleep.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand),
                            mb->mbxStatus);
                }
        } else {
                if (mb->mbxCommand != MBX_DOWN_LOAD
                    /* && mb->mbxCommand != MBX_DUMP_MEMORY */) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                            "Completed. %s: status=%x",
                            emlxs_mb_cmd_xlate(mb->mbxCommand),
                            mb->mbxStatus);
                }
        }

        /* Filter out passthru mailbox */
        if (mbq->flag & MBQ_PASSTHRU) {
                goto done;
        }

        if (mb->mbxStatus) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
                    "%s: status=0x%x", emlxs_mb_cmd_xlate(mb->mbxCommand),
                    (uint32_t)mb->mbxStatus);
        }

        if (mbq->mbox_cmpl) {
                rc = (mbq->mbox_cmpl)(hba, mbq);

                /* If mbox was retried, return immediately */
                if (rc) {
                        return;
                }
        }

done:

        /* Clean up the mailbox area */
        emlxs_mb_fini(hba, (MAILBOX *)mb, mb->mbxStatus);

        /* Attempt to send pending mailboxes */
        mbq = (MAILBOXQ *)emlxs_mb_get(hba);
        if (mbq) {
                /* Attempt to send pending mailboxes */
                rc =  emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);
                if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
                        emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
                }
        }
        return;

} /* emlxs_sli4_process_mbox_event() */


/*ARGSUSED*/
static void
emlxs_CQE_to_IOCB(emlxs_hba_t *hba, CQE_CmplWQ_t *cqe, emlxs_buf_t *sbp)
{
#ifdef DEBUG_FASTPATH
        emlxs_port_t *port = &PPORT;
#endif /* DEBUG_FASTPATH */
        IOCBQ *iocbq;
        IOCB *iocb;
        uint32_t *iptr;
        fc_packet_t *pkt;
        emlxs_wqe_t *wqe;

        iocbq = &sbp->iocbq;
        wqe = &iocbq->wqe;
        iocb = &iocbq->iocb;

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQE to IOCB: cmd:%x iotag:%x xri:%d", wqe->Command,
            wqe->RequestTag, wqe->XRITag);
#endif /* DEBUG_FASTPATH */

        iocb->ULPSTATUS = cqe->Status;
        iocb->un.ulpWord[4] = cqe->Parameter;
        iocb->ULPIOTAG = cqe->RequestTag;
        iocb->ULPCONTEXT = wqe->XRITag;

        switch (wqe->Command) {

        case CMD_FCP_ICMND64_CR:
                iocb->ULPCOMMAND = CMD_FCP_ICMND64_CX;
                break;

        case CMD_FCP_IREAD64_CR:
                iocb->ULPCOMMAND = CMD_FCP_IREAD64_CX;
                iocb->ULPPU = PARM_XFER_CHECK;
                if (iocb->ULPSTATUS ==  IOSTAT_FCP_RSP_ERROR) {
                        iocb->un.fcpi64.fcpi_parm =
                            wqe->un.FcpCmd.TotalTransferCount -
                            cqe->CmdSpecific;
                }
                break;

        case CMD_FCP_IWRITE64_CR:
                iocb->ULPCOMMAND = CMD_FCP_IWRITE64_CX;
                if (iocb->ULPSTATUS ==  IOSTAT_FCP_RSP_ERROR) {
                        if (wqe->un.FcpCmd.TotalTransferCount >
                            cqe->CmdSpecific) {
                                iocb->un.fcpi64.fcpi_parm =
                                    wqe->un.FcpCmd.TotalTransferCount -
                                    cqe->CmdSpecific;
                        } else {
                                iocb->un.fcpi64.fcpi_parm = 0;
                        }
                }
                break;

        case CMD_ELS_REQUEST64_CR:
                iocb->ULPCOMMAND = CMD_ELS_REQUEST64_CX;
                iocb->un.elsreq64.bdl.bdeSize = cqe->CmdSpecific;
                if (iocb->ULPSTATUS == 0) {
                        iocb->unsli3.ext_iocb.rsplen = cqe->CmdSpecific;
                }
                if (iocb->ULPSTATUS == IOSTAT_LS_RJT) {
                        /* For LS_RJT, the driver populates the rsp buffer */
                        pkt = PRIV2PKT(sbp);
                        iptr = (uint32_t *)pkt->pkt_resp;
                        *iptr++ = ELS_CMD_LS_RJT;
                        *iptr = cqe->Parameter;
                }
                break;

        case CMD_GEN_REQUEST64_CR:
                iocb->ULPCOMMAND = CMD_GEN_REQUEST64_CX;
                iocb->unsli3.ext_iocb.rsplen = cqe->CmdSpecific;
                break;

        case CMD_XMIT_SEQUENCE64_CR:
                iocb->ULPCOMMAND = CMD_XMIT_SEQUENCE64_CX;
                break;

        case CMD_ABORT_XRI_CX:
                iocb->ULPCONTEXT = wqe->AbortTag;
                break;

        case CMD_FCP_TRECEIVE64_CX:
                /* free memory for XRDY */
                if (iocbq->bp) {
                        emlxs_mem_buf_free(hba, iocbq->bp);
                        iocbq->bp = 0;
                }

                /*FALLTHROUGH*/

        case CMD_FCP_TSEND64_CX:
        case CMD_FCP_TRSP64_CX:
        default:
                iocb->ULPCOMMAND = wqe->Command;

        }
} /* emlxs_CQE_to_IOCB() */


/*ARGSUSED*/
static void
emlxs_sli4_hba_flush_chipq(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        CHANNEL *cp;
        emlxs_buf_t *sbp;
        IOCBQ *iocbq;
        uint16_t i;
        uint32_t trigger = 0;
        CQE_CmplWQ_t cqe;

        mutex_enter(&EMLXS_FCTAB_LOCK);
        for (i = 0; i < hba->max_iotag; i++) {
                sbp = hba->fc_table[i];
                if (sbp == NULL || sbp == STALE_PACKET) {
                        continue;
                }
                hba->fc_table[i] = STALE_PACKET;
                hba->io_count--;
                sbp->iotag = 0;
                mutex_exit(&EMLXS_FCTAB_LOCK);

                cp = sbp->channel;
                bzero(&cqe, sizeof (CQE_CmplWQ_t));
                cqe.RequestTag = i;
                cqe.Status = IOSTAT_LOCAL_REJECT;
                cqe.Parameter = IOERR_SEQUENCE_TIMEOUT;

                cp->hbaCmplCmd_sbp++;

#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
                if (sbp->fct_cmd) {
                        emlxs_fct_io_trace(port, sbp->fct_cmd,
                            EMLXS_FCT_IOCB_COMPLETE);
                }
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */

                if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
                        atomic_dec_32(&hba->io_active);
#ifdef NODE_THROTTLE_SUPPORT
                        if (sbp->node) {
                                atomic_dec_32(&sbp->node->io_active);
                        }
#endif /* NODE_THROTTLE_SUPPORT */
                }

                /* Copy entry to sbp's iocbq */
                iocbq = &sbp->iocbq;
                emlxs_CQE_to_IOCB(hba, &cqe, sbp);

                iocbq->next = NULL;

                /* Exchange is no longer busy on-chip, free it */
                emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);

                if (!(sbp->pkt_flags &
                    (PACKET_POLLED | PACKET_ALLOCATED))) {
                        /* Add the IOCB to the channel list */
                        mutex_enter(&cp->rsp_lock);
                        if (cp->rsp_head == NULL) {
                                cp->rsp_head = iocbq;
                                cp->rsp_tail = iocbq;
                        } else {
                                cp->rsp_tail->next = iocbq;
                                cp->rsp_tail = iocbq;
                        }
                        mutex_exit(&cp->rsp_lock);
                        trigger = 1;
                } else {
                        emlxs_proc_channel_event(hba, cp, iocbq);
                }
                mutex_enter(&EMLXS_FCTAB_LOCK);
        }
        mutex_exit(&EMLXS_FCTAB_LOCK);

        if (trigger) {
                for (i = 0; i < hba->chan_count; i++) {
                        cp = &hba->chan[i];
                        if (cp->rsp_head != NULL) {
                                emlxs_thread_trigger2(&cp->intr_thread,
                                    emlxs_proc_channel, cp);
                        }
                }
        }

} /* emlxs_sli4_hba_flush_chipq() */


/*ARGSUSED*/
static void
emlxs_sli4_process_oor_wqe_cmpl(emlxs_hba_t *hba,
    CQ_DESC_t *cq, CQE_CmplWQ_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        CHANNEL *cp;
        uint16_t request_tag;

        request_tag = cqe->RequestTag;

        /* 1 to 1 mapping between CQ and channel */
        cp = cq->channelp;

        cp->hbaCmplCmd++;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQ ENTRY: OOR Cmpl: iotag=%d", request_tag);

        emlxs_data_dump(port, "CQE", (uint32_t *)cqe, 4, 0);

} /* emlxs_sli4_process_oor_wqe_cmpl() */


/*ARGSUSED*/
static void
emlxs_sli4_process_wqe_cmpl(emlxs_hba_t *hba, CQ_DESC_t *cq, CQE_CmplWQ_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        CHANNEL *cp;
        emlxs_buf_t *sbp;
        IOCBQ *iocbq;
        uint16_t request_tag;
#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
        fct_cmd_t *fct_cmd;
        emlxs_buf_t *cmd_sbp;
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */

        request_tag = cqe->RequestTag;

        /* 1 to 1 mapping between CQ and channel */
        cp = cq->channelp;

        mutex_enter(&EMLXS_FCTAB_LOCK);
        sbp = hba->fc_table[request_tag];

        if (!sbp) {
                cp->hbaCmplCmd++;
                mutex_exit(&EMLXS_FCTAB_LOCK);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: NULL sbp. iotag=%d. Dropping...",
                    request_tag);
                return;
        }

        if (sbp == STALE_PACKET) {
                cp->hbaCmplCmd_sbp++;
                mutex_exit(&EMLXS_FCTAB_LOCK);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: Stale sbp. iotag=%d. Dropping...", request_tag);
                return;
        }

        if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
                atomic_add_32(&hba->io_active, -1);
#ifdef NODE_THROTTLE_SUPPORT
                if (sbp->node) {
                        atomic_add_32(&sbp->node->io_active, -1);
                }
#endif /* NODE_THROTTLE_SUPPORT */
        }

        if (!(sbp->xrip)) {
                cp->hbaCmplCmd++;
                mutex_exit(&EMLXS_FCTAB_LOCK);
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: NULL sbp xrip %p. iotag=%d. Dropping...",
                    sbp, request_tag);
                return;
        }

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQ ENTRY: process wqe compl");
#endif /* DEBUG_FASTPATH */
        cp->hbaCmplCmd_sbp++;

        /* Copy entry to sbp's iocbq */
        iocbq = &sbp->iocbq;
        emlxs_CQE_to_IOCB(hba, cqe, sbp);

        iocbq->next = NULL;

        if (cqe->XB) {
                /* Mark exchange as ABORT in progress */
                sbp->xrip->flag &= ~EMLXS_XRI_PENDING_IO;
                sbp->xrip->flag |= EMLXS_XRI_BUSY;

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: XRI BUSY: iotag=%d xri=%d", request_tag,
                    sbp->xrip->XRI);

                emlxs_sli4_free_xri(port, sbp, 0, 0);
        } else {
                /* Exchange is no longer busy on-chip, free it */
                emlxs_sli4_free_xri(port, sbp, sbp->xrip, 0);
        }

        mutex_exit(&EMLXS_FCTAB_LOCK);

#ifdef SFCT_SUPPORT
#ifdef FCT_IO_TRACE
        fct_cmd = sbp->fct_cmd;
        if (fct_cmd) {
                cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
                mutex_enter(&cmd_sbp->fct_mtx);
                EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_IOCB_COMPLETE);
                mutex_exit(&cmd_sbp->fct_mtx);
        }
#endif /* FCT_IO_TRACE */
#endif /* SFCT_SUPPORT */

        /*
         * If this is NOT a polled command completion
         * or a driver allocated pkt, then defer pkt
         * completion.
         */
        if (!(sbp->pkt_flags &
            (PACKET_POLLED | PACKET_ALLOCATED))) {
                /* Add the IOCB to the channel list */
                mutex_enter(&cp->rsp_lock);
                if (cp->rsp_head == NULL) {
                        cp->rsp_head = iocbq;
                        cp->rsp_tail = iocbq;
                } else {
                        cp->rsp_tail->next = iocbq;
                        cp->rsp_tail = iocbq;
                }
                mutex_exit(&cp->rsp_lock);

                /* Delay triggering thread till end of ISR */
                cp->chan_flag |= EMLXS_NEEDS_TRIGGER;
        } else {
                emlxs_proc_channel_event(hba, cp, iocbq);
        }

} /* emlxs_sli4_process_wqe_cmpl() */


/*ARGSUSED*/
static void
emlxs_sli4_process_release_wqe(emlxs_hba_t *hba, CQ_DESC_t *cq,
    CQE_RelWQ_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        WQ_DESC_t *wq;
        CHANNEL *cp;
        uint32_t i;
        uint16_t wqi;

        wqi = emlxs_sli4_wqid_to_index(hba, (uint16_t)cqe->WQid);

        /* Verify WQ index */
        if (wqi == 0xffff) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: Invalid WQid:%d. Dropping...",
                    cqe->WQid);
                return;
        }

        wq = &hba->sli.sli4.wq[wqi];

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQ ENTRY: process release wqe: old %d new %d", wq->port_index,
            cqe->WQindex);
#endif /* DEBUG_FASTPATH */

        wq->port_index = cqe->WQindex;

        /* Cmd ring may be available. Try sending more iocbs */
        for (i = 0; i < hba->chan_count; i++) {
                cp = &hba->chan[i];
                if (wq == (WQ_DESC_t *)cp->iopath) {
                        emlxs_sli4_issue_iocb_cmd(hba, cp, 0);
                }
        }

} /* emlxs_sli4_process_release_wqe() */


/*ARGSUSED*/
emlxs_iocbq_t *
emlxs_sli4_rxq_get(emlxs_hba_t *hba, fc_frame_hdr_t *fchdr)
{
        emlxs_queue_t *q;
        emlxs_iocbq_t *iocbq;
        emlxs_iocbq_t *prev;
        fc_frame_hdr_t *fchdr2;
        RXQ_DESC_t *rxq;

        switch (fchdr->type) {
        case 1: /* ELS */
                rxq = &hba->sli.sli4.rxq[EMLXS_RXQ_ELS];
                break;
        case 0x20: /* CT */
                rxq = &hba->sli.sli4.rxq[EMLXS_RXQ_CT];
                break;
        default:
                return (NULL);
        }

        mutex_enter(&rxq->lock);

        q = &rxq->active;
        iocbq  = (emlxs_iocbq_t *)q->q_first;
        prev = NULL;

        while (iocbq) {

                fchdr2 = (fc_frame_hdr_t *)iocbq->iocb.un.ulpWord;

                if ((fchdr2->s_id == fchdr->s_id) &&
                    (fchdr2->ox_id == fchdr->ox_id) &&
                    (fchdr2->seq_id == fchdr->seq_id)) {
                        /* Remove iocbq */
                        if (prev) {
                                prev->next = iocbq->next;
                        }
                        if (q->q_first == (uint8_t *)iocbq) {
                                q->q_first = (uint8_t *)iocbq->next;
                        }
                        if (q->q_last == (uint8_t *)iocbq) {
                                q->q_last = (uint8_t *)prev;
                        }
                        q->q_cnt--;

                        break;
                }

                prev  = iocbq;
                iocbq = iocbq->next;
        }

        mutex_exit(&rxq->lock);

        return (iocbq);

} /* emlxs_sli4_rxq_get() */


/*ARGSUSED*/
void
emlxs_sli4_rxq_put(emlxs_hba_t *hba, emlxs_iocbq_t *iocbq)
{
        emlxs_queue_t *q;
        fc_frame_hdr_t *fchdr;
        RXQ_DESC_t *rxq;

        fchdr = (fc_frame_hdr_t *)iocbq->iocb.RXFCHDR;

        switch (fchdr->type) {
        case 1: /* ELS */
                rxq = &hba->sli.sli4.rxq[EMLXS_RXQ_ELS];
                break;
        case 0x20: /* CT */
                rxq = &hba->sli.sli4.rxq[EMLXS_RXQ_CT];
                break;
        default:
                return;
        }

        mutex_enter(&rxq->lock);

        q = &rxq->active;

        if (q->q_last) {
                ((emlxs_iocbq_t *)q->q_last)->next = iocbq;
                q->q_cnt++;
        } else {
                q->q_first = (uint8_t *)iocbq;
                q->q_cnt = 1;
        }

        q->q_last = (uint8_t *)iocbq;
        iocbq->next = NULL;

        mutex_exit(&rxq->lock);

        return;

} /* emlxs_sli4_rxq_put() */


static void
emlxs_sli4_rq_post(emlxs_port_t *port, uint16_t rqid)
{
        emlxs_hba_t *hba = HBA;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "RQ POST: rqid=%d count=1", rqid);

        /* Ring the RQ doorbell once to repost the RQ buffer */

        emlxs_sli4_write_rqdb(hba, rqid, 1);

} /* emlxs_sli4_rq_post() */


/*ARGSUSED*/
static void
emlxs_sli4_process_unsol_rcv(emlxs_hba_t *hba, CQ_DESC_t *cq,
    CQE_UnsolRcv_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        emlxs_port_t *vport;
        RQ_DESC_t *hdr_rq;
        RQ_DESC_t *data_rq;
        MBUF_INFO *hdr_mp;
        MBUF_INFO *data_mp;
        MATCHMAP *seq_mp;
        uint32_t *data;
        fc_frame_hdr_t fchdr;
        uint16_t hdr_rqi;
        uint32_t host_index;
        emlxs_iocbq_t *iocbq = NULL;
        emlxs_iocb_t *iocb;
        emlxs_node_t *node = NULL;
        uint32_t i;
        uint32_t seq_len;
        uint32_t seq_cnt;
        uint32_t buf_type;
        char label[32];
        emlxs_wqe_t *wqe;
        CHANNEL *cp;
        XRIobj_t *xrip;
        RPIobj_t *rpip = NULL;
        uint32_t        cmd;
        uint32_t posted = 0;
        uint32_t abort = 1;
        off_t offset;
        uint32_t status;
        uint32_t data_size;
        uint16_t rqid;
        uint32_t hdr_size;
        fc_packet_t *pkt;
        emlxs_buf_t *sbp;

        if (cqe->Code == CQE_TYPE_UNSOL_RCV_V1) {
                CQE_UnsolRcvV1_t *cqeV1 = (CQE_UnsolRcvV1_t *)cqe;

                status    = cqeV1->Status;
                data_size = cqeV1->data_size;
                rqid      = cqeV1->RQid;
                hdr_size  = cqeV1->hdr_size;
        } else {
                status    = cqe->Status;
                data_size = cqe->data_size;
                rqid      = cqe->RQid;
                hdr_size  = cqe->hdr_size;
        }

        /* Validate the CQE */

        /* Check status */
        switch (status) {
        case RQ_STATUS_SUCCESS: /* 0x10 */
                break;

        case RQ_STATUS_BUFLEN_EXCEEDED:  /* 0x11 */
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: Unsol Rcv: Payload truncated.");
                break;

        case RQ_STATUS_NEED_BUFFER: /* 0x12 */
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: Unsol Rcv: Payload buffer needed.");
                return;

        case RQ_STATUS_FRAME_DISCARDED:  /* 0x13 */
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "CQ ENTRY: Unsol Rcv: Payload buffer discarded.");
                return;

        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: Unsol Rcv: Unknown status=%x.",
                    status);
                break;
        }

        /* Make sure there is a frame header */
        if (hdr_size < sizeof (fc_frame_hdr_t)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: Unsol Rcv: FC header too small. Dropping...");
                return;
        }

        hdr_rqi = emlxs_sli4_rqid_to_index(hba, rqid);

        /* Verify RQ index */
        if (hdr_rqi == 0xffff) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: Unsol Rcv: Invalid RQID:%d. Dropping...",
                    rqid);
                return;
        }

        hdr_rq  = &hba->sli.sli4.rq[hdr_rqi];
        data_rq = &hba->sli.sli4.rq[hdr_rqi + 1];

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQ ENTRY: Unsol Rcv:%x rqid=%d,%d index=%d status=%x "
            "hdr_size=%d data_size=%d",
            cqe->Code, rqid, hdr_rqi, hdr_rq->host_index, status, hdr_size,
            data_size);

        hdr_rq->num_proc++;

        /* Update host index */
        mutex_enter(&hba->sli.sli4.rq[hdr_rqi].lock);
        host_index = hdr_rq->host_index;
        hdr_rq->host_index++;

        if (hdr_rq->host_index >= hdr_rq->max_index) {
                hdr_rq->host_index = 0;
        }
        data_rq->host_index = hdr_rq->host_index;
        mutex_exit(&hba->sli.sli4.rq[hdr_rqi].lock);

        /* Get the next header rqb */
        hdr_mp  = &hdr_rq->rqb[host_index];

        offset = (off_t)((uint64_t)((unsigned long)hdr_mp->virt) -
            (uint64_t)((unsigned long)hba->sli.sli4.slim2.virt));

        EMLXS_MPDATA_SYNC(hdr_mp->dma_handle, offset,
            sizeof (fc_frame_hdr_t), DDI_DMA_SYNC_FORKERNEL);

        LE_SWAP32_BCOPY(hdr_mp->virt, (uint8_t *)&fchdr,
            sizeof (fc_frame_hdr_t));

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "RQ HDR[%d]: rctl:%x type:%x "
            "sid:%x did:%x oxid:%x rxid:%x",
            host_index, fchdr.r_ctl, fchdr.type,
            fchdr.s_id,  fchdr.d_id, fchdr.ox_id, fchdr.rx_id);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "RQ HDR[%d]: fctl:%x seq_id:%x seq_cnt:%x df_ctl:%x ro:%x",
            host_index, fchdr.f_ctl, fchdr.seq_id, fchdr.seq_cnt,
            fchdr.df_ctl, fchdr.ro);

        /* Verify fc header type */
        switch (fchdr.type) {
        case 0: /* BLS */
                if (fchdr.r_ctl != 0x81) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: Unexpected FC rctl (0x%x) "
                            "received. Dropping...",
                            fchdr.r_ctl);

                        goto done;
                }

                /* Make sure there is no payload */
                if (data_size != 0) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "RQ ENTRY: ABTS payload provided. Dropping...");

                        goto done;
                }

                buf_type = 0xFFFFFFFF;
                (void) strlcpy(label, "ABTS", sizeof (label));
                cp = &hba->chan[hba->channel_els];
                break;

        case 0x01: /* ELS */
                /* Make sure there is a payload */
                if (data_size == 0) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "RQ ENTRY: Unsol Rcv: No ELS payload provided. "
                            "Dropping...");

                        goto done;
                }

                buf_type = MEM_ELSBUF;
                (void) strlcpy(label, "Unsol ELS", sizeof (label));
                cp = &hba->chan[hba->channel_els];
                break;

        case 0x20: /* CT */
                /* Make sure there is a payload */
                if (data_size == 0) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "RQ ENTRY: Unsol Rcv: No CT payload provided. "
                            "Dropping...");

                        goto done;
                }

                buf_type = MEM_CTBUF;
                (void) strlcpy(label, "Unsol CT", sizeof (label));
                cp = &hba->chan[hba->channel_ct];
                break;

        case 0x08: /* FCT */
                /* Make sure there is a payload */
                if (data_size == 0) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "RQ ENTRY: Unsol Rcv: No FCP payload provided. "
                            "Dropping...");

                        goto done;
                }

                buf_type = MEM_FCTBUF;
                (void) strlcpy(label, "Unsol FCT", sizeof (label));
                cp = &hba->chan[hba->CHANNEL_FCT];
                break;

        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "RQ ENTRY: Unexpected FC type (0x%x) received. Dropping...",
                    fchdr.type);

                goto done;
        }
        /* Fc Header is valid */

        /* Check if this is an active sequence */
        iocbq = emlxs_sli4_rxq_get(hba, &fchdr);

        if (!iocbq) {
                if (fchdr.type != 0) {
                        if (!(fchdr.f_ctl & F_CTL_FIRST_SEQ)) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "RQ ENTRY: %s: First of sequence not"
                                    " set.  Dropping...",
                                    label);

                                goto done;
                        }
                }

                if ((fchdr.type != 0) && (fchdr.seq_cnt != 0)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Sequence count not zero (%d).  "
                            "Dropping...",
                            label, fchdr.seq_cnt);

                        goto done;
                }

                /* Find vport */
                for (i = 0; i < MAX_VPORTS; i++) {
                        vport = &VPORT(i);

                        if (vport->did == fchdr.d_id) {
                                port = vport;
                                break;
                        }
                }

                if (i == MAX_VPORTS) {
                        /* Allow unsol FLOGI & PLOGI for P2P */
                        if ((fchdr.type != 1 /* ELS*/) ||
                            ((fchdr.d_id != FABRIC_DID) &&
                            !(hba->flag & FC_PT_TO_PT))) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "RQ ENTRY: %s: Invalid did=%x. Dropping...",
                                    label, fchdr.d_id);

                                goto done;
                        }
                }

                /* Allocate an IOCBQ */
                iocbq = (emlxs_iocbq_t *)emlxs_mem_get(hba, MEM_IOCB);

                if (!iocbq) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Out of IOCB "
                            "resources.  Dropping...",
                            label);

                        goto done;
                }

                seq_mp = NULL;
                if (fchdr.type != 0) {
                        /* Allocate a buffer */
                        seq_mp = (MATCHMAP *)emlxs_mem_get(hba, buf_type);

                        if (!seq_mp) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "RQ ENTRY: %s: Out of buffer "
                                    "resources.  Dropping...",
                                    label);

                                goto done;
                        }

                        iocbq->bp = (uint8_t *)seq_mp;
                }

                node = (void *)emlxs_node_find_did(port, fchdr.s_id, 1);
                if (node == NULL) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Node not found. sid=%x",
                            label, fchdr.s_id);
                }

                /* Initialize the iocbq */
                iocbq->port = port;
                iocbq->channel = cp;
                iocbq->node = node;

                iocb = &iocbq->iocb;
                iocb->RXSEQCNT = 0;
                iocb->RXSEQLEN = 0;

                seq_len = 0;
                seq_cnt = 0;

        } else {

                iocb = &iocbq->iocb;
                port = iocbq->port;
                node = (emlxs_node_t *)iocbq->node;

                seq_mp = (MATCHMAP *)iocbq->bp;
                seq_len = iocb->RXSEQLEN;
                seq_cnt = iocb->RXSEQCNT;

                /* Check sequence order */
                if (fchdr.seq_cnt != seq_cnt) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Out of order frame received "
                            "(%d != %d).  Dropping...",
                            label, fchdr.seq_cnt, seq_cnt);

                        goto done;
                }
        }

        /* We now have an iocbq */

        if (!port->vpip->vfip) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "RQ ENTRY: %s: No fabric connection. "
                    "Dropping...",
                    label);

                goto done;
        }

        /* Save the frame data to our seq buffer */
        if (data_size && seq_mp) {
                /* Get the next data rqb */
                data_mp = &data_rq->rqb[host_index];

                offset = (off_t)((uint64_t)((unsigned long)
                    data_mp->virt) -
                    (uint64_t)((unsigned long)
                    hba->sli.sli4.slim2.virt));

                EMLXS_MPDATA_SYNC(data_mp->dma_handle, offset,
                    data_size, DDI_DMA_SYNC_FORKERNEL);

                data = (uint32_t *)data_mp->virt;

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "RQ DAT[%d]: %08x %08x %08x %08x %08x %08x ...",
                    host_index, data[0], data[1], data[2], data[3],
                    data[4], data[5]);

                /* Check sequence length */
                if ((seq_len + data_size) > seq_mp->size) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "RQ ENTRY: %s: Sequence buffer overflow. "
                            "(%d > %d). Dropping...",
                            label, (seq_len + data_size), seq_mp->size);

                        goto done;
                }

                /* Copy data to local receive buffer */
                bcopy((uint8_t *)data, ((uint8_t *)seq_mp->virt +
                    seq_len), data_size);

                seq_len += data_size;
        }

        /* If this is not the last frame of sequence, queue it. */
        if (!(fchdr.f_ctl & F_CTL_END_SEQ)) {
                /* Save sequence header */
                if (seq_cnt == 0) {
                        bcopy((uint8_t *)&fchdr, (uint8_t *)iocb->RXFCHDR,
                            sizeof (fc_frame_hdr_t));
                }

                /* Update sequence info in iocb */
                iocb->RXSEQCNT = seq_cnt + 1;
                iocb->RXSEQLEN = seq_len;

                /* Queue iocbq for next frame */
                emlxs_sli4_rxq_put(hba, iocbq);

                /* Don't free resources */
                iocbq = NULL;

                /* No need to abort */
                abort = 0;

                goto done;
        }

        emlxs_sli4_rq_post(port, hdr_rq->qid);
        posted = 1;

        /* End of sequence found. Process request now. */

        if (seq_cnt > 0) {
                /* Retrieve first frame of sequence */
                bcopy((uint8_t *)iocb->RXFCHDR, (uint8_t *)&fchdr,
                    sizeof (fc_frame_hdr_t));

                bzero((uint8_t *)iocb, sizeof (emlxs_iocb_t));
        }

        /* Build rcv iocb and process it */
        switch (fchdr.type) {
        case 0: /* BLS */

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "RQ ENTRY: %s: oxid:%x rxid %x sid:%x. Sending BLS ACC...",
                    label, fchdr.ox_id, fchdr.rx_id, fchdr.s_id);

                /* Try to send abort response */
                if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Unable to alloc pkt. Dropping...",
                            label);
                        goto done;
                }

                /* Setup sbp / iocb for driver initiated cmd */
                sbp = PKT2PRIV(pkt);

                /* Free the temporary iocbq */
                emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);

                iocbq = (emlxs_iocbq_t *)&sbp->iocbq;
                iocbq->port = port;
                iocbq->channel = cp;
                iocbq->node = node;

                sbp->pkt_flags &= ~PACKET_ULP_OWNED;

                if (node) {
                        sbp->node = node;
                        sbp->did  = node->nlp_DID;
                }

                iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);

                /* BLS ACC Response */
                wqe = &iocbq->wqe;
                bzero((void *)wqe, sizeof (emlxs_wqe_t));

                iocbq->iocb.ULPCOMMAND = CMD_XMIT_BLS_RSP64_CX;
                wqe->Command = CMD_XMIT_BLS_RSP64_CX;
                wqe->CmdType = WQE_TYPE_GEN;

                wqe->un.BlsRsp.Payload0 = 0x80;
                wqe->un.BlsRsp.Payload1 = fchdr.seq_id;

                wqe->un.BlsRsp.OXId = fchdr.ox_id;
                wqe->un.BlsRsp.RXId = fchdr.rx_id;

                wqe->un.BlsRsp.SeqCntLow = 0;
                wqe->un.BlsRsp.SeqCntHigh = 0xFFFF;

                wqe->un.BlsRsp.XO = ((fchdr.f_ctl & F_CTL_XCHG_CONTEXT)? 1:0);
                wqe->un.BlsRsp.AR = 0;

                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (rpip) {
                        wqe->ContextType = WQE_RPI_CONTEXT;
                        wqe->ContextTag = rpip->RPI;
                } else {
                        wqe->ContextType = WQE_VPI_CONTEXT;
                        wqe->ContextTag = port->vpip->VPI;

                        rpip = emlxs_rpi_reserve_notify(port, fchdr.s_id, 0);

                        if (!rpip) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "RQ ENTRY: %s: Unable to alloc "
                                    "reserved RPI. Dropping...",
                                    label);

                                goto done;
                        }

                        /* Store the reserved rpi */
                        wqe->CmdSpecific = rpip->RPI;

                        wqe->un.BlsRsp.RemoteId = fchdr.s_id;
                        wqe->un.BlsRsp.LocalId = fchdr.d_id;
                }

                if (fchdr.f_ctl & F_CTL_CHAINED_SEQ) {
                        wqe->CCPE = 1;
                        wqe->CCP = fchdr.rsvd;
                }

                /* Allocate an exchange for this command */
                xrip = emlxs_sli4_alloc_xri(port, sbp, rpip,
                    EMLXS_XRI_SOL_BLS_TYPE);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Unable to alloc XRI. Dropping...",
                            label);
                        goto done;
                }

                wqe->XRITag = xrip->XRI;
                wqe->Class = CLASS3;
                wqe->RequestTag = xrip->iotag;
                wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */

                sbp->ticks = hba->timer_tics + 30;

                emlxs_sli4_issue_iocb_cmd(hba, iocbq->channel, iocbq);

                /* The temporary iocbq has been freed already */
                iocbq = NULL;

                break;

        case 1: /* ELS */
                cmd = *((uint32_t *)seq_mp->virt);
                cmd &= ELS_CMD_MASK;

                if (!(port->vpip->flag & EMLXS_VPI_PORT_ENABLED)) {
                        uint32_t dropit = 1;

                        /* Allow for P2P handshaking */
                        switch (cmd) {
                        case ELS_CMD_FLOGI:
                                dropit = 0;
                                break;

                        case ELS_CMD_PLOGI:
                        case ELS_CMD_PRLI:
                                if (hba->flag & FC_PT_TO_PT) {
                                        dropit = 0;
                                }
                                break;
                        }

                        if (dropit) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_sli_detail_msg,
                                    "RQ ENTRY: %s: Port not yet enabled. "
                                    "Dropping...",
                                    label);
                                goto done;
                        }
                }

                rpip = NULL;

                if (cmd != ELS_CMD_LOGO) {
                        rpip = EMLXS_NODE_TO_RPI(port, node);
                }

                if (!rpip) {
                        /* Use the fabric rpi */
                        rpip = port->vpip->fabric_rpip;
                }

                xrip = emlxs_sli4_reserve_xri(port, rpip,
                    EMLXS_XRI_UNSOL_ELS_TYPE, fchdr.ox_id);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Out of exchange "
                            "resources.  Dropping...",
                            label);

                        goto done;
                }

                /* Build CMD_RCV_ELS64_CX */
                iocb->un.rcvels64.elsReq.tus.f.bdeFlags = 0;
                iocb->un.rcvels64.elsReq.tus.f.bdeSize  = seq_len;
                iocb->un.rcvels64.elsReq.addrLow  = PADDR_LO(seq_mp->phys);
                iocb->un.rcvels64.elsReq.addrHigh = PADDR_HI(seq_mp->phys);
                iocb->ULPBDECOUNT = 1;

                iocb->un.rcvels64.remoteID = fchdr.s_id;
                iocb->un.rcvels64.parmRo = fchdr.d_id;

                iocb->ULPPU = 0x3;
                iocb->ULPCONTEXT = xrip->XRI;
                iocb->ULPIOTAG = ((node)? node->nlp_Rpi:0);
                iocb->ULPCLASS = CLASS3;
                iocb->ULPCOMMAND = CMD_RCV_ELS64_CX;

                iocb->unsli3.ext_rcv.seq_len = seq_len;
                iocb->unsli3.ext_rcv.vpi = port->vpip->VPI;
                iocb->unsli3.ext_rcv.oxid = fchdr.ox_id;

                if (fchdr.f_ctl & F_CTL_CHAINED_SEQ) {
                        iocb->unsli3.ext_rcv.ccpe = 1;
                        iocb->unsli3.ext_rcv.ccp = fchdr.rsvd;
                }

                if (port->mode == MODE_INITIATOR) {
                        (void) emlxs_els_handle_unsol_req(port, iocbq->channel,
                            iocbq, seq_mp, seq_len);
                }
#ifdef SFCT_SUPPORT
                else if (port->mode == MODE_TARGET) {
                        (void) emlxs_fct_handle_unsol_els(port, iocbq->channel,
                            iocbq, seq_mp, seq_len);
                }
#endif /* SFCT_SUPPORT */
                break;

#ifdef SFCT_SUPPORT
        case 8: /* FCT */
                if (!(port->VPIobj.flag & EMLXS_VPI_PORT_ENABLED)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Port not yet enabled. "
                            "Dropping...",
                            label);

                        goto done;
                }

                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (!rpip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Port not logged in. "
                            "Dropping...",
                            label);

                        goto done;
                }

                xrip = emlxs_sli4_reserve_xri(port, rpip,
                    EMLXS_XRI_UNSOL_FCP_TYPE, fchdr.ox_id);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Out of exchange "
                            "resources.  Dropping...",
                            label);

                        goto done;
                }

                /* Build CMD_RCV_SEQUENCE64_CX */
                iocb->un.rcvseq64.rcvBde.tus.f.bdeFlags = 0;
                iocb->un.rcvseq64.rcvBde.tus.f.bdeSize  = seq_len;
                iocb->un.rcvseq64.rcvBde.addrLow  = PADDR_LO(seq_mp->phys);
                iocb->un.rcvseq64.rcvBde.addrHigh = PADDR_HI(seq_mp->phys);
                iocb->ULPBDECOUNT = 1;

                iocb->ULPPU = 0x3;
                iocb->ULPCONTEXT = xrip->XRI;
                iocb->ULPIOTAG = ((node)? node->nlp_Rpi:0);
                iocb->ULPCLASS = CLASS3;
                iocb->ULPCOMMAND = CMD_RCV_ELS64_CX;

                iocb->unsli3.ext_rcv.seq_len = seq_len;
                iocb->unsli3.ext_rcv.vpi = port->VPIobj.VPI;
                iocb->unsli3.ext_rcv.oxid = fchdr.ox_id;

                if (fchdr.f_ctl & F_CTL_CHAINED_SEQ) {
                        iocb->unsli3.ext_rcv.ccpe = 1;
                        iocb->unsli3.ext_rcv.ccp = fchdr.rsvd;
                }

                /* pass xrip to FCT in the iocbq */
                iocbq->sbp = xrip;

                (void) emlxs_fct_handle_unsol_req(port, cp, iocbq,
                    seq_mp, seq_len);
                break;
#endif /* SFCT_SUPPORT */

        case 0x20: /* CT */
                if (!(port->vpip->flag & EMLXS_VPI_PORT_ENABLED) &&
                    !(hba->flag & FC_LOOPBACK_MODE)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Port not yet enabled. "
                            "Dropping...",
                            label);

                        goto done;
                }

                if (!node) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Node not found (did=%x).  "
                            "Dropping...",
                            label, fchdr.d_id);

                        goto done;
                }

                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (!rpip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: RPI not found (did=%x rpi=%d).  "
                            "Dropping...",
                            label, fchdr.d_id, node->nlp_Rpi);

                        goto done;
                }

                xrip = emlxs_sli4_reserve_xri(port, rpip,
                    EMLXS_XRI_UNSOL_CT_TYPE, fchdr.ox_id);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ ENTRY: %s: Out of exchange "
                            "resources.  Dropping...",
                            label);

                        goto done;
                }

                /* Build CMD_RCV_SEQ64_CX */
                iocb->un.rcvseq64.rcvBde.tus.f.bdeFlags = 0;
                iocb->un.rcvseq64.rcvBde.tus.f.bdeSize  = seq_len;
                iocb->un.rcvseq64.rcvBde.addrLow  = PADDR_LO(seq_mp->phys);
                iocb->un.rcvseq64.rcvBde.addrHigh = PADDR_HI(seq_mp->phys);
                iocb->ULPBDECOUNT = 1;

                iocb->un.rcvseq64.xrsqRo = 0;
                iocb->un.rcvseq64.w5.hcsw.Rctl = fchdr.r_ctl;
                iocb->un.rcvseq64.w5.hcsw.Type = fchdr.type;
                iocb->un.rcvseq64.w5.hcsw.Dfctl = fchdr.df_ctl;
                iocb->un.rcvseq64.w5.hcsw.Fctl = fchdr.f_ctl;

                iocb->ULPPU = 0x3;
                iocb->ULPCONTEXT = xrip->XRI;
                iocb->ULPIOTAG = rpip->RPI;
                iocb->ULPCLASS = CLASS3;
                iocb->ULPCOMMAND = CMD_RCV_SEQ64_CX;

                iocb->unsli3.ext_rcv.seq_len = seq_len;
                iocb->unsli3.ext_rcv.vpi = port->vpip->VPI;

                if (fchdr.f_ctl & F_CTL_CHAINED_SEQ) {
                        iocb->unsli3.ext_rcv.ccpe = 1;
                        iocb->unsli3.ext_rcv.ccp = fchdr.rsvd;
                }

                (void) emlxs_ct_handle_unsol_req(port, iocbq->channel,
                    iocbq, seq_mp, seq_len);

                break;
        }

        /* Sequence handled, no need to abort */
        abort = 0;

done:

        if (!posted) {
                emlxs_sli4_rq_post(port, hdr_rq->qid);
        }

        if (abort) {
                /* Send ABTS for this exchange */
                /* !!! Currently, we have no implementation for this !!! */
                abort = 0;
        }

        /* Return memory resources to pools */
        if (iocbq) {
                if (iocbq->bp) {
                        emlxs_mem_put(hba, buf_type, (void *)iocbq->bp);
                        iocbq->bp = 0;
                }

                emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
        }

#ifdef FMA_SUPPORT
        if (emlxs_fm_check_dma_handle(hba,
            hba->sli.sli4.slim2.dma_handle)
            != DDI_FM_OK) {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_invalid_dma_handle_msg,
                    "sli4_process_unsol_rcv: hdl=%p",
                    hba->sli.sli4.slim2.dma_handle);

                emlxs_thread_spawn(hba, emlxs_restart_thread,
                    0, 0);
        }
#endif
        return;

} /* emlxs_sli4_process_unsol_rcv() */


/*ARGSUSED*/
static void
emlxs_sli4_process_xri_aborted(emlxs_hba_t *hba, CQ_DESC_t *cq,
    CQE_XRI_Abort_t *cqe)
{
        emlxs_port_t *port = &PPORT;
        XRIobj_t *xrip;

        mutex_enter(&EMLXS_FCTAB_LOCK);

        xrip = emlxs_sli4_find_xri(port, cqe->XRI);
        if (xrip == NULL) {
                /* EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg, */
                /*    "CQ ENTRY: process xri aborted ignored");  */

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return;
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "CQ ENTRY: XRI Aborted: xri=%d IA=%d EO=%d BR=%d",
            cqe->XRI, cqe->IA, cqe->EO, cqe->BR);

        if (!(xrip->flag & EMLXS_XRI_BUSY)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "CQ ENTRY: XRI Aborted: xri=%d flag=%x. Bad state.",
                    xrip->XRI, xrip->flag);

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return;
        }

        /* Exchange is no longer busy on-chip, free it */
        emlxs_sli4_free_xri(port, 0, xrip, 0);

        mutex_exit(&EMLXS_FCTAB_LOCK);

        return;

} /* emlxs_sli4_process_xri_aborted () */


/*ARGSUSED*/
static void
emlxs_sli4_process_cq(emlxs_hba_t *hba, CQ_DESC_t *cq)
{
        emlxs_port_t *port = &PPORT;
        CQE_u *cqe;
        CQE_u cq_entry;
        int num_entries = 0;
        off_t offset;

        /* EMLXS_PORT_LOCK must be held when entering this routine */

        cqe = (CQE_u *)cq->addr.virt;
        cqe += cq->host_index;

        offset = (off_t)((uint64_t)((unsigned long)
            cq->addr.virt) -
            (uint64_t)((unsigned long)
            hba->sli.sli4.slim2.virt));

        EMLXS_MPDATA_SYNC(cq->addr.dma_handle, offset,
            4096, DDI_DMA_SYNC_FORKERNEL);

        for (;;) {
                cq_entry.word[3] = BE_SWAP32(cqe->word[3]);
                if (((cq_entry.word[3]>>31) & 0x01) != cq->qe_valid) {
#ifdef  DEBUG_CQE
                        if (num_entries == 0) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_sli_detail_msg, "CQE: Invalid CQE:"
                                    " eqid=%x cqid=%x cqe=%p %08x %08x %08x"
                                    " %08x. host_index=%x valid=%d Break...",
                                    cq->eqid, cq->qid, cqe,
                                    cqe->word[0], cqe->word[1],
                                    cqe->word[2], cqe->word[3],
                                    cq->host_index, cq->qe_valid);
                        }
#endif /* DEBUG_CQE */
                        break;
                }

                cq_entry.word[2] = BE_SWAP32(cqe->word[2]);
                cq_entry.word[1] = BE_SWAP32(cqe->word[1]);
                cq_entry.word[0] = BE_SWAP32(cqe->word[0]);

#ifdef  DEBUG_CQE
                emlxs_data_dump(port, "CQE", (uint32_t *)cqe, 6, 0);
#endif /* DEBUG_CQE */
                num_entries++;
                if (hba->sli.sli4.param.CqAV)
                        /* do not attach the valid bit */
                        cqe->word[3] &= BE_SWAP32(CQE_VALID);
                else
                        cqe->word[3] = 0;

                cq->host_index++;
                if (cq->host_index >= cq->max_index) {
                        cq->host_index = 0;
                        cqe = (CQE_u *)cq->addr.virt;
                        if (hba->sli.sli4.param.CqAV)
                                cq->qe_valid ^= 1;
                } else {
                        cqe++;
                }
                mutex_exit(&EMLXS_PORT_LOCK);

                /* Now handle specific cq type */
                if (cq->type == EMLXS_CQ_TYPE_GROUP1) {
                        if (cq_entry.cqAsyncEntry.async_evt) {
                                emlxs_sli4_process_async_event(hba,
                                    (CQE_ASYNC_t *)&cq_entry);
                        } else {
                                emlxs_sli4_process_mbox_event(hba,
                                    (CQE_MBOX_t *)&cq_entry);
                        }
                } else { /* EMLXS_CQ_TYPE_GROUP2 */
                        switch (cq_entry.cqCmplEntry.Code) {
                        case CQE_TYPE_WQ_COMPLETION:
                                if (cq_entry.cqCmplEntry.RequestTag <
                                    hba->max_iotag) {
                                        emlxs_sli4_process_wqe_cmpl(hba, cq,
                                            (CQE_CmplWQ_t *)&cq_entry);
                                } else {
                                        emlxs_sli4_process_oor_wqe_cmpl(hba, cq,
                                            (CQE_CmplWQ_t *)&cq_entry);
                                }
                                break;
                        case CQE_TYPE_RELEASE_WQE:
                                emlxs_sli4_process_release_wqe(hba, cq,
                                    (CQE_RelWQ_t *)&cq_entry);
                                break;
                        case CQE_TYPE_UNSOL_RCV:
                        case CQE_TYPE_UNSOL_RCV_V1:
                                emlxs_sli4_process_unsol_rcv(hba, cq,
                                    (CQE_UnsolRcv_t *)&cq_entry);
                                break;
                        case CQE_TYPE_XRI_ABORTED:
                                emlxs_sli4_process_xri_aborted(hba, cq,
                                    (CQE_XRI_Abort_t *)&cq_entry);
                                break;
                        default:
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                                    "Invalid CQ entry eqid=%x qid=%x code=%d: "
                                    "%08x %08x %08x %08x, host_index=%x "
                                    "valid=%d",
                                    cq->eqid, cq->qid,
                                    cq_entry.cqCmplEntry.Code, cq_entry.word[0],
                                    cq_entry.word[1], cq_entry.word[2],
                                    cq_entry.word[3], cq->host_index,
                                    cq->qe_valid);
                                break;
                        }
                }

                mutex_enter(&EMLXS_PORT_LOCK);
        }

        /* Number of times this routine gets called for this CQ */
        cq->isr_count++;

        /* num_entries is the number of CQEs we process in this specific CQ */
        cq->num_proc += num_entries;
        if (cq->max_proc < num_entries)
                cq->max_proc = num_entries;

        emlxs_sli4_write_cqdb(hba, cq->qid, num_entries, B_TRUE);

        /* EMLXS_PORT_LOCK must be held when exiting this routine */

} /* emlxs_sli4_process_cq() */


/*ARGSUSED*/
static void
emlxs_sli4_process_eq(emlxs_hba_t *hba, EQ_DESC_t *eq)
{
        emlxs_port_t *port = &PPORT;
        uint32_t *ptr;
        CHANNEL *cp;
        EQE_u eqe;
        uint32_t i;
        uint16_t cqi;
        int num_entries = 0;
        off_t offset;

        /* EMLXS_PORT_LOCK must be held when entering this routine */

        hba->intr_busy_cnt ++;

        ptr = eq->addr.virt;
        ptr += eq->host_index;

        offset = (off_t)((uint64_t)((unsigned long)
            eq->addr.virt) -
            (uint64_t)((unsigned long)
            hba->sli.sli4.slim2.virt));

        EMLXS_MPDATA_SYNC(eq->addr.dma_handle, offset,
            4096, DDI_DMA_SYNC_FORKERNEL);

        for (;;) {
                eqe.word = *ptr;
                eqe.word = BE_SWAP32(eqe.word);

                if ((eqe.word & EQE_VALID) != eq->qe_valid) {
#ifdef DEBUG_FASTPATH
                        if (num_entries == 0) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "EQE: Invalid EQE: %x. host_index=%x "
                                    "valid=%d Break...",
                                    eqe.word, eq->qe_valid);
                        }
#endif /* DEBUG_FASTPATH */
                        break;
                }

#ifdef DEBUG_FASTPATH
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "EQE00: %08x", eqe.word);
#endif /* DEBUG_FASTPATH */

                if (hba->sli.sli4.param.EqAV)
                        *ptr &= BE_SWAP32(EQE_VALID);
                else
                        *ptr = 0;
                num_entries++;
                eq->host_index++;
                if (eq->host_index >= eq->max_index) {
                        eq->host_index = 0;
                        ptr = eq->addr.virt;
                        if (hba->sli.sli4.param.EqAV)
                                eq->qe_valid ^= 1;
                } else {
                        ptr++;
                }

                cqi = emlxs_sli4_cqid_to_index(hba, eqe.entry.CQId);

                /* Verify CQ index */
                if (cqi == 0xffff) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                            "EQE: Invalid CQid: %d. valid=%d Dropping...",
                            eqe.entry.CQId, eq->qe_valid);
                        continue;
                }

#ifdef DEBUG_FASTPATH
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "EQE: qid=%x host_index=%x valid=%d iptr=%p CQIndex:%x "
                    "cqid:%x",
                    eq->qid, eq->host_index, eq->qe_valid, ptr, cqi,
                    eqe.entry.CQId);
#endif /* DEBUG_FASTPATH */

                emlxs_sli4_process_cq(hba, &hba->sli.sli4.cq[cqi]);
        }

        /* Number of times the ISR for this EQ gets called */
        eq->isr_count++;

        /* num_entries is the number of EQEs we process in this specific ISR */
        eq->num_proc += num_entries;
        if (eq->max_proc < num_entries) {
                eq->max_proc = num_entries;
        }

        if (num_entries != 0) {
                for (i = 0; i < hba->chan_count; i++) {
                        cp = &hba->chan[i];
                        if (cp->chan_flag & EMLXS_NEEDS_TRIGGER) {
                                cp->chan_flag &= ~EMLXS_NEEDS_TRIGGER;
                                emlxs_thread_trigger2(&cp->intr_thread,
                                    emlxs_proc_channel, cp);
                        }
                }
        }

        emlxs_sli4_write_eqdb(hba, eq->qid, num_entries, B_TRUE);

        /* EMLXS_PORT_LOCK must be held when exiting this routine */

        hba->intr_busy_cnt --;

} /* emlxs_sli4_process_eq() */


#ifdef MSI_SUPPORT
/*ARGSUSED*/
static uint32_t
emlxs_sli4_msi_intr(char *arg1, char *arg2)
{
        emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
#ifdef DEBUG_FASTPATH
        emlxs_port_t *port = &PPORT;
#endif /* DEBUG_FASTPATH */
        uint16_t msgid;
        int rc;

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "msiINTR arg1:%p arg2:%p", arg1, arg2);
#endif /* DEBUG_FASTPATH */

        /* Check for legacy interrupt handling */
        if (hba->intr_type == DDI_INTR_TYPE_FIXED) {
                rc = emlxs_sli4_intx_intr(arg1);
                return (rc);
        }

        /* Get MSI message id */
        msgid = (uint16_t)((unsigned long)arg2);

        /* Validate the message id */
        if (msgid >= hba->intr_count) {
                msgid = 0;
        }
        mutex_enter(&EMLXS_PORT_LOCK);

        if ((hba->state == FC_KILLED) || (hba->flag & FC_OFFLINE_MODE)) {
                mutex_exit(&EMLXS_PORT_LOCK);
                return (DDI_INTR_UNCLAIMED);
        }

        /* The eq[] index == the MSI vector number */
        emlxs_sli4_process_eq(hba, &hba->sli.sli4.eq[msgid]);

        mutex_exit(&EMLXS_PORT_LOCK);
        return (DDI_INTR_CLAIMED);

} /* emlxs_sli4_msi_intr() */
#endif /* MSI_SUPPORT */


/*ARGSUSED*/
static int
emlxs_sli4_intx_intr(char *arg)
{
        emlxs_hba_t *hba = (emlxs_hba_t *)arg;
#ifdef DEBUG_FASTPATH
        emlxs_port_t *port = &PPORT;
#endif /* DEBUG_FASTPATH */

#ifdef DEBUG_FASTPATH
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "intxINTR arg:%p", arg);
#endif /* DEBUG_FASTPATH */

        mutex_enter(&EMLXS_PORT_LOCK);

        if ((hba->state == FC_KILLED) || (hba->flag & FC_OFFLINE_MODE)) {
                mutex_exit(&EMLXS_PORT_LOCK);
                return (DDI_INTR_UNCLAIMED);
        }

        emlxs_sli4_process_eq(hba, &hba->sli.sli4.eq[0]);

        mutex_exit(&EMLXS_PORT_LOCK);
        return (DDI_INTR_CLAIMED);
} /* emlxs_sli4_intx_intr() */


static void
emlxs_sli4_hba_kill(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        uint32_t j;

        mutex_enter(&EMLXS_PORT_LOCK);
        if (hba->flag & FC_INTERLOCKED) {
                EMLXS_STATE_CHANGE_LOCKED(hba, FC_KILLED);

                mutex_exit(&EMLXS_PORT_LOCK);

                return;
        }

        j = 0;
        while (j++ < 10000) {
                if ((hba->mbox_queue_flag == 0) &&
                    (hba->intr_busy_cnt == 0)) {
                        break;
                }

                mutex_exit(&EMLXS_PORT_LOCK);
                BUSYWAIT_US(100);
                mutex_enter(&EMLXS_PORT_LOCK);
        }

        if ((hba->mbox_queue_flag != 0) || (hba->intr_busy_cnt > 0)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "Board kill failed. Adapter busy, %d, %d.",
                    hba->mbox_queue_flag, hba->intr_busy_cnt);
                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        hba->flag |= FC_INTERLOCKED;

        EMLXS_STATE_CHANGE_LOCKED(hba, FC_KILLED);

        mutex_exit(&EMLXS_PORT_LOCK);

} /* emlxs_sli4_hba_kill() */


extern void
emlxs_sli4_hba_reset_all(emlxs_hba_t *hba, uint32_t flag)
{
        emlxs_port_t *port = &PPORT;
        uint32_t value;

        mutex_enter(&EMLXS_PORT_LOCK);

        if ((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) != SLI_INTF_IF_TYPE_2 &&
            (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) != SLI_INTF_IF_TYPE_6) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
                    "Reset All failed. Invalid Operation.");
                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        /* Issue a Firmware Reset All Request */
        if (flag) {
                value = SLI_PHYDEV_FRST | SLI_PHYDEV_FRL_ALL | SLI_PHYDEV_DD;
        } else {
                value = SLI_PHYDEV_FRST | SLI_PHYDEV_FRL_ALL;
        }

        ddi_put32(hba->sli.sli4.bar0_acc_handle,
            hba->sli.sli4.PHYSDEV_reg_addr, value);

        mutex_exit(&EMLXS_PORT_LOCK);

} /* emlxs_sli4_hba_reset_all() */


static void
emlxs_sli4_enable_intr(emlxs_hba_t *hba)
{
        emlxs_config_t *cfg = &CFG;
        int i;
        int num_cq;

        hba->sli.sli4.flag |= EMLXS_SLI4_INTR_ENABLED;

        num_cq = (hba->intr_count * cfg[CFG_NUM_WQ].current) +
            EMLXS_CQ_OFFSET_WQ;

        /* ARM EQ / CQs */
        for (i = 0; i < num_cq; i++) {
                emlxs_sli4_write_cqdb(hba, hba->sli.sli4.cq[i].qid, 0, B_TRUE);
        }

        for (i = 0; i < hba->intr_count; i++) {
                emlxs_sli4_write_eqdb(hba, hba->sli.sli4.eq[i].qid, 0, B_TRUE);
        }
} /* emlxs_sli4_enable_intr() */


static void
emlxs_sli4_disable_intr(emlxs_hba_t *hba, uint32_t att)
{
        if (att) {
                return;
        }

        hba->sli.sli4.flag &= ~EMLXS_SLI4_INTR_ENABLED;

        /* Short of reset, we cannot disable interrupts */
} /* emlxs_sli4_disable_intr() */

static void
emlxs_sli4_resource_free(emlxs_hba_t *hba)
{
        emlxs_port_t    *port = &PPORT;
        MBUF_INFO       *buf_info;
        uint32_t        i;

        buf_info = &hba->sli.sli4.slim2;
        if (buf_info->virt == 0) {
                /* Already free */
                return;
        }

        emlxs_fcf_fini(hba);

        mutex_enter(&EMLXS_PORT_LOCK);

        buf_info = &hba->sli.sli4.HeaderTmplate;
        if (buf_info->virt) {
                bzero(buf_info, sizeof (MBUF_INFO));
        }

        if (hba->sli.sli4.XRIp) {
                XRIobj_t        *xrip;

                if ((hba->sli.sli4.XRIinuse_f !=
                    (XRIobj_t *)&hba->sli.sli4.XRIinuse_f) ||
                    (hba->sli.sli4.XRIinuse_b !=
                    (XRIobj_t *)&hba->sli.sli4.XRIinuse_f)) {
                        xrip = (XRIobj_t *)hba->sli.sli4.XRIinuse_f;
                        while (xrip != (XRIobj_t *)&hba->sli.sli4.XRIinuse_f) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
                                    "XRIs in use during free!: %p %p != %p "
                                    "XRI:%d iotag:%d\n",
                                    hba->sli.sli4.XRIinuse_f,
                                    hba->sli.sli4.XRIinuse_b, xrip, xrip->XRI,
                                    xrip->iotag);
                                xrip = xrip->_f;
                        }
                }

                xrip = hba->sli.sli4.XRIp;
                for (i = 0; i < hba->sli.sli4.XRICount; i++) {
                        xrip->XRI = emlxs_sli4_index_to_xri(hba, i);

                        if (xrip->XRI != 0)
                                emlxs_mem_put(hba, xrip->SGSeg, xrip->SGList);

                        xrip++;
                }

                kmem_free(hba->sli.sli4.XRIp,
                    (sizeof (XRIobj_t) * hba->sli.sli4.XRICount));
                hba->sli.sli4.XRIp = NULL;

                hba->sli.sli4.XRIfree_f =
                    (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
                hba->sli.sli4.XRIfree_b =
                    (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
                hba->sli.sli4.xrif_count = 0;
        }

        for (i = 0; i < hba->intr_count; i++) {
                mutex_destroy(&hba->sli.sli4.eq[i].lastwq_lock);
                bzero(&hba->sli.sli4.eq[i], sizeof (EQ_DESC_t));
                hba->sli.sli4.eq[i].qid = 0xffff;
        }
        for (i = 0; i < EMLXS_MAX_CQS; i++) {
                bzero(&hba->sli.sli4.cq[i], sizeof (CQ_DESC_t));
                hba->sli.sli4.cq[i].qid = 0xffff;
        }
        for (i = 0; i < EMLXS_MAX_WQS; i++) {
                bzero(&hba->sli.sli4.wq[i], sizeof (WQ_DESC_t));
                hba->sli.sli4.wq[i].qid = 0xffff;
        }
        for (i = 0; i < EMLXS_MAX_RXQS; i++) {
                mutex_destroy(&hba->sli.sli4.rxq[i].lock);
                bzero(&hba->sli.sli4.rxq[i], sizeof (RXQ_DESC_t));
        }
        for (i = 0; i < EMLXS_MAX_RQS; i++) {
                mutex_destroy(&hba->sli.sli4.rq[i].lock);
                bzero(&hba->sli.sli4.rq[i], sizeof (RQ_DESC_t));
                hba->sli.sli4.rq[i].qid = 0xffff;
        }

        /* Free the MQ */
        bzero(&hba->sli.sli4.mq, sizeof (MQ_DESC_t));


        buf_info = &hba->sli.sli4.slim2;
        if (buf_info->virt) {
                buf_info->flags = FC_MBUF_DMA;
                emlxs_mem_free(hba, buf_info);
                bzero(buf_info, sizeof (MBUF_INFO));
        }

        mutex_exit(&EMLXS_PORT_LOCK);

        /* GPIO lock */
        if (hba->model_info.flags & EMLXS_GPIO_LEDS)
                mutex_destroy(&hba->gpio_lock);


} /* emlxs_sli4_resource_free() */

static int
emlxs_sli4_resource_alloc(emlxs_hba_t *hba)
{
        emlxs_port_t    *port = &PPORT;
        emlxs_config_t  *cfg = &CFG;
        MBUF_INFO       *buf_info;
        int             num_eq;
        int             num_wq;
        uint16_t        i;
        uint32_t        j;
        uint32_t        k;
        uint16_t        cq_depth;
        uint32_t        cq_size;
        uint32_t        word;
        XRIobj_t        *xrip;
        RQE_t           *rqe;
        MBUF_INFO       *rqb;
        uint64_t        phys;
        uint64_t        tmp_phys;
        char            *virt;
        char            *tmp_virt;
        void            *data_handle;
        void            *dma_handle;
        int32_t         size;
        off_t           offset;
        uint32_t        count = 0;
        uint32_t        hddr_size = 0;
        uint32_t        align;
        uint32_t        iotag;
        uint32_t        mseg;

        buf_info = &hba->sli.sli4.slim2;
        if (buf_info->virt) {
                /* Already allocated */
                return (0);
        }

        emlxs_fcf_init(hba);

        switch (hba->sli.sli4.param.CQV) {
        case 0:
                cq_depth = CQ_DEPTH;
                break;
        case 2:
        default:
                cq_depth = CQ_DEPTH_V2;
                break;
        }
        cq_size = (cq_depth * CQE_SIZE);

        /* EQs - 1 per Interrupt vector */
        num_eq = hba->intr_count;

        /* CQs  - number of WQs + 1 for RQs + 1 for mbox/async events */
        num_wq = cfg[CFG_NUM_WQ].current * num_eq;

        /* Calculate total dmable memory we need */
        /* WARNING: make sure each section is aligned on 4K boundary */

        /* EQ */
        count += num_eq * 4096;

        /* CQ */
        count += (num_wq + EMLXS_CQ_OFFSET_WQ) * cq_size;

        /* WQ */
        count += num_wq * (4096 * EMLXS_NUM_WQ_PAGES);

        /* MQ */
        count +=  EMLXS_MAX_MQS * 4096;

        /* RQ */
        count +=  EMLXS_MAX_RQS * 4096;

        /* RQB/E */
        count += RQB_COUNT * (RQB_DATA_SIZE + RQB_HEADER_SIZE);
        count += (4096 - (count%4096)); /* Ensure 4K alignment */

        /* RPI Header Templates */
        if (hba->sli.sli4.param.HDRR) {
                /* Bytes per extent */
                j = hba->sli.sli4.RPIExtSize * sizeof (RPIHdrTmplate_t);

                /* Pages required per extent (page == 4096 bytes) */
                k = (j/4096) + ((j%4096)? 1:0);

                /* Total size */
                hddr_size = (k * hba->sli.sli4.RPIExtCount * 4096);

                count += hddr_size;
        }

        /* Allocate slim2 for SLI4 */
        buf_info = &hba->sli.sli4.slim2;
        buf_info->size = count;
        buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
        buf_info->align = ddi_ptob(hba->dip, 1L);

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "Allocating memory for slim2: %d", count);

        (void) emlxs_mem_alloc(hba, buf_info);

        if (buf_info->virt == NULL) {
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_failed_msg,
                    "Unable to allocate internal memory for SLI4: %d",
                    count);
                goto failed;
        }
        bzero(buf_info->virt, buf_info->size);
        EMLXS_MPDATA_SYNC(buf_info->dma_handle, 0,
            buf_info->size, DDI_DMA_SYNC_FORDEV);

        /* Assign memory to Head Template, EQ, CQ, WQ, RQ and MQ */
        data_handle = buf_info->data_handle;
        dma_handle = buf_info->dma_handle;
        phys = buf_info->phys;
        virt = (char *)buf_info->virt;

        /* Allocate space for queues */

        /* EQ */
        size = 4096;
        for (i = 0; i < num_eq; i++) {
                bzero(&hba->sli.sli4.eq[i], sizeof (EQ_DESC_t));

                buf_info = &hba->sli.sli4.eq[i].addr;
                buf_info->size = size;
                buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                buf_info->align = ddi_ptob(hba->dip, 1L);
                buf_info->phys = phys;
                buf_info->virt = (void *)virt;
                buf_info->data_handle = data_handle;
                buf_info->dma_handle = dma_handle;

                phys += size;
                virt += size;

                hba->sli.sli4.eq[i].max_index = EQ_DEPTH;
                hba->sli.sli4.eq[i].qid = 0xffff;

                mutex_init(&hba->sli.sli4.eq[i].lastwq_lock, NULL,
                    MUTEX_DRIVER, NULL);
                hba->sli.sli4.eq[i].qe_valid = 1;
        }


        /* CQ */
        for (i = 0; i < (num_wq + EMLXS_CQ_OFFSET_WQ); i++) {
                bzero(&hba->sli.sli4.cq[i], sizeof (CQ_DESC_t));

                buf_info = &hba->sli.sli4.cq[i].addr;
                buf_info->size = cq_size;
                buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                buf_info->align = ddi_ptob(hba->dip, 1L);
                buf_info->phys = phys;
                buf_info->virt = (void *)virt;
                buf_info->data_handle = data_handle;
                buf_info->dma_handle = dma_handle;

                phys += cq_size;
                virt += cq_size;

                hba->sli.sli4.cq[i].max_index = cq_depth;
                hba->sli.sli4.cq[i].qid = 0xffff;
                hba->sli.sli4.cq[i].qe_valid = 1;
        }


        /* WQ */
        size = 4096 * EMLXS_NUM_WQ_PAGES;
        for (i = 0; i < num_wq; i++) {
                bzero(&hba->sli.sli4.wq[i], sizeof (WQ_DESC_t));

                buf_info = &hba->sli.sli4.wq[i].addr;
                buf_info->size = size;
                buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                buf_info->align = ddi_ptob(hba->dip, 1L);
                buf_info->phys = phys;
                buf_info->virt = (void *)virt;
                buf_info->data_handle = data_handle;
                buf_info->dma_handle = dma_handle;

                phys += size;
                virt += size;

                hba->sli.sli4.wq[i].max_index = WQ_DEPTH;
                hba->sli.sli4.wq[i].release_depth = WQE_RELEASE_DEPTH;
                hba->sli.sli4.wq[i].qid = 0xFFFF;
        }


        /* MQ */
        size = 4096;
        bzero(&hba->sli.sli4.mq, sizeof (MQ_DESC_t));

        buf_info = &hba->sli.sli4.mq.addr;
        buf_info->size = size;
        buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
        buf_info->align = ddi_ptob(hba->dip, 1L);
        buf_info->phys = phys;
        buf_info->virt = (void *)virt;
        buf_info->data_handle = data_handle;
        buf_info->dma_handle = dma_handle;

        phys += size;
        virt += size;

        hba->sli.sli4.mq.max_index = MQ_DEPTH;


        /* RXQ */
        for (i = 0; i < EMLXS_MAX_RXQS; i++) {
                bzero(&hba->sli.sli4.rxq[i], sizeof (RXQ_DESC_t));

                mutex_init(&hba->sli.sli4.rxq[i].lock, NULL, MUTEX_DRIVER,
                    NULL);
        }


        /* RQ */
        size = 4096;
        for (i = 0; i < EMLXS_MAX_RQS; i++) {
                bzero(&hba->sli.sli4.rq[i], sizeof (RQ_DESC_t));

                buf_info = &hba->sli.sli4.rq[i].addr;
                buf_info->size = size;
                buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                buf_info->align = ddi_ptob(hba->dip, 1L);
                buf_info->phys = phys;
                buf_info->virt = (void *)virt;
                buf_info->data_handle = data_handle;
                buf_info->dma_handle = dma_handle;

                phys += size;
                virt += size;

                hba->sli.sli4.rq[i].max_index = RQ_DEPTH;
                hba->sli.sli4.rq[i].qid = 0xFFFF;

                mutex_init(&hba->sli.sli4.rq[i].lock, NULL, MUTEX_DRIVER, NULL);
        }


        /* RQB/E */
        for (i = 0; i < EMLXS_MAX_RQS; i++) {
                size = (i & 0x1) ? RQB_DATA_SIZE : RQB_HEADER_SIZE;
                tmp_phys = phys;
                tmp_virt = virt;

                /* Initialize the RQEs */
                rqe = (RQE_t *)hba->sli.sli4.rq[i].addr.virt;
                for (j = 0; j < (RQ_DEPTH/RQB_COUNT); j++) {
                        phys = tmp_phys;
                        virt = tmp_virt;
                        for (k = 0; k < RQB_COUNT; k++) {
                                word = PADDR_HI(phys);
                                rqe->AddrHi = BE_SWAP32(word);

                                word = PADDR_LO(phys);
                                rqe->AddrLo = BE_SWAP32(word);

                                rqb = &hba->sli.sli4.rq[i].
                                    rqb[k + (j * RQB_COUNT)];
                                rqb->size = size;
                                rqb->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
                                rqb->align = ddi_ptob(hba->dip, 1L);
                                rqb->phys = phys;
                                rqb->virt = (void *)virt;
                                rqb->data_handle = data_handle;
                                rqb->dma_handle = dma_handle;

                                phys += size;
                                virt += size;
#ifdef DEBUG_RQE
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "RQ_ALLOC: rq[%d] rqb[%d,%d]=%p flags=%d",
                                    i, j, k, rqb, rqb->flags);
#endif /* DEBUG_RQE */

                                rqe++;
                        }
                }

                offset = (off_t)((uint64_t)((unsigned long)
                    hba->sli.sli4.rq[i].addr.virt) -
                    (uint64_t)((unsigned long)
                    hba->sli.sli4.slim2.virt));

                /* Sync the RQ buffer list */
                EMLXS_MPDATA_SYNC(hba->sli.sli4.rq[i].addr.dma_handle, offset,
                    hba->sli.sli4.rq[i].addr.size, DDI_DMA_SYNC_FORDEV);
        }

        /* 4K Alignment */
        align = (4096 - (phys%4096));
        phys += align;
        virt += align;

        /* RPI Header Templates */
        if (hba->sli.sli4.param.HDRR) {
                buf_info = &hba->sli.sli4.HeaderTmplate;
                bzero(buf_info, sizeof (MBUF_INFO));
                buf_info->size = hddr_size;
                buf_info->flags = FC_MBUF_DMA;
                buf_info->align = ddi_ptob(hba->dip, 1L);
                buf_info->phys = phys;
                buf_info->virt = (void *)virt;
                buf_info->data_handle = data_handle;
                buf_info->dma_handle = dma_handle;
        }

        /* SGL */

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "Allocating memory for %d SGLs: %d/%d",
            hba->sli.sli4.XRICount, sizeof (XRIobj_t), size);

        /* Initialize double linked lists */
        hba->sli.sli4.XRIinuse_f =
            (XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
        hba->sli.sli4.XRIinuse_b =
            (XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
        hba->sli.sli4.xria_count = 0;

        hba->sli.sli4.XRIfree_f =
            (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
        hba->sli.sli4.XRIfree_b =
            (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
        hba->sli.sli4.xrif_count = 0;

        switch (hba->sli.sli4.mem_sgl_size) {
        case 1024:
                mseg = MEM_SGL1K;
                break;
        case 2048:
                mseg = MEM_SGL2K;
                break;
        case 4096:
                mseg = MEM_SGL4K;
                break;
        default:
                EMLXS_MSGF(EMLXS_CONTEXT,
                    &emlxs_init_failed_msg,
                    "Unsupported SGL Size: %d", hba->sli.sli4.mem_sgl_size);
                goto failed;
        }

        hba->sli.sli4.XRIp = (XRIobj_t *)kmem_zalloc(
            (sizeof (XRIobj_t) * hba->sli.sli4.XRICount), KM_SLEEP);

        xrip = hba->sli.sli4.XRIp;
        iotag = 1;

        for (i = 0; i < hba->sli.sli4.XRICount; i++) {
                xrip->XRI = emlxs_sli4_index_to_xri(hba, i);

                /* We don't use XRI==0, since it also represents an */
                /* uninitialized exchange */
                if (xrip->XRI == 0) {
                        xrip++;
                        continue;
                }

                xrip->iotag = iotag++;
                xrip->sge_count =
                    (hba->sli.sli4.mem_sgl_size / sizeof (ULP_SGE64));

                /* Add xrip to end of free list */
                xrip->_b = hba->sli.sli4.XRIfree_b;
                hba->sli.sli4.XRIfree_b->_f = xrip;
                xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
                hba->sli.sli4.XRIfree_b = xrip;
                hba->sli.sli4.xrif_count++;

                /* Allocate SGL for this xrip */
                xrip->SGSeg = mseg;
                xrip->SGList = emlxs_mem_get(hba, xrip->SGSeg);

                if (xrip->SGList == NULL) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to allocate memory for SGL %d", i);
                        goto failed;
                }

                EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
                    xrip->SGList->size, DDI_DMA_SYNC_FORDEV);

                xrip++;
        }

        /* GPIO lock */
        if (hba->model_info.flags & EMLXS_GPIO_LEDS)
                mutex_init(&hba->gpio_lock, NULL, MUTEX_DRIVER, NULL);

#ifdef FMA_SUPPORT
        if (hba->sli.sli4.slim2.dma_handle) {
                if (emlxs_fm_check_dma_handle(hba,
                    hba->sli.sli4.slim2.dma_handle)
                    != DDI_FM_OK) {
                        EMLXS_MSGF(EMLXS_CONTEXT,
                            &emlxs_invalid_dma_handle_msg,
                            "sli4_resource_alloc: hdl=%p",
                            hba->sli.sli4.slim2.dma_handle);
                        goto failed;
                }
        }
#endif /* FMA_SUPPORT */

        return (0);

failed:

        (void) emlxs_sli4_resource_free(hba);
        return (ENOMEM);

} /* emlxs_sli4_resource_alloc */


extern void
emlxs_sli4_zero_queue_stat(emlxs_hba_t *hba)
{
        uint32_t i;
        uint32_t num_wq;
        emlxs_config_t  *cfg = &CFG;
        clock_t         time;

        /* EQ */
        for (i = 0; i < hba->intr_count; i++) {
                hba->sli.sli4.eq[i].num_proc = 0;
                hba->sli.sli4.eq[i].max_proc = 0;
                hba->sli.sli4.eq[i].isr_count = 0;
        }
        num_wq = cfg[CFG_NUM_WQ].current * hba->intr_count;
        /* CQ */
        for (i = 0; i < (num_wq + EMLXS_CQ_OFFSET_WQ); i++) {
                hba->sli.sli4.cq[i].num_proc = 0;
                hba->sli.sli4.cq[i].max_proc = 0;
                hba->sli.sli4.cq[i].isr_count = 0;
        }
        /* WQ */
        for (i = 0; i < num_wq; i++) {
                hba->sli.sli4.wq[i].num_proc = 0;
                hba->sli.sli4.wq[i].num_busy = 0;
        }
        /* RQ */
        for (i = 0; i < EMLXS_MAX_RQS; i++) {
                hba->sli.sli4.rq[i].num_proc = 0;
        }
        (void) drv_getparm(LBOLT, &time);
        hba->sli.sli4.que_stat_timer = (uint32_t)time;

} /* emlxs_sli4_zero_queue_stat */


extern XRIobj_t *
emlxs_sli4_reserve_xri(emlxs_port_t *port,  RPIobj_t *rpip, uint32_t type,
    uint16_t rx_id)
{
        emlxs_hba_t *hba = HBA;
        XRIobj_t        *xrip;
        uint16_t        iotag;

        mutex_enter(&EMLXS_FCTAB_LOCK);

        xrip = hba->sli.sli4.XRIfree_f;

        if (xrip == (XRIobj_t *)&hba->sli.sli4.XRIfree_f) {
                mutex_exit(&EMLXS_FCTAB_LOCK);

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "Unable to reserve XRI. type=%d",
                    type);

                return (NULL);
        }

        iotag = xrip->iotag;

        if ((!iotag) ||
            ((hba->fc_table[iotag] != NULL) &&
            (hba->fc_table[iotag] != STALE_PACKET))) {
                /*
                 * No more command slots available, retry later
                 */
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Adapter Busy. Unable to reserve iotag. type=%d",
                    type);

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return (NULL);
        }

        xrip->state = XRI_STATE_ALLOCATED;
        xrip->type = type;
        xrip->flag = EMLXS_XRI_RESERVED;
        xrip->sbp = NULL;

        xrip->rpip = rpip;
        xrip->rx_id = rx_id;
        rpip->xri_count++;

        /* Take it off free list */
        (xrip->_b)->_f = xrip->_f;
        (xrip->_f)->_b = xrip->_b;
        xrip->_f = NULL;
        xrip->_b = NULL;
        hba->sli.sli4.xrif_count--;

        /* Add it to end of inuse list */
        xrip->_b = hba->sli.sli4.XRIinuse_b;
        hba->sli.sli4.XRIinuse_b->_f = xrip;
        xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
        hba->sli.sli4.XRIinuse_b = xrip;
        hba->sli.sli4.xria_count++;

        mutex_exit(&EMLXS_FCTAB_LOCK);
        return (xrip);

} /* emlxs_sli4_reserve_xri() */


extern uint32_t
emlxs_sli4_unreserve_xri(emlxs_port_t *port, uint16_t xri, uint32_t lock)
{
        emlxs_hba_t *hba = HBA;
        XRIobj_t *xrip;

        if (lock) {
                mutex_enter(&EMLXS_FCTAB_LOCK);
        }

        xrip = emlxs_sli4_find_xri(port, xri);

        if (!xrip || xrip->state == XRI_STATE_FREE) {
                if (lock) {
                        mutex_exit(&EMLXS_FCTAB_LOCK);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "sli4_unreserve_xri:%d already freed.", xri);
                return (0);
        }

        /* Flush this unsolicited ct command */
        if (xrip->type == EMLXS_XRI_UNSOL_CT_TYPE) {
                (void) emlxs_flush_ct_event(port, xrip->rx_id);
        }

        if (!(xrip->flag & EMLXS_XRI_RESERVED)) {
                if (lock) {
                        mutex_exit(&EMLXS_FCTAB_LOCK);
                }

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "sli4_unreserve_xri:%d in use. type=%d",
                    xrip->XRI, xrip->type);
                return (1);
        }

        if (xrip->iotag &&
            (hba->fc_table[xrip->iotag] != NULL) &&
            (hba->fc_table[xrip->iotag] != STALE_PACKET)) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
                    "sli4_unreserve_xri:%d  sbp dropped:%p type=%d",
                    xrip->XRI, hba->fc_table[xrip->iotag], xrip->type);

                hba->fc_table[xrip->iotag] = NULL;
                hba->io_count--;
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "sli4_unreserve_xri:%d unreserved. type=%d",
            xrip->XRI, xrip->type);

        xrip->state = XRI_STATE_FREE;
        xrip->type = 0;

        if (xrip->rpip) {
                xrip->rpip->xri_count--;
                xrip->rpip = NULL;
        }

        if (xrip->reserved_rpip) {
                xrip->reserved_rpip->xri_count--;
                xrip->reserved_rpip = NULL;
        }

        /* Take it off inuse list */
        (xrip->_b)->_f = xrip->_f;
        (xrip->_f)->_b = xrip->_b;
        xrip->_f = NULL;
        xrip->_b = NULL;
        hba->sli.sli4.xria_count--;

        /* Add it to end of free list */
        xrip->_b = hba->sli.sli4.XRIfree_b;
        hba->sli.sli4.XRIfree_b->_f = xrip;
        xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
        hba->sli.sli4.XRIfree_b = xrip;
        hba->sli.sli4.xrif_count++;

        if (lock) {
                mutex_exit(&EMLXS_FCTAB_LOCK);
        }

        return (0);

} /* emlxs_sli4_unreserve_xri() */


XRIobj_t *
emlxs_sli4_register_xri(emlxs_port_t *port, emlxs_buf_t *sbp, uint16_t xri,
    uint32_t did)
{
        emlxs_hba_t *hba = HBA;
        uint16_t        iotag;
        XRIobj_t        *xrip;
        emlxs_node_t    *node;
        RPIobj_t        *rpip;

        mutex_enter(&EMLXS_FCTAB_LOCK);

        xrip = sbp->xrip;
        if (!xrip) {
                xrip = emlxs_sli4_find_xri(port, xri);

                if (!xrip) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                            "sli4_register_xri:%d XRI not found.", xri);

                        mutex_exit(&EMLXS_FCTAB_LOCK);
                        return (NULL);
                }
        }

        if ((xrip->state == XRI_STATE_FREE) ||
            !(xrip->flag & EMLXS_XRI_RESERVED)) {

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "sli4_register_xri:%d Invalid XRI. xrip=%p "
                    "state=%x flag=%x",
                    xrip->XRI, xrip, xrip->state, xrip->flag);

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return (NULL);
        }

        iotag = xrip->iotag;

        if ((!iotag) ||
            ((hba->fc_table[iotag] != NULL) &&
            (hba->fc_table[iotag] != STALE_PACKET))) {

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "sli4_register_xri:%d Invalid fc_table entry. "
                    "iotag=%d entry=%p",
                    xrip->XRI, iotag, hba->fc_table[iotag]);

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return (NULL);
        }

        hba->fc_table[iotag] = sbp;
        hba->io_count++;

        sbp->iotag = iotag;
        sbp->xrip = xrip;

        xrip->flag &= ~EMLXS_XRI_RESERVED;
        xrip->sbp = sbp;

        /* If we did not have a registered RPI when we reserved */
        /* this exchange, check again now. */
        if (xrip->rpip && (xrip->rpip->RPI == FABRIC_RPI)) {
                node = emlxs_node_find_did(port, did, 1);
                rpip = EMLXS_NODE_TO_RPI(port, node);

                if (rpip && (rpip->RPI != FABRIC_RPI)) {
                        /* Move the XRI to the new RPI */
                        xrip->rpip->xri_count--;
                        xrip->rpip = rpip;
                        rpip->xri_count++;
                }
        }

        mutex_exit(&EMLXS_FCTAB_LOCK);

        return (xrip);

} /* emlxs_sli4_register_xri() */


/* Performs both reserve and register functions for XRI */
static XRIobj_t *
emlxs_sli4_alloc_xri(emlxs_port_t *port, emlxs_buf_t *sbp, RPIobj_t *rpip,
    uint32_t type)
{
        emlxs_hba_t *hba = HBA;
        XRIobj_t        *xrip;
        uint16_t        iotag;

        mutex_enter(&EMLXS_FCTAB_LOCK);

        xrip = hba->sli.sli4.XRIfree_f;

        if (xrip == (XRIobj_t *)&hba->sli.sli4.XRIfree_f) {
                mutex_exit(&EMLXS_FCTAB_LOCK);

                return (NULL);
        }

        /* Get the iotag by registering the packet */
        iotag = xrip->iotag;

        if ((!iotag) ||
            ((hba->fc_table[iotag] != NULL) &&
            (hba->fc_table[iotag] != STALE_PACKET))) {
                /*
                 * No more command slots available, retry later
                 */
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg,
                    "Adapter Busy. Unable to alloc iotag:(0x%x)(%p) type=%d",
                    iotag, hba->fc_table[iotag], type);

                mutex_exit(&EMLXS_FCTAB_LOCK);
                return (NULL);
        }

        hba->fc_table[iotag] = sbp;
        hba->io_count++;

        sbp->iotag = iotag;
        sbp->xrip = xrip;

        xrip->state = XRI_STATE_ALLOCATED;
        xrip->type = type;
        xrip->flag = 0;
        xrip->sbp = sbp;

        xrip->rpip = rpip;
        rpip->xri_count++;

        /* Take it off free list */
        (xrip->_b)->_f = xrip->_f;
        (xrip->_f)->_b = xrip->_b;
        xrip->_f = NULL;
        xrip->_b = NULL;
        hba->sli.sli4.xrif_count--;

        /* Add it to end of inuse list */
        xrip->_b = hba->sli.sli4.XRIinuse_b;
        hba->sli.sli4.XRIinuse_b->_f = xrip;
        xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
        hba->sli.sli4.XRIinuse_b = xrip;
        hba->sli.sli4.xria_count++;

        mutex_exit(&EMLXS_FCTAB_LOCK);

        return (xrip);

} /* emlxs_sli4_alloc_xri() */


/* EMLXS_FCTAB_LOCK must be held to enter */
extern XRIobj_t *
emlxs_sli4_find_xri(emlxs_port_t *port, uint16_t xri)
{
        emlxs_hba_t *hba = HBA;
        XRIobj_t        *xrip;

        xrip = (XRIobj_t *)hba->sli.sli4.XRIinuse_f;
        while (xrip != (XRIobj_t *)&hba->sli.sli4.XRIinuse_f) {
                if ((xrip->state >= XRI_STATE_ALLOCATED) &&
                    (xrip->XRI == xri)) {
                        return (xrip);
                }
                xrip = xrip->_f;
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "Unable to find XRI x%x", xri);

        return (NULL);

} /* emlxs_sli4_find_xri() */




extern void
emlxs_sli4_free_xri(emlxs_port_t *port, emlxs_buf_t *sbp, XRIobj_t *xrip,
    uint8_t lock)
{
        emlxs_hba_t *hba = HBA;

        if (lock) {
                mutex_enter(&EMLXS_FCTAB_LOCK);
        }

        if (xrip) {
                if (xrip->state == XRI_STATE_FREE) {
                        if (lock) {
                                mutex_exit(&EMLXS_FCTAB_LOCK);
                        }
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Free XRI:%x, Already freed. type=%d",
                            xrip->XRI, xrip->type);
                        return;
                }

                if (xrip->type == EMLXS_XRI_UNSOL_CT_TYPE) {
                        (void) emlxs_flush_ct_event(port, xrip->rx_id);
                }

                if (xrip->iotag &&
                    (hba->fc_table[xrip->iotag] != NULL) &&
                    (hba->fc_table[xrip->iotag] != STALE_PACKET)) {
                        hba->fc_table[xrip->iotag] = NULL;
                        hba->io_count--;
                }

                xrip->state = XRI_STATE_FREE;
                xrip->type  = 0;
                xrip->flag  = 0;

                if (xrip->rpip) {
                        xrip->rpip->xri_count--;
                        xrip->rpip = NULL;
                }

                if (xrip->reserved_rpip) {
                        xrip->reserved_rpip->xri_count--;
                        xrip->reserved_rpip = NULL;
                }

                /* Take it off inuse list */
                (xrip->_b)->_f = xrip->_f;
                (xrip->_f)->_b = xrip->_b;
                xrip->_f = NULL;
                xrip->_b = NULL;
                hba->sli.sli4.xria_count--;

                /* Add it to end of free list */
                xrip->_b = hba->sli.sli4.XRIfree_b;
                hba->sli.sli4.XRIfree_b->_f = xrip;
                xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
                hba->sli.sli4.XRIfree_b = xrip;
                hba->sli.sli4.xrif_count++;
        }

        if (sbp) {
                if (!(sbp->pkt_flags & PACKET_VALID) ||
                    (sbp->pkt_flags &
                    (PACKET_ULP_OWNED|PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
                        if (lock) {
                                mutex_exit(&EMLXS_FCTAB_LOCK);
                        }
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Free XRI: sbp invalid. sbp=%p flags=%x xri=%d",
                            sbp, sbp->pkt_flags, ((xrip)? xrip->XRI:0));
                        return;
                }

                if (xrip && (xrip->iotag != sbp->iotag)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
                            "sbp/iotag mismatch %p iotag:%d %d", sbp,
                            sbp->iotag, xrip->iotag);
                }

                if (sbp->iotag) {
                        if (sbp == hba->fc_table[sbp->iotag]) {
                                hba->fc_table[sbp->iotag] = NULL;
                                hba->io_count--;

                                if (sbp->xrip) {
                                        /* Exchange is still reserved */
                                        sbp->xrip->flag |= EMLXS_XRI_RESERVED;
                                }
                        }
                        sbp->iotag = 0;
                }

                if (xrip) {
                        sbp->xrip = 0;
                }

                if (lock) {
                        mutex_exit(&EMLXS_FCTAB_LOCK);
                }

                /* Clean up the sbp */
                mutex_enter(&sbp->mtx);

                if (sbp->pkt_flags & PACKET_IN_TXQ) {
                        sbp->pkt_flags &= ~PACKET_IN_TXQ;
                        hba->channel_tx_count--;
                }

                if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
                        sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
                }

                mutex_exit(&sbp->mtx);
        } else {
                if (lock) {
                        mutex_exit(&EMLXS_FCTAB_LOCK);
                }
        }

} /* emlxs_sli4_free_xri() */


static int
emlxs_sli4_post_sgl_pages(emlxs_hba_t *hba, MAILBOXQ *mbq)
{
        MAILBOX4        *mb = (MAILBOX4 *)mbq;
        emlxs_port_t    *port = &PPORT;
        XRIobj_t        *xrip;
        MATCHMAP        *mp;
        mbox_req_hdr_t  *hdr_req;
        uint32_t        i;
        uint32_t        cnt;
        uint32_t        xri_cnt;
        uint32_t        j;
        uint32_t        size;
        IOCTL_FCOE_CFG_POST_SGL_PAGES *post_sgl;

        bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
        mbq->bp = NULL;
        mbq->mbox_cmpl = NULL;

        if ((mp = emlxs_mem_buf_alloc(hba, EMLXS_MAX_NONEMBED_SIZE)) == 0) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "Unable to POST_SGL. Mailbox cmd=%x  ",
                    mb->mbxCommand);
                return (EIO);
        }
        mbq->nonembed = (void *)mp;

        /*
         * Signifies a non embedded command
         */
        mb->un.varSLIConfig.be.embedded = 0;
        mb->mbxCommand = MBX_SLI_CONFIG;
        mb->mbxOwner = OWN_HOST;

        hdr_req = (mbox_req_hdr_t *)mp->virt;
        post_sgl =
            (IOCTL_FCOE_CFG_POST_SGL_PAGES *)(hdr_req + 1);

        xrip = hba->sli.sli4.XRIp;

        /* For each extent */
        for (j = 0; j < hba->sli.sli4.XRIExtCount; j++) {
                cnt = hba->sli.sli4.XRIExtSize;
                while (cnt) {
                        if (xrip->XRI == 0) {
                                cnt--;
                                xrip++;
                                continue;
                        }

                        bzero((void *) hdr_req, mp->size);
                        size = mp->size - IOCTL_HEADER_SZ;

                        mb->un.varSLIConfig.be.payload_length =
                            mp->size;
                        mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
                            IOCTL_SUBSYSTEM_FCOE;
                        mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
                            FCOE_OPCODE_CFG_POST_SGL_PAGES;
                        mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
                        mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length = size;

                        hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE;
                        hdr_req->opcode = FCOE_OPCODE_CFG_POST_SGL_PAGES;
                        hdr_req->timeout = 0;
                        hdr_req->req_length = size;

                        post_sgl->params.request.xri_count = 0;
                        post_sgl->params.request.xri_start = xrip->XRI;

                        xri_cnt = (size -
                            sizeof (IOCTL_FCOE_CFG_POST_SGL_PAGES)) /
                            sizeof (FCOE_SGL_PAGES);

                        for (i = 0; (i < xri_cnt) && cnt; i++) {
                                post_sgl->params.request.xri_count++;
                                post_sgl->params.request.pages[i].\
                                    sgl_page0.addrLow =
                                    PADDR_LO(xrip->SGList->phys);
                                post_sgl->params.request.pages[i].\
                                    sgl_page0.addrHigh =
                                    PADDR_HI(xrip->SGList->phys);

                                cnt--;
                                xrip++;
                        }

                        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                            MBX_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                                    "Unable to POST_SGL. Mailbox cmd=%x "
                                    "status=%x XRI cnt:%d start:%d",
                                    mb->mbxCommand, mb->mbxStatus,
                                    post_sgl->params.request.xri_count,
                                    post_sgl->params.request.xri_start);
                                emlxs_mem_buf_free(hba, mp);
                                mbq->nonembed = NULL;
                                return (EIO);
                        }
                }
        }

        emlxs_mem_buf_free(hba, mp);
        mbq->nonembed = NULL;
        return (0);

} /* emlxs_sli4_post_sgl_pages() */


static int
emlxs_sli4_post_hdr_tmplates(emlxs_hba_t *hba, MAILBOXQ *mbq)
{
        MAILBOX4        *mb = (MAILBOX4 *)mbq;
        emlxs_port_t    *port = &PPORT;
        uint32_t        j;
        uint32_t        k;
        uint64_t        addr;
        IOCTL_FCOE_POST_HDR_TEMPLATES *post_hdr;
        uint16_t        num_pages;

        if (!(hba->sli.sli4.param.HDRR)) {
                return (0);
        }

        /* Bytes per extent */
        j = hba->sli.sli4.RPIExtSize * sizeof (RPIHdrTmplate_t);

        /* Pages required per extent (page == 4096 bytes) */
        num_pages = (j/4096) + ((j%4096)? 1:0);

        addr = hba->sli.sli4.HeaderTmplate.phys;

        /* For each extent */
        for (j = 0; j < hba->sli.sli4.RPIExtCount; j++) {
                bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
                mbq->bp = NULL;
                mbq->mbox_cmpl = NULL;

                /*
                 * Signifies an embedded command
                 */
                mb->un.varSLIConfig.be.embedded = 1;

                mb->mbxCommand = MBX_SLI_CONFIG;
                mb->mbxOwner = OWN_HOST;
                mb->un.varSLIConfig.be.payload_length =
                    sizeof (IOCTL_FCOE_POST_HDR_TEMPLATES) + IOCTL_HEADER_SZ;
                mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
                    IOCTL_SUBSYSTEM_FCOE;
                mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
                    FCOE_OPCODE_POST_HDR_TEMPLATES;
                mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
                mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
                    sizeof (IOCTL_FCOE_POST_HDR_TEMPLATES);

                post_hdr =
                    (IOCTL_FCOE_POST_HDR_TEMPLATES *)
                    &mb->un.varSLIConfig.payload;
                post_hdr->params.request.num_pages = num_pages;
                post_hdr->params.request.rpi_offset = hba->sli.sli4.RPIBase[j];

                for (k = 0; k < num_pages; k++) {
                        post_hdr->params.request.pages[k].addrLow =
                            PADDR_LO(addr);
                        post_hdr->params.request.pages[k].addrHigh =
                            PADDR_HI(addr);
                        addr += 4096;
                }

                if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                    MBX_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "Unable to POST_HDR_TEMPLATES. Mailbox cmd=%x "
                            "status=%x ",
                            mb->mbxCommand, mb->mbxStatus);
                        return (EIO);
                }
                emlxs_data_dump(port, "POST_HDR", (uint32_t *)mb, 18, 0);
        }

        return (0);

} /* emlxs_sli4_post_hdr_tmplates() */


static int
emlxs_sli4_create_queues(emlxs_hba_t *hba, MAILBOXQ *mbq)
{
        MAILBOX4        *mb = (MAILBOX4 *)mbq;
        emlxs_port_t    *port = &PPORT;
        emlxs_config_t  *cfg = &CFG;
        IOCTL_COMMON_EQ_CREATE *eq;
        IOCTL_COMMON_CQ_CREATE *cq;
        IOCTL_FCOE_WQ_CREATE *wq;
        IOCTL_FCOE_RQ_CREATE *rq;
        IOCTL_COMMON_MQ_CREATE *mq;
        IOCTL_COMMON_MQ_CREATE_EXT *mq_ext;
        uint16_t i, j;
        uint16_t num_cq, total_cq;
        uint16_t num_wq, total_wq;

        /*
         * The first CQ is reserved for ASYNC events,
         * the second is reserved for unsol rcv, the rest
         * correspond to WQs. (WQ0 -> CQ2, WQ1 -> CQ3, ...)
         */

        total_cq = 0;
        total_wq = 0;

        /* Create EQ's */
        for (i = 0; i < hba->intr_count; i++) {
                emlxs_mb_eq_create(hba, mbq, i);
                if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                    MBX_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to Create EQ %d: Mailbox cmd=%x status=%x ",
                            i, mb->mbxCommand, mb->mbxStatus);
                        return (EIO);
                }
                eq = (IOCTL_COMMON_EQ_CREATE *)&mb->un.varSLIConfig.payload;
                hba->sli.sli4.eq[i].qid = eq->params.response.EQId;
                hba->sli.sli4.eq[i].lastwq = total_wq;
                hba->sli.sli4.eq[i].msix_vector = i;

                emlxs_data_dump(port, "EQ0_CREATE", (uint32_t *)mb, 18, 0);
                num_wq = cfg[CFG_NUM_WQ].current;
                num_cq = num_wq;
                if (i == 0) {
                        /* One for RQ handling, one for mbox/event handling */
                        num_cq += EMLXS_CQ_OFFSET_WQ;
                }

                /* Create CQ's */
                for (j = 0; j < num_cq; j++) {
                        /* Reuse mbq from previous mbox */
                        bzero(mbq, sizeof (MAILBOXQ));

                        hba->sli.sli4.cq[total_cq].eqid =
                            hba->sli.sli4.eq[i].qid;

                        emlxs_mb_cq_create(hba, mbq, total_cq);
                        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                            MBX_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_init_failed_msg, "Unable to Create "
                                    "CQ %d: hba=%p Mailbox cmd=%x status=%x ",
                                    total_cq, hba, mb->mbxCommand,
                                    mb->mbxStatus);
                                return (EIO);
                        }
                        cq = (IOCTL_COMMON_CQ_CREATE *)
                            &mb->un.varSLIConfig.payload;
                        hba->sli.sli4.cq[total_cq].qid =
                            cq->params.response.CQId;

                        switch (total_cq) {
                        case EMLXS_CQ_MBOX:
                                /* First CQ is for async event handling */
                                hba->sli.sli4.cq[total_cq].type =
                                    EMLXS_CQ_TYPE_GROUP1;
                                break;

                        case EMLXS_CQ_RCV:
                                /* Second CQ is for unsol receive handling */
                                hba->sli.sli4.cq[total_cq].type =
                                    EMLXS_CQ_TYPE_GROUP2;
                                break;

                        default:
                                /* Setup CQ to channel mapping */
                                hba->sli.sli4.cq[total_cq].type =
                                    EMLXS_CQ_TYPE_GROUP2;
                                hba->sli.sli4.cq[total_cq].channelp =
                                    &hba->chan[total_cq - EMLXS_CQ_OFFSET_WQ];
                                break;
                        }
                        hba->sli.sli4.cq[total_cq].qe_valid = 1;
                        emlxs_data_dump(port, "CQX_CREATE", (uint32_t *)mb,
                            18, 0);
                        total_cq++;
                }

                /* Create WQ's */
                for (j = 0; j < num_wq; j++) {
                        /* Reuse mbq from previous mbox */
                        bzero(mbq, sizeof (MAILBOXQ));

                        hba->sli.sli4.wq[total_wq].cqid =
                            hba->sli.sli4.cq[total_wq + EMLXS_CQ_OFFSET_WQ].qid;

                        emlxs_mb_wq_create(hba, mbq, total_wq);
                        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                            MBX_SUCCESS) {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_init_failed_msg, "Unable to Create "
                                    "WQ %d: Mailbox cmd=%x status=%x ",
                                    total_wq, mb->mbxCommand, mb->mbxStatus);
                                return (EIO);
                        }
                        wq = (IOCTL_FCOE_WQ_CREATE *)
                            &mb->un.varSLIConfig.payload;
                        hba->sli.sli4.wq[total_wq].qid =
                            wq->params.response.WQId;

                        hba->sli.sli4.wq[total_wq].cqid =
                            hba->sli.sli4.cq[total_wq+EMLXS_CQ_OFFSET_WQ].qid;
                        emlxs_data_dump(port, "WQ_CREATE", (uint32_t *)mb,
                            18, 0);
                        total_wq++;
                }
                hba->last_msiid = i;
        }

        /* 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:
                        hba->sli.sli4.rq[i].cqid =
                            hba->sli.sli4.cq[EMLXS_CQ_RCV].qid;
                        break;
                case 1:
                        hba->sli.sli4.rq[i].cqid =
                            hba->sli.sli4.cq[EMLXS_CQ_RCV].qid;
                        break;
                default:
                        hba->sli.sli4.rq[i].cqid = 0xffff;
                }

                /* Reuse mbq from previous mbox */
                bzero(mbq, sizeof (MAILBOXQ));

                emlxs_mb_rq_create(hba, mbq, i);
                if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                    MBX_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to Create RQ %d: Mailbox cmd=%x status=%x ",
                            i, mb->mbxCommand, mb->mbxStatus);
                        return (EIO);
                }

                rq = (IOCTL_FCOE_RQ_CREATE *)&mb->un.varSLIConfig.payload;
                hba->sli.sli4.rq[i].qid = rq->params.response.RQId;
                emlxs_data_dump(port, "RQ CREATE", (uint32_t *)mb, 18, 0);

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "RQ CREATE: rq[%d].qid=%d cqid=%d",
                    i, hba->sli.sli4.rq[i].qid, hba->sli.sli4.rq[i].cqid);

                /* Initialize the host_index */
                hba->sli.sli4.rq[i].host_index = 0;

                /* If Data queue was just created, */
                /* then post buffers using the header qid */
                if ((i & 0x1)) {
                        /* Ring the RQ doorbell to post buffers */

                        emlxs_sli4_write_rqdb(hba, hba->sli.sli4.rq[i-1].qid,
                            RQB_COUNT);

                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                            "RQ CREATE: Doorbell rang: qid=%d count=%d",
                            hba->sli.sli4.rq[i-1].qid, RQB_COUNT);
                }
        }

        /* Create MQ */

        /* Personalize the MQ */
        hba->sli.sli4.mq.cqid = hba->sli.sli4.cq[EMLXS_CQ_MBOX].qid;

        /* Reuse mbq from previous mbox */
        bzero(mbq, sizeof (MAILBOXQ));

        emlxs_mb_mq_create_ext(hba, mbq);
        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
            MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to Create MQ_EXT %d: Mailbox cmd=%x status=%x ",
                    i, mb->mbxCommand, mb->mbxStatus);

                /* Reuse mbq from previous mbox */
                bzero(mbq, sizeof (MAILBOXQ));

                emlxs_mb_mq_create(hba, mbq);
                if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) !=
                    MBX_SUCCESS) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                            "Unable to Create MQ %d: Mailbox cmd=%x status=%x ",
                            i, mb->mbxCommand, mb->mbxStatus);
                        return (EIO);
                }

                mq = (IOCTL_COMMON_MQ_CREATE *)&mb->un.varSLIConfig.payload;
                hba->sli.sli4.mq.qid = mq->params.response.MQId;
                return (0);
        }

        mq_ext = (IOCTL_COMMON_MQ_CREATE_EXT *)&mb->un.varSLIConfig.payload;
        hba->sli.sli4.mq.qid = mq_ext->params.response.MQId;
        return (0);

} /* emlxs_sli4_create_queues() */


extern void
emlxs_sli4_timer(emlxs_hba_t *hba)
{
        /* Perform SLI4 level timer checks */

        emlxs_fcf_timer_notify(hba);

        emlxs_sli4_timer_check_mbox(hba);

        return;

} /* emlxs_sli4_timer() */


static void
emlxs_sli4_timer_check_mbox(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        emlxs_config_t *cfg = &CFG;
        MAILBOX *mb = NULL;

        if (!cfg[CFG_TIMEOUT_ENABLE].current) {
                return;
        }

        mutex_enter(&EMLXS_PORT_LOCK);

        /* Return if timer hasn't expired */
        if (!hba->mbox_timer || (hba->timer_tics < hba->mbox_timer)) {
                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        /* The first to service the mbox queue will clear the timer */
        hba->mbox_timer = 0;

        if (hba->mbox_queue_flag) {
                if (hba->mbox_mbq) {
                        mb = (MAILBOX *)hba->mbox_mbq;
                }
        }

        if (mb) {
                switch (hba->mbox_queue_flag) {
                case MBX_NOWAIT:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_timeout_msg,
                            "%s: Nowait.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand));
                        break;

                case MBX_SLEEP:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_timeout_msg,
                            "%s: mb=%p Sleep.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand),
                            mb);
                        break;

                case MBX_POLL:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_timeout_msg,
                            "%s: mb=%p Polled.",
                            emlxs_mb_cmd_xlate(mb->mbxCommand),
                            mb);
                        break;

                default:
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_timeout_msg,
                            "%s: mb=%p (%d).",
                            emlxs_mb_cmd_xlate(mb->mbxCommand),
                            mb, hba->mbox_queue_flag);
                        break;
                }
        } else {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_timeout_msg, NULL);
        }

        hba->flag |= FC_MBOX_TIMEOUT;
        EMLXS_STATE_CHANGE_LOCKED(hba, FC_ERROR);

        mutex_exit(&EMLXS_PORT_LOCK);

        /* Perform mailbox cleanup */
        /* This will wake any sleeping or polling threads */
        emlxs_mb_fini(hba, NULL, MBX_TIMEOUT);

        /* Trigger adapter shutdown */
        emlxs_thread_spawn(hba, emlxs_shutdown_thread, 0, 0);

        return;

} /* emlxs_sli4_timer_check_mbox() */

static void
emlxs_sli4_gpio_timer_start(emlxs_hba_t *hba)
{
        mutex_enter(&hba->gpio_lock);

        if (!hba->gpio_timer) {
                hba->gpio_timer = timeout(emlxs_sli4_gpio_timer, (void *)hba,
                    drv_usectohz(100000));
        }

        mutex_exit(&hba->gpio_lock);

} /* emlxs_sli4_gpio_timer_start() */

static void
emlxs_sli4_gpio_timer_stop(emlxs_hba_t *hba)
{
        mutex_enter(&hba->gpio_lock);

        if (hba->gpio_timer) {
                (void) untimeout(hba->gpio_timer);
                hba->gpio_timer = 0;
        }

        mutex_exit(&hba->gpio_lock);

        delay(drv_usectohz(300000));
} /* emlxs_sli4_gpio_timer_stop() */

static void
emlxs_sli4_gpio_timer(void *arg)
{
        emlxs_hba_t *hba = (emlxs_hba_t *)arg;

        mutex_enter(&hba->gpio_lock);

        if (hba->gpio_timer) {
                emlxs_sli4_check_gpio(hba);
                hba->gpio_timer = timeout(emlxs_sli4_gpio_timer, (void *)hba,
                    drv_usectohz(100000));
        }

        mutex_exit(&hba->gpio_lock);
} /* emlxs_sli4_gpio_timer() */

static void
emlxs_sli4_check_gpio(emlxs_hba_t *hba)
{
        hba->gpio_desired = 0;

        if (hba->flag & FC_GPIO_LINK_UP) {
                if (hba->io_active)
                        hba->gpio_desired |= EMLXS_GPIO_ACT;

                /* This is model specific to ATTO gen5 lancer cards */

                switch (hba->linkspeed) {
                        case LA_4GHZ_LINK:
                                hba->gpio_desired |= EMLXS_GPIO_LO;
                                break;

                        case LA_8GHZ_LINK:
                                hba->gpio_desired |= EMLXS_GPIO_HI;
                                break;

                        case LA_16GHZ_LINK:
                                hba->gpio_desired |=
                                    EMLXS_GPIO_LO | EMLXS_GPIO_HI;
                                break;
                }
        }

        if (hba->gpio_current != hba->gpio_desired) {
                emlxs_port_t *port = &PPORT;
                uint8_t pin;
                uint8_t pinval;
                MAILBOXQ *mbq;
                uint32_t rval;

                if (!emlxs_sli4_fix_gpio(hba, &pin, &pinval))
                        return;

                if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == NULL) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                            "Unable to allocate GPIO mailbox.");

                        hba->gpio_bit = 0;
                        return;
                }

                emlxs_mb_gpio_write(hba, mbq, pin, pinval);
                mbq->mbox_cmpl = emlxs_sli4_fix_gpio_mbcmpl;

                rval = emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);

                if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                            "Unable to start GPIO mailbox.");

                        hba->gpio_bit = 0;
                        emlxs_mem_put(hba, MEM_MBOX, mbq);
                        return;
                }
        }
} /* emlxs_sli4_check_gpio */

static uint32_t
emlxs_sli4_fix_gpio(emlxs_hba_t *hba, uint8_t *pin, uint8_t *pinval)
{
        uint8_t dif = hba->gpio_desired ^ hba->gpio_current;
        uint8_t bit;
        uint8_t i;

        /* Get out if no pins to set a GPIO request is pending */

        if (dif == 0 || hba->gpio_bit)
                return (0);

        /* Fix one pin at a time */

        bit = dif & -dif;
        hba->gpio_bit = bit;
        dif = hba->gpio_current ^ bit;

        for (i = EMLXS_GPIO_PIN_LO; bit > 1; ++i) {
                dif >>= 1;
                bit >>= 1;
        }

        /* Pins are active low so invert the bit value */

        *pin = hba->gpio_pin[i];
        *pinval = ~dif & bit;

        return (1);
} /* emlxs_sli4_fix_gpio */

static uint32_t
emlxs_sli4_fix_gpio_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq)
{
        MAILBOX *mb;
        uint8_t pin;
        uint8_t pinval;

        mb = (MAILBOX *)mbq;

        mutex_enter(&hba->gpio_lock);

        if (mb->mbxStatus == 0)
                hba->gpio_current ^= hba->gpio_bit;

        hba->gpio_bit = 0;

        if (emlxs_sli4_fix_gpio(hba, &pin, &pinval)) {
                emlxs_port_t *port = &PPORT;
                MAILBOXQ *mbq;
                uint32_t rval;

                /*
                 * We're not using the mb_retry routine here because for some
                 * reason it doesn't preserve the completion routine. Just let
                 * this mbox cmd fail to start here and run when the mailbox
                 * is no longer busy.
                 */

                if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == NULL) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                            "Unable to allocate GPIO mailbox.");

                        hba->gpio_bit = 0;
                        goto done;
                }

                emlxs_mb_gpio_write(hba, mbq, pin, pinval);
                mbq->mbox_cmpl = emlxs_sli4_fix_gpio_mbcmpl;

                rval = emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);

                if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                            "Unable to start GPIO mailbox.");

                        hba->gpio_bit = 0;
                        emlxs_mem_put(hba, MEM_MBOX, mbq);
                        goto done;
                }
        }

done:
        mutex_exit(&hba->gpio_lock);

        return (0);
}

extern void
emlxs_data_dump(emlxs_port_t *port, char *str, uint32_t *iptr, int cnt, int err)
{
        void *msg;

        if (!port || !str || !iptr || !cnt) {
                return;
        }

        if (err) {
                msg = &emlxs_sli_err_msg;
        } else {
                msg = &emlxs_sli_detail_msg;
        }

        if (cnt) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s00: %08x %08x %08x %08x %08x %08x", str, *iptr,
                    *(iptr+1), *(iptr+2), *(iptr+3), *(iptr+4), *(iptr+5));
        }
        if (cnt > 6) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s06: %08x %08x %08x %08x %08x %08x", str, *(iptr+6),
                    *(iptr+7), *(iptr+8), *(iptr+9), *(iptr+10), *(iptr+11));
        }
        if (cnt > 12) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s12: %08x %08x %08x %08x %08x %08x", str, *(iptr+12),
                    *(iptr+13), *(iptr+14), *(iptr+15), *(iptr+16), *(iptr+17));
        }
        if (cnt > 18) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s18: %08x %08x %08x %08x %08x %08x", str, *(iptr+18),
                    *(iptr+19), *(iptr+20), *(iptr+21), *(iptr+22), *(iptr+23));
        }
        if (cnt > 24) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s24: %08x %08x %08x %08x %08x %08x", str, *(iptr+24),
                    *(iptr+25), *(iptr+26), *(iptr+27), *(iptr+28), *(iptr+29));
        }
        if (cnt > 30) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s30: %08x %08x %08x %08x %08x %08x", str, *(iptr+30),
                    *(iptr+31), *(iptr+32), *(iptr+33), *(iptr+34), *(iptr+35));
        }
        if (cnt > 36) {
                EMLXS_MSGF(EMLXS_CONTEXT, msg,
                    "%s36: %08x %08x %08x %08x %08x %08x", str, *(iptr+36),
                    *(iptr+37), *(iptr+38), *(iptr+39), *(iptr+40), *(iptr+41));
        }

} /* emlxs_data_dump() */


extern void
emlxs_ue_dump(emlxs_hba_t *hba, char *str)
{
        emlxs_port_t *port = &PPORT;
        uint32_t status;
        uint32_t ue_h;
        uint32_t ue_l;
        uint32_t on1;
        uint32_t on2;

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ue_l = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                ue_h = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);

                on1 = ddi_get32(hba->pci_acc_handle,
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_STATUS_ONLINE1));
                on2 = ddi_get32(hba->pci_acc_handle,
                    (uint32_t *)(hba->pci_addr + PCICFG_UE_STATUS_ONLINE2));

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "%s: ueLow:%08x ueHigh:%08x on1:%08x on2:%08x", str,
                    ue_l, ue_h, on1, on2);
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                status = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.STATUS_reg_addr);

                ue_l = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                ue_h = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);

                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "%s: status:%08x err1:%08x err2:%08x", str,
                    status, ue_l, ue_h);

                break;
        }

#ifdef FMA_SUPPORT
        /* Access handle validation */
        EMLXS_CHK_ACC_HANDLE(hba, hba->pci_acc_handle);
#endif  /* FMA_SUPPORT */

} /* emlxs_ue_dump() */


static void
emlxs_sli4_poll_erratt(emlxs_hba_t *hba)
{
        emlxs_port_t *port = &PPORT;
        uint32_t status;
        uint32_t ue_h;
        uint32_t ue_l;
        uint32_t error = 0;

        if (hba->flag & FC_HARDWARE_ERROR) {
                return;
        }

        switch (hba->sli_intf & SLI_INTF_IF_TYPE_MASK) {
        case SLI_INTF_IF_TYPE_0:
                ue_l = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR1_reg_addr);
                ue_h = ddi_get32(hba->pci_acc_handle,
                    hba->sli.sli4.ERR2_reg_addr);

                if ((~hba->sli.sli4.ue_mask_lo & ue_l) ||
                    (~hba->sli.sli4.ue_mask_hi & ue_h) ||
                    (hba->sli.sli4.flag & EMLXS_SLI4_HW_ERROR)) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_hardware_error_msg,
                            "Host Error: ueLow:%08x ueHigh:%08x maskLow:%08x "
                            "maskHigh:%08x flag:%08x",
                            ue_l, ue_h, hba->sli.sli4.ue_mask_lo,
                            hba->sli.sli4.ue_mask_hi, hba->sli.sli4.flag);

                        error = 2;
                }
                break;

        case SLI_INTF_IF_TYPE_2:
        case SLI_INTF_IF_TYPE_6:
                status = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                    hba->sli.sli4.STATUS_reg_addr);

                if ((status & SLI_STATUS_ERROR) ||
                    (hba->sli.sli4.flag & EMLXS_SLI4_HW_ERROR)) {
                        ue_l = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                            hba->sli.sli4.ERR1_reg_addr);
                        ue_h = ddi_get32(hba->sli.sli4.bar0_acc_handle,
                            hba->sli.sli4.ERR2_reg_addr);

                        error = (status & SLI_STATUS_RESET_NEEDED)? 1:2;

                        if (error == 1) {
                                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
                                    "Host Error: status:%08x err1:%08x "
                                    "err2:%08x flag:%08x reset",
                                    status, ue_l, ue_h, hba->sli.sli4.flag);
                        } else {
                                EMLXS_MSGF(EMLXS_CONTEXT,
                                    &emlxs_hardware_error_msg,
                                    "Host Error: status:%08x err1:%08x "
                                    "err2:%08x flag:%08x shutdown",
                                    status, ue_l, ue_h, hba->sli.sli4.flag);
                        }
                }
                break;
        }

        if (error == 2) {
                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                emlxs_sli4_hba_flush_chipq(hba);

                emlxs_thread_spawn(hba, emlxs_shutdown_thread, 0, 0);

        } else if (error == 1) {
                EMLXS_STATE_CHANGE(hba, FC_ERROR);

                emlxs_sli4_hba_flush_chipq(hba);

                emlxs_thread_spawn(hba, emlxs_restart_thread, 0, 0);
        }

#ifdef FMA_SUPPORT
        /* Access handle validation */
        EMLXS_CHK_ACC_HANDLE(hba, hba->pci_acc_handle);
#endif  /* FMA_SUPPORT */

} /* emlxs_sli4_poll_erratt() */


static uint32_t
emlxs_sli4_reg_did(emlxs_port_t *port, uint32_t did, SERV_PARM *param,
    emlxs_buf_t *sbp, fc_unsol_buf_t *ubp, IOCBQ *iocbq)
{
        emlxs_hba_t     *hba = HBA;
        NODELIST        *node;
        RPIobj_t        *rpip;
        uint32_t        rval;

        /* Check for invalid node ids to register */
        if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) {
                return (1);
        }

        if (did & 0xff000000) {
                return (1);
        }

        /* We don't register our own did */
        if ((did == port->did) && (!(hba->flag & FC_LOOPBACK_MODE))) {
                return (1);
        }

        if (did != FABRIC_DID) {
                if ((rval = emlxs_mb_check_sparm(hba, param))) {
                        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
                            "Invalid service parameters. did=%06x rval=%d", did,
                            rval);

                        return (1);
                }
        }

        /* Check if the node limit has been reached */
        if (port->node_count >= hba->max_nodes) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
                    "Limit reached. did=%06x count=%d", did,
                    port->node_count);

                return (1);
        }

        node = emlxs_node_find_did(port, did, 1);
        rpip = EMLXS_NODE_TO_RPI(port, node);

        rval = emlxs_rpi_online_notify(port, rpip, did, param, (void *)sbp,
            (void *)ubp, (void *)iocbq);

        return (rval);

} /* emlxs_sli4_reg_did() */


static uint32_t
emlxs_sli4_unreg_node(emlxs_port_t *port, emlxs_node_t *node,
    emlxs_buf_t *sbp, fc_unsol_buf_t *ubp, IOCBQ *iocbq)
{
        RPIobj_t        *rpip;
        uint32_t        rval;

        if (!node) {
                /* Unreg all nodes */
                (void) emlxs_sli4_unreg_all_nodes(port);
                return (1);
        }

        /* Check for base node */
        if (node == &port->node_base) {
                /* Just flush base node */
                (void) emlxs_tx_node_flush(port, &port->node_base,
                    0, 0, 0);

                (void) emlxs_chipq_node_flush(port, 0,
                    &port->node_base, 0);

                port->did = 0;

                /* Return now */
                return (1);
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
            "unreg_node:%p did=%x rpi=%d",
            node, node->nlp_DID, node->nlp_Rpi);

        rpip = EMLXS_NODE_TO_RPI(port, node);

        if (!rpip) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "unreg_node:%p did=%x rpi=%d. RPI not found.",
                    node, node->nlp_DID, node->nlp_Rpi);

                emlxs_node_rm(port, node);
                return (1);
        }

        rval = emlxs_rpi_offline_notify(port, rpip, (void *)sbp, (void *)ubp,
            (void *)iocbq);

        return (rval);

} /* emlxs_sli4_unreg_node() */


extern uint32_t
emlxs_sli4_unreg_all_nodes(emlxs_port_t *port)
{
        NODELIST        *nlp;
        int             i;
        uint32_t        found;

        /* Set the node tags */
        /* We will process all nodes with this tag */
        rw_enter(&port->node_rwlock, RW_READER);
        found = 0;
        for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
                nlp = port->node_table[i];
                while (nlp != NULL) {
                        found = 1;
                        nlp->nlp_tag = 1;
                        nlp = nlp->nlp_list_next;
                }
        }
        rw_exit(&port->node_rwlock);

        if (!found) {
                return (0);
        }

        for (;;) {
                rw_enter(&port->node_rwlock, RW_READER);
                found = 0;
                for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
                        nlp = port->node_table[i];
                        while (nlp != NULL) {
                                if (!nlp->nlp_tag) {
                                        nlp = nlp->nlp_list_next;
                                        continue;
                                }
                                nlp->nlp_tag = 0;
                                found = 1;
                                break;
                        }

                        if (found) {
                                break;
                        }
                }
                rw_exit(&port->node_rwlock);

                if (!found) {
                        break;
                }

                (void) emlxs_sli4_unreg_node(port, nlp, 0, 0, 0);
        }

        return (0);

} /* emlxs_sli4_unreg_all_nodes() */


static void
emlxs_sli4_handle_fcoe_link_event(emlxs_hba_t *hba, CQE_ASYNC_t *cqe)
{
        emlxs_port_t *port = &PPORT;

        /* Handle link down */
        if ((cqe->un.link.link_status == ASYNC_EVENT_LOGICAL_LINK_DOWN) ||
            (cqe->un.link.link_status == ASYNC_EVENT_PHYS_LINK_DOWN)) {
                (void) emlxs_fcf_linkdown_notify(port);

                mutex_enter(&EMLXS_PORT_LOCK);
                hba->sli.sli4.flag &= ~EMLXS_SLI4_DOWN_LINK;
                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        /* Link is up */

        /* Set linkspeed */
        switch (cqe->un.link.port_speed) {
        case PHY_1GHZ_LINK:
                hba->linkspeed = LA_1GHZ_LINK;
                break;
        case PHY_10GHZ_LINK:
                hba->linkspeed = LA_10GHZ_LINK;
                break;
        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "sli4_handle_fcoe_link_event: Unknown link speed=%x.",
                    cqe->un.link.port_speed);
                hba->linkspeed = 0;
                break;
        }

        /* Set qos_linkspeed */
        hba->qos_linkspeed = cqe->un.link.qos_link_speed;

        /* Set topology */
        hba->topology = TOPOLOGY_PT_PT;

        mutex_enter(&EMLXS_PORT_LOCK);
        hba->sli.sli4.flag &= ~EMLXS_SLI4_DOWN_LINK;
        mutex_exit(&EMLXS_PORT_LOCK);

        (void) emlxs_fcf_linkup_notify(port);

        return;

} /* emlxs_sli4_handle_fcoe_link_event()  */


static void
emlxs_sli4_handle_fc_link_att(emlxs_hba_t *hba, CQE_ASYNC_t *cqe)
{
        emlxs_port_t *port = &PPORT;

        /* Handle link down */
        if (cqe->un.fc.att_type == ATT_TYPE_LINK_DOWN) {
                (void) emlxs_fcf_linkdown_notify(port);

                mutex_enter(&EMLXS_PORT_LOCK);
                hba->sli.sli4.flag &= ~EMLXS_SLI4_DOWN_LINK;
                mutex_exit(&EMLXS_PORT_LOCK);
                return;
        }

        /* Link is up */

        /* Set linkspeed */
        switch (cqe->un.fc.port_speed) {
        case 1:
                hba->linkspeed = LA_1GHZ_LINK;
                break;
        case 2:
                hba->linkspeed = LA_2GHZ_LINK;
                break;
        case 4:
                hba->linkspeed = LA_4GHZ_LINK;
                break;
        case 8:
                hba->linkspeed = LA_8GHZ_LINK;
                break;
        case 10:
                hba->linkspeed = LA_10GHZ_LINK;
                break;
        case 16:
                hba->linkspeed = LA_16GHZ_LINK;
                break;
        case 32:
                hba->linkspeed = LA_32GHZ_LINK;
                break;
        default:
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
                    "sli4_handle_fc_link_att: Unknown link speed=%x.",
                    cqe->un.fc.port_speed);
                hba->linkspeed = 0;
                break;
        }

        /* Set qos_linkspeed */
        hba->qos_linkspeed = cqe->un.fc.link_speed;

        /* Set topology */
        hba->topology = cqe->un.fc.topology;

        mutex_enter(&EMLXS_PORT_LOCK);
        hba->sli.sli4.flag &= ~EMLXS_SLI4_DOWN_LINK;
        mutex_exit(&EMLXS_PORT_LOCK);

        (void) emlxs_fcf_linkup_notify(port);

        return;

} /* emlxs_sli4_handle_fc_link_att() */


static int
emlxs_sli4_init_extents(emlxs_hba_t *hba, MAILBOXQ *mbq)
{
        emlxs_port_t *port = &PPORT;
        MAILBOX4 *mb4;
        IOCTL_COMMON_EXTENTS *ep;
        uint32_t i;
        uint32_t ExtentCnt;

        if (!(hba->sli.sli4.param.EXT)) {
                return (0);
        }

        mb4 = (MAILBOX4 *) mbq;

        /* Discover XRI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_get_extents_info(hba, mbq, RSC_TYPE_FCOE_XRI);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to discover XRI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }

        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;
        hba->sli.sli4.XRIExtSize = ep->params.response.ExtentSize;
        ExtentCnt = ep->params.response.ExtentCnt;

        /* Allocate XRI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_alloc_extents(hba, mbq, RSC_TYPE_FCOE_XRI, ExtentCnt);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate XRI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }
        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;

        bcopy((uint8_t *)ep->params.response.RscId,
            (uint8_t *)hba->sli.sli4.XRIBase,
            (ep->params.response.ExtentCnt * sizeof (uint16_t)));

        hba->sli.sli4.XRIExtCount = ep->params.response.ExtentCnt;
        hba->sli.sli4.XRICount = hba->sli.sli4.XRIExtCount *
            hba->sli.sli4.XRIExtSize;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "XRI Ext: size=%d cnt=%d/%d",
            hba->sli.sli4.XRIExtSize,
            hba->sli.sli4.XRIExtCount, ExtentCnt);

        for (i = 0; i < ep->params.response.ExtentCnt; i += 4) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "XRI Ext%d: %d, %d, %d, %d", i,
                    hba->sli.sli4.XRIBase[i],
                    hba->sli.sli4.XRIBase[i+1],
                    hba->sli.sli4.XRIBase[i+2],
                    hba->sli.sli4.XRIBase[i+3]);
        }


        /* Discover RPI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_get_extents_info(hba, mbq, RSC_TYPE_FCOE_RPI);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to discover RPI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }

        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;
        hba->sli.sli4.RPIExtSize = ep->params.response.ExtentSize;
        ExtentCnt = ep->params.response.ExtentCnt;

        /* Allocate RPI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_alloc_extents(hba, mbq, RSC_TYPE_FCOE_RPI, ExtentCnt);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate RPI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }
        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;

        bcopy((uint8_t *)ep->params.response.RscId,
            (uint8_t *)hba->sli.sli4.RPIBase,
            (ep->params.response.ExtentCnt * sizeof (uint16_t)));

        hba->sli.sli4.RPIExtCount = ep->params.response.ExtentCnt;
        hba->sli.sli4.RPICount = hba->sli.sli4.RPIExtCount *
            hba->sli.sli4.RPIExtSize;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "RPI Ext: size=%d cnt=%d/%d",
            hba->sli.sli4.RPIExtSize,
            hba->sli.sli4.RPIExtCount, ExtentCnt);

        for (i = 0; i < ep->params.response.ExtentCnt; i += 4) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "RPI Ext%d: %d, %d, %d, %d", i,
                    hba->sli.sli4.RPIBase[i],
                    hba->sli.sli4.RPIBase[i+1],
                    hba->sli.sli4.RPIBase[i+2],
                    hba->sli.sli4.RPIBase[i+3]);
        }


        /* Discover VPI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_get_extents_info(hba, mbq, RSC_TYPE_FCOE_VPI);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to discover VPI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }

        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;
        hba->sli.sli4.VPIExtSize = ep->params.response.ExtentSize;
        ExtentCnt = ep->params.response.ExtentCnt;

        /* Allocate VPI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_alloc_extents(hba, mbq, RSC_TYPE_FCOE_VPI, ExtentCnt);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate VPI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }
        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;

        bcopy((uint8_t *)ep->params.response.RscId,
            (uint8_t *)hba->sli.sli4.VPIBase,
            (ep->params.response.ExtentCnt * sizeof (uint16_t)));

        hba->sli.sli4.VPIExtCount = ep->params.response.ExtentCnt;
        hba->sli.sli4.VPICount = hba->sli.sli4.VPIExtCount *
            hba->sli.sli4.VPIExtSize;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "VPI Ext: size=%d cnt=%d/%d",
            hba->sli.sli4.VPIExtSize,
            hba->sli.sli4.VPIExtCount, ExtentCnt);

        for (i = 0; i < ep->params.response.ExtentCnt; i += 4) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "VPI Ext%d: %d, %d, %d, %d", i,
                    hba->sli.sli4.VPIBase[i],
                    hba->sli.sli4.VPIBase[i+1],
                    hba->sli.sli4.VPIBase[i+2],
                    hba->sli.sli4.VPIBase[i+3]);
        }

        /* Discover VFI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_get_extents_info(hba, mbq, RSC_TYPE_FCOE_VFI);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to discover VFI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }

        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;
        hba->sli.sli4.VFIExtSize = ep->params.response.ExtentSize;
        ExtentCnt = ep->params.response.ExtentCnt;

        /* Allocate VFI Extents */
        bzero(mbq, sizeof (MAILBOXQ));
        emlxs_mb_alloc_extents(hba, mbq, RSC_TYPE_FCOE_VFI, ExtentCnt);

        if (emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
                    "Unable to allocate VFI extents.  Mailbox cmd=%x status=%x",
                    mb4->mbxCommand, mb4->mbxStatus);

                return (EIO);
        }
        ep = (IOCTL_COMMON_EXTENTS *)&mb4->un.varSLIConfig.payload;

        bcopy((uint8_t *)ep->params.response.RscId,
            (uint8_t *)hba->sli.sli4.VFIBase,
            (ep->params.response.ExtentCnt * sizeof (uint16_t)));

        hba->sli.sli4.VFIExtCount = ep->params.response.ExtentCnt;
        hba->sli.sli4.VFICount = hba->sli.sli4.VFIExtCount *
            hba->sli.sli4.VFIExtSize;

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
            "VFI Ext: size=%d cnt=%d/%d",
            hba->sli.sli4.VFIExtSize,
            hba->sli.sli4.VFIExtCount, ExtentCnt);

        for (i = 0; i < ep->params.response.ExtentCnt; i += 4) {
                EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                    "VFI Ext%d: %d, %d, %d, %d", i,
                    hba->sli.sli4.VFIBase[i],
                    hba->sli.sli4.VFIBase[i+1],
                    hba->sli.sli4.VFIBase[i+2],
                    hba->sli.sli4.VFIBase[i+3]);
        }

        return (0);

} /* emlxs_sli4_init_extents() */


extern uint32_t
emlxs_sli4_index_to_rpi(emlxs_hba_t *hba, uint32_t index)
{
        uint32_t i;
        uint32_t j;
        uint32_t rpi;

        i = index / hba->sli.sli4.RPIExtSize;
        j = index % hba->sli.sli4.RPIExtSize;
        rpi = hba->sli.sli4.RPIBase[i] + j;

        return (rpi);

} /* emlxs_sli4_index_to_rpi */


extern uint32_t
emlxs_sli4_rpi_to_index(emlxs_hba_t *hba, uint32_t rpi)
{
        uint32_t i;
        uint32_t lo;
        uint32_t hi;
        uint32_t index = hba->sli.sli4.RPICount;

        for (i = 0; i < hba->sli.sli4.RPIExtCount; i++) {
                lo = hba->sli.sli4.RPIBase[i];
                hi = lo + hba->sli.sli4.RPIExtSize;

                if ((rpi < hi) && (rpi >= lo)) {
                        index = (i * hba->sli.sli4.RPIExtSize) + (rpi - lo);
                        break;
                }
        }

        return (index);

} /* emlxs_sli4_rpi_to_index */


extern uint32_t
emlxs_sli4_index_to_xri(emlxs_hba_t *hba, uint32_t index)
{
        uint32_t i;
        uint32_t j;
        uint32_t xri;

        i = index / hba->sli.sli4.XRIExtSize;
        j = index % hba->sli.sli4.XRIExtSize;
        xri = hba->sli.sli4.XRIBase[i] + j;

        return (xri);

} /* emlxs_sli4_index_to_xri */




extern uint32_t
emlxs_sli4_index_to_vpi(emlxs_hba_t *hba, uint32_t index)
{
        uint32_t i;
        uint32_t j;
        uint32_t vpi;

        i = index / hba->sli.sli4.VPIExtSize;
        j = index % hba->sli.sli4.VPIExtSize;
        vpi = hba->sli.sli4.VPIBase[i] + j;

        return (vpi);

} /* emlxs_sli4_index_to_vpi */


extern uint32_t
emlxs_sli4_vpi_to_index(emlxs_hba_t *hba, uint32_t vpi)
{
        uint32_t i;
        uint32_t lo;
        uint32_t hi;
        uint32_t index = hba->sli.sli4.VPICount;

        for (i = 0; i < hba->sli.sli4.VPIExtCount; i++) {
                lo = hba->sli.sli4.VPIBase[i];
                hi = lo + hba->sli.sli4.VPIExtSize;

                if ((vpi < hi) && (vpi >= lo)) {
                        index = (i * hba->sli.sli4.VPIExtSize) + (vpi - lo);
                        break;
                }
        }

        return (index);

} /* emlxs_sli4_vpi_to_index */




extern uint32_t
emlxs_sli4_index_to_vfi(emlxs_hba_t *hba, uint32_t index)
{
        uint32_t i;
        uint32_t j;
        uint32_t vfi;

        i = index / hba->sli.sli4.VFIExtSize;
        j = index % hba->sli.sli4.VFIExtSize;
        vfi = hba->sli.sli4.VFIBase[i] + j;

        return (vfi);

} /* emlxs_sli4_index_to_vfi */


static uint16_t
emlxs_sli4_rqid_to_index(emlxs_hba_t *hba, uint16_t rqid)
{
        uint16_t i;

        if (rqid < 0xffff) {
                for (i = 0; i < EMLXS_MAX_RQS; i++) {
                        if (hba->sli.sli4.rq[i].qid == rqid) {
                                return (i);
                        }
                }
        }

        return (0xffff);

} /* emlxs_sli4_rqid_to_index */


static uint16_t
emlxs_sli4_wqid_to_index(emlxs_hba_t *hba, uint16_t wqid)
{
        uint16_t i;

        if (wqid < 0xffff) {
                for (i = 0; i < EMLXS_MAX_WQS; i++) {
                        if (hba->sli.sli4.wq[i].qid == wqid) {
                                return (i);
                        }
                }
        }

        return (0xffff);

} /* emlxs_sli4_wqid_to_index */


static uint16_t
emlxs_sli4_cqid_to_index(emlxs_hba_t *hba, uint16_t cqid)
{
        uint16_t i;

        if (cqid < 0xffff) {
                for (i = 0; i < EMLXS_MAX_CQS; i++) {
                        if (hba->sli.sli4.cq[i].qid == cqid) {
                                return (i);
                        }
                }
        }

        return (0xffff);

} /* emlxs_sli4_cqid_to_index */