This converts ipr's queuecommand path to use percpu refcounts
rather than atomics.

Signed-off-by: Brian King <brk...@linux.vnet.ibm.com>
---

 drivers/scsi/ipr.c |  111 ++++++++++++++++++++++++++++++++++++++++++-----------
 drivers/scsi/ipr.h |   53 +++----------------------
 2 files changed, 98 insertions(+), 66 deletions(-)

diff -puN drivers/scsi/ipr.h~ipr_lockless_percpu drivers/scsi/ipr.h
--- linux-2.6.git/drivers/scsi/ipr.h~ipr_lockless_percpu        2016-09-06 
21:08:18.268234535 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.h    2016-09-06 21:08:18.278234468 
-0500
@@ -33,6 +33,7 @@
 #include <linux/list.h>
 #include <linux/kref.h>
 #include <linux/irq_poll.h>
+#include <linux/percpu-refcount.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
@@ -512,7 +513,6 @@ struct ipr_hrr_queue {
        struct list_head hrrq_error_q;
        spinlock_t _lock;
        spinlock_t *lock;
-       atomic_t active;
 
        volatile u32 toggle_bit;
        u32 size;
@@ -522,7 +522,6 @@ struct ipr_hrr_queue {
        u8 ioa_is_dead:1;
        u8 allow_cmds:1;
        u8 removing_ioa:1;
-       u8 is_active:1;
 
        struct irq_poll iopoll;
 };
@@ -1472,6 +1471,12 @@ enum ipr_sdt_state {
        DUMP_OBTAINED
 };
 
+struct ipr_ioa_ref_cnt {
+       struct percpu_ref       ref;
+       int released;
+       struct ipr_ioa_cfg *ioa_cfg;
+};
+
 /* Per-controller data */
 struct ipr_ioa_cfg {
        char eye_catcher[8];
@@ -1547,7 +1552,6 @@ struct ipr_ioa_cfg {
        struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
        u32 hrrq_num;
        atomic_t  hrrq_index;
-       atomic_t  hrrq_active;
        u16 identify_hrrq_index;
 
        struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
@@ -1592,6 +1596,7 @@ struct ipr_ioa_cfg {
        int (*reset) (struct ipr_cmnd *);
 
        struct ata_host ata_host;
+       struct ipr_ioa_ref_cnt  *ioa_usage_counter;
        char ipr_cmd_label[8];
 #define IPR_CMD_LABEL          "ipr_cmd"
        u32 max_cmds;
@@ -1872,48 +1877,6 @@ static inline void ipr_free_cmd(struct i
                  ipr_cmd->hrrq->active_map);
 }
 
-static inline void ipr_hrrq_activate(struct ipr_hrr_queue *hrrq)
-{
-       if (!hrrq->is_active) {
-               atomic_inc(&hrrq->active);
-               atomic_inc(&hrrq->ioa_cfg->hrrq_active);
-               hrrq->is_active = 1;
-       }
-}
-
-static inline void ipr_hrrq_deactivate(struct ipr_hrr_queue *hrrq)
-{
-       if (hrrq->is_active) {
-               hrrq->is_active = 0;
-
-               if (!atomic_dec_return(&hrrq->active))
-                       atomic_dec(&hrrq->ioa_cfg->hrrq_active);
-       }
-}
-
-static inline int ipr_hrrq_enter(struct ipr_hrr_queue *hrrq)
-{
-       return atomic_inc_not_zero(&hrrq->active);
-}
-
-static void ipr_reset_ioa_job(struct ipr_cmnd *);
-
-static inline void ipr_hrrq_exit(struct ipr_hrr_queue *hrrq)
-{
-       unsigned long flags;
-       struct ipr_ioa_cfg *ioa_cfg;
-
-       if (!atomic_dec_return(&hrrq->active)) {
-               ioa_cfg = hrrq->ioa_cfg;
-
-               if (!atomic_dec_return(&ioa_cfg->hrrq_active)) {
-                       spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-                       ipr_reset_ioa_job(ioa_cfg->reset_cmd);
-                       spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
-               }
-       }
-}
-
 static inline struct ipr_cmnd* ipr_first_active_cmd(struct ipr_hrr_queue *hrrq)
 {
        int i = find_first_bit(hrrq->active_map, hrrq->size);
diff -puN drivers/scsi/ipr.c~ipr_lockless_percpu drivers/scsi/ipr.c
--- linux-2.6.git/drivers/scsi/ipr.c~ipr_lockless_percpu        2016-09-06 
21:08:18.272234509 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.c    2016-09-06 21:08:18.280234455 
-0500
@@ -6511,7 +6511,7 @@ static int ipr_queuecommand(struct Scsi_
 
        hrrq = &ioa_cfg->hrrq[hrrq_id];
 
-       if (!ipr_hrrq_enter(hrrq)) {
+       if (!percpu_ref_tryget_live(&ioa_cfg->ioa_usage_counter->ref)) {
                dev_info(&ioa_cfg->pdev->dev, "Failed to get a ref\n");
 
                spin_lock_irqsave(hrrq->lock, hrrq_flags);
@@ -6529,7 +6529,7 @@ static int ipr_queuecommand(struct Scsi_
 
        ipr_cmd = __ipr_get_free_ipr_cmnd(hrrq);
        if (ipr_cmd == NULL) {
-               ipr_hrrq_exit(hrrq);
+               percpu_ref_put(&ioa_cfg->ioa_usage_counter->ref);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
@@ -6591,7 +6591,7 @@ static int ipr_queuecommand(struct Scsi_
                        ipr_free_cmd(ipr_cmd);
                        scsi_dma_unmap(scsi_cmd);
                }
-               ipr_hrrq_exit(hrrq);
+               percpu_ref_put(&ioa_cfg->ioa_usage_counter->ref);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
@@ -6599,7 +6599,7 @@ static int ipr_queuecommand(struct Scsi_
 
        ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
        ipr_send_command(ipr_cmd);
-       ipr_hrrq_exit(hrrq);
+       percpu_ref_put(&ioa_cfg->ioa_usage_counter->ref);
        return 0;
 }
 
@@ -7161,14 +7161,17 @@ static int ipr_ioa_reset_done(struct ipr
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_resource_entry *res;
+       struct ipr_hrr_queue *hrrq;
        int j;
 
        ENTER;
        ioa_cfg->in_reset_reload = 0;
+       hrrq = &ioa_cfg->hrrq[IPR_INIT_HRRQ];
+       if (!hrrq->ioa_is_dead && !hrrq->removing_ioa)
+               ioa_cfg->allow_cmds = 1;
        for (j = 0; j < ioa_cfg->hrrq_num; j++) {
                spin_lock(&ioa_cfg->hrrq[j]._lock);
                ioa_cfg->hrrq[j].allow_cmds = 1;
-               ipr_hrrq_activate(&ioa_cfg->hrrq[j]);
                spin_unlock(&ioa_cfg->hrrq[j]._lock);
        }
        wmb();
@@ -7203,6 +7206,8 @@ static int ipr_ioa_reset_done(struct ipr
        wake_up_all(&ioa_cfg->reset_wait_q);
 
        spin_unlock_irq(ioa_cfg->host->host_lock);
+       if (ioa_cfg->allow_cmds)
+               percpu_ref_reinit(&ioa_cfg->ioa_usage_counter->ref);
        scsi_unblock_requests(ioa_cfg->host);
        ipr_send_back_failed_ops(ioa_cfg);
        spin_lock_irq(ioa_cfg->host->host_lock);
@@ -9119,9 +9124,6 @@ static void ipr_reset_ioa_job(struct ipr
                        return;
                }
 
-               if (atomic_read(&ioa_cfg->hrrq_active))
-                       return;
-
                if (IPR_IOASC_SENSE_KEY(ioasc)) {
                        rc = ipr_cmd->job_step_failed(ipr_cmd);
                        if (rc == IPR_RC_JOB_RETURN)
@@ -9134,6 +9136,48 @@ static void ipr_reset_ioa_job(struct ipr
        } while (rc == IPR_RC_JOB_CONTINUE);
 }
 
+static void ipr_ioa_usage_counter_release(struct percpu_ref *ref)
+{
+       struct ipr_ioa_ref_cnt *ioa_ref = (struct ipr_ioa_ref_cnt *)ref;
+       struct ipr_ioa_cfg *ioa_cfg = ioa_ref->ioa_cfg;
+       unsigned long lock_flags;
+
+       ENTER;
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       if (ioa_cfg->reset_cmd)
+               ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       LEAVE;
+}
+
+/**
+ * ipr_reset_quiesce_work - Quiesce queuecommand
+ * @work:      work struct
+ *
+ * Description: Quiesce queuecommand.
+ *
+ **/
+static void ipr_reset_quiesce_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;
+       unsigned long lock_flags = 0;
+       int allow_cmds;
+       ENTER;
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       allow_cmds = ioa_cfg->allow_cmds;
+       ioa_cfg->allow_cmds = 0;
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+       /* xxx add a timeout here? */
+       if (allow_cmds)
+               percpu_ref_kill(&ioa_cfg->ioa_usage_counter->ref);
+       else
+               ipr_ioa_usage_counter_release(&ioa_cfg->ioa_usage_counter->ref);
+       LEAVE;
+}
+
 /**
  * _ipr_initiate_ioa_reset - Initiate an adapter reset
  * @ioa_cfg:           ioa config struct
@@ -9159,7 +9203,6 @@ static void _ipr_initiate_ioa_reset(stru
        for (i = 0; i < ioa_cfg->hrrq_num; i++) {
                spin_lock(&ioa_cfg->hrrq[i]._lock);
                ioa_cfg->hrrq[i].allow_cmds = 0;
-               ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
                spin_unlock(&ioa_cfg->hrrq[i]._lock);
        }
        wmb();
@@ -9171,7 +9214,8 @@ static void _ipr_initiate_ioa_reset(stru
        ipr_cmd->job_step = job_step;
        ipr_cmd->u.shutdown_type = shutdown_type;
 
-       ipr_reset_ioa_job(ipr_cmd);
+       INIT_WORK(&ipr_cmd->work, ipr_reset_quiesce_work);
+       queue_work(ioa_cfg->reset_work_q, &ipr_cmd->work);
 }
 
 /**
@@ -9346,7 +9390,6 @@ static void ipr_pci_perm_failure(struct
                for (i = 0; i < ioa_cfg->hrrq_num; i++) {
                        spin_lock(&ioa_cfg->hrrq[i]._lock);
                        ioa_cfg->hrrq[i].allow_cmds = 0;
-                       ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
                        spin_unlock(&ioa_cfg->hrrq[i]._lock);
                }
                wmb();
@@ -9403,6 +9446,7 @@ static int ipr_probe_ioa_part2(struct ip
        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;
+       ioa_cfg->allow_cmds = 1;
        if (ioa_cfg->needs_hard_reset) {
                ioa_cfg->needs_hard_reset = 0;
                ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
@@ -9540,6 +9584,8 @@ static void ipr_free_all_resources(struc
        iounmap(ioa_cfg->hdw_dma_regs);
        pci_release_regions(pdev);
        ipr_free_mem(ioa_cfg);
+       percpu_ref_exit(&ioa_cfg->ioa_usage_counter->ref);
+       kfree(ioa_cfg->ioa_usage_counter);
        scsi_host_put(ioa_cfg->host);
        pci_disable_device(pdev);
        LEAVE;
@@ -10146,11 +10192,21 @@ static int ipr_probe_ioa(struct pci_dev
                goto out_scsi_host_put;
        }
 
+       ioa_cfg->ioa_usage_counter = 
kzalloc(sizeof(*ioa_cfg->ioa_usage_counter),
+                                            GFP_KERNEL);
+
+       if (!ioa_cfg->ioa_usage_counter) {
+               dev_err(&pdev->dev, "Failed to allocate ioa_usage_counter\n");
+               rc = -ENOMEM;
+               goto out_scsi_host_put;
+       }
+
        /* set SIS 32 or SIS 64 */
        ioa_cfg->sis64 = ioa_cfg->ipr_chip->sis_type == IPR_SIS64 ? 1 : 0;
        ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg;
        ioa_cfg->clear_isr = ioa_cfg->chip_cfg->clear_isr;
        ioa_cfg->max_cmds = ioa_cfg->chip_cfg->max_cmds;
+       ioa_cfg->ioa_usage_counter->ioa_cfg = ioa_cfg;
 
        if (ipr_transop_timeout)
                ioa_cfg->transop_timeout = ipr_transop_timeout;
@@ -10163,13 +10219,24 @@ static int ipr_probe_ioa(struct pci_dev
 
        ipr_init_ioa_cfg(ioa_cfg, host, pdev);
 
+       rc = percpu_ref_init(&ioa_cfg->ioa_usage_counter->ref,
+                            ipr_ioa_usage_counter_release,
+                            0, GFP_KERNEL);
+
+       if (rc) {
+               dev_err(&pdev->dev,
+                       "Couldn't initialize percpu counter\n");
+               kfree(ioa_cfg->ioa_usage_counter);
+               goto out_scsi_host_put;
+       }
+
        ipr_regs_pci = pci_resource_start(pdev, 0);
 
        rc = pci_request_regions(pdev, IPR_NAME);
        if (rc < 0) {
                dev_err(&pdev->dev,
                        "Couldn't register memory range of registers\n");
-               goto out_scsi_host_put;
+               goto out_percpu_ref;
        }
 
        rc = pci_enable_device(pdev);
@@ -10373,18 +10440,18 @@ static int ipr_probe_ioa(struct pci_dev
            (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");
-                       rc = -ENOMEM;
-                       goto out_free_sata_work_q;
-               }
        } else
                ioa_cfg->reset = ipr_reset_start_bist;
 
+       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");
+               rc = -ENOMEM;
+               goto out_free_sata_work_q;
+       }
+
        spin_lock_irqsave(&ipr_driver_lock, driver_lock_flags);
        list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
        spin_unlock_irqrestore(&ipr_driver_lock, driver_lock_flags);
@@ -10411,6 +10478,8 @@ out_disable:
        pci_disable_device(pdev);
 out_release_regions:
        pci_release_regions(pdev);
+out_percpu_ref:
+       percpu_ref_exit(&ioa_cfg->ioa_usage_counter->ref);
 out_scsi_host_put:
        scsi_host_put(host);
        goto out;
_


------------------------------------------------------------------------------
_______________________________________________
Iprdd-devel mailing list
Iprdd-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/iprdd-devel

Reply via email to