]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/qla2xxx/qla_os.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / drivers / scsi / qla2xxx / qla_os.c
index 1e4bff695254b4fb6a4adbc1008ba4a999352088..2c0876c81a3f6e5793d504b825146b6de7c2ae81 100644 (file)
@@ -160,6 +160,11 @@ MODULE_PARM_DESC(ql2xtargetreset,
                 "Enable target reset."
                 "Default is 1 - use hw defaults.");
 
+int ql2xgffidenable;
+module_param(ql2xgffidenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xgffidenable,
+               "Enables GFF_ID checks of port type. "
+               "Default is 0 - Do not use GFF_ID information.");
 
 int ql2xasynctmfenable;
 module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR);
@@ -174,8 +179,7 @@ static int qla2xxx_slave_alloc(struct scsi_device *);
 static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
 static void qla2xxx_scan_start(struct Scsi_Host *);
 static void qla2xxx_slave_destroy(struct scsi_device *);
-static int qla2xxx_queuecommand(struct scsi_cmnd *cmd,
-               void (*fn)(struct scsi_cmnd *));
+static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int qla2xxx_eh_abort(struct scsi_cmnd *);
 static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
@@ -255,6 +259,7 @@ static void qla2x00_rst_aen(scsi_qla_host_t *);
 
 static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t,
        struct req_que **, struct rsp_que **);
+static void qla2x00_free_fw_dump(struct qla_hw_data *);
 static void qla2x00_mem_free(struct qla_hw_data *);
 static void qla2x00_sp_free_dma(srb_t *);
 
@@ -529,7 +534,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
 }
 
 static int
-qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -539,6 +544,7 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        srb_t *sp;
        int rval;
 
+       spin_unlock_irq(vha->host->host_lock);
        if (ha->flags.eeh_busy) {
                if (ha->flags.pci_channel_io_perm_failure)
                        cmd->result = DID_NO_CONNECT << 16;
@@ -553,10 +559,6 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
                goto qc24_fail_command;
        }
 
-       /* Close window on fcport/rport state-transitioning. */
-       if (fcport->drport)
-               goto qc24_target_busy;
-
        if (!vha->flags.difdix_supported &&
                scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
                        DEBUG2(qla_printk(KERN_ERR, ha,
@@ -567,15 +569,14 @@ qla2xxx_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(&base_vha->loop_state) == LOOP_DEAD) {
+                       atomic_read(&fcport->state) == FCS_DEVICE_LOST ||
+                       atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
                goto qc24_target_busy;
        }
 
-       spin_unlock_irq(vha->host->host_lock);
-
        sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done);
        if (!sp)
                goto qc24_host_busy_lock;
@@ -597,14 +598,18 @@ qc24_host_busy_lock:
        return SCSI_MLQUEUE_HOST_BUSY;
 
 qc24_target_busy:
+       spin_lock_irq(vha->host->host_lock);
        return SCSI_MLQUEUE_TARGET_BUSY;
 
 qc24_fail_command:
+       spin_lock_irq(vha->host->host_lock);
        done(cmd);
 
        return 0;
 }
 
+static DEF_SCSI_QCMD(qla2xxx_queuecommand)
+
 
 /*
  * qla2x00_eh_wait_on_command
@@ -824,81 +829,58 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        srb_t *sp;
-       int ret, i;
+       int ret = SUCCESS;
        unsigned int id, lun;
-       unsigned long serial;
        unsigned long flags;
        int wait = 0;
        struct qla_hw_data *ha = vha->hw;
-       struct req_que *req = vha->req;
-       srb_t *spt;
-       int got_ref = 0;
 
        fc_block_scsi_eh(cmd);
 
        if (!CMD_SP(cmd))
                return SUCCESS;
 
-       ret = SUCCESS;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
-       spt = (srb_t *) CMD_SP(cmd);
-       if (!spt)
-               return SUCCESS;
 
-       /* Check active list for command command. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-               sp = req->outstanding_cmds[i];
-
-               if (sp == NULL)
-                       continue;
-               if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) &&
-                   !IS_PROT_IO(sp))
-                       continue;
-               if (sp->cmd != cmd)
-                       continue;
+       sp = (srb_t *) CMD_SP(cmd);
+       if (!sp) {
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return SUCCESS;
+       }
 
-               DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
-               " pid=%ld.\n", __func__, vha->host_no, sp, serial));
+       DEBUG2(printk("%s(%ld): aborting sp %p from RISC.",
+           __func__, vha->host_no, sp));
 
-               /* Get a reference to the sp and drop the lock.*/
-               sp_get(sp);
-               got_ref++;
+       /* Get a reference to the sp and drop the lock.*/
+       sp_get(sp);
 
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-               if (ha->isp_ops->abort_command(sp)) {
-                       DEBUG2(printk("%s(%ld): abort_command "
-                       "mbx failed.\n", __func__, vha->host_no));
-                       ret = FAILED;
-               } else {
-                       DEBUG3(printk("%s(%ld): abort_command "
-                       "mbx success.\n", __func__, vha->host_no));
-                       wait = 1;
-               }
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               break;
-       }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       if (ha->isp_ops->abort_command(sp)) {
+               DEBUG2(printk("%s(%ld): abort_command "
+               "mbx failed.\n", __func__, vha->host_no));
+               ret = FAILED;
+       } else {
+               DEBUG3(printk("%s(%ld): abort_command "
+               "mbx success.\n", __func__, vha->host_no));
+               wait = 1;
+       }
+       qla2x00_sp_compl(ha, sp);
 
        /* Wait for the command to be returned. */
        if (wait) {
                if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
                        qla_printk(KERN_ERR, ha,
-                           "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
-                           "%x.\n", vha->host_no, id, lun, serial, ret);
+                           "scsi(%ld:%d:%d): Abort handler timed out -- %x.\n",
+                           vha->host_no, id, lun, ret);
                        ret = FAILED;
                }
        }
 
-       if (got_ref)
-               qla2x00_sp_compl(ha, sp);
-
        qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
-           vha->host_no, id, lun, wait, serial, ret);
+           "scsi(%ld:%d:%d): Abort command issued -- %d %x.\n",
+           vha->host_no, id, lun, wait, ret);
 
        return ret;
 }
@@ -1043,13 +1025,11 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
-       unsigned long serial;
 
        fc_block_scsi_eh(cmd);
 
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
 
        if (!fcport)
                return ret;
@@ -1104,14 +1084,12 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        struct qla_hw_data *ha = vha->hw;
        int ret = FAILED;
        unsigned int id, lun;
-       unsigned long serial;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
        fc_block_scsi_eh(cmd);
 
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
 
        if (!fcport)
                return ret;
@@ -1295,17 +1273,12 @@ static int
 qla2xxx_slave_configure(struct scsi_device *sdev)
 {
        scsi_qla_host_t *vha = shost_priv(sdev->host);
-       struct qla_hw_data *ha = vha->hw;
-       struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
        struct req_que *req = vha->req;
 
        if (sdev->tagged_supported)
                scsi_activate_tcq(sdev, req->max_q_depth);
        else
                scsi_deactivate_tcq(sdev, req->max_q_depth);
-
-       rport->dev_loss_tmo = ha->port_down_retry_count;
-
        return 0;
 }
 
@@ -1979,6 +1952,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->bars = bars;
        ha->mem_only = mem_only;
        spin_lock_init(&ha->hardware_lock);
+       spin_lock_init(&ha->vport_slock);
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -2090,6 +2064,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
                ha->gid_list_info_size = 8;
                ha->optrom_size = OPTROM_SIZE_82XX;
+               ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
                ha->isp_ops = &qla82xx_isp_ops;
                ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
                ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
@@ -2141,8 +2116,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        else
                base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
                                                base_vha->vp_idx;
-       if (IS_QLA2100(ha))
-               host->sg_tablesize = 32;
+
+       /* Set the SG table size based on ISP type */
+       if (!IS_FWI2_CAPABLE(ha)) {
+               if (IS_QLA2100(ha))
+                       host->sg_tablesize = 32;
+       } else {
+               if (!IS_QLA82XX(ha))
+                       host->sg_tablesize = QLA_SG_ALL;
+       }
+
        host->max_id = max_id;
        host->this_id = 255;
        host->cmd_per_lun = 3;
@@ -2338,6 +2321,42 @@ probe_out:
        return ret;
 }
 
+static void
+qla2x00_shutdown(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data  *ha;
+
+       vha = pci_get_drvdata(pdev);
+       ha = vha->hw;
+
+       /* Turn-off FCE trace */
+       if (ha->flags.fce_enabled) {
+               qla2x00_disable_fce_trace(vha, NULL, NULL);
+               ha->flags.fce_enabled = 0;
+       }
+
+       /* Turn-off EFT trace */
+       if (ha->eft)
+               qla2x00_disable_eft_trace(vha);
+
+       /* Stop currently executing firmware. */
+       qla2x00_try_to_stop_firmware(vha);
+
+       /* Turn adapter off line */
+       vha->flags.online = 0;
+
+       /* turn-off interrupts on the card */
+       if (ha->interrupts_on) {
+               vha->flags.init_done = 0;
+               ha->isp_ops->disable_intrs(ha);
+       }
+
+       qla2x00_free_irqs(vha);
+
+       qla2x00_free_fw_dump(ha);
+}
+
 static void
 qla2x00_remove_one(struct pci_dev *pdev)
 {
@@ -2594,12 +2613,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
                        continue;
                if (atomic_read(&fcport->state) == FCS_ONLINE) {
+                       atomic_set(&fcport->state, FCS_DEVICE_LOST);
                        if (defer)
                                qla2x00_schedule_rport_del(vha, fcport, defer);
                        else if (vha->vp_idx == fcport->vp_idx)
                                qla2x00_schedule_rport_del(vha, fcport, defer);
                }
-               atomic_set(&fcport->state, FCS_DEVICE_LOST);
        }
 }
 
@@ -2827,28 +2846,48 @@ fail:
 }
 
 /*
-* qla2x00_mem_free
-*      Frees all adapter allocated memory.
+* qla2x00_free_fw_dump
+*      Frees fw dump stuff.
 *
 * Input:
-*      ha = adapter block pointer.
+*      ha = adapter block pointer.
 */
 static void
-qla2x00_mem_free(struct qla_hw_data *ha)
+qla2x00_free_fw_dump(struct qla_hw_data *ha)
 {
-       if (ha->srb_mempool)
-               mempool_destroy(ha->srb_mempool);
-
        if (ha->fce)
                dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
-               ha->fce_dma);
+                   ha->fce_dma);
 
        if (ha->fw_dump) {
                if (ha->eft)
                        dma_free_coherent(&ha->pdev->dev,
-                       ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+                           ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
                vfree(ha->fw_dump);
        }
+       ha->fce = NULL;
+       ha->fce_dma = 0;
+       ha->eft = NULL;
+       ha->eft_dma = 0;
+       ha->fw_dump = NULL;
+       ha->fw_dumped = 0;
+       ha->fw_dump_reading = 0;
+}
+
+/*
+* qla2x00_mem_free
+*      Frees all adapter allocated memory.
+*
+* Input:
+*      ha = adapter block pointer.
+*/
+static void
+qla2x00_mem_free(struct qla_hw_data *ha)
+{
+       qla2x00_free_fw_dump(ha);
+
+       if (ha->srb_mempool)
+               mempool_destroy(ha->srb_mempool);
 
        if (ha->dcbx_tlv)
                dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
@@ -2922,8 +2961,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->srb_mempool = NULL;
        ha->ctx_mempool = NULL;
-       ha->eft = NULL;
-       ha->eft_dma = 0;
        ha->sns_cmd = NULL;
        ha->sns_cmd_dma = 0;
        ha->ct_sns = NULL;
@@ -2943,10 +2980,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->gid_list = NULL;
        ha->gid_list_dma = 0;
-
-       ha->fw_dump = NULL;
-       ha->fw_dumped = 0;
-       ha->fw_dump_reading = 0;
 }
 
 struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -3544,49 +3577,24 @@ void
 qla2x00_timer(scsi_qla_host_t *vha)
 {
        unsigned long   cpu_flags = 0;
-       fc_port_t       *fcport;
        int             start_dpc = 0;
        int             index;
        srb_t           *sp;
-       int             t;
        uint16_t        w;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req;
 
+       if (ha->flags.eeh_busy) {
+               qla2x00_restart_timer(vha, WATCH_INTERVAL);
+               return;
+       }
+
        if (IS_QLA82XX(ha))
                qla82xx_watchdog(vha);
 
        /* Hardware read to raise pending EEH errors during mailbox waits. */
        if (!pci_channel_offline(ha->pdev))
                pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
-       /*
-        * Ports - Port down timer.
-        *
-        * Whenever, a port is in the LOST state we start decrementing its port
-        * down timer every second until it reaches zero. Once  it reaches zero
-        * the port it marked DEAD.
-        */
-       t = 0;
-       list_for_each_entry(fcport, &vha->vp_fcports, list) {
-               if (fcport->port_type != FCT_TARGET)
-                       continue;
-
-               if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
-
-                       if (atomic_read(&fcport->port_down_timer) == 0)
-                               continue;
-
-                       if (atomic_dec_and_test(&fcport->port_down_timer) != 0)
-                               atomic_set(&fcport->state, FCS_DEVICE_DEAD);
-
-                       DEBUG(printk("scsi(%ld): fcport-%d - port retry count: "
-                           "%d remaining\n",
-                           vha->host_no,
-                           t, atomic_read(&fcport->port_down_timer)));
-               }
-               t++;
-       } /* End of for fcport  */
-
 
        /* Loop down handler. */
        if (atomic_read(&vha->loop_down_timer) > 0 &&
@@ -3782,8 +3790,21 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
                return PCI_ERS_RESULT_CAN_RECOVER;
        case pci_channel_io_frozen:
                ha->flags.eeh_busy = 1;
+               /* For ISP82XX complete any pending mailbox cmd */
+               if (IS_QLA82XX(ha)) {
+                       ha->flags.fw_hung = 1;
+                       if (ha->flags.mbox_busy) {
+                               ha->flags.mbox_int = 1;
+                               DEBUG2(qla_printk(KERN_ERR, ha,
+                                       "Due to pci channel io frozen, doing premature "
+                                       "completion of mbx command\n"));
+                               complete(&ha->mbx_intr_comp);
+                       }
+               }
                qla2x00_free_irqs(vha);
                pci_disable_device(pdev);
+               /* Return back all IOs */
+               qla2x00_abort_all_cmds(vha, DID_RESET << 16);
                return PCI_ERS_RESULT_NEED_RESET;
        case pci_channel_io_perm_failure:
                ha->flags.pci_channel_io_perm_failure = 1;
@@ -3804,6 +3825,9 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
 
+       if (IS_QLA82XX(ha))
+               return PCI_ERS_RESULT_RECOVERED;
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
        if (IS_QLA2100(ha) || IS_QLA2200(ha)){
                stat = RD_REG_DWORD(&reg->hccr);
@@ -3830,6 +3854,109 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
                return PCI_ERS_RESULT_RECOVERED;
 }
 
+uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
+{
+       uint32_t rval = QLA_FUNCTION_FAILED;
+       uint32_t drv_active = 0;
+       struct qla_hw_data *ha = base_vha->hw;
+       int fn;
+       struct pci_dev *other_pdev = NULL;
+
+       DEBUG17(qla_printk(KERN_INFO, ha,
+           "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no));
+
+       set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+
+       if (base_vha->flags.online) {
+               /* Abort all outstanding commands,
+                * so as to be requeued later */
+               qla2x00_abort_isp_cleanup(base_vha);
+       }
+
+
+       fn = PCI_FUNC(ha->pdev->devfn);
+       while (fn > 0) {
+               fn--;
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "Finding pci device at function = 0x%x\n", fn));
+               other_pdev =
+                   pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
+                   ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
+                   fn));
+
+               if (!other_pdev)
+                       continue;
+               if (atomic_read(&other_pdev->enable_cnt)) {
+                       DEBUG17(qla_printk(KERN_INFO, ha,
+                           "Found PCI func availabe and enabled at 0x%x\n",
+                           fn));
+                       pci_dev_put(other_pdev);
+                       break;
+               }
+               pci_dev_put(other_pdev);
+       }
+
+       if (!fn) {
+               /* Reset owner */
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "This devfn is reset owner = 0x%x\n", ha->pdev->devfn));
+               qla82xx_idc_lock(ha);
+
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                   QLA82XX_DEV_INITIALIZING);
+
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
+                   QLA82XX_IDC_VERSION);
+
+               drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "drv_active = 0x%x\n", drv_active));
+
+               qla82xx_idc_unlock(ha);
+               /* Reset if device is not already reset
+                * drv_active would be 0 if a reset has already been done
+                */
+               if (drv_active)
+                       rval = qla82xx_start_firmware(base_vha);
+               else
+                       rval = QLA_SUCCESS;
+               qla82xx_idc_lock(ha);
+
+               if (rval != QLA_SUCCESS) {
+                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       qla82xx_clear_drv_active(ha);
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                           QLA82XX_DEV_FAILED);
+               } else {
+                       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                           QLA82XX_DEV_READY);
+                       qla82xx_idc_unlock(ha);
+                       ha->flags.fw_hung = 0;
+                       rval = qla82xx_restart_isp(base_vha);
+                       qla82xx_idc_lock(ha);
+                       /* Clear driver state register */
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
+                       qla82xx_set_drv_active(base_vha);
+               }
+               qla82xx_idc_unlock(ha);
+       } else {
+               DEBUG17(qla_printk(KERN_INFO, ha,
+                   "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn));
+               if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
+                   QLA82XX_DEV_READY)) {
+                       ha->flags.fw_hung = 0;
+                       rval = qla82xx_restart_isp(base_vha);
+                       qla82xx_idc_lock(ha);
+                       qla82xx_set_drv_active(base_vha);
+                       qla82xx_idc_unlock(ha);
+               }
+       }
+       clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+
+       return rval;
+}
+
 static pci_ers_result_t
 qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 {
@@ -3862,15 +3989,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
        if (rc) {
                qla_printk(KERN_WARNING, ha,
                    "Can't re-enable PCI device after reset.\n");
-               return ret;
+               goto exit_slot_reset;
        }
 
        rsp = ha->rsp_q_map[0];
        if (qla2x00_request_irqs(ha, rsp))
-               return ret;
+               goto exit_slot_reset;
 
        if (ha->isp_ops->pci_config(base_vha))
-               return ret;
+               goto exit_slot_reset;
+
+       if (IS_QLA82XX(ha)) {
+               if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) {
+                       ret = PCI_ERS_RESULT_RECOVERED;
+                       goto exit_slot_reset;
+               } else
+                       goto exit_slot_reset;
+       }
 
        while (ha->flags.mbox_busy && retries--)
                msleep(1000);
@@ -3881,6 +4016,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
        clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
 
+exit_slot_reset:
        DEBUG17(qla_printk(KERN_WARNING, ha,
            "slot_reset-return:ret=%x\n", ret));
 
@@ -3943,11 +4079,13 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = qla2x00_remove_one,
+       .shutdown       = qla2x00_shutdown,
        .err_handler    = &qla2xxx_err_handler,
 };
 
 static struct file_operations apidev_fops = {
        .owner = THIS_MODULE,
+       .llseek = noop_llseek,
 };
 
 /**