Skip to content

Commit

Permalink
[SCSI] stex: add shared tags from block
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ed Lin authored and James Bottomley committed Sep 2, 2006
1 parent 5a25ba1 commit cf35588
Showing 1 changed file with 57 additions and 120 deletions.
177 changes: 57 additions & 120 deletions drivers/scsi/stex.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand All @@ -808,22 +740,23 @@ 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;
}
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:
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down

0 comments on commit cf35588

Please sign in to comment.