ipr: Reset in task context
authorBrian King <brking@linux.vnet.ibm.com>
Thu, 26 Mar 2015 16:23:52 +0000 (11:23 -0500)
committerJames Bottomley <JBottomley@Odin.com>
Thu, 9 Apr 2015 20:43:14 +0000 (13:43 -0700)
The pci_set_pcie_reset_state has changed semantics to not be callable
from interrupt context, so change ipr's usage of the API to comply with
this change by ensuring this occurs from a workqueue.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Reviewed-by: Wen Xiong <wenxiong@linux.vnet.ibm.com>
Reviewed-by: Daniel Kreling <kreling@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/ipr.c
drivers/scsi/ipr.h

index 190d0ae0193f1115d50c6bcf689ebba4c68cc5b2..200110caae175badd47ef7c46eb0f168d7da2440 100644 (file)
@@ -8319,13 +8319,38 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
 static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
 {
        ENTER;
-       pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
        ipr_cmd->job_step = ipr_reset_bist_done;
        ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
        LEAVE;
        return IPR_RC_JOB_RETURN;
 }
 
+/**
+ * ipr_reset_reset_work - Pulse a PCIe fundamental reset
+ * @work:      work struct
+ *
+ * Description: This pulses warm reset to a slot.
+ *
+ **/
+static void ipr_reset_reset_work(struct work_struct *work)
+{
+       struct ipr_cmnd *ipr_cmd = container_of(work, struct ipr_cmnd, work);
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct pci_dev *pdev = ioa_cfg->pdev;
+       unsigned long lock_flags = 0;
+
+       ENTER;
+       pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+       msleep(jiffies_to_msecs(IPR_PCI_RESET_TIMEOUT));
+       pci_set_pcie_reset_state(pdev, pcie_deassert_reset);
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       if (ioa_cfg->reset_cmd == ipr_cmd)
+               ipr_reset_ioa_job(ipr_cmd);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       LEAVE;
+}
+
 /**
  * ipr_reset_slot_reset - Reset the PCI slot of the adapter.
  * @ipr_cmd:   ipr command struct
@@ -8338,12 +8363,11 @@ static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
 static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-       struct pci_dev *pdev = ioa_cfg->pdev;
 
        ENTER;
-       pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+       INIT_WORK(&ipr_cmd->work, ipr_reset_reset_work);
+       queue_work(ioa_cfg->reset_work_q, &ipr_cmd->work);
        ipr_cmd->job_step = ipr_reset_slot_reset_done;
-       ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
        LEAVE;
        return IPR_RC_JOB_RETURN;
 }
@@ -9092,26 +9116,25 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
 }
 
 /**
- * ipr_free_all_resources - Free all allocated resources for an adapter.
- * @ipr_cmd:   ipr command struct
+ * ipr_free_irqs - Free all allocated IRQs for the adapter.
+ * @ioa_cfg:   ipr cfg struct
  *
- * This function frees all allocated resources for the
+ * This function frees all allocated IRQs for the
  * specified adapter.
  *
  * Return value:
  *     none
  **/
-static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
+static void ipr_free_irqs(struct ipr_ioa_cfg *ioa_cfg)
 {
        struct pci_dev *pdev = ioa_cfg->pdev;
 
-       ENTER;
        if (ioa_cfg->intr_flag == IPR_USE_MSI ||
            ioa_cfg->intr_flag == IPR_USE_MSIX) {
                int i;
                for (i = 0; i < ioa_cfg->nvectors; i++)
                        free_irq(ioa_cfg->vectors_info[i].vec,
-                               &ioa_cfg->hrrq[i]);
+                                &ioa_cfg->hrrq[i]);
        } else
                free_irq(pdev->irq, &ioa_cfg->hrrq[0]);
 
@@ -9122,7 +9145,26 @@ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
                pci_disable_msix(pdev);
                ioa_cfg->intr_flag &= ~IPR_USE_MSIX;
        }
+}
+
+/**
+ * ipr_free_all_resources - Free all allocated resources for an adapter.
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function frees all allocated resources for the
+ * specified adapter.
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
+{
+       struct pci_dev *pdev = ioa_cfg->pdev;
 
+       ENTER;
+       ipr_free_irqs(ioa_cfg);
+       if (ioa_cfg->reset_work_q)
+               destroy_workqueue(ioa_cfg->reset_work_q);
        iounmap(ioa_cfg->hdw_dma_regs);
        pci_release_regions(pdev);
        ipr_free_mem(ioa_cfg);
@@ -9942,6 +9984,14 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
            (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) {
                ioa_cfg->needs_warm_reset = 1;
                ioa_cfg->reset = ipr_reset_slot_reset;
+
+               ioa_cfg->reset_work_q = alloc_ordered_workqueue("ipr_reset_%d",
+                                                               WQ_MEM_RECLAIM, host->host_no);
+
+               if (!ioa_cfg->reset_work_q) {
+                       dev_err(&pdev->dev, "Couldn't register reset workqueue\n");
+                       goto out_free_irq;
+               }
        } else
                ioa_cfg->reset = ipr_reset_start_bist;
 
@@ -9953,6 +10003,8 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
 out:
        return rc;
 
+out_free_irq:
+       ipr_free_irqs(ioa_cfg);
 cleanup_nolog:
        ipr_free_mem(ioa_cfg);
 out_msi_disable:
@@ -10033,6 +10085,8 @@ static void __ipr_remove(struct pci_dev *pdev)
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
        wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
        flush_work(&ioa_cfg->work_q);
+       if (ioa_cfg->reset_work_q)
+               flush_workqueue(ioa_cfg->reset_work_q);
        INIT_LIST_HEAD(&ioa_cfg->used_res_q);
        spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
 
@@ -10178,22 +10232,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
        if (ipr_fast_reboot && system_state == SYSTEM_RESTART && ioa_cfg->sis64) {
-               if (ioa_cfg->intr_flag == IPR_USE_MSI ||
-                   ioa_cfg->intr_flag == IPR_USE_MSIX) {
-                       int i;
-                       for (i = 0; i < ioa_cfg->nvectors; i++)
-                               free_irq(ioa_cfg->vectors_info[i].vec,
-                                        &ioa_cfg->hrrq[i]);
-               }
-
-               if (ioa_cfg->intr_flag == IPR_USE_MSI) {
-                       pci_disable_msi(ioa_cfg->pdev);
-                       ioa_cfg->intr_flag &= ~IPR_USE_MSI;
-               } else if (ioa_cfg->intr_flag == IPR_USE_MSIX) {
-                       pci_disable_msix(ioa_cfg->pdev);
-                       ioa_cfg->intr_flag &= ~IPR_USE_MSIX;
-               }
-
+               ipr_free_irqs(ioa_cfg);
                pci_disable_device(ioa_cfg->pdev);
        }
 }
index 34eec5bcdce010b80e8fb60cc76178532153e0ef..f7d0e375e4f643710130f814c98866049b563b67 100644 (file)
@@ -1540,6 +1540,7 @@ struct ipr_ioa_cfg {
        u8 saved_mode_page_len;
 
        struct work_struct work_q;
+       struct workqueue_struct *reset_work_q;
 
        wait_queue_head_t reset_wait_q;
        wait_queue_head_t msi_wait_q;
@@ -1591,6 +1592,7 @@ struct ipr_cmnd {
        struct ata_queued_cmd *qc;
        struct completion completion;
        struct timer_list timer;
+       struct work_struct work;
        void (*fast_done) (struct ipr_cmnd *);
        void (*done) (struct ipr_cmnd *);
        int (*job_step) (struct ipr_cmnd *);