]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/ipr.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / scsi / ipr.c
index 3f5b56a998920e02087fc79767add1c6d3d81612..924b0ba74dfea7aceadbf19673fa72ba6c82b10a 100644 (file)
@@ -1143,6 +1143,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
        res->add_to_ml = 0;
        res->del_from_ml = 0;
        res->resetting_device = 0;
+       res->reset_occurred = 0;
        res->sdev = NULL;
        res->sata_port = NULL;
 
@@ -2366,6 +2367,42 @@ static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
                         be32_to_cpu(hostrcb->hcam.length));
 }
 
+/**
+ * ipr_log_sis64_device_error - Log a cache error.
+ * @ioa_cfg:   ioa config struct
+ * @hostrcb:   hostrcb struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_sis64_device_error(struct ipr_ioa_cfg *ioa_cfg,
+                                        struct ipr_hostrcb *hostrcb)
+{
+       struct ipr_hostrcb_type_21_error *error;
+       char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+       error = &hostrcb->hcam.u.error64.u.type_21_error;
+
+       ipr_err("-----Failing Device Information-----\n");
+       ipr_err("World Wide Unique ID: %08X%08X%08X%08X\n",
+               be32_to_cpu(error->wwn[0]), be32_to_cpu(error->wwn[1]),
+                be32_to_cpu(error->wwn[2]), be32_to_cpu(error->wwn[3]));
+       ipr_err("Device Resource Path: %s\n",
+               __ipr_format_res_path(error->res_path,
+                                     buffer, sizeof(buffer)));
+       error->primary_problem_desc[sizeof(error->primary_problem_desc) - 1] = '\0';
+       error->second_problem_desc[sizeof(error->second_problem_desc) - 1] = '\0';
+       ipr_err("Primary Problem Description: %s\n", error->primary_problem_desc);
+       ipr_err("Secondary Problem Description:  %s\n", error->second_problem_desc);
+       ipr_err("SCSI Sense Data:\n");
+       ipr_log_hex_data(ioa_cfg, error->sense_data, sizeof(error->sense_data));
+       ipr_err("SCSI Command Descriptor Block: \n");
+       ipr_log_hex_data(ioa_cfg, error->cdb, sizeof(error->cdb));
+
+       ipr_err("Additional IOA Data:\n");
+       ipr_log_hex_data(ioa_cfg, error->ioa_data, be32_to_cpu(error->length_of_error));
+}
+
 /**
  * ipr_get_error - Find the specfied IOASC in the ipr_error_table.
  * @ioasc:     IOASC
@@ -2467,6 +2504,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
        case IPR_HOST_RCB_OVERLAY_ID_20:
                ipr_log_fabric_error(ioa_cfg, hostrcb);
                break;
+       case IPR_HOST_RCB_OVERLAY_ID_21:
+               ipr_log_sis64_device_error(ioa_cfg, hostrcb);
+               break;
        case IPR_HOST_RCB_OVERLAY_ID_23:
                ipr_log_sis64_config_error(ioa_cfg, hostrcb);
                break;
@@ -3630,16 +3670,14 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
                return strlen(buf);
        }
 
-       if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
-                       ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+       if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
                for (i = 1; i < ioa_cfg->hrrq_num; i++)
                        blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
        }
 
        spin_lock_irqsave(shost->host_lock, lock_flags);
        ioa_cfg->iopoll_weight = user_iopoll_weight;
-       if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
-                       ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+       if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
                for (i = 1; i < ioa_cfg->hrrq_num; i++) {
                        blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
                                        ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -5015,6 +5053,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
        } else
                rc = ipr_device_reset(ioa_cfg, res);
        res->resetting_device = 0;
+       res->reset_occurred = 1;
 
        LEAVE;
        return rc ? FAILED : SUCCESS;
@@ -5484,8 +5523,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
                return IRQ_NONE;
        }
 
-       if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
-                       ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+       if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
                if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
                       hrrq->toggle_bit) {
                        if (!blk_iopoll_sched_prep(&hrrq->iopoll))
@@ -6183,8 +6221,10 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
                        ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
 
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
-               if (ipr_is_gscsi(res))
+               if (ipr_is_gscsi(res) && res->reset_occurred) {
+                       res->reset_occurred = 0;
                        ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
+               }
                ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
                ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
        }
@@ -8640,6 +8680,25 @@ static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd)
        return IPR_RC_JOB_RETURN;
 }
 
+/**
+ * ipr_pci_mmio_enabled - Called when MMIO has been re-enabled
+ * @pdev:      PCI device struct
+ *
+ * Description: This routine is called to tell us that the MMIO
+ * access to the IOA has been restored
+ */
+static pci_ers_result_t ipr_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       unsigned long flags = 0;
+       struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       if (!ioa_cfg->probe_done)
+               pci_save_state(pdev);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
 /**
  * ipr_pci_frozen - Called when slot has experienced a PCI bus error.
  * @pdev:      PCI device struct
@@ -8654,7 +8713,8 @@ static void ipr_pci_frozen(struct pci_dev *pdev)
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-       _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
+       if (ioa_cfg->probe_done)
+               _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
 
@@ -8672,11 +8732,14 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-       if (ioa_cfg->needs_warm_reset)
-               ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
-       else
-               _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
-                                       IPR_SHUTDOWN_NONE);
+       if (ioa_cfg->probe_done) {
+               if (ioa_cfg->needs_warm_reset)
+                       ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+               else
+                       _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+                                               IPR_SHUTDOWN_NONE);
+       } else
+               wake_up_all(&ioa_cfg->eeh_wait_q);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
        return PCI_ERS_RESULT_RECOVERED;
 }
@@ -8695,17 +8758,20 @@ static void ipr_pci_perm_failure(struct pci_dev *pdev)
        int i;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-       if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
-               ioa_cfg->sdt_state = ABORT_DUMP;
-       ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
-       ioa_cfg->in_ioa_bringdown = 1;
-       for (i = 0; i < ioa_cfg->hrrq_num; i++) {
-               spin_lock(&ioa_cfg->hrrq[i]._lock);
-               ioa_cfg->hrrq[i].allow_cmds = 0;
-               spin_unlock(&ioa_cfg->hrrq[i]._lock);
-       }
-       wmb();
-       ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+       if (ioa_cfg->probe_done) {
+               if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
+                       ioa_cfg->sdt_state = ABORT_DUMP;
+               ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
+               ioa_cfg->in_ioa_bringdown = 1;
+               for (i = 0; i < ioa_cfg->hrrq_num; i++) {
+                       spin_lock(&ioa_cfg->hrrq[i]._lock);
+                       ioa_cfg->hrrq[i].allow_cmds = 0;
+                       spin_unlock(&ioa_cfg->hrrq[i]._lock);
+               }
+               wmb();
+               ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+       } else
+               wake_up_all(&ioa_cfg->eeh_wait_q);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
 
@@ -8725,7 +8791,7 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
        switch (state) {
        case pci_channel_io_frozen:
                ipr_pci_frozen(pdev);
-               return PCI_ERS_RESULT_NEED_RESET;
+               return PCI_ERS_RESULT_CAN_RECOVER;
        case pci_channel_io_perm_failure:
                ipr_pci_perm_failure(pdev);
                return PCI_ERS_RESULT_DISCONNECT;
@@ -8755,6 +8821,7 @@ static int ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
        ENTER;
        spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
        dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg);
+       ioa_cfg->probe_done = 1;
        if (ioa_cfg->needs_hard_reset) {
                ioa_cfg->needs_hard_reset = 0;
                ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
@@ -9030,16 +9097,6 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
        if (!ioa_cfg->vpd_cbs)
                goto out_free_res_entries;
 
-       for (i = 0; i < ioa_cfg->hrrq_num; i++) {
-               INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
-               INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
-               spin_lock_init(&ioa_cfg->hrrq[i]._lock);
-               if (i == 0)
-                       ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
-               else
-                       ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
-       }
-
        if (ipr_alloc_cmd_blks(ioa_cfg))
                goto out_free_vpd_cbs;
 
@@ -9139,6 +9196,48 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
        }
 }
 
+/**
+ * ipr_init_regs - Initialize IOA registers
+ * @ioa_cfg:   ioa config struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_init_regs(struct ipr_ioa_cfg *ioa_cfg)
+{
+       const struct ipr_interrupt_offsets *p;
+       struct ipr_interrupts *t;
+       void __iomem *base;
+
+       p = &ioa_cfg->chip_cfg->regs;
+       t = &ioa_cfg->regs;
+       base = ioa_cfg->hdw_dma_regs;
+
+       t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
+       t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+       t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
+       t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+       t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
+       t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+       t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
+       t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+       t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
+       t->ioarrin_reg = base + p->ioarrin_reg;
+       t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+       t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
+       t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+       t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
+       t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
+       t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
+
+       if (ioa_cfg->sis64) {
+               t->init_feedback_reg = base + p->init_feedback_reg;
+               t->dump_addr_reg = base + p->dump_addr_reg;
+               t->dump_data_reg = base + p->dump_data_reg;
+               t->endian_swap_reg = base + p->endian_swap_reg;
+       }
+}
+
 /**
  * ipr_init_ioa_cfg - Initialize IOA config struct
  * @ioa_cfg:   ioa config struct
@@ -9151,9 +9250,7 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
 static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
                             struct Scsi_Host *host, struct pci_dev *pdev)
 {
-       const struct ipr_interrupt_offsets *p;
-       struct ipr_interrupts *t;
-       void __iomem *base;
+       int i;
 
        ioa_cfg->host = host;
        ioa_cfg->pdev = pdev;
@@ -9173,6 +9270,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
        INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
        init_waitqueue_head(&ioa_cfg->reset_wait_q);
        init_waitqueue_head(&ioa_cfg->msi_wait_q);
+       init_waitqueue_head(&ioa_cfg->eeh_wait_q);
        ioa_cfg->sdt_state = INACTIVE;
 
        ipr_initialize_bus_attr(ioa_cfg);
@@ -9183,44 +9281,33 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
                host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
                if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
                        ioa_cfg->max_devs_supported = IPR_MAX_SIS64_DEVS;
+               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
+                                          + ((sizeof(struct ipr_config_table_entry64)
+                                              * ioa_cfg->max_devs_supported)));
        } else {
                host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
                host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
                if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
                        ioa_cfg->max_devs_supported = IPR_MAX_PHYSICAL_DEVS;
+               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
+                                          + ((sizeof(struct ipr_config_table_entry)
+                                              * ioa_cfg->max_devs_supported)));
        }
+
        host->max_channel = IPR_MAX_BUS_TO_SCAN;
        host->unique_id = host->host_no;
        host->max_cmd_len = IPR_MAX_CDB_LEN;
        host->can_queue = ioa_cfg->max_cmds;
        pci_set_drvdata(pdev, ioa_cfg);
 
-       p = &ioa_cfg->chip_cfg->regs;
-       t = &ioa_cfg->regs;
-       base = ioa_cfg->hdw_dma_regs;
-
-       t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
-       t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
-       t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
-       t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
-       t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
-       t->clr_interrupt_reg = base + p->clr_interrupt_reg;
-       t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
-       t->sense_interrupt_reg = base + p->sense_interrupt_reg;
-       t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
-       t->ioarrin_reg = base + p->ioarrin_reg;
-       t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
-       t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
-       t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
-       t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
-       t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
-       t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
-
-       if (ioa_cfg->sis64) {
-               t->init_feedback_reg = base + p->init_feedback_reg;
-               t->dump_addr_reg = base + p->dump_addr_reg;
-               t->dump_data_reg = base + p->dump_data_reg;
-               t->endian_swap_reg = base + p->endian_swap_reg;
+       for (i = 0; i < ARRAY_SIZE(ioa_cfg->hrrq); i++) {
+               INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
+               INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
+               spin_lock_init(&ioa_cfg->hrrq[i]._lock);
+               if (i == 0)
+                       ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
+               else
+                       ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
        }
 }
 
@@ -9243,54 +9330,63 @@ ipr_get_chip_info(const struct pci_device_id *dev_id)
        return NULL;
 }
 
+/**
+ * ipr_wait_for_pci_err_recovery - Wait for any PCI error recovery to complete
+ *                                             during probe time
+ * @ioa_cfg:   ioa config struct
+ *
+ * Return value:
+ *     None
+ **/
+static void ipr_wait_for_pci_err_recovery(struct ipr_ioa_cfg *ioa_cfg)
+{
+       struct pci_dev *pdev = ioa_cfg->pdev;
+
+       if (pci_channel_offline(pdev)) {
+               wait_event_timeout(ioa_cfg->eeh_wait_q,
+                                  !pci_channel_offline(pdev),
+                                  IPR_PCI_ERROR_RECOVERY_TIMEOUT);
+               pci_restore_state(pdev);
+       }
+}
+
 static int ipr_enable_msix(struct ipr_ioa_cfg *ioa_cfg)
 {
        struct msix_entry entries[IPR_MAX_MSIX_VECTORS];
-       int i, err, vectors;
+       int i, vectors;
 
        for (i = 0; i < ARRAY_SIZE(entries); ++i)
                entries[i].entry = i;
 
-       vectors = ipr_number_of_msix;
-
-       while ((err = pci_enable_msix(ioa_cfg->pdev, entries, vectors)) > 0)
-                       vectors = err;
-
-       if (err < 0) {
-               pci_disable_msix(ioa_cfg->pdev);
-               return err;
+       vectors = pci_enable_msix_range(ioa_cfg->pdev,
+                                       entries, 1, ipr_number_of_msix);
+       if (vectors < 0) {
+               ipr_wait_for_pci_err_recovery(ioa_cfg);
+               return vectors;
        }
 
-       if (!err) {
-               for (i = 0; i < vectors; i++)
-                       ioa_cfg->vectors_info[i].vec = entries[i].vector;
-               ioa_cfg->nvectors = vectors;
-       }
+       for (i = 0; i < vectors; i++)
+               ioa_cfg->vectors_info[i].vec = entries[i].vector;
+       ioa_cfg->nvectors = vectors;
 
-       return err;
+       return 0;
 }
 
 static int ipr_enable_msi(struct ipr_ioa_cfg *ioa_cfg)
 {
-       int i, err, vectors;
-
-       vectors = ipr_number_of_msix;
+       int i, vectors;
 
-       while ((err = pci_enable_msi_block(ioa_cfg->pdev, vectors)) > 0)
-                       vectors = err;
-
-       if (err < 0) {
-               pci_disable_msi(ioa_cfg->pdev);
-               return err;
+       vectors = pci_enable_msi_range(ioa_cfg->pdev, 1, ipr_number_of_msix);
+       if (vectors < 0) {
+               ipr_wait_for_pci_err_recovery(ioa_cfg);
+               return vectors;
        }
 
-       if (!err) {
-               for (i = 0; i < vectors; i++)
-                       ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
-               ioa_cfg->nvectors = vectors;
-       }
+       for (i = 0; i < vectors; i++)
+               ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
+       ioa_cfg->nvectors = vectors;
 
-       return err;
+       return 0;
 }
 
 static void name_msi_vectors(struct ipr_ioa_cfg *ioa_cfg)
@@ -9355,7 +9451,7 @@ static irqreturn_t ipr_test_intr(int irq, void *devp)
  * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support.
  * @pdev:              PCI device struct
  *
- * Description: The return value from pci_enable_msi() can not always be
+ * Description: The return value from pci_enable_msi_range() can not always be
  * trusted.  This routine sets up and initiates a test interrupt to determine
  * if the interrupt is received via the ipr_test_intr() service routine.
  * If the tests fails, the driver will fall back to LSI.
@@ -9434,19 +9530,13 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
 
        ENTER;
 
-       if ((rc = pci_enable_device(pdev))) {
-               dev_err(&pdev->dev, "Cannot enable adapter\n");
-               goto out;
-       }
-
        dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
-
        host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
 
        if (!host) {
                dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n");
                rc = -ENOMEM;
-               goto out_disable;
+               goto out;
        }
 
        ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
@@ -9476,6 +9566,8 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
 
        ioa_cfg->revid = pdev->revision;
 
+       ipr_init_ioa_cfg(ioa_cfg, host, pdev);
+
        ipr_regs_pci = pci_resource_start(pdev, 0);
 
        rc = pci_request_regions(pdev, IPR_NAME);
@@ -9485,22 +9577,35 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                goto out_scsi_host_put;
        }
 
+       rc = pci_enable_device(pdev);
+
+       if (rc || pci_channel_offline(pdev)) {
+               if (pci_channel_offline(pdev)) {
+                       ipr_wait_for_pci_err_recovery(ioa_cfg);
+                       rc = pci_enable_device(pdev);
+               }
+
+               if (rc) {
+                       dev_err(&pdev->dev, "Cannot enable adapter\n");
+                       ipr_wait_for_pci_err_recovery(ioa_cfg);
+                       goto out_release_regions;
+               }
+       }
+
        ipr_regs = pci_ioremap_bar(pdev, 0);
 
        if (!ipr_regs) {
                dev_err(&pdev->dev,
                        "Couldn't map memory range of registers\n");
                rc = -ENOMEM;
-               goto out_release_regions;
+               goto out_disable;
        }
 
        ioa_cfg->hdw_dma_regs = ipr_regs;
        ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci;
        ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs;
 
-       ipr_init_ioa_cfg(ioa_cfg, host, pdev);
-
-       pci_set_master(pdev);
+       ipr_init_regs(ioa_cfg);
 
        if (ioa_cfg->sis64) {
                rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -9508,7 +9613,6 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                        dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n");
                        rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                }
-
        } else
                rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 
@@ -9522,10 +9626,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
 
        if (rc != PCIBIOS_SUCCESSFUL) {
                dev_err(&pdev->dev, "Write of cache line size failed\n");
+               ipr_wait_for_pci_err_recovery(ioa_cfg);
                rc = -EIO;
                goto cleanup_nomem;
        }
 
+       /* Issue MMIO read to ensure card is not in EEH */
+       interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
+       ipr_wait_for_pci_err_recovery(ioa_cfg);
+
        if (ipr_number_of_msix > IPR_MAX_MSIX_VECTORS) {
                dev_err(&pdev->dev, "The max number of MSIX is %d\n",
                        IPR_MAX_MSIX_VECTORS);
@@ -9544,10 +9653,22 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                dev_info(&pdev->dev, "Cannot enable MSI.\n");
        }
 
+       pci_set_master(pdev);
+
+       if (pci_channel_offline(pdev)) {
+               ipr_wait_for_pci_err_recovery(ioa_cfg);
+               pci_set_master(pdev);
+               if (pci_channel_offline(pdev)) {
+                       rc = -EIO;
+                       goto out_msi_disable;
+               }
+       }
+
        if (ioa_cfg->intr_flag == IPR_USE_MSI ||
            ioa_cfg->intr_flag == IPR_USE_MSIX) {
                rc = ipr_test_msi(ioa_cfg, pdev);
                if (rc == -EOPNOTSUPP) {
+                       ipr_wait_for_pci_err_recovery(ioa_cfg);
                        if (ioa_cfg->intr_flag == IPR_USE_MSI) {
                                ioa_cfg->intr_flag &= ~IPR_USE_MSI;
                                pci_disable_msi(pdev);
@@ -9577,30 +9698,12 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                                (unsigned int)num_online_cpus(),
                                (unsigned int)IPR_MAX_HRRQ_NUM);
 
-       /* Save away PCI config space for use following IOA reset */
-       rc = pci_save_state(pdev);
-
-       if (rc != PCIBIOS_SUCCESSFUL) {
-               dev_err(&pdev->dev, "Failed to save PCI config space\n");
-               rc = -EIO;
-               goto out_msi_disable;
-       }
-
        if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
                goto out_msi_disable;
 
        if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
                goto out_msi_disable;
 
-       if (ioa_cfg->sis64)
-               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
-                               + ((sizeof(struct ipr_config_table_entry64)
-                               * ioa_cfg->max_devs_supported)));
-       else
-               ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
-                               + ((sizeof(struct ipr_config_table_entry)
-                               * ioa_cfg->max_devs_supported)));
-
        rc = ipr_alloc_mem(ioa_cfg);
        if (rc < 0) {
                dev_err(&pdev->dev,
@@ -9608,6 +9711,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                goto out_msi_disable;
        }
 
+       /* Save away PCI config space for use following IOA reset */
+       rc = pci_save_state(pdev);
+
+       if (rc != PCIBIOS_SUCCESSFUL) {
+               dev_err(&pdev->dev, "Failed to save PCI config space\n");
+               rc = -EIO;
+               goto cleanup_nolog;
+       }
+
        /*
         * If HRRQ updated interrupt is not masked, or reset alert is set,
         * the card is in an unknown state and needs a hard reset
@@ -9664,18 +9776,19 @@ out:
 cleanup_nolog:
        ipr_free_mem(ioa_cfg);
 out_msi_disable:
+       ipr_wait_for_pci_err_recovery(ioa_cfg);
        if (ioa_cfg->intr_flag == IPR_USE_MSI)
                pci_disable_msi(pdev);
        else if (ioa_cfg->intr_flag == IPR_USE_MSIX)
                pci_disable_msix(pdev);
 cleanup_nomem:
        iounmap(ipr_regs);
+out_disable:
+       pci_disable_device(pdev);
 out_release_regions:
        pci_release_regions(pdev);
 out_scsi_host_put:
        scsi_host_put(host);
-out_disable:
-       pci_disable_device(pdev);
        goto out;
 }
 
@@ -9859,8 +9972,7 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
        ioa_cfg->host->max_channel = IPR_VSET_BUS;
        ioa_cfg->iopoll_weight = ioa_cfg->chip_cfg->iopoll_weight;
 
-       if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
-                       ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+       if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
                for (i = 1; i < ioa_cfg->hrrq_num; i++) {
                        blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
                                        ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -9889,8 +10001,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
        int i;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-       if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
-                       ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+       if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
                ioa_cfg->iopoll_weight = 0;
                for (i = 1; i < ioa_cfg->hrrq_num; i++)
                        blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
@@ -9993,6 +10104,8 @@ static struct pci_device_id ipr_pci_table[] = {
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D8, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D9, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57DA, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EB, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
@@ -10005,12 +10118,19 @@ static struct pci_device_id ipr_pci_table[] = {
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EF, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57F0, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCA, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CD2, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCD, 0, 0, 0 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
 
 static const struct pci_error_handlers ipr_err_handler = {
        .error_detected = ipr_pci_error_detected,
+       .mmio_enabled = ipr_pci_mmio_enabled,
        .slot_reset = ipr_pci_slot_reset,
 };