Commit e7d2d832 authored by James Bottomley's avatar James Bottomley

[PATCH] first cut at fixing unable to requeue with no outstanding

 commands

The attached represents an attempt to break the scsi mid-layer of the 
assumption that any device can queue at least one command.

What essentially happens if the host rejects a command with no other 
outstanding commands, it does a very crude countdown (basically counts the 
number of cycles through the scsi request function) until the device gets 
enabled again when the count reaches zero.  I think the iteration in the 
request function is better than a fixed timer because it makes the system more 
responsive to I/O pressure (and also, it's easier to code).

I've tested this by making a SCSI driver artificially reject commands with 
none outstanding (and run it on my root device).  A value of seven seems to 
cause a delay of between half and five seconds before the host starts up again 
(depending on the I/O load).

If this approach looks acceptable, I plan the following enhancements

1. Make device_busy count down in the same fashion
2. give ->queuecommand() a two value return (one for blocking the entire host 
and another for just blocking the device).
3. Make the countdown tuneable from the host template.
parent 7570df54
......@@ -210,7 +210,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
retval->eh_notify = NULL; /* Who we notify when we exit. */
retval->host_blocked = FALSE;
retval->host_blocked = 0;
retval->host_self_blocked = FALSE;
#ifdef DEBUG
......
......@@ -394,11 +394,6 @@ struct Scsi_Host
unsigned highmem_io:1;
unsigned use_blk_tcq:1;
/*
* Host has rejected a command because it was busy.
*/
unsigned host_blocked:1;
/*
* Host has requested that no further requests come through for the
* time being.
......@@ -417,6 +412,19 @@ struct Scsi_Host
*/
unsigned some_device_starved:1;
/*
* Host has rejected a command because it was busy.
*/
unsigned int host_blocked;
/*
* Initial value for the blocking. If the queue is empty, host_blocked
* counts down in the request_fn until it restarts host operations as
* zero is reached.
*
* FIXME: This should probably be a value in the template */
#define SCSI_START_HOST_BLOCKED 7
void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
/*
......
......@@ -627,7 +627,7 @@ static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
return 0;
}
}
host->host_blocked = TRUE;
host->host_blocked = SCSI_START_HOST_BLOCKED;
} else {
if (cmd->device->device_busy == 0) {
if (scsi_retry_command(cmd) == 0) {
......@@ -1396,7 +1396,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* for both the queue full condition on a device, and for a
* host full condition on the host.
*/
host->host_blocked = FALSE;
host->host_blocked = 0;
device->device_blocked = FALSE;
/*
......
......@@ -754,6 +754,16 @@ void scsi_request_fn(request_queue_t * q)
if (SHpnt->in_recovery || blk_queue_plugged(q))
return;
if(SHpnt->host_busy == 0 && SHpnt->host_blocked) {
/* unblock after host_blocked iterates to zero */
if(--host_blocked == 0) {
printk("scsi%d unblocking host at zero depth\n", SHpnt->host_no);
} else {
blk_plug_device(q);
break;
}
}
/*
* If the device cannot accept another request, then quit.
*/
......
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