This patch enables full scsi-mq support for the hpsa driver.
Due to some reports of performance regressions this patch
also adds a parameter 'use_blk_mq' which can be used to
disable multiqueue support if required.

Signed-off-by: Hannes Reinecke <[email protected]>
---
 drivers/scsi/hpsa.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 52 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 0df0e04..ef4e81a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -91,6 +91,9 @@
 MODULE_PARM_DESC(hpsa_simple_mode,
        "Use 'simple mode' rather than 'performant mode'");
 
+bool use_blk_mq = true;
+module_param(use_blk_mq, bool, 0);
+
 /* define the PCI info for the cards we can control */
 static const struct pci_device_id hpsa_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
@@ -1137,12 +1140,13 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info 
*h,
        }
 }
 
-static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList 
*c)
+static void enqueue_cmd_and_start_io(struct ctlr_info *h,
+                                    struct CommandList *c, int reply_queue)
 {
        if (unlikely(hpsa_is_pending_event(c)))
                return finish_cmd(c);
 
-       __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
+       __enqueue_cmd_and_start_io(h, c, reply_queue);
 }
 
 static inline int is_hba_lunid(unsigned char scsi3addr[])
@@ -4614,6 +4618,7 @@ static int hpsa_scsi_ioaccel1_queue_command(struct 
ctlr_info *h,
        int use_sg, i;
        struct SGDescriptor *curr_sg;
        u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
+       int reply_queue = DEFAULT_REPLY_QUEUE;
 
        /* TODO: implement chaining support */
        if (scsi_sg_count(cmd) > h->ioaccel_maxsg) {
@@ -4683,8 +4688,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct 
ctlr_info *h,
        cp->control = cpu_to_le32(control);
        memcpy(cp->CDB, cdb, cdb_len);
        memcpy(cp->CISS_LUN, scsi3addr, 8);
+       if (shost_use_blk_mq(cmd->device->host)) {
+               u32 blk_tag = blk_mq_unique_tag(cmd->request);
+               reply_queue = blk_mq_unique_tag_to_hwq(blk_tag);
+       }
        /* Tag was already set at init time. */
-       enqueue_cmd_and_start_io(h, c);
+       enqueue_cmd_and_start_io(h, c, reply_queue);
        return 0;
 }
 
@@ -4778,6 +4787,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct 
ctlr_info *h,
        u64 addr64;
        u32 len;
        u32 total_len = 0;
+       int reply_queue = DEFAULT_REPLY_QUEUE;
 
        if (!cmd->device)
                return -1;
@@ -4882,7 +4892,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct 
ctlr_info *h,
        } else
                cp->sg_count = (u8) use_sg;
 
-       enqueue_cmd_and_start_io(h, c);
+       if (shost_use_blk_mq(cmd->device->host)) {
+               u32 blk_tag = blk_mq_unique_tag(cmd->request);
+               reply_queue = blk_mq_unique_tag_to_hwq(blk_tag);
+       }
+       enqueue_cmd_and_start_io(h, c, reply_queue);
        return 0;
 }
 
@@ -5284,6 +5298,8 @@ static int hpsa_ciss_submit(struct ctlr_info *h,
        struct CommandList *c, struct scsi_cmnd *cmd,
        unsigned char scsi3addr[])
 {
+       int reply_queue = DEFAULT_REPLY_QUEUE;
+
        cmd->host_scribble = (unsigned char *) c;
        c->cmd_type = CMD_SCSI;
        c->scsi_cmd = cmd;
@@ -5339,7 +5355,11 @@ static int hpsa_ciss_submit(struct ctlr_info *h,
                hpsa_cmd_resolve_and_free(h, c);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
-       enqueue_cmd_and_start_io(h, c);
+       if (shost_use_blk_mq(cmd->device->host)) {
+               u32 blk_tag = blk_mq_unique_tag(cmd->request);
+               reply_queue = blk_mq_unique_tag_to_hwq(blk_tag);
+       }
+       enqueue_cmd_and_start_io(h, c, reply_queue);
        /* the cmd'll come back via intr handler in complete_scsi_command()  */
        return 0;
 }
@@ -5642,13 +5662,23 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h)
 static int hpsa_scsi_add_host(struct ctlr_info *h)
 {
        int rv;
+       struct Scsi_Host *sh = h->scsi_host;
 
-       rv = scsi_add_host(h->scsi_host, &h->pdev->dev);
+       if (h->intr_mode == PERF_MODE_INT && h->msix_vectors > 0)
+               sh->nr_hw_queues = h->msix_vectors;
+       else
+               sh->nr_hw_queues = 1;
+
+       if (use_blk_mq) {
+               sh->can_queue = sh->can_queue / sh->nr_hw_queues;
+               sh->use_blk_mq = 1;
+       }
+       rv = scsi_add_host(sh, &h->pdev->dev);
        if (rv) {
                dev_err(&h->pdev->dev, "scsi_add_host failed\n");
                return rv;
        }
-       scsi_scan_host(h->scsi_host);
+       scsi_scan_host(sh);
        return 0;
 }
 
@@ -5658,10 +5688,20 @@ static int hpsa_scsi_add_host(struct ctlr_info *h)
  * an index to select our command block.  (The offset allows us to reserve the
  * low-numbered entries for our own uses.)
  */
-static int hpsa_get_cmd_index(struct scsi_cmnd *scmd)
+static int hpsa_get_cmd_index(struct ctlr_info *h, struct scsi_cmnd *scmd)
 {
        int idx = scmd->request->tag;
 
+       if (shost_use_blk_mq(scmd->device->host)) {
+               u32 blk_tag = blk_mq_unique_tag(scmd->request);
+               u16 hwq = blk_mq_unique_tag_to_hwq(blk_tag);
+               u16 tag = blk_mq_unique_tag_to_tag(blk_tag);
+               int msix_vectors, hwq_size;
+
+               msix_vectors = h->msix_vectors > 0 ? h->msix_vectors : 1;
+               hwq_size = (h->nr_cmds - HPSA_NRESERVED_CMDS) / msix_vectors;
+               idx = (hwq * hwq_size) + tag;
+       }
        if (idx < 0)
                return idx;
 
@@ -5811,7 +5851,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd 
*scsicmd)
        if (lockup_detected(h)) {
                snprintf(msg, sizeof(msg),
                         "cmd %d RESET FAILED, lockup detected",
-                        hpsa_get_cmd_index(scsicmd));
+                        hpsa_get_cmd_index(h, scsicmd));
                hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
                return FAILED;
        }
@@ -5820,7 +5860,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd 
*scsicmd)
        if (detect_controller_lockup(h)) {
                snprintf(msg, sizeof(msg),
                         "cmd %d RESET FAILED, new lockup detected",
-                        hpsa_get_cmd_index(scsicmd));
+                        hpsa_get_cmd_index(h, scsicmd));
                hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
                return FAILED;
        }
@@ -6293,7 +6333,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
 static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
                                            struct scsi_cmnd *scmd)
 {
-       int idx = hpsa_get_cmd_index(scmd);
+       int idx = hpsa_get_cmd_index(h, scmd);
        struct CommandList *c = h->cmd_pool + idx;
 
        if (idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds) {
@@ -6857,7 +6897,7 @@ static void hpsa_send_host_reset(struct ctlr_info *h, 
unsigned char *scsi3addr,
                RAID_CTLR_LUNID, TYPE_MSG);
        c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
        c->waiting = NULL;
-       enqueue_cmd_and_start_io(h, c);
+       enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
        /* Don't wait for completion, the reset won't complete.  Don't free
         * the command either.  This is the last command we will send before
         * re-initializing everything, so it doesn't matter and won't leak.
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to