scsi: hisi_sas: alloc queue id of slot according to device id
authorXiang Chen <chenxiang66@hisilicon.com>
Mon, 7 Nov 2016 12:48:31 +0000 (20:48 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 25 Nov 2016 14:54:39 +0000 (09:54 -0500)
Currently slots are allocated from queues in a round-robin fashion.
This causes a problem for internal commands in device mode. For this
mode, we should ensure that the internal abort command is the last
command seen in the host for that device. We can only ensure this when
we place the internal abort command after the preceding commands for
device that in the same queue, as there is no order in which the host
will select a queue to execute the next command.

This queue restriction makes supporting scsi mq more tricky in
the future, but should not be a blocker.

Note: Even though v1 hw does not support internal abort, the
      allocation method is chosen to be the same for consistency.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

index 64046c5853a5c6412eb81391bc7db531b308e079..bf59fab77765d23a32ea0c24d332e5cee0c5b092 100644 (file)
@@ -150,7 +150,8 @@ struct hisi_sas_hw {
                                struct domain_device *device);
        struct hisi_sas_device *(*alloc_dev)(struct domain_device *device);
        void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
-       int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s);
+       int (*get_free_slot)(struct hisi_hba *hisi_hba, u32 dev_id,
+                       int *q, int *s);
        void (*start_delivery)(struct hisi_hba *hisi_hba);
        int (*prep_ssp)(struct hisi_hba *hisi_hba,
                        struct hisi_sas_slot *slot, int is_tmf,
@@ -207,7 +208,6 @@ struct hisi_hba {
        struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
 
        int     queue_count;
-       int     queue;
        struct hisi_sas_slot    *slot_prep;
 
        struct dma_pool *sge_page_pool;
index 9afc6978cb776e72f39cb820d4d5ecad2f334658..9f5ccc59075aad80b9b6ffab8b5c90e90d60c386 100644 (file)
@@ -232,8 +232,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
                rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
        if (rc)
                goto err_out;
-       rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
-                                        &dlvry_queue_slot);
+       rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
+                                       &dlvry_queue, &dlvry_queue_slot);
        if (rc)
                goto err_out_tag;
 
@@ -987,8 +987,8 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
        rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
        if (rc)
                goto err_out;
-       rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
-                                        &dlvry_queue_slot);
+       rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
+                                       &dlvry_queue, &dlvry_queue_slot);
        if (rc)
                goto err_out_tag;
 
index c0ac49d8bc8d256e9711edcb3a826a19293b5e58..bbc5760dfaf4d1c924dd54b5101acae062faca67 100644 (file)
@@ -862,29 +862,23 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
  * The callpath to this function and upto writing the write
  * queue pointer should be safe from interruption.
  */
-static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+                               int *q, int *s)
 {
        struct device *dev = &hisi_hba->pdev->dev;
        struct hisi_sas_dq *dq;
        u32 r, w;
-       int queue = hisi_hba->queue;
-
-       while (1) {
-               dq = &hisi_hba->dq[queue];
-               w = dq->wr_point;
-               r = hisi_sas_read32_relaxed(hisi_hba,
-                                   DLVRY_Q_0_RD_PTR + (queue * 0x14));
-               if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
-                       queue = (queue + 1) % hisi_hba->queue_count;
-                       if (queue == hisi_hba->queue) {
-                               dev_warn(dev, "could not find free slot\n");
-                               return -EAGAIN;
-                       }
-                       continue;
-               }
-               break;
+       int queue = dev_id % hisi_hba->queue_count;
+
+       dq = &hisi_hba->dq[queue];
+       w = dq->wr_point;
+       r = hisi_sas_read32_relaxed(hisi_hba,
+                               DLVRY_Q_0_RD_PTR + (queue * 0x14));
+       if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+               dev_warn(dev, "could not find free slot\n");
+               return -EAGAIN;
        }
-       hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+
        *q = queue;
        *s = w;
        return 0;
index 9e70e6d64724ad60789e9d8ddd442805fc8bc178..cb19e73457c808d5561ff9a3701b5918b7bf4461 100644 (file)
@@ -1089,29 +1089,24 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
  * The callpath to this function and upto writing the write
  * queue pointer should be safe from interruption.
  */
-static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, u32 dev_id,
+                               int *q, int *s)
 {
        struct device *dev = &hisi_hba->pdev->dev;
        struct hisi_sas_dq *dq;
        u32 r, w;
-       int queue = hisi_hba->queue;
+       int queue = dev_id % hisi_hba->queue_count;
 
-       while (1) {
-               dq = &hisi_hba->dq[queue];
-               w = dq->wr_point;
-               r = hisi_sas_read32_relaxed(hisi_hba,
-                                           DLVRY_Q_0_RD_PTR + (queue * 0x14));
-               if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
-                       queue = (queue + 1) % hisi_hba->queue_count;
-                       if (queue == hisi_hba->queue) {
-                               dev_warn(dev, "could not find free slot\n");
-                               return -EAGAIN;
-                       }
-                       continue;
-               }
-               break;
+       dq = &hisi_hba->dq[queue];
+       w = dq->wr_point;
+       r = hisi_sas_read32_relaxed(hisi_hba,
+                               DLVRY_Q_0_RD_PTR + (queue * 0x14));
+       if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+               dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
+                               queue, r, w);
+               return -EAGAIN;
        }
-       hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+
        *q = queue;
        *s = w;
        return 0;