]> Pileus Git - ~andy/linux/commitdiff
[SCSI] stex: add shared tags from block
authorEd Lin <ed.lin@promise.com>
Fri, 1 Sep 2006 06:31:51 +0000 (14:31 +0800)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Sat, 2 Sep 2006 18:57:02 +0000 (13:57 -0500)
Use block shared tags entirely within the driver. In the case of
shutdown, assume that there are no other outstanding commands, so tag
0 is fine.

Signed-off-by: Ed Lin <ed.lin@promise.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/stex.c

index fd093302bf1a946ea6de1b909ff6c5fbc39eb48f..15fb99f224ee16b697722633c365faccf9ba5305 100644 (file)
@@ -34,6 +34,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 
 #define DRV_NAME "stex"
 #define ST_DRIVER_VERSION "2.9.0.13"
@@ -95,7 +96,6 @@ enum {
 
        /* request count, etc. */
        MU_MAX_REQUEST                          = 32,
-       TAG_BITMAP_LENGTH                       = MU_MAX_REQUEST,
 
        /* one message wasted, use MU_MAX_REQUEST+1
                to handle MU_MAX_REQUEST messages */
@@ -265,7 +265,6 @@ struct st_hba {
        struct Scsi_Host *host;
        struct pci_dev *pdev;
 
-       u32 tag;
        u32 req_head;
        u32 req_tail;
        u32 status_head;
@@ -309,40 +308,6 @@ static void stex_gettime(__le32 *time)
        *(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
 }
 
-static u16 __stex_alloc_tag(unsigned long *bitmap)
-{
-       int i;
-       i = find_first_zero_bit(bitmap, TAG_BITMAP_LENGTH);
-       if (i < TAG_BITMAP_LENGTH)
-               __set_bit(i, bitmap);
-       return (u16)i;
-}
-
-static u16 stex_alloc_tag(struct st_hba *hba, unsigned long *bitmap)
-{
-       unsigned long flags;
-       u16 tag;
-
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       tag = __stex_alloc_tag(bitmap);
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
-       return tag;
-}
-
-static void __stex_free_tag(unsigned long *bitmap, u16 tag)
-{
-       __clear_bit((int)tag, bitmap);
-}
-
-static void stex_free_tag(struct st_hba *hba, unsigned long *bitmap, u16 tag)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       __stex_free_tag(bitmap, tag);
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
-}
-
 static struct status_msg *stex_get_status(struct st_hba *hba)
 {
        struct status_msg *status =
@@ -534,58 +499,32 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
        readl(hba->mmio_base + IDBL); /* flush */
 }
 
+static int
+stex_slave_alloc(struct scsi_device *sdev)
+{
+       /* Cheat: usually extracted from Inquiry data */
+       sdev->tagged_supported = 1;
+
+       scsi_activate_tcq(sdev, sdev->host->can_queue);
+
+       return 0;
+}
+
 static int
 stex_slave_config(struct scsi_device *sdev)
 {
        sdev->use_10_for_rw = 1;
        sdev->use_10_for_ms = 1;
        sdev->timeout = 60 * HZ;
+       sdev->tagged_supported = 1;
+
        return 0;
 }
 
 static void
 stex_slave_destroy(struct scsi_device *sdev)
 {
-       struct st_hba *hba = (struct st_hba *) sdev->host->hostdata;
-       struct req_msg *req;
-       unsigned long flags;
-       unsigned long before;
-       u16 tag;
-
-       if (sdev->type != TYPE_DISK)
-               return;
-
-       before = jiffies;
-       while ((tag = stex_alloc_tag(hba, (unsigned long *)&hba->tag))
-               == TAG_BITMAP_LENGTH) {
-               if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
-                       return;
-               msleep(10);
-       }
-
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       req = stex_alloc_req(hba);
-       memset(req->cdb, 0, STEX_CDB_LENGTH);
-
-       req->target = sdev->id;
-       req->lun = sdev->channel; /* firmware lun issue work around */
-       req->cdb[0] = SYNCHRONIZE_CACHE;
-
-       hba->ccb[tag].cmd = NULL;
-       hba->ccb[tag].sg_count = 0;
-       hba->ccb[tag].sense_bufflen = 0;
-       hba->ccb[tag].sense_buffer = NULL;
-       hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE;
-
-       stex_send_cmd(hba, req, tag);
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
-
-       wait_event_timeout(hba->waitq,
-               !(hba->ccb[tag].req_type), ST_INTERNAL_TIMEOUT * HZ);
-       if (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE)
-               return;
-
-       stex_free_tag(hba, (unsigned long *)&hba->tag, tag);
+       scsi_deactivate_tcq(sdev, 1);
 }
 
 static int
@@ -650,8 +589,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
 
        cmd->scsi_done = done;
 
-       if (unlikely((tag = __stex_alloc_tag((unsigned long *)&hba->tag))
-               == TAG_BITMAP_LENGTH))
+       tag = cmd->request->tag;
+
+       if (unlikely(tag >= host->can_queue))
                return SCSI_MLQUEUE_HOST_BUSY;
 
        req = stex_alloc_req(hba);
@@ -771,26 +711,18 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
        while (hba->status_tail != hba->status_head) {
                resp = stex_get_status(hba);
                tag = le16_to_cpu(resp->tag);
-               if (unlikely(tag >= TAG_BITMAP_LENGTH)) {
+               if (unlikely(tag >= hba->host->can_queue)) {
                        printk(KERN_WARNING DRV_NAME
                                "(%s): invalid tag\n", pci_name(hba->pdev));
                        continue;
                }
-               if (unlikely((hba->tag & (1 << tag)) == 0)) {
-                       printk(KERN_WARNING DRV_NAME
-                               "(%s): null tag\n", pci_name(hba->pdev));
-                       continue;
-               }
 
-               hba->out_req_cnt--;
                ccb = &hba->ccb[tag];
                if (hba->wait_ccb == ccb)
                        hba->wait_ccb = NULL;
                if (unlikely(ccb->req == NULL)) {
                        printk(KERN_WARNING DRV_NAME
                                "(%s): lagging req\n", pci_name(hba->pdev));
-                       __stex_free_tag((unsigned long *)&hba->tag, tag);
-                       stex_unmap_sg(hba, ccb->cmd); /* ??? */
                        continue;
                }
 
@@ -808,7 +740,15 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
                ccb->srb_status = resp->srb_status;
                ccb->scsi_status = resp->scsi_status;
 
-               if (ccb->req_type & PASSTHRU_REQ_TYPE) {
+               if (likely(ccb->cmd != NULL)) {
+                       if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
+                               ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
+                               stex_controller_info(hba, ccb);
+                       stex_unmap_sg(hba, ccb->cmd);
+                       stex_scsi_done(ccb);
+                       hba->out_req_cnt--;
+               } else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
+                       hba->out_req_cnt--;
                        if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) {
                                ccb->req_type = 0;
                                continue;
@@ -816,14 +756,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
                        ccb->req_type = 0;
                        if (waitqueue_active(&hba->waitq))
                                wake_up(&hba->waitq);
-                       continue;
                }
-               if (ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
-                       ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)
-                       stex_controller_info(hba, ccb);
-               __stex_free_tag((unsigned long *)&hba->tag, tag);
-               stex_unmap_sg(hba, ccb->cmd);
-               stex_scsi_done(ccb);
        }
 
 update_status:
@@ -933,21 +866,24 @@ static int stex_abort(struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *host = cmd->device->host;
        struct st_hba *hba = (struct st_hba *)host->hostdata;
-       u16 tag;
+       u16 tag = cmd->request->tag;
        void __iomem *base;
        u32 data;
        int result = SUCCESS;
        unsigned long flags;
        base = hba->mmio_base;
        spin_lock_irqsave(host->host_lock, flags);
-
-       for (tag = 0; tag < MU_MAX_REQUEST; tag++)
-               if (hba->ccb[tag].cmd == cmd && (hba->tag & (1 << tag))) {
-                       hba->wait_ccb = &(hba->ccb[tag]);
-                       break;
-               }
-       if (tag >= MU_MAX_REQUEST)
-               goto out;
+       if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
+               hba->wait_ccb = &hba->ccb[tag];
+       else {
+               for (tag = 0; tag < host->can_queue; tag++)
+                       if (hba->ccb[tag].cmd == cmd) {
+                               hba->wait_ccb = &hba->ccb[tag];
+                               break;
+                       }
+               if (tag >= host->can_queue)
+                       goto out;
+       }
 
        data = readl(base + ODBL);
        if (data == 0 || data == 0xffffffff)
@@ -965,6 +901,7 @@ static int stex_abort(struct scsi_cmnd *cmd)
        }
 
 fail_out:
+       stex_unmap_sg(hba, cmd);
        hba->wait_ccb->req = NULL; /* nullify the req's future return */
        hba->wait_ccb = NULL;
        result = FAILED;
@@ -1025,7 +962,6 @@ static int stex_reset(struct scsi_cmnd *cmd)
                return FAILED;
        }
        spin_lock_irqsave(hba->host->host_lock, flags);
-       hba->tag = 0;
        hba->req_head = 0;
        hba->req_tail = 0;
        hba->status_head = 0;
@@ -1061,6 +997,7 @@ static struct scsi_host_template driver_template = {
        .proc_name                      = DRV_NAME,
        .bios_param                     = stex_biosparam,
        .queuecommand                   = stex_queuecommand,
+       .slave_alloc                    = stex_slave_alloc,
        .slave_configure                = stex_slave_config,
        .slave_destroy                  = stex_slave_destroy,
        .eh_abort_handler               = stex_abort,
@@ -1171,6 +1108,14 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (err)
                goto out_free_irq;
 
+       scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
+       if (host->bqt == NULL) {
+               err = -ENOMEM;
+               printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
+                       pci_name(pdev));
+               goto out_free_irq;
+       }
+
        pci_set_drvdata(pdev, hba);
 
        err = scsi_add_host(host, &pdev->dev);
@@ -1206,15 +1151,7 @@ static void stex_hba_stop(struct st_hba *hba)
        struct req_msg *req;
        unsigned long flags;
        unsigned long before;
-       u16 tag;
-
-       before = jiffies;
-       while ((tag = stex_alloc_tag(hba, (unsigned long *)&hba->tag))
-               == TAG_BITMAP_LENGTH) {
-               if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
-                       return;
-               msleep(10);
-       }
+       u16 tag = 0;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
        req = stex_alloc_req(hba);
@@ -1233,12 +1170,12 @@ static void stex_hba_stop(struct st_hba *hba)
        stex_send_cmd(hba, req, tag);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
-       wait_event_timeout(hba->waitq,
-               !(hba->ccb[tag].req_type), ST_INTERNAL_TIMEOUT * HZ);
-       if (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE)
-               return;
-
-       stex_free_tag(hba, (unsigned long *)&hba->tag, tag);
+       before = jiffies;
+       while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
+               if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
+                       return;
+               msleep(10);
+       }
 }
 
 static void stex_hba_free(struct st_hba *hba)