Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[safe/jmp/linux-2.6] / drivers / scsi / qla2xxx / qla_isr.c
index f033703..ab90329 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2005 QLogic Corporation
+ * Copyright (c)  2003-2008 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -8,15 +8,15 @@
 
 #include <linux/delay.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_bsg_fc.h>
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
-static void qla2x00_status_entry(scsi_qla_host_t *, void *);
-static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
-static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);
-static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *);
-
-static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *);
+static void qla2x00_process_completed_request(struct scsi_qla_host *,
+       struct req_que *, uint32_t);
+static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
+static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
+static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
+       sts_entry_t *);
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -30,25 +30,29 @@ static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *);
 irqreturn_t
 qla2100_intr_handler(int irq, void *dev_id)
 {
-       scsi_qla_host_t *ha;
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
        struct device_reg_2xxx __iomem *reg;
        int             status;
-       unsigned long   flags;
        unsigned long   iter;
        uint16_t        hccr;
        uint16_t        mb[4];
+       struct rsp_que *rsp;
+       unsigned long   flags;
 
-       ha = (scsi_qla_host_t *) dev_id;
-       if (!ha) {
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL host pointer\n", __func__);
+                   "%s(): NULL response queue pointer\n", __func__);
                return (IRQ_NONE);
        }
 
+       ha = rsp->hw;
        reg = &ha->iobase->isp;
        status = 0;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                hccr = RD_REG_WORD(&reg->hccr);
                if (hccr & HCCR_RISC_PAUSE) {
@@ -63,8 +67,8 @@ qla2100_intr_handler(int irq, void *dev_id)
                        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
                        RD_REG_WORD(&reg->hccr);
 
-                       ha->isp_ops->fw_dump(ha, 1);
-                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       ha->isp_ops->fw_dump(vha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        break;
                } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
                        break;
@@ -76,24 +80,24 @@ qla2100_intr_handler(int irq, void *dev_id)
                        /* Get mailbox data. */
                        mb[0] = RD_MAILBOX_REG(ha, reg, 0);
                        if (mb[0] > 0x3fff && mb[0] < 0x8000) {
-                               qla2x00_mbx_completion(ha, mb[0]);
+                               qla2x00_mbx_completion(vha, mb[0]);
                                status |= MBX_INTERRUPT;
                        } else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
                                mb[1] = RD_MAILBOX_REG(ha, reg, 1);
                                mb[2] = RD_MAILBOX_REG(ha, reg, 2);
                                mb[3] = RD_MAILBOX_REG(ha, reg, 3);
-                               qla2x00_async_event(ha, mb);
+                               qla2x00_async_event(vha, rsp, mb);
                        } else {
                                /*EMPTY*/
                                DEBUG2(printk("scsi(%ld): Unrecognized "
                                    "interrupt type (%d).\n",
-                                   ha->host_no, mb[0]));
+                                   vha->host_no, mb[0]));
                        }
                        /* Release mailbox registers. */
                        WRT_REG_WORD(&reg->semaphore, 0);
                        RD_REG_WORD(&reg->semaphore);
                } else {
-                       qla2x00_process_response_queue(ha);
+                       qla2x00_process_response_queue(rsp);
 
                        WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
                        RD_REG_WORD(&reg->hccr);
@@ -122,30 +126,34 @@ qla2100_intr_handler(int irq, void *dev_id)
 irqreturn_t
 qla2300_intr_handler(int irq, void *dev_id)
 {
-       scsi_qla_host_t *ha;
+       scsi_qla_host_t *vha;
        struct device_reg_2xxx __iomem *reg;
        int             status;
-       unsigned long   flags;
        unsigned long   iter;
        uint32_t        stat;
        uint16_t        hccr;
        uint16_t        mb[4];
+       struct rsp_que *rsp;
+       struct qla_hw_data *ha;
+       unsigned long   flags;
 
-       ha = (scsi_qla_host_t *) dev_id;
-       if (!ha) {
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL host pointer\n", __func__);
+                   "%s(): NULL response queue pointer\n", __func__);
                return (IRQ_NONE);
        }
 
+       ha = rsp->hw;
        reg = &ha->iobase->isp;
        status = 0;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
                if (stat & HSR_RISC_PAUSED) {
-                       if (pci_channel_offline(ha->pdev))
+                       if (unlikely(pci_channel_offline(ha->pdev)))
                                break;
 
                        hccr = RD_REG_WORD(&reg->hccr);
@@ -164,8 +172,8 @@ qla2300_intr_handler(int irq, void *dev_id)
                        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
                        RD_REG_WORD(&reg->hccr);
 
-                       ha->isp_ops->fw_dump(ha, 1);
-                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       ha->isp_ops->fw_dump(vha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        break;
                } else if ((stat & HSR_RISC_INT) == 0)
                        break;
@@ -175,7 +183,7 @@ qla2300_intr_handler(int irq, void *dev_id)
                case 0x2:
                case 0x10:
                case 0x11:
-                       qla2x00_mbx_completion(ha, MSW(stat));
+                       qla2x00_mbx_completion(vha, MSW(stat));
                        status |= MBX_INTERRUPT;
 
                        /* Release mailbox registers. */
@@ -186,26 +194,26 @@ qla2300_intr_handler(int irq, void *dev_id)
                        mb[1] = RD_MAILBOX_REG(ha, reg, 1);
                        mb[2] = RD_MAILBOX_REG(ha, reg, 2);
                        mb[3] = RD_MAILBOX_REG(ha, reg, 3);
-                       qla2x00_async_event(ha, mb);
+                       qla2x00_async_event(vha, rsp, mb);
                        break;
                case 0x13:
-                       qla2x00_process_response_queue(ha);
+                       qla2x00_process_response_queue(rsp);
                        break;
                case 0x15:
                        mb[0] = MBA_CMPLT_1_16BIT;
                        mb[1] = MSW(stat);
-                       qla2x00_async_event(ha, mb);
+                       qla2x00_async_event(vha, rsp, mb);
                        break;
                case 0x16:
                        mb[0] = MBA_SCSI_COMPLETION;
                        mb[1] = MSW(stat);
                        mb[2] = RD_MAILBOX_REG(ha, reg, 2);
-                       qla2x00_async_event(ha, mb);
+                       qla2x00_async_event(vha, rsp, mb);
                        break;
                default:
                        DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
                            "(%d).\n",
-                           ha->host_no, stat & 0xff));
+                           vha->host_no, stat & 0xff));
                        break;
                }
                WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
@@ -228,10 +236,11 @@ qla2300_intr_handler(int irq, void *dev_id)
  * @mb0: Mailbox0 register
  */
 static void
-qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
+qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 {
        uint16_t        cnt;
        uint16_t __iomem *wptr;
+       struct qla_hw_data *ha = vha->hw;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        /* Load return mailbox registers. */
@@ -252,33 +261,72 @@ qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
 
        if (ha->mcp) {
                DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, ha->host_no, ha->mcp->mb[0]));
+                   __func__, vha->host_no, ha->mcp->mb[0]));
        } else {
                DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, ha->host_no));
+                   __func__, vha->host_no));
        }
 }
 
+static void
+qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
+{
+       static char *event[] =
+               { "Complete", "Request Notification", "Time Extension" };
+       int rval;
+       struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
+       uint16_t __iomem *wptr;
+       uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
+
+       /* Seed data -- mailbox1 -> mailbox7. */
+       wptr = (uint16_t __iomem *)&reg24->mailbox1;
+       for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
+               mb[cnt] = RD_REG_WORD(wptr);
+
+       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
+           "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
+           event[aen & 0xff],
+           mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
+
+       /* Acknowledgement needed? [Notify && non-zero timeout]. */
+       timeout = (descr >> 8) & 0xf;
+       if (aen != MBA_IDC_NOTIFY || !timeout)
+               return;
+
+       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
+           "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
+
+       rval = qla2x00_post_idc_ack_work(vha, mb);
+       if (rval != QLA_SUCCESS)
+               qla_printk(KERN_WARNING, vha->hw,
+                   "IDC failed to post ACK.\n");
+}
+
 /**
  * qla2x00_async_event() - Process aynchronous events.
  * @ha: SCSI driver HA context
  * @mb: Mailbox registers (0 - 3)
  */
 void
-qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
+qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 {
 #define LS_UNKNOWN     2
-       static char     *link_speeds[5] = { "1", "2", "?", "4", "8" };
+       static char     *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
        char            *link_speed;
        uint16_t        handle_cnt;
-       uint16_t        cnt;
+       uint16_t        cnt, mbx;
        uint32_t        handles[5];
+       struct qla_hw_data *ha = vha->hw;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
        uint32_t        rscn_entry, host_pid;
        uint8_t         rscn_queue_index;
+       unsigned long   flags;
 
        /* Setup to process RIO completion. */
        handle_cnt = 0;
+       if (IS_QLA81XX(ha))
+               goto skip_rio;
        switch (mb[0]) {
        case MBA_SCSI_COMPLETION:
                handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
@@ -330,86 +378,92 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
        default:
                break;
        }
-
+skip_rio:
        switch (mb[0]) {
        case MBA_SCSI_COMPLETION:       /* Fast Post */
-               if (!ha->flags.online)
+               if (!vha->flags.online)
                        break;
 
                for (cnt = 0; cnt < handle_cnt; cnt++)
-                       qla2x00_process_completed_request(ha, handles[cnt]);
+                       qla2x00_process_completed_request(vha, rsp->req,
+                               handles[cnt]);
                break;
 
        case MBA_RESET:                 /* Reset */
-               DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n", ha->host_no));
+               DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
+                       vha->host_no));
 
-               set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+               set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_SYSTEM_ERR:            /* System Error */
+               mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
                qla_printk(KERN_INFO, ha,
-                   "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
-                   mb[1], mb[2], mb[3]);
+                   "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
+                   "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
 
-               ha->isp_ops->fw_dump(ha, 1);
+               ha->isp_ops->fw_dump(vha, 1);
 
                if (IS_FWI2_CAPABLE(ha)) {
                        if (mb[1] == 0 && mb[2] == 0) {
                                qla_printk(KERN_ERR, ha,
                                    "Unrecoverable Hardware Error: adapter "
                                    "marked OFFLINE!\n");
-                               ha->flags.online = 0;
+                               vha->flags.online = 0;
                        } else
-                               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                } else if (mb[1] == 0) {
                        qla_printk(KERN_INFO, ha,
                            "Unrecoverable Hardware Error: adapter marked "
                            "OFFLINE!\n");
-                       ha->flags.online = 0;
+                       vha->flags.online = 0;
                } else
-                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_REQ_TRANSFER_ERR:      /* Request Transfer Error */
-               DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",
-                   ha->host_no));
-               qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
+               DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
+                   vha->host_no, mb[1]));
+               qla_printk(KERN_WARNING, ha,
+                   "ISP Request Transfer Error (%x).\n", mb[1]);
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_RSP_TRANSFER_ERR:      /* Response Transfer Error */
                DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
-                   ha->host_no));
+                   vha->host_no));
                qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_WAKEUP_THRES:          /* Request Queue Wake-up */
                DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
-                   ha->host_no));
+                   vha->host_no));
                break;
 
        case MBA_LIP_OCCURRED:          /* Loop Initialization Procedure */
-               DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,
+               DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
                    mb[1]));
-               qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);
+               qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
 
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&ha->loop_state, LOOP_DOWN);
-                       atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha, 1);
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                       atomic_set(&vha->loop_state, LOOP_DOWN);
+                       atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+                       qla2x00_mark_all_devices_lost(vha, 1);
                }
 
-               if (ha->parent) {
-                       atomic_set(&ha->vp_state, VP_FAILED);
-                       fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+               if (vha->vp_idx) {
+                       atomic_set(&vha->vp_state, VP_FAILED);
+                       fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
                }
 
-               set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+               set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+               set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
 
-               ha->flags.management_server_logged_in = 0;
+               vha->flags.management_server_logged_in = 0;
+               qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
                break;
 
        case MBA_LOOP_UP:               /* Loop Up Event */
@@ -420,94 +474,107 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                        link_speed = link_speeds[LS_UNKNOWN];
                        if (mb[1] < 5)
                                link_speed = link_speeds[mb[1]];
+                       else if (mb[1] == 0x13)
+                               link_speed = link_speeds[5];
                        ha->link_data_rate = mb[1];
                }
 
                DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
-                   ha->host_no, link_speed));
+                   vha->host_no, link_speed));
                qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
                    link_speed);
 
-               ha->flags.management_server_logged_in = 0;
+               vha->flags.management_server_logged_in = 0;
+               qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
                break;
 
        case MBA_LOOP_DOWN:             /* Loop Down Event */
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN (%x).\n",
-                   ha->host_no, mb[1]));
-               qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x).\n", mb[1]);
-
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&ha->loop_state, LOOP_DOWN);
-                       atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-                       ha->device_flags |= DFLG_NO_CABLE;
-                       qla2x00_mark_all_devices_lost(ha, 1);
+               mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
+               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
+                   "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
+                   mbx));
+               qla_printk(KERN_INFO, ha,
+                   "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
+                   mbx);
+
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                       atomic_set(&vha->loop_state, LOOP_DOWN);
+                       atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+                       vha->device_flags |= DFLG_NO_CABLE;
+                       qla2x00_mark_all_devices_lost(vha, 1);
                }
 
-               if (ha->parent) {
-                       atomic_set(&ha->vp_state, VP_FAILED);
-                       fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+               if (vha->vp_idx) {
+                       atomic_set(&vha->vp_state, VP_FAILED);
+                       fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
                }
 
-               ha->flags.management_server_logged_in = 0;
+               vha->flags.management_server_logged_in = 0;
                ha->link_data_rate = PORT_SPEED_UNKNOWN;
-               if (ql2xfdmienable)
-                       set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
+               qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
                break;
 
        case MBA_LIP_RESET:             /* LIP reset occurred */
                DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
-                   ha->host_no, mb[1]));
+                   vha->host_no, mb[1]));
                qla_printk(KERN_INFO, ha,
-                   "LIP reset occured (%x).\n", mb[1]);
+                   "LIP reset occurred (%x).\n", mb[1]);
 
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&ha->loop_state, LOOP_DOWN);
-                       atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha, 1);
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                       atomic_set(&vha->loop_state, LOOP_DOWN);
+                       atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+                       qla2x00_mark_all_devices_lost(vha, 1);
                }
 
-               if (ha->parent) {
-                       atomic_set(&ha->vp_state, VP_FAILED);
-                       fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+               if (vha->vp_idx) {
+                       atomic_set(&vha->vp_state, VP_FAILED);
+                       fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
                }
 
-               set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+               set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
 
                ha->operating_mode = LOOP;
-               ha->flags.management_server_logged_in = 0;
+               vha->flags.management_server_logged_in = 0;
+               qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
                break;
 
+       /* case MBA_DCBX_COMPLETE: */
        case MBA_POINT_TO_POINT:        /* Point-to-Point */
                if (IS_QLA2100(ha))
                        break;
 
-               DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n",
-                   ha->host_no));
+               if (IS_QLA81XX(ha))
+                       DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
+                           "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               else
+                       DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
+                           "received.\n", vha->host_no));
 
                /*
                 * Until there's a transition from loop down to loop up, treat
                 * this as loop down only.
                 */
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&ha->loop_state, LOOP_DOWN);
-                       if (!atomic_read(&ha->loop_down_timer))
-                               atomic_set(&ha->loop_down_timer,
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                       atomic_set(&vha->loop_state, LOOP_DOWN);
+                       if (!atomic_read(&vha->loop_down_timer))
+                               atomic_set(&vha->loop_down_timer,
                                    LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha, 1);
+                       qla2x00_mark_all_devices_lost(vha, 1);
                }
 
-               if (ha->parent) {
-                       atomic_set(&ha->vp_state, VP_FAILED);
-                       fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+               if (vha->vp_idx) {
+                       atomic_set(&vha->vp_state, VP_FAILED);
+                       fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
                }
 
-               if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
-                       set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-               }
-               set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+               if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
+                       set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
+
+               set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+               set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
 
                ha->flags.gpsc_supported = 1;
-               ha->flags.management_server_logged_in = 0;
+               vha->flags.management_server_logged_in = 0;
                break;
 
        case MBA_CHG_IN_CONNECTION:     /* Change in connection mode */
@@ -516,234 +583,613 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 
                DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
                    "received.\n",
-                   ha->host_no));
+                   vha->host_no));
                qla_printk(KERN_INFO, ha,
                    "Configuration change detected: value=%x.\n", mb[1]);
 
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&ha->loop_state, LOOP_DOWN);
-                       if (!atomic_read(&ha->loop_down_timer))
-                               atomic_set(&ha->loop_down_timer,
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                       atomic_set(&vha->loop_state, LOOP_DOWN);
+                       if (!atomic_read(&vha->loop_down_timer))
+                               atomic_set(&vha->loop_down_timer,
                                    LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha, 1);
+                       qla2x00_mark_all_devices_lost(vha, 1);
                }
 
-               if (ha->parent) {
-                       atomic_set(&ha->vp_state, VP_FAILED);
-                       fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+               if (vha->vp_idx) {
+                       atomic_set(&vha->vp_state, VP_FAILED);
+                       fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
                }
 
-               set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
-               set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
                break;
 
        case MBA_PORT_UPDATE:           /* Port database update */
                /*
-                * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
+                * Handle only global and vn-port update events
+                *
+                * Relevant inputs:
+                * mb[1] = N_Port handle of changed port
+                * OR 0xffff for global event
+                * mb[2] = New login state
+                * 7 = Port logged out
+                * mb[3] = LSB is vp_idx, 0xff = all vps
+                *
+                * Skip processing if:
+                *       Event is global, vp_idx is NOT all vps,
+                *           vp_idx does not match
+                *       Event is not global, vp_idx does not match
+                */
+               if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff)
+                       || (mb[1] != 0xffff)) {
+                       if (vha->vp_idx != (mb[3] & 0xff))
+                               break;
+               }
+
+               /* Global event -- port logout or port unavailable. */
+               if (mb[1] == 0xffff && mb[2] == 0x7) {
+                       DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
+                           vha->host_no));
+                       DEBUG(printk(KERN_INFO
+                           "scsi(%ld): Port unavailable %04x %04x %04x.\n",
+                           vha->host_no, mb[1], mb[2], mb[3]));
+
+                       if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+                               atomic_set(&vha->loop_state, LOOP_DOWN);
+                               atomic_set(&vha->loop_down_timer,
+                                   LOOP_DOWN_TIME);
+                               vha->device_flags |= DFLG_NO_CABLE;
+                               qla2x00_mark_all_devices_lost(vha, 1);
+                       }
+
+                       if (vha->vp_idx) {
+                               atomic_set(&vha->vp_state, VP_FAILED);
+                               fc_vport_set_state(vha->fc_vport,
+                                   FC_VPORT_FAILED);
+                               qla2x00_mark_all_devices_lost(vha, 1);
+                       }
+
+                       vha->flags.management_server_logged_in = 0;
+                       ha->link_data_rate = PORT_SPEED_UNKNOWN;
+                       break;
+               }
+
+               /*
+                * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
                 * event etc. earlier indicating loop is down) then process
                 * it.  Otherwise ignore it and Wait for RSCN to come in.
                 */
-               atomic_set(&ha->loop_down_timer, 0);
-               if (atomic_read(&ha->loop_state) != LOOP_DOWN &&
-                   atomic_read(&ha->loop_state) != LOOP_DEAD) {
+               atomic_set(&vha->loop_down_timer, 0);
+               if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
+                   atomic_read(&vha->loop_state) != LOOP_DEAD) {
                        DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
-                           "ignored %04x/%04x/%04x.\n", ha->host_no, mb[1],
+                           "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
                            mb[2], mb[3]));
                        break;
                }
 
                DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
-                   ha->host_no));
+                   vha->host_no));
                DEBUG(printk(KERN_INFO
                    "scsi(%ld): Port database changed %04x %04x %04x.\n",
-                   ha->host_no, mb[1], mb[2], mb[3]));
+                   vha->host_no, mb[1], mb[2], mb[3]));
 
                /*
                 * Mark all devices as missing so we will login again.
                 */
-               atomic_set(&ha->loop_state, LOOP_UP);
+               atomic_set(&vha->loop_state, LOOP_UP);
 
-               qla2x00_mark_all_devices_lost(ha, 1);
+               qla2x00_mark_all_devices_lost(vha, 1);
 
-               ha->flags.rscn_queue_overflow = 1;
+               vha->flags.rscn_queue_overflow = 1;
 
-               set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
-               set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
                break;
 
        case MBA_RSCN_UPDATE:           /* State Change Registration */
                /* Check if the Vport has issued a SCR */
-               if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
+               if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
                        break;
                /* Only handle SCNs for our Vport index. */
-               if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
+               if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
                        break;
 
                DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
-                   ha->host_no));
+                   vha->host_no));
                DEBUG(printk(KERN_INFO
                    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
-                   ha->host_no, mb[1], mb[2], mb[3]));
+                   vha->host_no, mb[1], mb[2], mb[3]));
 
-               rscn_entry = (mb[1] << 16) | mb[2];
-               host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
-                   ha->d_id.b.al_pa;
+               rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
+               host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
+                               | vha->d_id.b.al_pa;
                if (rscn_entry == host_pid) {
                        DEBUG(printk(KERN_INFO
                            "scsi(%ld): Ignoring RSCN update to local host "
                            "port ID (%06x)\n",
-                           ha->host_no, host_pid));
+                           vha->host_no, host_pid));
                        break;
                }
 
-               rscn_queue_index = ha->rscn_in_ptr + 1;
+               /* Ignore reserved bits from RSCN-payload. */
+               rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
+               rscn_queue_index = vha->rscn_in_ptr + 1;
                if (rscn_queue_index == MAX_RSCN_COUNT)
                        rscn_queue_index = 0;
-               if (rscn_queue_index != ha->rscn_out_ptr) {
-                       ha->rscn_queue[ha->rscn_in_ptr] = rscn_entry;
-                       ha->rscn_in_ptr = rscn_queue_index;
+               if (rscn_queue_index != vha->rscn_out_ptr) {
+                       vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
+                       vha->rscn_in_ptr = rscn_queue_index;
                } else {
-                       ha->flags.rscn_queue_overflow = 1;
+                       vha->flags.rscn_queue_overflow = 1;
                }
 
-               atomic_set(&ha->loop_state, LOOP_UPDATE);
-               atomic_set(&ha->loop_down_timer, 0);
-               ha->flags.management_server_logged_in = 0;
+               atomic_set(&vha->loop_state, LOOP_UPDATE);
+               atomic_set(&vha->loop_down_timer, 0);
+               vha->flags.management_server_logged_in = 0;
 
-               set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
-               set_bit(RSCN_UPDATE, &ha->dpc_flags);
+               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               set_bit(RSCN_UPDATE, &vha->dpc_flags);
+               qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
                break;
 
        /* case MBA_RIO_RESPONSE: */
        case MBA_ZIO_RESPONSE:
-               DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n",
-                   ha->host_no));
-               DEBUG(printk(KERN_INFO
-                   "scsi(%ld): [R|Z]IO update completion.\n",
-                   ha->host_no));
+               DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
+                   vha->host_no));
 
                if (IS_FWI2_CAPABLE(ha))
-                       qla24xx_process_response_queue(ha);
+                       qla24xx_process_response_queue(vha, rsp);
                else
-                       qla2x00_process_response_queue(ha);
+                       qla2x00_process_response_queue(rsp);
                break;
 
        case MBA_DISCARD_RND_FRAME:
                DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
-                   "%04x.\n", ha->host_no, mb[1], mb[2], mb[3]));
+                   "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
                break;
 
        case MBA_TRACE_NOTIFICATION:
                DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
-               ha->host_no, mb[1], mb[2]));
+               vha->host_no, mb[1], mb[2]));
+               break;
+
+       case MBA_ISP84XX_ALERT:
+               DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
+                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+
+               spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
+               switch (mb[1]) {
+               case A84_PANIC_RECOVERY:
+                       qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
+                           "%04x %04x\n", mb[2], mb[3]);
+                       break;
+               case A84_OP_LOGIN_COMPLETE:
+                       ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
+                           "firmware version %x\n", ha->cs84xx->op_fw_version));
+                       break;
+               case A84_DIAG_LOGIN_COMPLETE:
+                       ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
+                           "diagnostic firmware version %x\n",
+                           ha->cs84xx->diag_fw_version));
+                       break;
+               case A84_GOLD_LOGIN_COMPLETE:
+                       ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
+                       ha->cs84xx->fw_update = 1;
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
+                           "firmware version %x\n",
+                           ha->cs84xx->gold_fw_version));
+                       break;
+               default:
+                       qla_printk(KERN_ERR, ha,
+                           "Alert 84xx: Invalid Alert %04x %04x %04x\n",
+                           mb[1], mb[2], mb[3]);
+               }
+               spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
+               break;
+       case MBA_DCBX_START:
+               DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
+                   vha->host_no, mb[1], mb[2], mb[3]));
+               break;
+       case MBA_DCBX_PARAM_UPDATE:
+               DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
+                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               break;
+       case MBA_FCF_CONF_ERR:
+               DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
+                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               break;
+       case MBA_IDC_COMPLETE:
+       case MBA_IDC_NOTIFY:
+       case MBA_IDC_TIME_EXT:
+               qla81xx_idc_event(vha, mb[0], mb[1]);
                break;
        }
 
-       if (!ha->parent && ha->num_vhosts)
-               qla2x00_alert_all_vps(ha, mb);
+       if (!vha->vp_idx && ha->num_vhosts)
+               qla2x00_alert_all_vps(rsp, mb);
 }
 
+/**
+ * qla2x00_process_completed_request() - Process a Fast Post response.
+ * @ha: SCSI driver HA context
+ * @index: SRB index
+ */
 static void
-qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
+qla2x00_process_completed_request(struct scsi_qla_host *vha,
+                               struct req_que *req, uint32_t index)
 {
-       fc_port_t *fcport = data;
+       srb_t *sp;
+       struct qla_hw_data *ha = vha->hw;
 
-       if (fcport->ha->max_q_depth <= sdev->queue_depth)
+       /* Validate handle. */
+       if (index >= MAX_OUTSTANDING_COMMANDS) {
+               DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
+                   vha->host_no, index));
+               qla_printk(KERN_WARNING, ha,
+                   "Invalid SCSI completion handle %d.\n", index);
+
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                return;
+       }
 
-       if (sdev->ordered_tags)
-               scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
-                   sdev->queue_depth + 1);
-       else
-               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
-                   sdev->queue_depth + 1);
+       sp = req->outstanding_cmds[index];
+       if (sp) {
+               /* Free outstanding command slot. */
+               req->outstanding_cmds[index] = NULL;
 
-       fcport->last_ramp_up = jiffies;
+               /* Save ISP completion status */
+               sp->cmd->result = DID_OK << 16;
+               qla2x00_sp_compl(ha, sp);
+       } else {
+               DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
+                       " handle(%d)\n", vha->host_no, req->id, index));
+               qla_printk(KERN_WARNING, ha,
+                   "Invalid ISP SCSI completion handle\n");
 
-       DEBUG2(qla_printk(KERN_INFO, fcport->ha,
-           "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
-           fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
-           sdev->queue_depth));
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+       }
 }
 
-static void
-qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
+static srb_t *
+qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
+    struct req_que *req, void *iocb)
 {
-       fc_port_t *fcport = data;
+       struct qla_hw_data *ha = vha->hw;
+       sts_entry_t *pkt = iocb;
+       srb_t *sp = NULL;
+       uint16_t index;
 
-       if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
-               return;
+       index = LSW(pkt->handle);
+       if (index >= MAX_OUTSTANDING_COMMANDS) {
+               qla_printk(KERN_WARNING, ha,
+                   "%s: Invalid completion handle (%x).\n", func, index);
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+               goto done;
+       }
+       sp = req->outstanding_cmds[index];
+       if (!sp) {
+               qla_printk(KERN_WARNING, ha,
+                   "%s: Invalid completion handle (%x) -- timed-out.\n", func,
+                   index);
+               return sp;
+       }
+       if (sp->handle != index) {
+               qla_printk(KERN_WARNING, ha,
+                   "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
+                   index);
+               return NULL;
+       }
+
+       req->outstanding_cmds[index] = NULL;
 
-       DEBUG2(qla_printk(KERN_INFO, fcport->ha,
-           "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
-           fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
-           sdev->queue_depth));
+done:
+       return sp;
 }
 
-static inline void
-qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
+static void
+qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct mbx_entry *mbx)
 {
+       const char func[] = "MBX-IOCB";
+       const char *type;
+       struct qla_hw_data *ha = vha->hw;
        fc_port_t *fcport;
-       struct scsi_device *sdev;
+       srb_t *sp;
+       struct srb_logio *lio;
+       uint16_t data[2];
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
+       if (!sp)
+               return;
 
-       sdev = sp->cmd->device;
-       if (sdev->queue_depth >= ha->max_q_depth)
+       type = NULL;
+       lio = sp->ctx;
+       switch (lio->ctx.type) {
+       case SRB_LOGIN_CMD:
+               type = "login";
+               break;
+       case SRB_LOGOUT_CMD:
+               type = "logout";
+               break;
+       default:
+               qla_printk(KERN_WARNING, ha,
+                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+                   lio->ctx.type);
                return;
+       }
 
+       del_timer(&lio->ctx.timer);
        fcport = sp->fcport;
-       if (time_before(jiffies,
-           fcport->last_ramp_up + ql2xqfullrampup * HZ))
+
+       data[0] = data[1] = 0;
+       if (mbx->entry_status) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
+                   "status=%x state-flag=%x status-flags=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   mbx->entry_status, le16_to_cpu(mbx->status),
+                   le16_to_cpu(mbx->state_flags),
+                   le16_to_cpu(mbx->status_flags)));
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
+
+               data[0] = MBS_COMMAND_ERROR;
+               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
+                   QLA_LOGIO_LOGIN_RETRIED: 0;
+               goto done_post_logio_done_work;
+       }
+
+       if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
+               DEBUG2(printk(KERN_DEBUG
+                   "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   le16_to_cpu(mbx->mb1)));
+
+               data[0] = MBS_COMMAND_COMPLETE;
+               if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1)
+                       fcport->flags |= FCF_FCP2_DEVICE;
+
+               goto done_post_logio_done_work;
+       }
+
+       data[0] = le16_to_cpu(mbx->mb0);
+       switch (data[0]) {
+       case MBS_PORT_ID_USED:
+               data[1] = le16_to_cpu(mbx->mb1);
+               break;
+       case MBS_LOOP_ID_USED:
+               break;
+       default:
+               data[0] = MBS_COMMAND_ERROR;
+               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
+                   QLA_LOGIO_LOGIN_RETRIED: 0;
+               break;
+       }
+
+       DEBUG2(printk(KERN_WARNING
+           "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
+           "mb6=%x mb7=%x.\n",
+           fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status),
+           le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
+           le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
+           le16_to_cpu(mbx->mb7)));
+
+done_post_logio_done_work:
+       lio->ctx.type == SRB_LOGIN_CMD ?
+           qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
+           qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
+
+       lio->ctx.free(sp);
+}
+
+static void
+qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct sts_entry_24xx *pkt, int iocb_type)
+{
+       const char func[] = "ELS_CT_IOCB";
+       const char *type;
+       struct qla_hw_data *ha = vha->hw;
+       srb_t *sp;
+       struct srb_bsg *sp_bsg;
+       struct fc_bsg_job *bsg_job;
+       uint16_t comp_status;
+       uint32_t fw_status[3];
+       uint8_t* fw_sts_ptr;
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+       if (!sp)
                return;
-       if (time_before(jiffies,
-           fcport->last_queue_full + ql2xqfullrampup * HZ))
+       sp_bsg = (struct srb_bsg*)sp->ctx;
+       bsg_job = sp_bsg->bsg_job;
+
+       type = NULL;
+       switch (sp_bsg->ctx.type) {
+       case SRB_ELS_CMD_RPT:
+       case SRB_ELS_CMD_HST:
+               type = "els";
+               break;
+       case SRB_CT_CMD:
+               type = "ct pass-through";
+               break;
+       default:
+               qla_printk(KERN_WARNING, ha,
+                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+                   sp_bsg->ctx.type);
                return;
+       }
+
+       comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
+       fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
+       fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
+
+       /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
+        * fc payload  to the caller
+        */
+       bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
+       bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
+
+       if (comp_status != CS_COMPLETE) {
+               if (comp_status == CS_DATA_UNDERRUN) {
+                       bsg_job->reply->result = DID_OK << 16;
+                       bsg_job->reply->reply_payload_rcv_len =
+                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
+
+                       DEBUG2(qla_printk(KERN_WARNING, ha,
+                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                           "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
+                               vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
+                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
+                       fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+                       memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
+               }
+               else {
+                       DEBUG2(qla_printk(KERN_WARNING, ha,
+                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                           "error subcode 1=0x%x error subcode 2=0x%x.\n",
+                               vha->host_no, sp->handle, type, comp_status,
+                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
+                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
+                       bsg_job->reply->result = DID_ERROR << 16;
+                       bsg_job->reply->reply_payload_rcv_len = 0;
+                       fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+                       memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
+               }
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+       }
+       else {
+               bsg_job->reply->result =  DID_OK << 16;;
+               bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
+               bsg_job->reply_len = 0;
+       }
 
-       starget_for_each_device(sdev->sdev_target, fcport,
-           qla2x00_adjust_sdev_qdepth_up);
+       dma_unmap_sg(&ha->pdev->dev,
+           bsg_job->request_payload.sg_list,
+           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       dma_unmap_sg(&ha->pdev->dev,
+           bsg_job->reply_payload.sg_list,
+           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+       if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) ||
+           (sp_bsg->ctx.type == SRB_CT_CMD))
+               kfree(sp->fcport);
+       kfree(sp->ctx);
+       mempool_free(sp, ha->srb_mempool);
+       bsg_job->job_done(bsg_job);
 }
 
-/**
- * qla2x00_process_completed_request() - Process a Fast Post response.
- * @ha: SCSI driver HA context
- * @index: SRB index
- */
 static void
-qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
+qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct logio_entry_24xx *logio)
 {
+       const char func[] = "LOGIO-IOCB";
+       const char *type;
+       struct qla_hw_data *ha = vha->hw;
+       fc_port_t *fcport;
        srb_t *sp;
+       struct srb_logio *lio;
+       uint16_t data[2];
+       uint32_t iop[2];
 
-       /* Validate handle. */
-       if (index >= MAX_OUTSTANDING_COMMANDS) {
-               DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
-                   ha->host_no, index));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid SCSI completion handle %d.\n", index);
+       sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
+       if (!sp)
+               return;
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+       type = NULL;
+       lio = sp->ctx;
+       switch (lio->ctx.type) {
+       case SRB_LOGIN_CMD:
+               type = "login";
+               break;
+       case SRB_LOGOUT_CMD:
+               type = "logout";
+               break;
+       default:
+               qla_printk(KERN_WARNING, ha,
+                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+                   lio->ctx.type);
                return;
        }
 
-       sp = ha->outstanding_cmds[index];
-       if (sp) {
-               /* Free outstanding command slot. */
-               ha->outstanding_cmds[index] = NULL;
-
-               CMD_COMPL_STATUS(sp->cmd) = 0L;
-               CMD_SCSI_STATUS(sp->cmd) = 0L;
+       del_timer(&lio->ctx.timer);
+       fcport = sp->fcport;
 
-               /* Save ISP completion status */
-               sp->cmd->result = DID_OK << 16;
+       data[0] = data[1] = 0;
+       if (logio->entry_status) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   logio->entry_status));
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
+
+               data[0] = MBS_COMMAND_ERROR;
+               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
+                   QLA_LOGIO_LOGIN_RETRIED: 0;
+               goto done_post_logio_done_work;
+       }
 
-               qla2x00_ramp_up_queue_depth(ha, sp);
-               qla2x00_sp_compl(ha, sp);
-       } else {
-               DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
-                   ha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid ISP SCSI completion handle\n");
+       if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
+               DEBUG2(printk(KERN_DEBUG
+                   "scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   le32_to_cpu(logio->io_parameter[0])));
+
+               data[0] = MBS_COMMAND_COMPLETE;
+               if (lio->ctx.type == SRB_LOGOUT_CMD)
+                       goto done_post_logio_done_work;
+
+               iop[0] = le32_to_cpu(logio->io_parameter[0]);
+               if (iop[0] & BIT_4) {
+                       fcport->port_type = FCT_TARGET;
+                       if (iop[0] & BIT_8)
+                               fcport->flags |= FCF_FCP2_DEVICE;
+               }
+               if (iop[0] & BIT_5)
+                       fcport->port_type = FCT_INITIATOR;
+               if (logio->io_parameter[7] || logio->io_parameter[8])
+                       fcport->supported_classes |= FC_COS_CLASS2;
+               if (logio->io_parameter[9] || logio->io_parameter[10])
+                       fcport->supported_classes |= FC_COS_CLASS3;
+
+               goto done_post_logio_done_work;
+       }
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+       iop[0] = le32_to_cpu(logio->io_parameter[0]);
+       iop[1] = le32_to_cpu(logio->io_parameter[1]);
+       switch (iop[0]) {
+       case LSC_SCODE_PORTID_USED:
+               data[0] = MBS_PORT_ID_USED;
+               data[1] = LSW(iop[1]);
+               break;
+       case LSC_SCODE_NPORT_USED:
+               data[0] = MBS_LOOP_ID_USED;
+               break;
+       case LSC_SCODE_CMD_FAILED:
+               if ((iop[1] & 0xff) == 0x05) {
+                       data[0] = MBS_NOT_LOGGED_IN;
+                       break;
+               }
+               /* Fall through. */
+       default:
+               data[0] = MBS_COMMAND_ERROR;
+               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
+                   QLA_LOGIO_LOGIN_RETRIED: 0;
+               break;
        }
+
+       DEBUG2(printk(KERN_WARNING
+           "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
+           fcport->vha->host_no, sp->handle, type,
+           le16_to_cpu(logio->comp_status),
+           le32_to_cpu(logio->io_parameter[0]),
+           le32_to_cpu(logio->io_parameter[1])));
+
+done_post_logio_done_work:
+       lio->ctx.type == SRB_LOGIN_CMD ?
+           qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
+           qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
+
+       lio->ctx.free(sp);
 }
 
 /**
@@ -751,32 +1197,36 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
  * @ha: SCSI driver HA context
  */
 void
-qla2x00_process_response_queue(struct scsi_qla_host *ha)
+qla2x00_process_response_queue(struct rsp_que *rsp)
 {
+       struct scsi_qla_host *vha;
+       struct qla_hw_data *ha = rsp->hw;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        sts_entry_t     *pkt;
        uint16_t        handle_cnt;
        uint16_t        cnt;
 
-       if (!ha->flags.online)
+       vha = pci_get_drvdata(ha->pdev);
+
+       if (!vha->flags.online)
                return;
 
-       while (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
-               pkt = (sts_entry_t *)ha->response_ring_ptr;
+       while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
+               pkt = (sts_entry_t *)rsp->ring_ptr;
 
-               ha->rsp_ring_index++;
-               if (ha->rsp_ring_index == ha->response_q_length) {
-                       ha->rsp_ring_index = 0;
-                       ha->response_ring_ptr = ha->response_ring;
+               rsp->ring_index++;
+               if (rsp->ring_index == rsp->length) {
+                       rsp->ring_index = 0;
+                       rsp->ring_ptr = rsp->ring;
                } else {
-                       ha->response_ring_ptr++;
+                       rsp->ring_ptr++;
                }
 
                if (pkt->entry_status != 0) {
                        DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", ha->host_no));
+                           "scsi(%ld): Process error entry.\n", vha->host_no));
 
-                       qla2x00_error_entry(ha, pkt);
+                       qla2x00_error_entry(vha, rsp, pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
                        wmb();
                        continue;
@@ -784,34 +1234,34 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
 
                switch (pkt->entry_type) {
                case STATUS_TYPE:
-                       qla2x00_status_entry(ha, pkt);
+                       qla2x00_status_entry(vha, rsp, pkt);
                        break;
                case STATUS_TYPE_21:
                        handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
                        for (cnt = 0; cnt < handle_cnt; cnt++) {
-                               qla2x00_process_completed_request(ha,
+                               qla2x00_process_completed_request(vha, rsp->req,
                                    ((sts21_entry_t *)pkt)->handle[cnt]);
                        }
                        break;
                case STATUS_TYPE_22:
                        handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
                        for (cnt = 0; cnt < handle_cnt; cnt++) {
-                               qla2x00_process_completed_request(ha,
+                               qla2x00_process_completed_request(vha, rsp->req,
                                    ((sts22_entry_t *)pkt)->handle[cnt]);
                        }
                        break;
                case STATUS_CONT_TYPE:
-                       qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt);
-                       break;
-               case MS_IOCB_TYPE:
-                       qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt);
+                       qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
                        break;
+               case MBX_IOCB_TYPE:
+                       qla2x00_mbx_iocb_entry(vha, rsp->req,
+                           (struct mbx_entry *)pkt);
                default:
                        /* Type Not Supported. */
                        DEBUG4(printk(KERN_WARNING
                            "scsi(%ld): Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           ha->host_no, pkt->entry_type, pkt->entry_status));
+                           vha->host_no, pkt->entry_type, pkt->entry_status));
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -819,18 +1269,18 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
        }
 
        /* Adjust ring index */
-       WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
+       WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
 }
 
 static inline void
-qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
+       struct rsp_que *rsp)
 {
        struct scsi_cmnd *cp = sp->cmd;
 
        if (sense_len >= SCSI_SENSE_BUFFERSIZE)
                sense_len = SCSI_SENSE_BUFFERSIZE;
 
-       CMD_ACTUAL_SNSLEN(cp) = sense_len;
        sp->request_sense_length = sense_len;
        sp->request_sense_ptr = cp->sense_buffer;
        if (sp->request_sense_length > 32)
@@ -841,14 +1291,14 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
        sp->request_sense_ptr += sense_len;
        sp->request_sense_length -= sense_len;
        if (sp->request_sense_length != 0)
-               sp->ha->status_srb = sp;
+               rsp->status_srb = sp;
 
        DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
-           "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
-           cp->device->id, cp->device->lun, cp, cp->serial_number));
+           "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
+           cp->device->channel, cp->device->id, cp->device->lun, cp,
+           cp->serial_number));
        if (sense_len)
-               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-                   CMD_ACTUAL_SNSLEN(cp)));
+               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
 }
 
 /**
@@ -857,7 +1307,7 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
  * @pkt: Entry pointer
  */
 static void
-qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
+qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 {
        srb_t           *sp;
        fc_port_t       *fcport;
@@ -870,6 +1320,10 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
        int32_t         resid;
        uint32_t        sense_len, rsp_info_len, resid_len, fw_resid_len;
        uint8_t         *rsp_info, *sense_data;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t handle;
+       uint16_t que;
+       struct req_que *req;
 
        sts = (sts_entry_t *) pkt;
        sts24 = (struct sts_entry_24xx *) pkt;
@@ -880,34 +1334,36 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                comp_status = le16_to_cpu(sts->comp_status);
                scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
        }
-
+       handle = (uint32_t) LSW(sts->handle);
+       que = MSW(sts->handle);
+       req = ha->req_q_map[que];
        /* Fast path completion. */
        if (comp_status == CS_COMPLETE && scsi_status == 0) {
-               qla2x00_process_completed_request(ha, sts->handle);
+               qla2x00_process_completed_request(vha, req, handle);
 
                return;
        }
 
        /* Validate handle. */
-       if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
-               sp = ha->outstanding_cmds[sts->handle];
-               ha->outstanding_cmds[sts->handle] = NULL;
+       if (handle < MAX_OUTSTANDING_COMMANDS) {
+               sp = req->outstanding_cmds[handle];
+               req->outstanding_cmds[handle] = NULL;
        } else
                sp = NULL;
 
        if (sp == NULL) {
                DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
-                   ha->host_no));
+                   vha->host_no));
                qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-               qla2xxx_wake_dpc(ha);
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+               qla2xxx_wake_dpc(vha);
                return;
        }
        cp = sp->cmd;
        if (cp == NULL) {
                DEBUG2(printk("scsi(%ld): Command already returned back to OS "
-                   "pkt->handle=%d sp=%p.\n", ha->host_no, sts->handle, sp));
+                   "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
                qla_printk(KERN_WARNING, ha,
                    "Command is NULL: already returned to OS (sp=%p)\n", sp);
 
@@ -915,24 +1371,27 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
        }
 
        lscsi_status = scsi_status & STATUS_MASK;
-       CMD_ENTRY_STATUS(cp) = sts->entry_status;
-       CMD_COMPL_STATUS(cp) = comp_status;
-       CMD_SCSI_STATUS(cp) = scsi_status;
 
        fcport = sp->fcport;
 
        sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
        if (IS_FWI2_CAPABLE(ha)) {
-               sense_len = le32_to_cpu(sts24->sense_len);
-               rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
-               resid_len = le32_to_cpu(sts24->rsp_residual_count);
-               fw_resid_len = le32_to_cpu(sts24->residual_len);
+               if (scsi_status & SS_SENSE_LEN_VALID)
+                       sense_len = le32_to_cpu(sts24->sense_len);
+               if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
+                       rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
+               if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+                       resid_len = le32_to_cpu(sts24->rsp_residual_count);
+               if (comp_status == CS_DATA_UNDERRUN)
+                       fw_resid_len = le32_to_cpu(sts24->residual_len);
                rsp_info = sts24->data;
                sense_data = sts24->data;
                host_to_fcp_swap(sts24->data, sizeof(sts24->data));
        } else {
-               sense_len = le16_to_cpu(sts->req_sense_length);
-               rsp_info_len = le16_to_cpu(sts->rsp_info_len);
+               if (scsi_status & SS_SENSE_LEN_VALID)
+                       sense_len = le16_to_cpu(sts->req_sense_length);
+               if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
+                       rsp_info_len = le16_to_cpu(sts->rsp_info_len);
                resid_len = le32_to_cpu(sts->residual_length);
                rsp_info = sts->rsp_info;
                sense_data = sts->req_sense_data;
@@ -946,7 +1405,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (rsp_info_len > 3 && rsp_info[3]) {
                        DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
                            "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
-                           "retrying command\n", ha->host_no,
+                           "retrying command\n", vha->host_no,
                            cp->device->channel, cp->device->id,
                            cp->device->lun, rsp_info_len, rsp_info[0],
                            rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
@@ -976,7 +1435,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
                        resid = resid_len;
                        scsi_set_resid(cp, resid);
-                       CMD_RESID_LEN(cp) = resid;
 
                        if (!lscsi_status &&
                            ((unsigned)(scsi_bufflen(cp) - resid) <
@@ -984,7 +1442,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                                qla_printk(KERN_INFO, ha,
                                           "scsi(%ld:%d:%d:%d): Mid-layer underflow "
                                           "detected (%x of %x bytes)...returning "
-                                          "error status.\n", ha->host_no,
+                                          "error status.\n", vha->host_no,
                                           cp->device->channel, cp->device->id,
                                           cp->device->lun, resid,
                                           scsi_bufflen(cp));
@@ -998,13 +1456,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
                        DEBUG2(printk(KERN_INFO
                            "scsi(%ld): QUEUE FULL status detected "
-                           "0x%x-0x%x.\n", ha->host_no, comp_status,
+                           "0x%x-0x%x.\n", vha->host_no, comp_status,
                            scsi_status));
-
-                       /* Adjust queue depth for all luns on the port. */
-                       fcport->last_queue_full = jiffies;
-                       starget_for_each_device(cp->device->sdev_target,
-                           fcport, qla2x00_adjust_sdev_qdepth_down);
                        break;
                }
                if (lscsi_status != SS_CHECK_CONDITION)
@@ -1014,56 +1467,71 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                if (!(scsi_status & SS_SENSE_LEN_VALID))
                        break;
 
-               qla2x00_handle_sense(sp, sense_data, sense_len);
+               qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
                break;
 
        case CS_DATA_UNDERRUN:
-               resid = resid_len;
+               DEBUG2(printk(KERN_INFO
+                   "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
+                   "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
+                   vha->host_no, cp->device->id, cp->device->lun, comp_status,
+                   scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
+                   cp->underflow));
+
                /* Use F/W calculated residual length. */
-               if (IS_FWI2_CAPABLE(ha)) {
-                       if (scsi_status & SS_RESIDUAL_UNDER &&
-                           resid != fw_resid_len) {
-                               scsi_status &= ~SS_RESIDUAL_UNDER;
-                               lscsi_status = 0;
+               resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
+               scsi_set_resid(cp, resid);
+               if (scsi_status & SS_RESIDUAL_UNDER) {
+                       if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
+                               DEBUG2(printk(
+                                   "scsi(%ld:%d:%d:%d) Dropped frame(s) "
+                                   "detected (%x of %x bytes)...residual "
+                                   "length mismatch...retrying command.\n",
+                                   vha->host_no, cp->device->channel,
+                                   cp->device->id, cp->device->lun, resid,
+                                   scsi_bufflen(cp)));
+
+                               cp->result = DID_ERROR << 16 | lscsi_status;
+                               break;
                        }
-                       resid = fw_resid_len;
-               }
 
-               if (scsi_status & SS_RESIDUAL_UNDER) {
-                       scsi_set_resid(cp, resid);
-                       CMD_RESID_LEN(cp) = resid;
-               } else {
-                       DEBUG2(printk(KERN_INFO
-                           "scsi(%ld:%d:%d) UNDERRUN status detected "
-                           "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
-                           "os_underflow=0x%x\n", ha->host_no,
-                           cp->device->id, cp->device->lun, comp_status,
-                           scsi_status, resid_len, resid, cp->cmnd[0],
-                           cp->underflow));
+                       if (!lscsi_status &&
+                           ((unsigned)(scsi_bufflen(cp) - resid) <
+                           cp->underflow)) {
+                               qla_printk(KERN_INFO, ha,
+                                   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+                                   "detected (%x of %x bytes)...returning "
+                                   "error status.\n", vha->host_no,
+                                   cp->device->channel, cp->device->id,
+                                   cp->device->lun, resid, scsi_bufflen(cp));
 
+                               cp->result = DID_ERROR << 16;
+                               break;
+                       }
+               } else if (!lscsi_status) {
+                       DEBUG2(printk(
+                           "scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
+                           "(%x of %x bytes)...firmware reported underrun..."
+                           "retrying command.\n", vha->host_no,
+                           cp->device->channel, cp->device->id,
+                           cp->device->lun, resid, scsi_bufflen(cp)));
+
+                       cp->result = DID_ERROR << 16;
+                       break;
                }
 
+               cp->result = DID_OK << 16 | lscsi_status;
+
                /*
                 * Check to see if SCSI Status is non zero. If so report SCSI
                 * Status.
                 */
                if (lscsi_status != 0) {
-                       cp->result = DID_OK << 16 | lscsi_status;
-
                        if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
                                DEBUG2(printk(KERN_INFO
                                    "scsi(%ld): QUEUE FULL status detected "
-                                   "0x%x-0x%x.\n", ha->host_no, comp_status,
+                                   "0x%x-0x%x.\n", vha->host_no, comp_status,
                                    scsi_status));
-
-                               /*
-                                * Adjust queue depth for all luns on the
-                                * port.
-                                */
-                               fcport->last_queue_full = jiffies;
-                               starget_for_each_device(
-                                   cp->device->sdev_target, fcport,
-                                   qla2x00_adjust_sdev_qdepth_down);
                                break;
                        }
                        if (lscsi_status != SS_CHECK_CONDITION)
@@ -1073,68 +1541,14 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                        if (!(scsi_status & SS_SENSE_LEN_VALID))
                                break;
 
-                       qla2x00_handle_sense(sp, sense_data, sense_len);
-
-                       /*
-                        * In case of a Underrun condition, set both the lscsi
-                        * status and the completion status to appropriate
-                        * values.
-                        */
-                       if (resid &&
-                           ((unsigned)(scsi_bufflen(cp) - resid) <
-                            cp->underflow)) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
-                                   "detected (%x of %x bytes)...returning "
-                                   "error status.\n", ha->host_no,
-                                   cp->device->channel, cp->device->id,
-                                   cp->device->lun, resid,
-                                   scsi_bufflen(cp)));
-
-                               cp->result = DID_ERROR << 16 | lscsi_status;
-                       }
-               } else {
-                       /*
-                        * If RISC reports underrun and target does not report
-                        * it then we must have a lost frame, so tell upper
-                        * layer to retry it by reporting a bus busy.
-                        */
-                       if (!(scsi_status & SS_RESIDUAL_UNDER)) {
-                               DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
-                                             "frame(s) detected (%x of %x bytes)..."
-                                             "retrying command.\n", ha->host_no,
-                                             cp->device->channel, cp->device->id,
-                                             cp->device->lun, resid,
-                                             scsi_bufflen(cp)));
-
-                               cp->result = DID_BUS_BUSY << 16;
-                               break;
-                       }
-
-                       /* Handle mid-layer underflow */
-                       if ((unsigned)(scsi_bufflen(cp) - resid) <
-                           cp->underflow) {
-                               qla_printk(KERN_INFO, ha,
-                                          "scsi(%ld:%d:%d:%d): Mid-layer underflow "
-                                          "detected (%x of %x bytes)...returning "
-                                          "error status.\n", ha->host_no,
-                                          cp->device->channel, cp->device->id,
-                                          cp->device->lun, resid,
-                                          scsi_bufflen(cp));
-
-                               cp->result = DID_ERROR << 16;
-                               break;
-                       }
-
-                       /* Everybody online, looking good... */
-                       cp->result = DID_OK << 16;
+                       qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
                }
                break;
 
        case CS_DATA_OVERRUN:
                DEBUG2(printk(KERN_INFO
                    "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
-                   ha->host_no, cp->device->id, cp->device->lun, comp_status,
+                   vha->host_no, cp->device->id, cp->device->lun, comp_status,
                    scsi_status));
                DEBUG2(printk(KERN_INFO
                    "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
@@ -1160,20 +1574,24 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                 */
                DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
                    "pid=%ld, compl status=0x%x, port state=0x%x\n",
-                   ha->host_no, cp->device->id, cp->device->lun,
+                   vha->host_no, cp->device->id, cp->device->lun,
                    cp->serial_number, comp_status,
                    atomic_read(&fcport->state)));
 
-               cp->result = DID_BUS_BUSY << 16;
-               if (atomic_read(&fcport->state) == FCS_ONLINE) {
-                       qla2x00_mark_device_lost(ha, fcport, 1, 1);
-               }
+               /*
+                * We are going to have the fc class block the rport
+                * while we try to recover so instruct the mid layer
+                * to requeue until the class decides how to handle this.
+                */
+               cp->result = DID_TRANSPORT_DISRUPTED << 16;
+               if (atomic_read(&fcport->state) == FCS_ONLINE)
+                       qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
                break;
 
        case CS_RESET:
                DEBUG2(printk(KERN_INFO
                    "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
-                   ha->host_no, comp_status, scsi_status));
+                   vha->host_no, comp_status, scsi_status));
 
                cp->result = DID_RESET << 16;
                break;
@@ -1186,36 +1604,41 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                 */
                DEBUG2(printk(KERN_INFO
                    "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
-                   ha->host_no, comp_status, scsi_status));
+                   vha->host_no, comp_status, scsi_status));
 
                cp->result = DID_RESET << 16;
                break;
 
        case CS_TIMEOUT:
-               cp->result = DID_BUS_BUSY << 16;
+               /*
+                * We are going to have the fc class block the rport
+                * while we try to recover so instruct the mid layer
+                * to requeue until the class decides how to handle this.
+                */
+               cp->result = DID_TRANSPORT_DISRUPTED << 16;
 
                if (IS_FWI2_CAPABLE(ha)) {
                        DEBUG2(printk(KERN_INFO
                            "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
-                           "0x%x-0x%x\n", ha->host_no, cp->device->channel,
+                           "0x%x-0x%x\n", vha->host_no, cp->device->channel,
                            cp->device->id, cp->device->lun, comp_status,
                            scsi_status));
                        break;
                }
                DEBUG2(printk(KERN_INFO
                    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
-                   "sflags=%x.\n", ha->host_no, cp->device->channel,
+                   "sflags=%x.\n", vha->host_no, cp->device->channel,
                    cp->device->id, cp->device->lun, comp_status, scsi_status,
                    le16_to_cpu(sts->status_flags)));
 
                /* Check to see if logout occurred. */
                if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
-                       qla2x00_mark_device_lost(ha, fcport, 1, 1);
+                       qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
                break;
 
        default:
                DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
-                   "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status));
+                   "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
                qla_printk(KERN_INFO, ha,
                    "Unknown status detected 0x%x-0x%x.\n",
                    comp_status, scsi_status);
@@ -1225,7 +1648,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
        }
 
        /* Place command on done queue. */
-       if (ha->status_srb == NULL)
+       if (rsp->status_srb == NULL)
                qla2x00_sp_compl(ha, sp);
 }
 
@@ -1237,10 +1660,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
  * Extended sense data.
  */
 static void
-qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
+qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
        uint8_t         sense_sz = 0;
-       srb_t           *sp = ha->status_srb;
+       struct qla_hw_data *ha = rsp->hw;
+       srb_t           *sp = rsp->status_srb;
        struct scsi_cmnd *cp;
 
        if (sp != NULL && sp->request_sense_length != 0) {
@@ -1252,7 +1676,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
                            "cmd is NULL: already returned to OS (sp=%p)\n",
                            sp);
 
-                       ha->status_srb = NULL;
+                       rsp->status_srb = NULL;
                        return;
                }
 
@@ -1273,7 +1697,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
 
                /* Place command on done queue. */
                if (sp->request_sense_length == 0) {
-                       ha->status_srb = NULL;
+                       rsp->status_srb = NULL;
                        qla2x00_sp_compl(ha, sp);
                }
        }
@@ -1285,10 +1709,13 @@ qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
  * @pkt: Entry pointer
  */
 static void
-qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
+qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
 {
        srb_t *sp;
-
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t handle = LSW(pkt->handle);
+       uint16_t que = MSW(pkt->handle);
+       struct req_que *req = ha->req_q_map[que];
 #if defined(QL_DEBUG_LEVEL_2)
        if (pkt->entry_status & RF_INV_E_ORDER)
                qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
@@ -1306,14 +1733,14 @@ qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
 #endif
 
        /* Validate handle. */
-       if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-               sp = ha->outstanding_cmds[pkt->handle];
+       if (handle < MAX_OUTSTANDING_COMMANDS)
+               sp = req->outstanding_cmds[handle];
        else
                sp = NULL;
 
        if (sp) {
                /* Free outstanding command slot. */
-               ha->outstanding_cmds[pkt->handle] = NULL;
+               req->outstanding_cmds[handle] = NULL;
 
                /* Bad payload or header */
                if (pkt->entry_status &
@@ -1330,63 +1757,26 @@ qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
        } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
            COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
                DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
-                   ha->host_no));
+                   vha->host_no));
                qla_printk(KERN_WARNING, ha,
                    "Error entry - invalid handle\n");
 
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-               qla2xxx_wake_dpc(ha);
-       }
-}
-
-/**
- * qla2x00_ms_entry() - Process a Management Server entry.
- * @ha: SCSI driver HA context
- * @index: Response queue out pointer
- */
-static void
-qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt)
-{
-       srb_t          *sp;
-
-       DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
-           __func__, ha->host_no, pkt, pkt->handle1));
-
-       /* Validate handle. */
-       if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS)
-               sp = ha->outstanding_cmds[pkt->handle1];
-       else
-               sp = NULL;
-
-       if (sp == NULL) {
-               DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",
-                   ha->host_no));
-               qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n");
-
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-               return;
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+               qla2xxx_wake_dpc(vha);
        }
-
-       CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status);
-       CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;
-
-       /* Free outstanding command slot. */
-       ha->outstanding_cmds[pkt->handle1] = NULL;
-
-       qla2x00_sp_compl(ha, sp);
 }
 
-
 /**
  * qla24xx_mbx_completion() - Process mailbox command completions.
  * @ha: SCSI driver HA context
  * @mb0: Mailbox0 register
  */
 static void
-qla24xx_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
+qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 {
        uint16_t        cnt;
        uint16_t __iomem *wptr;
+       struct qla_hw_data *ha = vha->hw;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
        /* Load return mailbox registers. */
@@ -1401,10 +1791,10 @@ qla24xx_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
 
        if (ha->mcp) {
                DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, ha->host_no, ha->mcp->mb[0]));
+                   __func__, vha->host_no, ha->mcp->mb[0]));
        } else {
                DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, ha->host_no));
+                   __func__, vha->host_no));
        }
 }
 
@@ -1412,31 +1802,30 @@ qla24xx_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
  * qla24xx_process_response_queue() - Process response queue entries.
  * @ha: SCSI driver HA context
  */
-void
-qla24xx_process_response_queue(struct scsi_qla_host *ha)
+void qla24xx_process_response_queue(struct scsi_qla_host *vha,
+       struct rsp_que *rsp)
 {
-       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        struct sts_entry_24xx *pkt;
 
-       if (!ha->flags.online)
+       if (!vha->flags.online)
                return;
 
-       while (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
-               pkt = (struct sts_entry_24xx *)ha->response_ring_ptr;
+       while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
+               pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
 
-               ha->rsp_ring_index++;
-               if (ha->rsp_ring_index == ha->response_q_length) {
-                       ha->rsp_ring_index = 0;
-                       ha->response_ring_ptr = ha->response_ring;
+               rsp->ring_index++;
+               if (rsp->ring_index == rsp->length) {
+                       rsp->ring_index = 0;
+                       rsp->ring_ptr = rsp->ring;
                } else {
-                       ha->response_ring_ptr++;
+                       rsp->ring_ptr++;
                }
 
                if (pkt->entry_status != 0) {
                        DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", ha->host_no));
+                           "scsi(%ld): Process error entry.\n", vha->host_no));
 
-                       qla2x00_error_entry(ha, (sts_entry_t *) pkt);
+                       qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
                        wmb();
                        continue;
@@ -1444,24 +1833,32 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
 
                switch (pkt->entry_type) {
                case STATUS_TYPE:
-                       qla2x00_status_entry(ha, pkt);
+                       qla2x00_status_entry(vha, rsp, pkt);
                        break;
                case STATUS_CONT_TYPE:
-                       qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt);
-                       break;
-               case MS_IOCB_TYPE:
-                       qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);
+                       qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
                        break;
                case VP_RPT_ID_IOCB_TYPE:
-                       qla24xx_report_id_acquisition(ha,
+                       qla24xx_report_id_acquisition(vha,
                            (struct vp_rpt_id_entry_24xx *)pkt);
                        break;
+               case LOGINOUT_PORT_IOCB_TYPE:
+                       qla24xx_logio_entry(vha, rsp->req,
+                           (struct logio_entry_24xx *)pkt);
+                       break;
+                case CT_IOCB_TYPE:
+                       qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
+                       clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
+                       break;
+                case ELS_IOCB_TYPE:
+                       qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
+                       break;
                default:
                        /* Type Not Supported. */
                        DEBUG4(printk(KERN_WARNING
                            "scsi(%ld): Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           ha->host_no, pkt->entry_type, pkt->entry_status));
+                           vha->host_no, pkt->entry_type, pkt->entry_status));
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -1469,17 +1866,18 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
        }
 
        /* Adjust ring index */
-       WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);
+       WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
 }
 
 static void
-qla2xxx_check_risc_status(scsi_qla_host_t *ha)
+qla2xxx_check_risc_status(scsi_qla_host_t *vha)
 {
        int rval;
        uint32_t cnt;
+       struct qla_hw_data *ha = vha->hw;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
-       if (!IS_QLA25XX(ha))
+       if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
                return;
 
        rval = QLA_SUCCESS;
@@ -1530,30 +1928,37 @@ done:
 irqreturn_t
 qla24xx_intr_handler(int irq, void *dev_id)
 {
-       scsi_qla_host_t *ha;
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
        struct device_reg_24xx __iomem *reg;
        int             status;
-       unsigned long   flags;
        unsigned long   iter;
        uint32_t        stat;
        uint32_t        hccr;
        uint16_t        mb[4];
+       struct rsp_que *rsp;
+       unsigned long   flags;
 
-       ha = (scsi_qla_host_t *) dev_id;
-       if (!ha) {
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL host pointer\n", __func__);
+                   "%s(): NULL response queue pointer\n", __func__);
                return IRQ_NONE;
        }
 
+       ha = rsp->hw;
        reg = &ha->iobase->isp24;
        status = 0;
 
+       if (unlikely(pci_channel_offline(ha->pdev)))
+               return IRQ_HANDLED;
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
-                       if (pci_channel_offline(ha->pdev))
+                       if (unlikely(pci_channel_offline(ha->pdev)))
                                break;
 
                        hccr = RD_REG_DWORD(&reg->hccr);
@@ -1561,10 +1966,10 @@ qla24xx_intr_handler(int irq, void *dev_id)
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
 
-                       qla2xxx_check_risc_status(ha);
+                       qla2xxx_check_risc_status(vha);
 
-                       ha->isp_ops->fw_dump(ha, 1);
-                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       ha->isp_ops->fw_dump(vha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        break;
                } else if ((stat & HSRX_RISC_INT) == 0)
                        break;
@@ -1574,7 +1979,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
                case 0x2:
                case 0x10:
                case 0x11:
-                       qla24xx_mbx_completion(ha, MSW(stat));
+                       qla24xx_mbx_completion(vha, MSW(stat));
                        status |= MBX_INTERRUPT;
 
                        break;
@@ -1583,15 +1988,16 @@ qla24xx_intr_handler(int irq, void *dev_id)
                        mb[1] = RD_REG_WORD(&reg->mailbox1);
                        mb[2] = RD_REG_WORD(&reg->mailbox2);
                        mb[3] = RD_REG_WORD(&reg->mailbox3);
-                       qla2x00_async_event(ha, mb);
+                       qla2x00_async_event(vha, rsp, mb);
                        break;
                case 0x13:
-                       qla24xx_process_response_queue(ha);
+               case 0x14:
+                       qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
                        DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
                            "(%d).\n",
-                           ha->host_no, stat & 0xff));
+                           vha->host_no, stat & 0xff));
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -1608,66 +2014,62 @@ qla24xx_intr_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/**
- * qla24xx_ms_entry() - Process a Management Server entry.
- * @ha: SCSI driver HA context
- * @index: Response queue out pointer
- */
-static void
-qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
+static irqreturn_t
+qla24xx_msix_rsp_q(int irq, void *dev_id)
 {
-       srb_t          *sp;
-
-       DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
-           __func__, ha->host_no, pkt, pkt->handle));
-
-       DEBUG9(printk("%s: ct pkt dump:\n", __func__));
-       DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx)));
-
-       /* Validate handle. */
-       if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-               sp = ha->outstanding_cmds[pkt->handle];
-       else
-               sp = NULL;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
+       struct device_reg_24xx __iomem *reg;
+       struct scsi_qla_host *vha;
+       unsigned long flags;
 
-       if (sp == NULL) {
-               DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",
-                   ha->host_no));
-               DEBUG10(printk("scsi(%ld): MS entry - invalid handle\n",
-                   ha->host_no));
-               qla_printk(KERN_WARNING, ha, "MS entry - invalid handle %d\n",
-                   pkt->handle);
-
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-               return;
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+               "%s(): NULL response queue pointer\n", __func__);
+               return IRQ_NONE;
        }
+       ha = rsp->hw;
+       reg = &ha->iobase->isp24;
 
-       CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->comp_status);
-       CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;
+       spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       /* Free outstanding command slot. */
-       ha->outstanding_cmds[pkt->handle] = NULL;
+       vha = pci_get_drvdata(ha->pdev);
+       qla24xx_process_response_queue(vha, rsp);
+       if (!ha->flags.disable_msix_handshake) {
+               WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+               RD_REG_DWORD_RELAXED(&reg->hccr);
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       qla2x00_sp_compl(ha, sp);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t
-qla24xx_msix_rsp_q(int irq, void *dev_id)
+qla25xx_msix_rsp_q(int irq, void *dev_id)
 {
-       scsi_qla_host_t *ha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
        struct device_reg_24xx __iomem *reg;
        unsigned long flags;
 
-       ha = dev_id;
-       reg = &ha->iobase->isp24;
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-
-       qla24xx_process_response_queue(ha);
-
-       WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer\n", __func__);
+               return IRQ_NONE;
+       }
+       ha = rsp->hw;
 
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       /* Clear the interrupt, if enabled, for this response queue */
+       if (rsp->options & ~BIT_6) {
+               reg = &ha->iobase->isp24;
+               spin_lock_irqsave(&ha->hardware_lock, flags);
+               WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+               RD_REG_DWORD_RELAXED(&reg->hccr);
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       }
+       queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
 
        return IRQ_HANDLED;
 }
@@ -1675,23 +2077,32 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
 static irqreturn_t
 qla24xx_msix_default(int irq, void *dev_id)
 {
-       scsi_qla_host_t *ha;
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
        struct device_reg_24xx __iomem *reg;
        int             status;
-       unsigned long   flags;
        uint32_t        stat;
        uint32_t        hccr;
        uint16_t        mb[4];
+       unsigned long flags;
 
-       ha = dev_id;
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               DEBUG(printk(
+               "%s(): NULL response queue pointer\n", __func__));
+               return IRQ_NONE;
+       }
+       ha = rsp->hw;
        reg = &ha->iobase->isp24;
        status = 0;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
        do {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
-                       if (pci_channel_offline(ha->pdev))
+                       if (unlikely(pci_channel_offline(ha->pdev)))
                                break;
 
                        hccr = RD_REG_DWORD(&reg->hccr);
@@ -1699,10 +2110,10 @@ qla24xx_msix_default(int irq, void *dev_id)
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                            "Dumping firmware!\n", hccr);
 
-                       qla2xxx_check_risc_status(ha);
+                       qla2xxx_check_risc_status(vha);
 
-                       ha->isp_ops->fw_dump(ha, 1);
-                       set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+                       ha->isp_ops->fw_dump(vha, 1);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        break;
                } else if ((stat & HSRX_RISC_INT) == 0)
                        break;
@@ -1712,7 +2123,7 @@ qla24xx_msix_default(int irq, void *dev_id)
                case 0x2:
                case 0x10:
                case 0x11:
-                       qla24xx_mbx_completion(ha, MSW(stat));
+                       qla24xx_mbx_completion(vha, MSW(stat));
                        status |= MBX_INTERRUPT;
 
                        break;
@@ -1721,15 +2132,16 @@ qla24xx_msix_default(int irq, void *dev_id)
                        mb[1] = RD_REG_WORD(&reg->mailbox1);
                        mb[2] = RD_REG_WORD(&reg->mailbox2);
                        mb[3] = RD_REG_WORD(&reg->mailbox3);
-                       qla2x00_async_event(ha, mb);
+                       qla2x00_async_event(vha, rsp, mb);
                        break;
                case 0x13:
-                       qla24xx_process_response_queue(ha);
+               case 0x14:
+                       qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
                        DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
                            "(%d).\n",
-                           ha->host_no, stat & 0xff));
+                           vha->host_no, stat & 0xff));
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -1741,97 +2153,133 @@ qla24xx_msix_default(int irq, void *dev_id)
                set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
                complete(&ha->mbx_intr_comp);
        }
-
        return IRQ_HANDLED;
 }
 
 /* Interrupt handling helpers. */
 
 struct qla_init_msix_entry {
-       uint16_t entry;
-       uint16_t index;
        const char *name;
        irq_handler_t handler;
 };
 
-static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
-       { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
-               "qla2xxx (default)", qla24xx_msix_default },
-
-       { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
-               "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
+static struct qla_init_msix_entry msix_entries[3] = {
+       { "qla2xxx (default)", qla24xx_msix_default },
+       { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
+       { "qla2xxx (multiq)", qla25xx_msix_rsp_q },
 };
 
 static void
-qla24xx_disable_msix(scsi_qla_host_t *ha)
+qla24xx_disable_msix(struct qla_hw_data *ha)
 {
        int i;
        struct qla_msix_entry *qentry;
 
-       for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
-               qentry = &ha->msix_entries[imsix_entries[i].index];
+       for (i = 0; i < ha->msix_count; i++) {
+               qentry = &ha->msix_entries[i];
                if (qentry->have_irq)
-                       free_irq(qentry->msix_vector, ha);
+                       free_irq(qentry->vector, qentry->rsp);
        }
        pci_disable_msix(ha->pdev);
+       kfree(ha->msix_entries);
+       ha->msix_entries = NULL;
+       ha->flags.msix_enabled = 0;
 }
 
 static int
-qla24xx_enable_msix(scsi_qla_host_t *ha)
+qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
+#define MIN_MSIX_COUNT 2
        int i, ret;
-       struct msix_entry entries[QLA_MSIX_ENTRIES];
+       struct msix_entry *entries;
        struct qla_msix_entry *qentry;
 
-       for (i = 0; i < QLA_MSIX_ENTRIES; i++)
-               entries[i].entry = imsix_entries[i].entry;
+       entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
+                                       GFP_KERNEL);
+       if (!entries)
+               return -ENOMEM;
+
+       for (i = 0; i < ha->msix_count; i++)
+               entries[i].entry = i;
 
-       ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+       ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
        if (ret) {
+               if (ret < MIN_MSIX_COUNT)
+                       goto msix_failed;
+
                qla_printk(KERN_WARNING, ha,
-                   "MSI-X: Failed to enable support -- %d/%d\n",
-                   QLA_MSIX_ENTRIES, ret);
+                       "MSI-X: Failed to enable support -- %d/%d\n"
+                       " Retry with %d vectors\n", ha->msix_count, ret, ret);
+               ha->msix_count = ret;
+               ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
+               if (ret) {
+msix_failed:
+                       qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
+                               " support, giving up -- %d/%d\n",
+                               ha->msix_count, ret);
+                       goto msix_out;
+               }
+               ha->max_rsp_queues = ha->msix_count - 1;
+       }
+       ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
+                               ha->msix_count, GFP_KERNEL);
+       if (!ha->msix_entries) {
+               ret = -ENOMEM;
                goto msix_out;
        }
        ha->flags.msix_enabled = 1;
 
-       for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
-               qentry = &ha->msix_entries[imsix_entries[i].index];
-               qentry->msix_vector = entries[i].vector;
-               qentry->msix_entry = entries[i].entry;
+       for (i = 0; i < ha->msix_count; i++) {
+               qentry = &ha->msix_entries[i];
+               qentry->vector = entries[i].vector;
+               qentry->entry = entries[i].entry;
                qentry->have_irq = 0;
-               ret = request_irq(qentry->msix_vector,
-                   imsix_entries[i].handler, 0, imsix_entries[i].name, ha);
+               qentry->rsp = NULL;
+       }
+
+       /* Enable MSI-X vectors for the base queue */
+       for (i = 0; i < 2; i++) {
+               qentry = &ha->msix_entries[i];
+               ret = request_irq(qentry->vector, msix_entries[i].handler,
+                                       0, msix_entries[i].name, rsp);
                if (ret) {
                        qla_printk(KERN_WARNING, ha,
-                           "MSI-X: Unable to register handler -- %x/%d.\n",
-                           imsix_entries[i].index, ret);
+                       "MSI-X: Unable to register handler -- %x/%d.\n",
+                       qentry->vector, ret);
                        qla24xx_disable_msix(ha);
+                       ha->mqenable = 0;
                        goto msix_out;
                }
                qentry->have_irq = 1;
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
        }
 
+       /* Enable MSI-X vector for response queue update for queue 0 */
+       if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
+               ha->mqenable = 1;
+
 msix_out:
+       kfree(entries);
        return ret;
 }
 
 int
-qla2x00_request_irqs(scsi_qla_host_t *ha)
+qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
        int ret;
        device_reg_t __iomem *reg = ha->iobase;
-       unsigned long flags;
 
        /* If possible, enable MSI-X. */
-       if (!IS_QLA2432(ha) && !IS_QLA2532(ha))
+       if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
+           !IS_QLA8432(ha) && !IS_QLA8001(ha))
                goto skip_msix;
 
-        if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
-           !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
+       if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
+               !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
                DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
-                   ha->chip_revision, ha->fw_attributes));
+               "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
+                       ha->pdev->revision, ha->fw_attributes));
 
                goto skip_msix;
        }
@@ -1848,7 +2296,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
                goto skip_msi;
        }
 
-       ret = qla24xx_enable_msix(ha);
+       ret = qla24xx_enable_msix(ha, rsp);
        if (!ret) {
                DEBUG2(qla_printk(KERN_INFO, ha,
                    "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
@@ -1859,7 +2307,8 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
            "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
 
-       if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))
+       if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
+           !IS_QLA8001(ha))
                goto skip_msi;
 
        ret = pci_enable_msi(ha->pdev);
@@ -1870,7 +2319,7 @@ skip_msix:
 skip_msi:
 
        ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
-           IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
+           IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
        if (ret) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to reserve interrupt %d already in use.\n",
@@ -1878,11 +2327,15 @@ skip_msi:
                goto fail;
        }
        ha->flags.inta_enabled = 1;
-       ha->host->irq = ha->pdev->irq;
 clear_risc_ints:
 
-       ha->isp_ops->disable_intrs(ha);
-       spin_lock_irqsave(&ha->hardware_lock, flags);
+       /*
+        * FIXME: Noted that 8014s were being dropped during NK testing.
+        * Timing deltas during MSI-X/INTa transitions?
+        */
+       if (IS_QLA81XX(ha))
+               goto fail;
+       spin_lock_irq(&ha->hardware_lock);
        if (IS_FWI2_CAPABLE(ha)) {
                WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
                WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
@@ -1891,21 +2344,43 @@ clear_risc_ints:
                WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
                WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
        }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       ha->isp_ops->enable_intrs(ha);
+       spin_unlock_irq(&ha->hardware_lock);
 
 fail:
        return ret;
 }
 
 void
-qla2x00_free_irqs(scsi_qla_host_t *ha)
+qla2x00_free_irqs(scsi_qla_host_t *vha)
 {
+       struct qla_hw_data *ha = vha->hw;
+       struct rsp_que *rsp = ha->rsp_q_map[0];
 
        if (ha->flags.msix_enabled)
                qla24xx_disable_msix(ha);
-       else if (ha->flags.inta_enabled) {
-               free_irq(ha->host->irq, ha);
+       else if (ha->flags.msi_enabled) {
+               free_irq(ha->pdev->irq, rsp);
                pci_disable_msi(ha->pdev);
+       } else
+               free_irq(ha->pdev->irq, rsp);
+}
+
+
+int qla25xx_request_irq(struct rsp_que *rsp)
+{
+       struct qla_hw_data *ha = rsp->hw;
+       struct qla_init_msix_entry *intr = &msix_entries[2];
+       struct qla_msix_entry *msix = rsp->msix;
+       int ret;
+
+       ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
+       if (ret) {
+               qla_printk(KERN_WARNING, ha,
+                       "MSI-X: Unable to register handler -- %x/%d.\n",
+                       msix->vector, ret);
+               return ret;
        }
+       msix->have_irq = 1;
+       msix->rsp = rsp;
+       return ret;
 }