From: "Ed Lin" <[email protected]>
- indicate correct MODE SENSE caching page for shutdown sd flush
- implement slave_destroy for driver unload flush
- modify notification routine(stex_hba_stop) for firmware to prepare shutdown
- adjust alloc/free tag functions for this purpose as necessary
Signed-off-by: Ed Lin <[email protected]>
---
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index cb17415..fd09330 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -309,7 +309,7 @@ static void stex_gettime(__le32 *time)
*(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
}
-static u16 stex_alloc_tag(unsigned long *bitmap)
+static u16 __stex_alloc_tag(unsigned long *bitmap)
{
int i;
i = find_first_zero_bit(bitmap, TAG_BITMAP_LENGTH);
@@ -318,11 +318,31 @@ static u16 stex_alloc_tag(unsigned long
return (u16)i;
}
-static void stex_free_tag(unsigned long *bitmap, u16 tag)
+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 =
@@ -523,6 +543,51 @@ stex_slave_config(struct scsi_device *sd
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);
+}
+
static int
stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
{
@@ -539,11 +604,17 @@ stex_queuecommand(struct scsi_cmnd *cmd,
switch (cmd->cmnd[0]) {
case MODE_SENSE_10:
{
- static char mode_sense10[8] = { 0, 6, 0, 0, 0, 0, 0, 0 };
-
- stex_direct_copy(cmd, mode_sense10, sizeof(mode_sense10));
- cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
- done(cmd);
+ static char ms10_caching_page[12] =
+ { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 };
+ unsigned char page;
+ page = cmd->cmnd[2] & 0x3f;
+ if (page == 0x8 || page == 0x3f) {
+ stex_direct_copy(cmd, ms10_caching_page,
+ sizeof(ms10_caching_page));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ } else
+ stex_invalid_field(cmd, done);
return 0;
}
case INQUIRY:
@@ -579,7 +650,7 @@ stex_queuecommand(struct scsi_cmnd *cmd,
cmd->scsi_done = done;
- if (unlikely((tag = stex_alloc_tag((unsigned long *)&hba->tag))
+ if (unlikely((tag = __stex_alloc_tag((unsigned long *)&hba->tag))
== TAG_BITMAP_LENGTH))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -718,7 +789,7 @@ static void stex_mu_intr(struct st_hba *
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_free_tag((unsigned long *)&hba->tag, tag);
stex_unmap_sg(hba, ccb->cmd); /* ??? */
continue;
}
@@ -750,7 +821,7 @@ static void stex_mu_intr(struct st_hba *
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_free_tag((unsigned long *)&hba->tag, tag);
stex_unmap_sg(hba, ccb->cmd);
stex_scsi_done(ccb);
}
@@ -965,34 +1036,6 @@ static int stex_reset(struct scsi_cmnd *
return SUCCESS;
}
-static void stex_internal_flush(struct st_hba *hba, int id, u16 tag)
-{
- struct req_msg *req;
-
- req = stex_alloc_req(hba);
- memset(req->cdb, 0, STEX_CDB_LENGTH);
-
- if (id < ST_MAX_ARRAY_SUPPORTED*ST_MAX_LUN_PER_TARGET) {
- req->target = id/ST_MAX_LUN_PER_TARGET;
- req->lun = id%ST_MAX_LUN_PER_TARGET;
- req->cdb[0] = CONTROLLER_CMD;
- req->cdb[1] = CTLR_POWER_STATE_CHANGE;
- req->cdb[2] = CTLR_POWER_SAVING;
- } else {
- req->target = id/ST_MAX_LUN_PER_TARGET - ST_MAX_ARRAY_SUPPORTED;
- req->lun = id%ST_MAX_LUN_PER_TARGET;
- 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);
-}
-
static int stex_biosparam(struct scsi_device *sdev,
struct block_device *bdev, sector_t capacity, int geom[])
{
@@ -1019,6 +1062,7 @@ static struct scsi_host_template driver_
.bios_param = stex_biosparam,
.queuecommand = stex_queuecommand,
.slave_configure = stex_slave_config,
+ .slave_destroy = stex_slave_destroy,
.eh_abort_handler = stex_abort,
.eh_host_reset_handler = stex_reset,
.can_queue = ST_CAN_QUEUE,
@@ -1159,31 +1203,42 @@ out_disable:
static void stex_hba_stop(struct st_hba *hba)
{
+ struct req_msg *req;
unsigned long flags;
- int i;
+ unsigned long before;
u16 tag;
- spin_lock_irqsave(hba->host->host_lock, flags);
- if ((tag = stex_alloc_tag((unsigned long *)&hba->tag))
+ before = jiffies;
+ while ((tag = stex_alloc_tag(hba, (unsigned long *)&hba->tag))
== TAG_BITMAP_LENGTH) {
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- printk(KERN_ERR DRV_NAME "(%s): unable to alloc tag\n",
- pci_name(hba->pdev));
- return;
- }
- for (i=0; i<(ST_MAX_ARRAY_SUPPORTED*ST_MAX_LUN_PER_TARGET*2); i++) {
- stex_internal_flush(hba, i, 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)
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
return;
- spin_lock_irqsave(hba->host->host_lock, flags);
+ msleep(10);
}
- stex_free_tag((unsigned long *)&hba->tag, tag);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ req = stex_alloc_req(hba);
+ memset(req->cdb, 0, STEX_CDB_LENGTH);
+
+ req->cdb[0] = CONTROLLER_CMD;
+ req->cdb[1] = CTLR_POWER_STATE_CHANGE;
+ req->cdb[2] = CTLR_POWER_SAVING;
+
+ 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 void stex_hba_free(struct st_hba *hba)