[SCSI] stex: add shared tags from block
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>
This commit is contained in:
parent
5a25ba1677
commit
cf355883f5
|
@ -34,6 +34,7 @@
|
||||||
#include <scsi/scsi_device.h>
|
#include <scsi/scsi_device.h>
|
||||||
#include <scsi/scsi_cmnd.h>
|
#include <scsi/scsi_cmnd.h>
|
||||||
#include <scsi/scsi_host.h>
|
#include <scsi/scsi_host.h>
|
||||||
|
#include <scsi/scsi_tcq.h>
|
||||||
|
|
||||||
#define DRV_NAME "stex"
|
#define DRV_NAME "stex"
|
||||||
#define ST_DRIVER_VERSION "2.9.0.13"
|
#define ST_DRIVER_VERSION "2.9.0.13"
|
||||||
|
@ -95,7 +96,6 @@ enum {
|
||||||
|
|
||||||
/* request count, etc. */
|
/* request count, etc. */
|
||||||
MU_MAX_REQUEST = 32,
|
MU_MAX_REQUEST = 32,
|
||||||
TAG_BITMAP_LENGTH = MU_MAX_REQUEST,
|
|
||||||
|
|
||||||
/* one message wasted, use MU_MAX_REQUEST+1
|
/* one message wasted, use MU_MAX_REQUEST+1
|
||||||
to handle MU_MAX_REQUEST messages */
|
to handle MU_MAX_REQUEST messages */
|
||||||
|
@ -265,7 +265,6 @@ struct st_hba {
|
||||||
struct Scsi_Host *host;
|
struct Scsi_Host *host;
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
|
|
||||||
u32 tag;
|
|
||||||
u32 req_head;
|
u32 req_head;
|
||||||
u32 req_tail;
|
u32 req_tail;
|
||||||
u32 status_head;
|
u32 status_head;
|
||||||
|
@ -309,40 +308,6 @@ static void stex_gettime(__le32 *time)
|
||||||
*(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
|
*(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)
|
static struct status_msg *stex_get_status(struct st_hba *hba)
|
||||||
{
|
{
|
||||||
struct status_msg *status =
|
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 */
|
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
|
static int
|
||||||
stex_slave_config(struct scsi_device *sdev)
|
stex_slave_config(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
sdev->use_10_for_rw = 1;
|
sdev->use_10_for_rw = 1;
|
||||||
sdev->use_10_for_ms = 1;
|
sdev->use_10_for_ms = 1;
|
||||||
sdev->timeout = 60 * HZ;
|
sdev->timeout = 60 * HZ;
|
||||||
|
sdev->tagged_supported = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stex_slave_destroy(struct scsi_device *sdev)
|
stex_slave_destroy(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
struct st_hba *hba = (struct st_hba *) sdev->host->hostdata;
|
scsi_deactivate_tcq(sdev, 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -650,8 +589,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
||||||
|
|
||||||
cmd->scsi_done = done;
|
cmd->scsi_done = done;
|
||||||
|
|
||||||
if (unlikely((tag = __stex_alloc_tag((unsigned long *)&hba->tag))
|
tag = cmd->request->tag;
|
||||||
== TAG_BITMAP_LENGTH))
|
|
||||||
|
if (unlikely(tag >= host->can_queue))
|
||||||
return SCSI_MLQUEUE_HOST_BUSY;
|
return SCSI_MLQUEUE_HOST_BUSY;
|
||||||
|
|
||||||
req = stex_alloc_req(hba);
|
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) {
|
while (hba->status_tail != hba->status_head) {
|
||||||
resp = stex_get_status(hba);
|
resp = stex_get_status(hba);
|
||||||
tag = le16_to_cpu(resp->tag);
|
tag = le16_to_cpu(resp->tag);
|
||||||
if (unlikely(tag >= TAG_BITMAP_LENGTH)) {
|
if (unlikely(tag >= hba->host->can_queue)) {
|
||||||
printk(KERN_WARNING DRV_NAME
|
printk(KERN_WARNING DRV_NAME
|
||||||
"(%s): invalid tag\n", pci_name(hba->pdev));
|
"(%s): invalid tag\n", pci_name(hba->pdev));
|
||||||
continue;
|
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];
|
ccb = &hba->ccb[tag];
|
||||||
if (hba->wait_ccb == ccb)
|
if (hba->wait_ccb == ccb)
|
||||||
hba->wait_ccb = NULL;
|
hba->wait_ccb = NULL;
|
||||||
if (unlikely(ccb->req == NULL)) {
|
if (unlikely(ccb->req == NULL)) {
|
||||||
printk(KERN_WARNING DRV_NAME
|
printk(KERN_WARNING DRV_NAME
|
||||||
"(%s): lagging req\n", pci_name(hba->pdev));
|
"(%s): lagging req\n", pci_name(hba->pdev));
|
||||||
__stex_free_tag((unsigned long *)&hba->tag, tag);
|
|
||||||
stex_unmap_sg(hba, ccb->cmd); /* ??? */
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +740,15 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
||||||
ccb->srb_status = resp->srb_status;
|
ccb->srb_status = resp->srb_status;
|
||||||
ccb->scsi_status = resp->scsi_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) {
|
if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) {
|
||||||
ccb->req_type = 0;
|
ccb->req_type = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -816,14 +756,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
||||||
ccb->req_type = 0;
|
ccb->req_type = 0;
|
||||||
if (waitqueue_active(&hba->waitq))
|
if (waitqueue_active(&hba->waitq))
|
||||||
wake_up(&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:
|
update_status:
|
||||||
|
@ -933,21 +866,24 @@ static int stex_abort(struct scsi_cmnd *cmd)
|
||||||
{
|
{
|
||||||
struct Scsi_Host *host = cmd->device->host;
|
struct Scsi_Host *host = cmd->device->host;
|
||||||
struct st_hba *hba = (struct st_hba *)host->hostdata;
|
struct st_hba *hba = (struct st_hba *)host->hostdata;
|
||||||
u16 tag;
|
u16 tag = cmd->request->tag;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
u32 data;
|
u32 data;
|
||||||
int result = SUCCESS;
|
int result = SUCCESS;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
base = hba->mmio_base;
|
base = hba->mmio_base;
|
||||||
spin_lock_irqsave(host->host_lock, flags);
|
spin_lock_irqsave(host->host_lock, flags);
|
||||||
|
if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
|
||||||
for (tag = 0; tag < MU_MAX_REQUEST; tag++)
|
hba->wait_ccb = &hba->ccb[tag];
|
||||||
if (hba->ccb[tag].cmd == cmd && (hba->tag & (1 << tag))) {
|
else {
|
||||||
hba->wait_ccb = &(hba->ccb[tag]);
|
for (tag = 0; tag < host->can_queue; tag++)
|
||||||
break;
|
if (hba->ccb[tag].cmd == cmd) {
|
||||||
}
|
hba->wait_ccb = &hba->ccb[tag];
|
||||||
if (tag >= MU_MAX_REQUEST)
|
break;
|
||||||
goto out;
|
}
|
||||||
|
if (tag >= host->can_queue)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
data = readl(base + ODBL);
|
data = readl(base + ODBL);
|
||||||
if (data == 0 || data == 0xffffffff)
|
if (data == 0 || data == 0xffffffff)
|
||||||
|
@ -965,6 +901,7 @@ static int stex_abort(struct scsi_cmnd *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fail_out:
|
fail_out:
|
||||||
|
stex_unmap_sg(hba, cmd);
|
||||||
hba->wait_ccb->req = NULL; /* nullify the req's future return */
|
hba->wait_ccb->req = NULL; /* nullify the req's future return */
|
||||||
hba->wait_ccb = NULL;
|
hba->wait_ccb = NULL;
|
||||||
result = FAILED;
|
result = FAILED;
|
||||||
|
@ -1025,7 +962,6 @@ static int stex_reset(struct scsi_cmnd *cmd)
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
hba->tag = 0;
|
|
||||||
hba->req_head = 0;
|
hba->req_head = 0;
|
||||||
hba->req_tail = 0;
|
hba->req_tail = 0;
|
||||||
hba->status_head = 0;
|
hba->status_head = 0;
|
||||||
|
@ -1061,6 +997,7 @@ static struct scsi_host_template driver_template = {
|
||||||
.proc_name = DRV_NAME,
|
.proc_name = DRV_NAME,
|
||||||
.bios_param = stex_biosparam,
|
.bios_param = stex_biosparam,
|
||||||
.queuecommand = stex_queuecommand,
|
.queuecommand = stex_queuecommand,
|
||||||
|
.slave_alloc = stex_slave_alloc,
|
||||||
.slave_configure = stex_slave_config,
|
.slave_configure = stex_slave_config,
|
||||||
.slave_destroy = stex_slave_destroy,
|
.slave_destroy = stex_slave_destroy,
|
||||||
.eh_abort_handler = stex_abort,
|
.eh_abort_handler = stex_abort,
|
||||||
|
@ -1171,6 +1108,14 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_free_irq;
|
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);
|
pci_set_drvdata(pdev, hba);
|
||||||
|
|
||||||
err = scsi_add_host(host, &pdev->dev);
|
err = scsi_add_host(host, &pdev->dev);
|
||||||
|
@ -1206,15 +1151,7 @@ static void stex_hba_stop(struct st_hba *hba)
|
||||||
struct req_msg *req;
|
struct req_msg *req;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long before;
|
unsigned long before;
|
||||||
u16 tag;
|
u16 tag = 0;
|
||||||
|
|
||||||
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);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
req = stex_alloc_req(hba);
|
req = stex_alloc_req(hba);
|
||||||
|
@ -1233,12 +1170,12 @@ static void stex_hba_stop(struct st_hba *hba)
|
||||||
stex_send_cmd(hba, req, tag);
|
stex_send_cmd(hba, req, tag);
|
||||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||||
|
|
||||||
wait_event_timeout(hba->waitq,
|
before = jiffies;
|
||||||
!(hba->ccb[tag].req_type), ST_INTERNAL_TIMEOUT * HZ);
|
while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
|
||||||
if (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE)
|
if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
|
||||||
return;
|
return;
|
||||||
|
msleep(10);
|
||||||
stex_free_tag(hba, (unsigned long *)&hba->tag, tag);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stex_hba_free(struct st_hba *hba)
|
static void stex_hba_free(struct st_hba *hba)
|
||||||
|
|
Loading…
Reference in New Issue