]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_os.c
[SCSI] qla2xxx: Correct infinite-login-retry issue.
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_os.c
index dd076da86a465d668d6b251512492176a65e81be..4314f94bd4770180f8f44c9d8a713016944e93ce 100644 (file)
@@ -29,8 +29,7 @@ static struct kmem_cache *srb_cachep;
 /*
  * Ioctl related information.
  */
-static int num_hosts;
-
+int num_hosts;
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -112,7 +111,7 @@ static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
 static int qla2x00_change_queue_depth(struct scsi_device *, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
 
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla2x00_queuecommand,
@@ -143,7 +142,7 @@ static struct scsi_host_template qla2x00_driver_template = {
        .shost_attrs            = qla2x00_host_attrs,
 };
 
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla24xx_queuecommand,
@@ -171,21 +170,21 @@ static struct scsi_host_template qla24xx_driver_template = {
 };
 
 static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
 
 /* TODO Convert to inlines
  *
  * Timer routines
  */
-#define        WATCH_INTERVAL          1       /* number of seconds */
 
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
 
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
     void *, unsigned long);
 static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
 
-static inline void
+__inline__ void
 qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
 {
        init_timer(&ha->timer);
@@ -202,7 +201,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
        mod_timer(&ha->timer, jiffies + interval * HZ);
 }
 
-static __inline__ void
+__inline__ void
 qla2x00_stop_timer(scsi_qla_host_t *ha)
 {
        del_timer_sync(&ha->timer);
@@ -213,8 +212,8 @@ static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
 
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
 static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
@@ -266,6 +265,8 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
                strcpy(str, "PCIe (");
                if (lspeed == 1)
                        strcat(str, "2.5Gb/s ");
+               else if (lspeed == 2)
+                       strcat(str, "5.0Gb/s ");
                else
                        strcat(str, "<unknown> ");
                snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
@@ -344,6 +345,12 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
                strcat(str, "[IP] ");
        if (ha->fw_attributes & BIT_2)
                strcat(str, "[Multi-ID] ");
+       if (ha->fw_attributes & BIT_3)
+               strcat(str, "[SB-2] ");
+       if (ha->fw_attributes & BIT_4)
+               strcat(str, "[T10 CRC] ");
+       if (ha->fw_attributes & BIT_5)
+               strcat(str, "[VI] ");
        if (ha->fw_attributes & BIT_13)
                strcat(str, "[Experimental]");
        return str;
@@ -378,6 +385,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        srb_t *sp;
        int rval;
 
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc_fail_command;
+       }
+
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
@@ -438,6 +450,12 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
+
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc24_fail_command;
+       }
 
        rval = fc_remote_port_chkready(rport);
        if (rval) {
@@ -453,7 +471,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-                   atomic_read(&ha->loop_state) == LOOP_DEAD) {
+                   atomic_read(&pha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
@@ -462,7 +480,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 
        spin_unlock_irq(ha->host->host_lock);
 
-       sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+       sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
        if (!sp)
                goto qc24_host_busy_lock;
 
@@ -475,8 +493,8 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        return 0;
 
 qc24_host_busy_free_sp:
-       qla2x00_sp_free_dma(ha, sp);
-       mempool_free(sp, ha->srb_mempool);
+       qla2x00_sp_free_dma(pha, sp);
+       mempool_free(sp, pha->srb_mempool);
 
 qc24_host_busy_lock:
        spin_lock_irq(ha->host->host_lock);
@@ -548,16 +566,17 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
 {
        int             return_status;
        unsigned long   wait_online;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
-       while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
-           test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
-           test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
-           ha->dpc_active) && time_before(jiffies, wait_online)) {
+       while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+           test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+           test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+           pha->dpc_active) && time_before(jiffies, wait_online)) {
 
                msleep(1000);
        }
-       if (ha->flags.online)
+       if (pha->flags.online)
                return_status = QLA_SUCCESS;
        else
                return_status = QLA_FUNCTION_FAILED;
@@ -588,14 +607,15 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
 {
        int      return_status = QLA_SUCCESS;
        unsigned long loop_timeout ;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        /* wait for 5 min at the max for loop to be ready */
        loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
 
-       while ((!atomic_read(&ha->loop_down_timer) &&
-           atomic_read(&ha->loop_state) == LOOP_DOWN) ||
-           atomic_read(&ha->loop_state) != LOOP_READY) {
-               if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+       while ((!atomic_read(&pha->loop_down_timer) &&
+           atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+           atomic_read(&pha->loop_state) != LOOP_READY) {
+               if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
                        return_status = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -650,6 +670,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        unsigned long serial;
        unsigned long flags;
        int wait = 0;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        qla2x00_block_error_handler(cmd);
 
@@ -663,9 +684,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        serial = cmd->serial_number;
 
        /* Check active list for command command. */
-       spin_lock_irqsave(&ha->hardware_lock, flags);
+       spin_lock_irqsave(&pha->hardware_lock, flags);
        for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-               sp = ha->outstanding_cmds[i];
+               sp = pha->outstanding_cmds[i];
 
                if (sp == NULL)
                        continue;
@@ -677,8 +698,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                    __func__, ha->host_no, sp, serial));
                DEBUG3(qla2x00_print_scsi_cmd(cmd));
 
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-               if (ha->isp_ops.abort_command(ha, sp)) {
+               spin_unlock_irqrestore(&pha->hardware_lock, flags);
+               if (ha->isp_ops->abort_command(ha, sp)) {
                        DEBUG2(printk("%s(%ld): abort_command "
                            "mbx failed.\n", __func__, ha->host_no));
                } else {
@@ -686,11 +707,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                            "mbx success.\n", __func__, ha->host_no));
                        wait = 1;
                }
-               spin_lock_irqsave(&ha->hardware_lock, flags);
+               spin_lock_irqsave(&pha->hardware_lock, flags);
 
                break;
        }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
        /* Wait for the command to be returned. */
        if (wait) {
@@ -731,6 +752,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
        srb_t           *sp;
        struct scsi_cmnd *cmd;
        unsigned long flags;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        status = 0;
 
@@ -739,19 +761,20 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
         * array
         */
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               sp = ha->outstanding_cmds[cnt];
+               spin_lock_irqsave(&pha->hardware_lock, flags);
+               sp = pha->outstanding_cmds[cnt];
                if (sp) {
                        cmd = sp->cmd;
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-                       if (cmd->device->id == t) {
+                       spin_unlock_irqrestore(&pha->hardware_lock, flags);
+                       if (cmd->device->id == t &&
+                           ha->vp_idx == sp->ha->vp_idx) {
                                if (!qla2x00_eh_wait_on_command(ha, cmd)) {
                                        status = 1;
                                        break;
                                }
                        }
                } else {
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       spin_unlock_irqrestore(&pha->hardware_lock, flags);
                }
        }
        return (status);
@@ -782,14 +805,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -810,7 +831,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 #if defined(LOGOUT_AFTER_DEVICE_RESET)
                if (ret == SUCCESS) {
                        if (fcport->flags & FC_FABRIC_DEVICE) {
-                               ha->isp_ops.fabric_logout(ha, fcport->loop_id);
+                               ha->isp_ops->fabric_logout(ha, fcport->loop_id);
                                qla2x00_mark_device_lost(ha, fcport, 0, 0);
                        }
                }
@@ -912,15 +933,14 @@ static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *pha = to_qla_parent(ha);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -944,7 +964,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
                goto eh_bus_reset_done;
 
        /* Flush outstanding commands. */
-       if (!qla2x00_eh_wait_for_pending_commands(ha))
+       if (!qla2x00_eh_wait_for_pending_commands(pha))
                ret = FAILED;
 
 eh_bus_reset_done:
@@ -974,14 +994,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-       int ret;
+       int ret = FAILED;
        unsigned int id, lun;
        unsigned long serial;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        qla2x00_block_error_handler(cmd);
 
-       ret = FAILED;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
        serial = cmd->serial_number;
@@ -1004,21 +1023,24 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
         * while dpc is stuck for the mailbox to complete.
         */
        qla2x00_wait_for_loop_ready(ha);
-       set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
-       if (qla2x00_abort_isp(ha)) {
-               clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+       if (qla2x00_abort_isp(pha)) {
+               clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
                /* failed. schedule dpc to try */
-               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
 
                if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
                        goto eh_host_reset_lock;
        }
-       clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
 
        /* Waiting for our command in done_queue to be returned to OS.*/
-       if (qla2x00_eh_wait_for_pending_commands(ha))
+       if (qla2x00_eh_wait_for_pending_commands(pha))
                ret = SUCCESS;
 
+       if (ha->parent)
+               qla2x00_vp_abort_isp(ha);
+
 eh_host_reset_lock:
        qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
            (ret == FAILED) ? "failed" : "succeded");
@@ -1101,7 +1123,7 @@ static int
 qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
 {
        /* Abort Target command will clear Reservation */
-       return ha->isp_ops.abort_target(reset_fcport);
+       return ha->isp_ops->abort_target(reset_fcport);
 }
 
 static int
@@ -1180,8 +1202,8 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
                    !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
                        /* Ok, a 64bit DMA mask is applicable. */
                        ha->flags.enable_64bit_addressing = 1;
-                       ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
-                       ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
+                       ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
+                       ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
                        return;
                }
        }
@@ -1190,6 +1212,193 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
        pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
 }
 
+static void
+qla2x00_enable_intrs(scsi_qla_host_t *ha)
+{
+       unsigned long flags = 0;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       ha->interrupts_on = 1;
+       /* enable risc and host interrupts */
+       WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
+       RD_REG_WORD(&reg->ictrl);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+static void
+qla2x00_disable_intrs(scsi_qla_host_t *ha)
+{
+       unsigned long flags = 0;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       ha->interrupts_on = 0;
+       /* disable risc and host interrupts */
+       WRT_REG_WORD(&reg->ictrl, 0);
+       RD_REG_WORD(&reg->ictrl);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_enable_intrs(scsi_qla_host_t *ha)
+{
+       unsigned long flags = 0;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       ha->interrupts_on = 1;
+       WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
+       RD_REG_DWORD(&reg->ictrl);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_disable_intrs(scsi_qla_host_t *ha)
+{
+       unsigned long flags = 0;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       ha->interrupts_on = 0;
+       WRT_REG_DWORD(&reg->ictrl, 0);
+       RD_REG_DWORD(&reg->ictrl);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static struct isp_operations qla2100_isp_ops = {
+       .pci_config             = qla2100_pci_config,
+       .reset_chip             = qla2x00_reset_chip,
+       .chip_diag              = qla2x00_chip_diag,
+       .config_rings           = qla2x00_config_rings,
+       .reset_adapter          = qla2x00_reset_adapter,
+       .nvram_config           = qla2x00_nvram_config,
+       .update_fw_options      = qla2x00_update_fw_options,
+       .load_risc              = qla2x00_load_risc,
+       .pci_info_str           = qla2x00_pci_info_str,
+       .fw_version_str         = qla2x00_fw_version_str,
+       .intr_handler           = qla2100_intr_handler,
+       .enable_intrs           = qla2x00_enable_intrs,
+       .disable_intrs          = qla2x00_disable_intrs,
+       .abort_command          = qla2x00_abort_command,
+       .abort_target           = qla2x00_abort_target,
+       .fabric_login           = qla2x00_login_fabric,
+       .fabric_logout          = qla2x00_fabric_logout,
+       .calc_req_entries       = qla2x00_calc_iocbs_32,
+       .build_iocbs            = qla2x00_build_scsi_iocbs_32,
+       .prep_ms_iocb           = qla2x00_prep_ms_iocb,
+       .prep_ms_fdmi_iocb      = qla2x00_prep_ms_fdmi_iocb,
+       .read_nvram             = qla2x00_read_nvram_data,
+       .write_nvram            = qla2x00_write_nvram_data,
+       .fw_dump                = qla2100_fw_dump,
+       .beacon_on              = NULL,
+       .beacon_off             = NULL,
+       .beacon_blink           = NULL,
+       .read_optrom            = qla2x00_read_optrom_data,
+       .write_optrom           = qla2x00_write_optrom_data,
+       .get_flash_version      = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla2300_isp_ops = {
+       .pci_config             = qla2300_pci_config,
+       .reset_chip             = qla2x00_reset_chip,
+       .chip_diag              = qla2x00_chip_diag,
+       .config_rings           = qla2x00_config_rings,
+       .reset_adapter          = qla2x00_reset_adapter,
+       .nvram_config           = qla2x00_nvram_config,
+       .update_fw_options      = qla2x00_update_fw_options,
+       .load_risc              = qla2x00_load_risc,
+       .pci_info_str           = qla2x00_pci_info_str,
+       .fw_version_str         = qla2x00_fw_version_str,
+       .intr_handler           = qla2300_intr_handler,
+       .enable_intrs           = qla2x00_enable_intrs,
+       .disable_intrs          = qla2x00_disable_intrs,
+       .abort_command          = qla2x00_abort_command,
+       .abort_target           = qla2x00_abort_target,
+       .fabric_login           = qla2x00_login_fabric,
+       .fabric_logout          = qla2x00_fabric_logout,
+       .calc_req_entries       = qla2x00_calc_iocbs_32,
+       .build_iocbs            = qla2x00_build_scsi_iocbs_32,
+       .prep_ms_iocb           = qla2x00_prep_ms_iocb,
+       .prep_ms_fdmi_iocb      = qla2x00_prep_ms_fdmi_iocb,
+       .read_nvram             = qla2x00_read_nvram_data,
+       .write_nvram            = qla2x00_write_nvram_data,
+       .fw_dump                = qla2300_fw_dump,
+       .beacon_on              = qla2x00_beacon_on,
+       .beacon_off             = qla2x00_beacon_off,
+       .beacon_blink           = qla2x00_beacon_blink,
+       .read_optrom            = qla2x00_read_optrom_data,
+       .write_optrom           = qla2x00_write_optrom_data,
+       .get_flash_version      = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla24xx_isp_ops = {
+       .pci_config             = qla24xx_pci_config,
+       .reset_chip             = qla24xx_reset_chip,
+       .chip_diag              = qla24xx_chip_diag,
+       .config_rings           = qla24xx_config_rings,
+       .reset_adapter          = qla24xx_reset_adapter,
+       .nvram_config           = qla24xx_nvram_config,
+       .update_fw_options      = qla24xx_update_fw_options,
+       .load_risc              = qla24xx_load_risc,
+       .pci_info_str           = qla24xx_pci_info_str,
+       .fw_version_str         = qla24xx_fw_version_str,
+       .intr_handler           = qla24xx_intr_handler,
+       .enable_intrs           = qla24xx_enable_intrs,
+       .disable_intrs          = qla24xx_disable_intrs,
+       .abort_command          = qla24xx_abort_command,
+       .abort_target           = qla24xx_abort_target,
+       .fabric_login           = qla24xx_login_fabric,
+       .fabric_logout          = qla24xx_fabric_logout,
+       .calc_req_entries       = NULL,
+       .build_iocbs            = NULL,
+       .prep_ms_iocb           = qla24xx_prep_ms_iocb,
+       .prep_ms_fdmi_iocb      = qla24xx_prep_ms_fdmi_iocb,
+       .read_nvram             = qla24xx_read_nvram_data,
+       .write_nvram            = qla24xx_write_nvram_data,
+       .fw_dump                = qla24xx_fw_dump,
+       .beacon_on              = qla24xx_beacon_on,
+       .beacon_off             = qla24xx_beacon_off,
+       .beacon_blink           = qla24xx_beacon_blink,
+       .read_optrom            = qla24xx_read_optrom_data,
+       .write_optrom           = qla24xx_write_optrom_data,
+       .get_flash_version      = qla24xx_get_flash_version,
+};
+
+static struct isp_operations qla25xx_isp_ops = {
+       .pci_config             = qla25xx_pci_config,
+       .reset_chip             = qla24xx_reset_chip,
+       .chip_diag              = qla24xx_chip_diag,
+       .config_rings           = qla24xx_config_rings,
+       .reset_adapter          = qla24xx_reset_adapter,
+       .nvram_config           = qla24xx_nvram_config,
+       .update_fw_options      = qla24xx_update_fw_options,
+       .load_risc              = qla24xx_load_risc,
+       .pci_info_str           = qla24xx_pci_info_str,
+       .fw_version_str         = qla24xx_fw_version_str,
+       .intr_handler           = qla24xx_intr_handler,
+       .enable_intrs           = qla24xx_enable_intrs,
+       .disable_intrs          = qla24xx_disable_intrs,
+       .abort_command          = qla24xx_abort_command,
+       .abort_target           = qla24xx_abort_target,
+       .fabric_login           = qla24xx_login_fabric,
+       .fabric_logout          = qla24xx_fabric_logout,
+       .calc_req_entries       = NULL,
+       .build_iocbs            = NULL,
+       .prep_ms_iocb           = qla24xx_prep_ms_iocb,
+       .prep_ms_fdmi_iocb      = qla24xx_prep_ms_fdmi_iocb,
+       .read_nvram             = qla25xx_read_nvram_data,
+       .write_nvram            = qla25xx_write_nvram_data,
+       .fw_dump                = qla25xx_fw_dump,
+       .beacon_on              = qla24xx_beacon_on,
+       .beacon_off             = qla24xx_beacon_off,
+       .beacon_blink           = qla24xx_beacon_blink,
+       .read_optrom            = qla25xx_read_optrom_data,
+       .write_optrom           = qla24xx_write_optrom_data,
+       .get_flash_version      = qla24xx_get_flash_version,
+};
+
 static inline void
 qla2x00_set_isp_flags(scsi_qla_host_t *ha)
 {
@@ -1234,19 +1443,32 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
        case PCI_DEVICE_ID_QLOGIC_ISP2422:
                ha->device_type |= DT_ISP2422;
                ha->device_type |= DT_ZIO_SUPPORTED;
+               ha->device_type |= DT_FWI2;
+               ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2432:
                ha->device_type |= DT_ISP2432;
                ha->device_type |= DT_ZIO_SUPPORTED;
+               ha->device_type |= DT_FWI2;
+               ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP5422:
                ha->device_type |= DT_ISP5422;
+               ha->device_type |= DT_FWI2;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP5432:
                ha->device_type |= DT_ISP5432;
+               ha->device_type |= DT_FWI2;
+               ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+               break;
+       case PCI_DEVICE_ID_QLOGIC_ISP2532:
+               ha->device_type |= DT_ISP2532;
+               ha->device_type |= DT_ZIO_SUPPORTED;
+               ha->device_type |= DT_FWI2;
+               ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        }
@@ -1318,61 +1540,6 @@ iospace_error_exit:
        return (-ENOMEM);
 }
 
-static void
-qla2x00_enable_intrs(scsi_qla_host_t *ha)
-{
-       unsigned long flags = 0;
-       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       ha->interrupts_on = 1;
-       /* enable risc and host interrupts */
-       WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
-       RD_REG_WORD(&reg->ictrl);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-}
-
-static void
-qla2x00_disable_intrs(scsi_qla_host_t *ha)
-{
-       unsigned long flags = 0;
-       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       ha->interrupts_on = 0;
-       /* disable risc and host interrupts */
-       WRT_REG_WORD(&reg->ictrl, 0);
-       RD_REG_WORD(&reg->ictrl);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_enable_intrs(scsi_qla_host_t *ha)
-{
-       unsigned long flags = 0;
-       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       ha->interrupts_on = 1;
-       WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
-       RD_REG_DWORD(&reg->ictrl);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_disable_intrs(scsi_qla_host_t *ha)
-{
-       unsigned long flags = 0;
-       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       ha->interrupts_on = 0;
-       WRT_REG_DWORD(&reg->ictrl, 0);
-       RD_REG_DWORD(&reg->ictrl);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
 static void
 qla2xxx_scan_start(struct Scsi_Host *shost)
 {
@@ -1407,18 +1574,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        struct Scsi_Host *host;
        scsi_qla_host_t *ha;
        unsigned long   flags = 0;
-       char pci_info[20];
+       char pci_info[30];
        char fw_str[30];
        struct scsi_host_template *sht;
 
        if (pci_enable_device(pdev))
                goto probe_out;
 
+       if (pci_find_aer_capability(pdev))
+               if (pci_enable_pcie_error_reporting(pdev))
+                       goto probe_out;
+
        sht = &qla2x00_driver_template;
        if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
-           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
+           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
+           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532)
                sht = &qla24xx_driver_template;
        host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
        if (host == NULL) {
@@ -1435,6 +1607,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->host = host;
        ha->host_no = host->host_no;
        sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+       ha->parent = NULL;
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -1452,7 +1625,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ha->prev_topology = 0;
        ha->init_cb_size = sizeof(init_cb_t);
-       ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+       ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
        ha->optrom_size = OPTROM_SIZE_2300;
 
@@ -1461,33 +1634,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->max_q_depth = ql2xmaxqdepth;
 
        /* Assign ISP specific operations. */
-       ha->isp_ops.pci_config          = qla2100_pci_config;
-       ha->isp_ops.reset_chip          = qla2x00_reset_chip;
-       ha->isp_ops.chip_diag           = qla2x00_chip_diag;
-       ha->isp_ops.config_rings        = qla2x00_config_rings;
-       ha->isp_ops.reset_adapter       = qla2x00_reset_adapter;
-       ha->isp_ops.nvram_config        = qla2x00_nvram_config;
-       ha->isp_ops.update_fw_options   = qla2x00_update_fw_options;
-       ha->isp_ops.load_risc           = qla2x00_load_risc;
-       ha->isp_ops.pci_info_str        = qla2x00_pci_info_str;
-       ha->isp_ops.fw_version_str      = qla2x00_fw_version_str;
-       ha->isp_ops.intr_handler        = qla2100_intr_handler;
-       ha->isp_ops.enable_intrs        = qla2x00_enable_intrs;
-       ha->isp_ops.disable_intrs       = qla2x00_disable_intrs;
-       ha->isp_ops.abort_command       = qla2x00_abort_command;
-       ha->isp_ops.abort_target        = qla2x00_abort_target;
-       ha->isp_ops.fabric_login        = qla2x00_login_fabric;
-       ha->isp_ops.fabric_logout       = qla2x00_fabric_logout;
-       ha->isp_ops.calc_req_entries    = qla2x00_calc_iocbs_32;
-       ha->isp_ops.build_iocbs         = qla2x00_build_scsi_iocbs_32;
-       ha->isp_ops.prep_ms_iocb        = qla2x00_prep_ms_iocb;
-       ha->isp_ops.prep_ms_fdmi_iocb   = qla2x00_prep_ms_fdmi_iocb;
-       ha->isp_ops.read_nvram          = qla2x00_read_nvram_data;
-       ha->isp_ops.write_nvram         = qla2x00_write_nvram_data;
-       ha->isp_ops.fw_dump             = qla2100_fw_dump;
-       ha->isp_ops.read_optrom         = qla2x00_read_optrom_data;
-       ha->isp_ops.write_optrom        = qla2x00_write_optrom_data;
-       ha->isp_ops.get_flash_version   = qla2x00_get_flash_version;
        if (IS_QLA2100(ha)) {
                host->max_id = MAX_TARGETS_2100;
                ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1496,6 +1642,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
                host->sg_tablesize = 32;
                ha->gid_list_info_size = 4;
+               ha->isp_ops = &qla2100_isp_ops;
        } else if (IS_QLA2200(ha)) {
                host->max_id = MAX_TARGETS_2200;
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1503,59 +1650,39 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
                ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
                ha->gid_list_info_size = 4;
+               ha->isp_ops = &qla2100_isp_ops;
        } else if (IS_QLA23XX(ha)) {
                host->max_id = MAX_TARGETS_2200;
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                ha->request_q_length = REQUEST_ENTRY_CNT_2200;
                ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
                ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
-               ha->isp_ops.pci_config = qla2300_pci_config;
-               ha->isp_ops.intr_handler = qla2300_intr_handler;
-               ha->isp_ops.fw_dump = qla2300_fw_dump;
-               ha->isp_ops.beacon_on = qla2x00_beacon_on;
-               ha->isp_ops.beacon_off = qla2x00_beacon_off;
-               ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
                ha->gid_list_info_size = 6;
                if (IS_QLA2322(ha) || IS_QLA6322(ha))
                        ha->optrom_size = OPTROM_SIZE_2322;
+               ha->isp_ops = &qla2300_isp_ops;
        } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
                host->max_id = MAX_TARGETS_2200;
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
                ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
                ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
-               ha->init_cb_size = sizeof(struct init_cb_24xx);
-               ha->mgmt_svr_loop_id = 10;
-               ha->isp_ops.pci_config = qla24xx_pci_config;
-               ha->isp_ops.reset_chip = qla24xx_reset_chip;
-               ha->isp_ops.chip_diag = qla24xx_chip_diag;
-               ha->isp_ops.config_rings = qla24xx_config_rings;
-               ha->isp_ops.reset_adapter = qla24xx_reset_adapter;
-               ha->isp_ops.nvram_config = qla24xx_nvram_config;
-               ha->isp_ops.update_fw_options = qla24xx_update_fw_options;
-               ha->isp_ops.load_risc = qla24xx_load_risc;
-               ha->isp_ops.pci_info_str = qla24xx_pci_info_str;
-               ha->isp_ops.fw_version_str = qla24xx_fw_version_str;
-               ha->isp_ops.intr_handler = qla24xx_intr_handler;
-               ha->isp_ops.enable_intrs = qla24xx_enable_intrs;
-               ha->isp_ops.disable_intrs = qla24xx_disable_intrs;
-               ha->isp_ops.abort_command = qla24xx_abort_command;
-               ha->isp_ops.abort_target = qla24xx_abort_target;
-               ha->isp_ops.fabric_login = qla24xx_login_fabric;
-               ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
-               ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
-               ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
-               ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
-               ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
-               ha->isp_ops.fw_dump = qla24xx_fw_dump;
-               ha->isp_ops.read_optrom = qla24xx_read_optrom_data;
-               ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
-               ha->isp_ops.beacon_on = qla24xx_beacon_on;
-               ha->isp_ops.beacon_off = qla24xx_beacon_off;
-               ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
-               ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
+               ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+               ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
                ha->gid_list_info_size = 8;
                ha->optrom_size = OPTROM_SIZE_24XX;
+               ha->isp_ops = &qla24xx_isp_ops;
+       } else if (IS_QLA25XX(ha)) {
+               host->max_id = MAX_TARGETS_2200;
+               ha->mbx_count = MAILBOX_REGISTER_COUNT;
+               ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
+               ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
+               ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
+               ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+               ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
+               ha->gid_list_info_size = 8;
+               ha->optrom_size = OPTROM_SIZE_25XX;
+               ha->isp_ops = &qla25xx_isp_ops;
        }
        host->can_queue = ha->request_q_length + 128;
 
@@ -1563,10 +1690,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->instance = num_hosts;
 
        init_MUTEX(&ha->mbx_cmd_sem);
+       init_MUTEX(&ha->vport_sem);
        init_MUTEX_LOCKED(&ha->mbx_intr_sem);
 
        INIT_LIST_HEAD(&ha->list);
        INIT_LIST_HEAD(&ha->fcports);
+       INIT_LIST_HEAD(&ha->vp_list);
+
+       set_bit(0, (unsigned long *) ha->vp_idx_map);
 
        qla2x00_config_dma_addressing(ha);
        if (qla2x00_mem_alloc(ha)) {
@@ -1619,11 +1750,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
            ha->host_no, ha));
 
-       ha->isp_ops.disable_intrs(ha);
+       ha->isp_ops->disable_intrs(ha);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        reg = ha->iobase;
-       if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+       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);
        } else {
@@ -1645,7 +1776,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       ha->isp_ops.enable_intrs(ha);
+       ha->isp_ops->enable_intrs(ha);
 
        pci_set_drvdata(pdev, ha);
 
@@ -1670,9 +1801,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            "  ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
            qla2x00_version_str, ha->model_number,
            ha->model_desc ? ha->model_desc: "", pdev->device,
-           ha->isp_ops.pci_info_str(ha, pci_info), pci_name(pdev),
+           ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev),
            ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
-           ha->isp_ops.fw_version_str(ha, fw_str));
+           ha->isp_ops->fw_version_str(ha, fw_str));
 
        return 0;
 
@@ -1738,7 +1869,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
 
        /* turn-off interrupts on the card */
        if (ha->interrupts_on)
-               ha->isp_ops.disable_intrs(ha);
+               ha->isp_ops->disable_intrs(ha);
 
        qla2x00_mem_free(ha);
 
@@ -1789,7 +1920,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
 void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
     int do_login, int defer)
 {
-       if (atomic_read(&fcport->state) == FCS_ONLINE)
+       if (atomic_read(&fcport->state) == FCS_ONLINE &&
+           ha->vp_idx == fcport->vp_idx)
                qla2x00_schedule_rport_del(ha, fcport, defer);
 
        /*
@@ -1840,19 +1972,23 @@ void
 qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 {
        fc_port_t *fcport;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
-       list_for_each_entry(fcport, &ha->fcports, list) {
-               if (fcport->port_type != FCT_TARGET)
+       list_for_each_entry(fcport, &pha->fcports, list) {
+               if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
                        continue;
-
                /*
                 * No point in marking the device as lost, if the device is
                 * already DEAD.
                 */
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
                        continue;
-               if (atomic_read(&fcport->state) == FCS_ONLINE)
-                       qla2x00_schedule_rport_del(ha, fcport, defer);
+               if (atomic_read(&fcport->state) == FCS_ONLINE) {
+                       if (defer)
+                               qla2x00_schedule_rport_del(ha, fcport, defer);
+                       else if (ha->vp_idx == fcport->vp_idx)
+                               qla2x00_schedule_rport_del(ha, fcport, defer);
+               }
                atomic_set(&fcport->state, FCS_DEVICE_LOST);
        }
 
@@ -1868,7 +2004,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 *      0  = success.
 *      1  = failure.
 */
-static uint8_t
+uint8_t
 qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
        char    name[16];
@@ -1920,33 +2056,33 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
                        continue;
                }
 
-               snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
-                   ha->host_no);
-               ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
-                   DMA_POOL_SIZE, 8, 0);
-               if (ha->s_dma_pool == NULL) {
+               /* get consistent memory allocated for init control block */
+               ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+                   ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+               if (ha->init_cb == NULL) {
                        qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - s_dma_pool\n");
+                           "Memory Allocation failed - init_cb\n");
 
                        qla2x00_mem_free(ha);
                        msleep(100);
 
                        continue;
                }
+               memset(ha->init_cb, 0, ha->init_cb_size);
 
-               /* get consistent memory allocated for init control block */
-               ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
-                   &ha->init_cb_dma);
-               if (ha->init_cb == NULL) {
+               snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
+                   ha->host_no);
+               ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+                   DMA_POOL_SIZE, 8, 0);
+               if (ha->s_dma_pool == NULL) {
                        qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - init_cb\n");
+                           "Memory Allocation failed - s_dma_pool\n");
 
                        qla2x00_mem_free(ha);
                        msleep(100);
 
                        continue;
                }
-               memset(ha->init_cb, 0, ha->init_cb_size);
 
                if (qla2x00_allocate_sp_pool(ha)) {
                        qla_printk(KERN_WARNING, ha,
@@ -2011,7 +2147,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
                        }
                        memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
 
-                       if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+                       if (IS_FWI2_CAPABLE(ha)) {
                                /*
                                 * Get consistent memory allocated for SFP
                                 * block.
@@ -2032,6 +2168,19 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
                        }
                }
 
+               /* Get memory for cached NVRAM */
+               ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
+               if (ha->nvram == NULL) {
+                       /* error */
+                       qla_printk(KERN_WARNING, ha,
+                           "Memory Allocation failed - nvram cache\n");
+
+                       qla2x00_mem_free(ha);
+                       msleep(100);
+
+                       continue;
+               }
+
                /* Done all allocations without any error. */
                status = 0;
 
@@ -2052,7 +2201,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 * Input:
 *      ha = adapter block pointer.
 */
-static void
+void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
        struct list_head        *fcpl, *fcptemp;
@@ -2088,12 +2237,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
        if (ha->ms_iocb)
                dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
-       if (ha->init_cb)
-               dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
-
        if (ha->s_dma_pool)
                dma_pool_destroy(ha->s_dma_pool);
 
+       if (ha->init_cb)
+               dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
+                   ha->init_cb, ha->init_cb_dma);
+
        if (ha->gid_list)
                dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
                    ha->gid_list_dma);
@@ -2143,6 +2293,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
        ha->fw_dump_reading = 0;
 
        vfree(ha->optrom_buffer);
+       kfree(ha->nvram);
 }
 
 /*
@@ -2199,6 +2350,7 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
 static int
 qla2x00_do_dpc(void *data)
 {
+       int             rval;
        scsi_qla_host_t *ha;
        fc_port_t       *fcport;
        uint8_t         status;
@@ -2285,11 +2437,10 @@ qla2x00_do_dpc(void *data)
                                if (atomic_read(&fcport->state) != FCS_ONLINE &&
                                    fcport->login_retry) {
 
-                                       fcport->login_retry--;
                                        if (fcport->flags & FCF_FABRIC_DEVICE) {
                                                if (fcport->flags &
                                                    FCF_TAPE_PRESENT)
-                                                       ha->isp_ops.fabric_logout(
+                                                       ha->isp_ops->fabric_logout(
                                                            ha, fcport->loop_id,
                                                            fcport->d_id.b.domain,
                                                            fcport->d_id.b.area,
@@ -2301,6 +2452,7 @@ qla2x00_do_dpc(void *data)
                                                    qla2x00_local_device_login(
                                                        ha, fcport);
 
+                                       fcport->login_retry--;
                                        if (status == QLA_SUCCESS) {
                                                fcport->old_loop_id = fcport->loop_id;
 
@@ -2318,6 +2470,8 @@ qla2x00_do_dpc(void *data)
                                        } else {
                                                fcport->login_retry = 0;
                                        }
+                                       if (fcport->login_retry == 0)
+                                               fcport->loop_id = FC_NO_LOOP_ID;
                                }
                                if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
                                        break;
@@ -2347,7 +2501,7 @@ qla2x00_do_dpc(void *data)
                        if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
                            &ha->dpc_flags))) {
 
-                               qla2x00_loop_resync(ha);
+                               rval = qla2x00_loop_resync(ha);
 
                                clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
                        }
@@ -2369,10 +2523,12 @@ qla2x00_do_dpc(void *data)
                }
 
                if (!ha->interrupts_on)
-                       ha->isp_ops.enable_intrs(ha);
+                       ha->isp_ops->enable_intrs(ha);
 
                if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
-                       ha->isp_ops.beacon_blink(ha);
+                       ha->isp_ops->beacon_blink(ha);
+
+               qla2x00_do_dpc_all_vps(ha);
 
                ha->dpc_active = 0;
        } /* End of while(1) */
@@ -2426,13 +2582,7 @@ qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp)
        struct scsi_cmnd *cmd = sp->cmd;
 
        if (sp->flags & SRB_DMA_VALID) {
-               if (cmd->use_sg) {
-                       dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
-                           cmd->use_sg, cmd->sc_data_direction);
-               } else if (cmd->request_bufflen) {
-                       dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
-                           cmd->request_bufflen, cmd->sc_data_direction);
-               }
+               scsi_dma_unmap(cmd);
                sp->flags &= ~SRB_DMA_VALID;
        }
        CMD_SP(cmd) = NULL;
@@ -2458,7 +2608,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
 *
 * Context: Interrupt
 ***************************************************************************/
-static void
+void
 qla2x00_timer(scsi_qla_host_t *ha)
 {
        unsigned long   cpu_flags = 0;
@@ -2467,6 +2617,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
        int             index;
        srb_t           *sp;
        int             t;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        /*
         * Ports - Port down timer.
@@ -2512,23 +2663,29 @@ qla2x00_timer(scsi_qla_host_t *ha)
                                atomic_set(&ha->loop_state, LOOP_DEAD);
 
                        /* Schedule an ISP abort to return any tape commands. */
-                       spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
-                       for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
-                           index++) {
-                               fc_port_t *sfcp;
-
-                               sp = ha->outstanding_cmds[index];
-                               if (!sp)
-                                       continue;
-                               sfcp = sp->fcport;
-                               if (!(sfcp->flags & FCF_TAPE_PRESENT))
-                                       continue;
+                       /* NPIV - scan physical port only */
+                       if (!ha->parent) {
+                               spin_lock_irqsave(&ha->hardware_lock,
+                                   cpu_flags);
+                               for (index = 1;
+                                   index < MAX_OUTSTANDING_COMMANDS;
+                                   index++) {
+                                       fc_port_t *sfcp;
+
+                                       sp = ha->outstanding_cmds[index];
+                                       if (!sp)
+                                               continue;
+                                       sfcp = sp->fcport;
+                                       if (!(sfcp->flags & FCF_TAPE_PRESENT))
+                                               continue;
 
-                               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
-                               break;
+                                       set_bit(ISP_ABORT_NEEDED,
+                                           &ha->dpc_flags);
+                                       break;
+                               }
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                   cpu_flags);
                        }
-                       spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
-
                        set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
                        start_dpc++;
                }
@@ -2572,8 +2729,9 @@ qla2x00_timer(scsi_qla_host_t *ha)
            test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
            test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
            test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+           test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
            test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
-               qla2xxx_wake_dpc(ha);
+               qla2xxx_wake_dpc(pha);
 
        qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
@@ -2590,25 +2748,27 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
                        return 0;
                if (msleep_interruptible(step))
                        break;
-       } while (--iterations >= 0);
+       } while (--iterations > 0);
 
        return -ETIMEDOUT;
 }
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS       5
+#define FW_BLOBS       6
 #define FW_ISP21XX     0
 #define FW_ISP22XX     1
 #define FW_ISP2300     2
 #define FW_ISP2322     3
 #define FW_ISP24XX     4
+#define FW_ISP25XX     5
 
 #define FW_FILE_ISP21XX        "ql2100_fw.bin"
 #define FW_FILE_ISP22XX        "ql2200_fw.bin"
 #define FW_FILE_ISP2300        "ql2300_fw.bin"
 #define FW_FILE_ISP2322        "ql2322_fw.bin"
 #define FW_FILE_ISP24XX        "ql2400_fw.bin"
+#define FW_FILE_ISP25XX        "ql2500_fw.bin"
 
 static DECLARE_MUTEX(qla_fw_lock);
 
@@ -2618,6 +2778,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
        { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
        { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
        { .name = FW_FILE_ISP24XX, },
+       { .name = FW_FILE_ISP25XX, },
 };
 
 struct fw_blob *
@@ -2636,6 +2797,8 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
                blob = &qla_fw_blobs[FW_ISP2322];
        } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
                blob = &qla_fw_blobs[FW_ISP24XX];
+       } else if (IS_QLA25XX(ha)) {
+               blob = &qla_fw_blobs[FW_ISP25XX];
        }
 
        down(&qla_fw_lock);
@@ -2667,6 +2830,105 @@ qla2x00_release_firmware(void)
        up(&qla_fw_lock);
 }
 
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       switch (state) {
+       case pci_channel_io_normal:
+               return PCI_ERS_RESULT_CAN_RECOVER;
+       case pci_channel_io_frozen:
+               pci_disable_device(pdev);
+               return PCI_ERS_RESULT_NEED_RESET;
+       case pci_channel_io_perm_failure:
+               qla2x00_remove_one(pdev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       int risc_paused = 0;
+       uint32_t stat;
+       unsigned long flags;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+               stat = RD_REG_DWORD(&reg->hccr);
+               if (stat & HCCR_RISC_PAUSE)
+                       risc_paused = 1;
+       } else if (IS_QLA23XX(ha)) {
+               stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+               if (stat & HSR_RISC_PAUSED)
+                       risc_paused = 1;
+       } else if (IS_FWI2_CAPABLE(ha)) {
+               stat = RD_REG_DWORD(&reg24->host_status);
+               if (stat & HSRX_RISC_PAUSED)
+                       risc_paused = 1;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       if (risc_paused) {
+               qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+                   "Dumping firmware!\n");
+               ha->isp_ops->fw_dump(ha, 0);
+
+               return PCI_ERS_RESULT_NEED_RESET;
+       } else
+               return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+       pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+       if (pci_enable_device(pdev)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Can't re-enable PCI device after reset.\n");
+
+               return ret;
+       }
+       pci_set_master(pdev);
+
+       if (ha->isp_ops->pci_config(ha))
+               return ret;
+
+       set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+               ret =  PCI_ERS_RESULT_RECOVERED;
+       clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+       return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = qla2x00_wait_for_hba_online(ha);
+       if (ret != QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                   "the device failed to resume I/O "
+                   "from slot/link_reset");
+       }
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+       .error_detected = qla2xxx_pci_error_detected,
+       .mmio_enabled = qla2xxx_pci_mmio_enabled,
+       .slot_reset = qla2xxx_pci_slot_reset,
+       .resume = qla2xxx_pci_resume,
+};
+
 static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2679,6 +2941,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
        { 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -2691,6 +2954,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = __devexit_p(qla2x00_remove_one),
+       .err_handler    = &qla2xxx_err_handler,
 };
 
 /**
@@ -2703,7 +2967,7 @@ qla2x00_module_init(void)
 
        /* Allocate cache for SRBs. */
        srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
-           SLAB_HWCACHE_ALIGN, NULL, NULL);
+           SLAB_HWCACHE_ALIGN, NULL);
        if (srb_cachep == NULL) {
                printk(KERN_ERR
                    "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
@@ -2717,14 +2981,24 @@ qla2x00_module_init(void)
 
        qla2xxx_transport_template =
            fc_attach_transport(&qla2xxx_transport_functions);
-       if (!qla2xxx_transport_template)
+       if (!qla2xxx_transport_template) {
+               kmem_cache_destroy(srb_cachep);
+               return -ENODEV;
+       }
+       qla2xxx_transport_vport_template =
+           fc_attach_transport(&qla2xxx_transport_vport_functions);
+       if (!qla2xxx_transport_vport_template) {
+               kmem_cache_destroy(srb_cachep);
+               fc_release_transport(qla2xxx_transport_template);
                return -ENODEV;
+       }
 
        printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
        ret = pci_register_driver(&qla2xxx_pci_driver);
        if (ret) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
+               fc_release_transport(qla2xxx_transport_vport_template);
        }
        return ret;
 }
@@ -2739,6 +3013,7 @@ qla2x00_module_exit(void)
        qla2x00_release_firmware();
        kmem_cache_destroy(srb_cachep);
        fc_release_transport(qla2xxx_transport_template);
+       fc_release_transport(qla2xxx_transport_vport_template);
 }
 
 module_init(qla2x00_module_init);