Commit f1b28fd9 authored by Luben Tuikov's avatar Luben Tuikov Committed by James Bottomley

scsi_softirq queue is now list_head, eliminate bh_next

The following patch gets rid of softscsi_data struct and
array for the more manageable
static struct list_head done_q[NR_CPUS] __cacheline_aligned;

Thus, scsi_cmnd::bh_next is eliminated, since it was used only
in the scsi softirq processing code.

The comments are updated.

80 chars per line for the affected functions: scsi_done()
and scsi_softirq().

Eliminated is the double loop in scsi_softirq() -- this is
better handled in do_softirq() and gives the system a ``breather''.
(There are pros and cons for either side and if you guys
think that it was better with the double loop, I'll change it and
resubmit the patch.)
parent 5f99bd9a
...@@ -96,12 +96,7 @@ unsigned long scsi_pid; ...@@ -96,12 +96,7 @@ unsigned long scsi_pid;
Scsi_Cmnd *last_cmnd; Scsi_Cmnd *last_cmnd;
static unsigned long serial_number; static unsigned long serial_number;
struct softscsi_data { static struct list_head done_q[NR_CPUS] __cacheline_aligned;
Scsi_Cmnd *head;
Scsi_Cmnd *tail;
};
static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned;
/* /*
* List of all highlevel drivers. * List of all highlevel drivers.
...@@ -637,79 +632,60 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt) ...@@ -637,79 +632,60 @@ void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt)
} }
/** /**
* scsi_done - Mark this command as done * scsi_done - Enqueue the finished SCSI command into the done queue.
* @SCpnt: The SCSI Command which we think we've completed. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
* * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
* This function is the mid-level interrupt routine, which decides how
* to handle error conditions. Each invocation of this function must
* do one and *only* one of the following:
* *
* 1) Insert command in BH queue. * This function is the mid-level's (SCSI Core) interrupt routine, which
* 2) Activate error handler for host. * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
* the command to the done queue for further processing.
* *
* There is no longer a problem with stack overflow. Interrupts queue * This is the producer of the done queue who enqueues at the tail.
* Scsi_Cmnd on a per-CPU queue and the softirq handler removes them
* from the queue one at a time.
* *
* This function is sometimes called from interrupt context, but sometimes * This function is interrupt context safe.
* from task context.
*/ */
void scsi_done(Scsi_Cmnd * SCpnt) void scsi_done(struct scsi_cmnd *cmd)
{ {
int cpu;
unsigned long flags; unsigned long flags;
int cpu, tstatus; struct list_head *pdone_q;
struct softscsi_data *queue;
/* /*
* We don't have to worry about this one timing out any more. * We don't have to worry about this one timing out any more.
*/ * If we are unable to remove the timer, then the command
tstatus = scsi_delete_timer(SCpnt); * has already timed out. In which case, we have no choice but to
/*
* If we are unable to remove the timer, it means that the command
* has already timed out. In this case, we have no choice but to
* let the timeout function run, as we have no idea where in fact * let the timeout function run, as we have no idea where in fact
* that function could really be. It might be on another processor, * that function could really be. It might be on another processor,
* etc, etc. * etc, etc.
*/ */
if (!tstatus) { if (!scsi_delete_timer(cmd))
return; return;
}
/* Set the serial numbers back to zero */ /* Set the serial numbers back to zero */
SCpnt->serial_number = 0; cmd->serial_number = 0;
SCpnt->serial_number_at_timeout = 0; cmd->serial_number_at_timeout = 0;
SCpnt->state = SCSI_STATE_BHQUEUE; cmd->state = SCSI_STATE_BHQUEUE;
SCpnt->owner = SCSI_OWNER_BH_HANDLER; cmd->owner = SCSI_OWNER_BH_HANDLER;
SCpnt->bh_next = NULL;
/* /*
* Next, put this command in the softirq queue. * Next, enqueue the command into the done queue.
* * It is a per-CPU queue, so we just disable local interrupts
* This is a per-CPU queue, so we just disable local interrupts
* and need no spinlock. * and need no spinlock.
*/ */
local_irq_save(flags); local_irq_save(flags);
cpu = smp_processor_id(); cpu = smp_processor_id();
queue = &softscsi_data[cpu]; pdone_q = &done_q[cpu];
list_add_tail(&cmd->eh_entry, pdone_q);
if (!queue->head) {
queue->head = SCpnt;
queue->tail = SCpnt;
} else {
queue->tail->bh_next = SCpnt;
queue->tail = SCpnt;
}
cpu_raise_softirq(cpu, SCSI_SOFTIRQ); cpu_raise_softirq(cpu, SCSI_SOFTIRQ);
local_irq_restore(flags); local_irq_restore(flags);
} }
/** /**
* scsi_softirq - Perform post-interrupt handling for completed commands * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
*
* This is the consumer of the done queue.
* *
* This is called with all interrupts enabled. This should reduce * This is called with all interrupts enabled. This should reduce
* interrupt latency, stack depth, and reentrancy of the low-level * interrupt latency, stack depth, and reentrancy of the low-level
...@@ -717,88 +693,92 @@ void scsi_done(Scsi_Cmnd * SCpnt) ...@@ -717,88 +693,92 @@ void scsi_done(Scsi_Cmnd * SCpnt)
*/ */
static void scsi_softirq(struct softirq_action *h) static void scsi_softirq(struct softirq_action *h)
{ {
int cpu = smp_processor_id(); LIST_HEAD(local_q);
struct softscsi_data *queue = &softscsi_data[cpu];
while (queue->head) { local_irq_disable();
Scsi_Cmnd *SCpnt, *SCnext; list_splice_init(&done_q[smp_processor_id()], &local_q);
local_irq_enable();
local_irq_disable(); while (!list_empty(&local_q)) {
SCpnt = queue->head; struct scsi_cmnd *cmd = list_entry(local_q.next,
queue->head = NULL; struct scsi_cmnd, eh_entry);
local_irq_enable(); list_del_init(&cmd->eh_entry);
for (; SCpnt; SCpnt = SCnext) { switch (scsi_decide_disposition(cmd)) {
SCnext = SCpnt->bh_next; case SUCCESS:
/*
* Add to BH queue.
*/
SCSI_LOG_MLCOMPLETE(3,
printk("Command finished %d %d "
"0x%x\n",
cmd->device->host->host_busy,
cmd->device->host->host_failed,
cmd->result));
scsi_finish_command(cmd);
break;
case NEEDS_RETRY:
/*
* We only come in here if we want to retry a
* command. The test to see whether the
* command should be retried should be keeping
* track of the number of tries, so we don't
* end up looping, of course.
*/
SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry "
"%d %d 0x%x\n",
cmd->device->host->host_busy,
cmd->device->host->host_failed,
cmd->result));
switch (scsi_decide_disposition(SCpnt)) { scsi_retry_command(cmd);
case SUCCESS: break;
/* case ADD_TO_MLQUEUE:
* Add to BH queue. /*
*/ * This typically happens for a QUEUE_FULL
SCSI_LOG_MLCOMPLETE(3, printk("Command finished %d %d 0x%x\n", SCpnt->device->host->host_busy, * message - typically only when the queue
SCpnt->device->host->host_failed, * depth is only approximate for a given
SCpnt->result)); * device. Adding a command to the queue for
* the device will prevent further commands
* from being sent to the device, so we
* shouldn't end up with tons of things being
* sent down that shouldn't be.
*/
SCSI_LOG_MLCOMPLETE(3, printk("Command rejected as "
"device queue full, "
"put on ml queue %p\n",
cmd));
scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
break;
default:
/*
* Here we have a fatal error of some sort.
* Turn it over to the error handler.
*/
SCSI_LOG_MLCOMPLETE(3,
printk("Command failed %p %x "
"busy=%d failed=%d\n",
cmd, cmd->result,
cmd->device->host->host_busy,
cmd->device->host->host_failed));
scsi_finish_command(SCpnt); /*
break; * Dump the sense information too.
case NEEDS_RETRY: */
/* if ((status_byte(cmd->result)&CHECK_CONDITION) != 0) {
* We only come in here if we want to retry a SCSI_LOG_MLCOMPLETE(3, print_sense("bh", cmd));
* command. The test to see whether the }
* command should be retried should be keeping
* track of the number of tries, so we don't
* end up looping, of course.
*/
SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry %d %d 0x%x\n", SCpnt->device->host->host_busy,
SCpnt->device->host->host_failed, SCpnt->result));
scsi_retry_command(SCpnt);
break;
case ADD_TO_MLQUEUE:
/*
* This typically happens for a QUEUE_FULL
* message - typically only when the queue
* depth is only approximate for a given
* device. Adding a command to the queue for
* the device will prevent further commands
* from being sent to the device, so we
* shouldn't end up with tons of things being
* sent down that shouldn't be.
*/
SCSI_LOG_MLCOMPLETE(3, printk("Command rejected as device queue full, put on ml queue %p\n",
SCpnt));
scsi_queue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
break;
default:
/*
* Here we have a fatal error of some sort.
* Turn it over to the error handler.
*/
SCSI_LOG_MLCOMPLETE(3,
printk("Command failed %p %x busy=%d failed=%d\n",
SCpnt, SCpnt->result,
SCpnt->device->host->host_busy,
SCpnt->device->host->host_failed));
if (!scsi_eh_scmd_add(cmd, 0)) {
/* /*
* Dump the sense information too. * We only get here if the error
* recovery thread has died.
*/ */
if ((status_byte(SCpnt->result) & CHECK_CONDITION) != 0) { scsi_finish_command(cmd);
SCSI_LOG_MLCOMPLETE(3, print_sense("bh", SCpnt)); }
} }
}
if (!scsi_eh_scmd_add(SCpnt, 0))
{
/*
* We only get here if the error
* recovery thread has died.
*/
scsi_finish_command(SCpnt);
}
} /* switch */
} /* for(; SCpnt...) */
} /* while(queue->head) */
} }
/* /*
...@@ -1481,7 +1461,7 @@ __setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags); ...@@ -1481,7 +1461,7 @@ __setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
static int __init init_scsi(void) static int __init init_scsi(void)
{ {
int error; int error, i;
error = scsi_init_queue(); error = scsi_init_queue();
if (error) if (error)
...@@ -1496,6 +1476,9 @@ static int __init init_scsi(void) ...@@ -1496,6 +1476,9 @@ static int __init init_scsi(void)
if (error) if (error)
goto cleanup_devlist; goto cleanup_devlist;
for (i = 0; i < NR_CPUS; i++)
INIT_LIST_HEAD(&done_q[i]);
scsi_host_init(); scsi_host_init();
devfs_mk_dir(NULL, "scsi", NULL); devfs_mk_dir(NULL, "scsi", NULL);
open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
......
...@@ -741,8 +741,7 @@ struct scsi_cmnd { ...@@ -741,8 +741,7 @@ struct scsi_cmnd {
* abort, etc are in process. * abort, etc are in process.
*/ */
unsigned volatile char internal_timeout; unsigned volatile char internal_timeout;
struct scsi_cmnd *bh_next; /* To enumerate the commands waiting
to be processed. */
unsigned char cmd_len; unsigned char cmd_len;
unsigned char old_cmd_len; unsigned char old_cmd_len;
unsigned char sc_data_direction; unsigned char sc_data_direction;
......
...@@ -125,7 +125,6 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) ...@@ -125,7 +125,6 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
*/ */
cmd->state = SCSI_STATE_MLQUEUE; cmd->state = SCSI_STATE_MLQUEUE;
cmd->owner = SCSI_OWNER_MIDLEVEL; cmd->owner = SCSI_OWNER_MIDLEVEL;
cmd->bh_next = NULL;
/* /*
* Decrement the counters, since these commands are no longer * Decrement the counters, since these commands are no longer
......
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