Commit a88b3261 authored by James Bottomley's avatar James Bottomley

Restore device command queue functionality

The recent slab allocation changes mean that we no longer keep a
permanent list of commands on the device_queue list.  However,
certain pieces of SCSI code relied on being able to traverse this
list to find details of all outstanding commands (the error handler
being the prime example).  This code adds back a new dynamic cmd_list
which keeps the list of commands currently allocated to the device.
Since the list is dynamic, it is protected by a lock (list_lock).
parent 28a59cb0
......@@ -2510,13 +2510,16 @@ static void adpt_fail_posted_scbs(adpt_hba* pHba)
Scsi_Device* d = NULL;
list_for_each_entry(d, &pHba->host->my_devices, siblings) {
for(cmd = d->device_queue; cmd ; cmd = cmd->next){
unsigned long flags;
spin_lock_irqsave(&d->list_lock, flags);
list_for_each_entry(cmd, &d->cmd_list, list) {
if(cmd->serial_number == 0){
continue;
}
cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1);
cmd->scsi_done(cmd);
}
spin_unlock_irqrestore(&d->list_lock, flags);
}
}
......
......@@ -205,13 +205,15 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
struct scsi_cmnd *scmd;
unsigned long flags;
/*
* Loop over all of the commands associated with the
* device. If any of them are busy, then set the state
* back to inactive and bail.
*/
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
if (scmd->request && scmd->request->rq_status != RQ_INACTIVE)
goto active;
......@@ -223,6 +225,7 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
if (scmd->request)
scmd->request->rq_status = RQ_SCSI_DISCONNECTING;
}
spin_unlock_irqrestore(&sdev->list_lock, flags);
return 0;
......@@ -233,12 +236,13 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
scmd->pid, scmd->state, scmd->owner);
list_for_each_entry(sdev, &shost->my_devices, siblings) {
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
list_for_each_entry(scmd, &sdev->cmd_list, list) {
if (scmd->request->rq_status == RQ_SCSI_DISCONNECTING)
scmd->request->rq_status = RQ_INACTIVE;
}
}
spin_unlock_irqrestore(&sdev->list_lock, flags);
printk(KERN_ERR "Device busy???\n");
return 1;
}
......
......@@ -403,12 +403,17 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
if (likely(cmd != NULL)) {
unsigned long flags;
memset(cmd, 0, sizeof(*cmd));
cmd->device = dev;
cmd->state = SCSI_STATE_UNUSED;
cmd->owner = SCSI_OWNER_NOBODY;
init_timer(&cmd->eh_timeout);
INIT_LIST_HEAD(&cmd->list);
spin_lock_irqsave(&dev->list_lock, flags);
list_add(&dev->cmd_list, &cmd->list);
spin_unlock_irqrestore(&dev->list_lock, flags);
}
return cmd;
......@@ -430,7 +435,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
struct Scsi_Host *shost = cmd->device->host;
unsigned long flags;
spin_lock_irqsave(&shost->free_list_lock, flags);
/* serious error if the command hasn't come from a device list */
spin_lock_irqsave(&cmd->device->list_lock, flags);
BUG_ON(list_empty(&cmd->list));
list_del_init(&cmd->list);
spin_unlock(&cmd->device->list_lock);
/* changing locks here, don't need to restore the irq state */
spin_lock(&shost->free_list_lock);
if (unlikely(list_empty(&shost->free_list))) {
list_add(&cmd->list, &shost->free_list);
cmd = NULL;
......
......@@ -571,9 +571,8 @@ struct scsi_device {
struct Scsi_Host *host;
request_queue_t *request_queue;
volatile unsigned short device_busy; /* commands actually active on low-level */
struct list_head free_cmnds; /* list of available Scsi_Cmnd structs */
struct list_head busy_cmnds; /* list of Scsi_Cmnd structs in use */
Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */
spinlock_t list_lock;
struct list_head cmd_list; /* queue of in use SCSI Command structures */
Scsi_Cmnd *current_cmnd; /* currently active command */
unsigned short queue_depth; /* How deep of a queue we want */
unsigned short last_queue_full_depth; /* These two are used by */
......@@ -724,7 +723,6 @@ struct scsi_cmnd {
unsigned short state;
unsigned short owner;
Scsi_Request *sc_request;
struct scsi_cmnd *next;
struct scsi_cmnd *reset_chain;
struct list_head list; /* scsi_cmnd participates in queue lists */
......
......@@ -233,7 +233,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
found = 0;
list_for_each_entry(sdev, &shost->my_devices, siblings) {
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
unsigned long flags;
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
if (scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
scmd->bh_next = *sc_list;
*sc_list = scmd;
......@@ -266,6 +269,7 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
}
}
}
spin_unlock_irqrestore(&sdev->list_lock, flags);
}
SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
......@@ -1739,25 +1743,13 @@ scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
int
scsi_reset_provider(Scsi_Device *dev, int flag)
{
struct scsi_cmnd SC, *SCpnt = &SC;
struct scsi_cmnd *SCpnt = scsi_get_command(dev, GFP_KERNEL);
struct request req;
int rtn;
SCpnt->request = &req;
memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
SCpnt->device = dev;
SCpnt->request->rq_status = RQ_SCSI_BUSY;
SCpnt->request->waiting = NULL;
SCpnt->use_sg = 0;
SCpnt->old_use_sg = 0;
SCpnt->old_cmd_len = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
SCpnt->resid = 0;
SCpnt->serial_number = 0;
SCpnt->serial_number_at_timeout = 0;
SCpnt->host_scribble = NULL;
SCpnt->next = NULL;
SCpnt->state = SCSI_STATE_INITIALIZING;
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
......@@ -1790,5 +1782,6 @@ scsi_reset_provider(Scsi_Device *dev, int flag)
rtn = scsi_new_reset(SCpnt, flag);
scsi_delete_timer(SCpnt);
scsi_put_command(SCpnt);
return rtn;
}
......@@ -359,7 +359,10 @@ static void scsi_dump_status(int level)
printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) "
"(ret all flg) (to/cmd to ito) cmd snse result\n");
list_for_each_entry(SDpnt, &shpnt->my_devices, siblings) {
for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
unsigned long flags;
spin_lock_irqsave(&SDpnt->list_lock, flags);
list_for_each_entry(SCpnt, &SDpnt->cmd_list, list) {
/* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
i++,
......@@ -389,6 +392,7 @@ static void scsi_dump_status(int level)
SCpnt->sense_buffer[2],
SCpnt->result);
}
spin_unlock_irqrestore(&SDpnt->list_lock, flags);
}
}
}
......
......@@ -449,6 +449,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev->online = TRUE;
INIT_LIST_HEAD(&sdev->siblings);
INIT_LIST_HEAD(&sdev->same_target_siblings);
spin_lock_init(&sdev->list_lock);
/*
* Some low level driver could use device->type
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment