Commit 4fac4dee authored by James Bottomley's avatar James Bottomley

[PATCH] remove mid-layer assumption that devices must be able to queue at least one command

This allows the request_fn() to recover properly from either host_blocked
or device_blocked at zero command depth.

Also adds the facility for queuecommand() to tell us whether it wants
the host or only the device blocked
parent e7d2d832
......@@ -209,6 +209,10 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
retval->ehandler = NULL; /* Initial value until the thing starts up. */
retval->eh_notify = NULL; /* Who we notify when we exit. */
retval->max_host_blocked = tpnt->max_host_blocked ? tpnt->max_host_blocked : SCSI_DEFAULT_HOST_BLOCKED;
printk("scsi%d: max_host_blocked set to %d\n", retval->host_no, retval->max_host_blocked);
retval->host_blocked = 0;
retval->host_self_blocked = FALSE;
......
......@@ -297,6 +297,19 @@ typedef struct SHT
*/
char *proc_name;
/*
* countdown for host blocking with no commands outstanding
*/
unsigned int max_host_blocked;
/*
* Default 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_DEFAULT_HOST_BLOCKED 7
} Scsi_Host_Template;
/*
......@@ -418,12 +431,9 @@ struct Scsi_Host
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
* Value host_blocked counts down from
*/
unsigned int max_host_blocked;
void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
......
......@@ -622,19 +622,9 @@ static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
* possibly work anyways.
*/
if (reason == SCSI_MLQUEUE_HOST_BUSY) {
if (host->host_busy == 0) {
if (scsi_retry_command(cmd) == 0) {
return 0;
}
}
host->host_blocked = SCSI_START_HOST_BLOCKED;
host->host_blocked = host->max_host_blocked;
} else {
if (cmd->device->device_busy == 0) {
if (scsi_retry_command(cmd) == 0) {
return 0;
}
}
cmd->device->device_blocked = TRUE;
cmd->device->device_blocked = cmd->device->max_device_blocked;
}
/*
......@@ -793,7 +783,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
spin_unlock_irqrestore(host->host_lock, flags);
if (rtn != 0) {
scsi_delete_timer(SCpnt);
scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
scsi_mlqueue_insert(SCpnt, rtn == SCSI_MLQUEUE_DEVICE_BUSY ? rtn : SCSI_MLQUEUE_HOST_BUSY);
SCSI_LOG_MLQUEUE(3,
printk("queuecommand : request rejected\n"));
}
......@@ -1397,7 +1387,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* host full condition on the host.
*/
host->host_blocked = 0;
device->device_blocked = FALSE;
device->device_blocked = 0;
/*
* If we have valid sense information, then some kind of recovery
......
......@@ -611,12 +611,18 @@ struct scsi_device {
* this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */
unsigned device_blocked:1; /* Device returned QUEUE_FULL. */
unsigned ten:1; /* support ten byte read / write */
unsigned remap:1; /* support remapping */
unsigned starved:1; /* unable to process commands because
host busy */
unsigned int device_blocked; /* Device returned QUEUE_FULL. */
unsigned int max_device_blocked; /* what device_blocked counts down from */
/* default value if the device doesn't override */
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
// Flag to allow revalidate to succeed in sd_open
int allow_revalidate;
struct device sdev_driverfs_dev;
......
......@@ -756,14 +756,22 @@ void scsi_request_fn(request_queue_t * q)
if(SHpnt->host_busy == 0 && SHpnt->host_blocked) {
/* unblock after host_blocked iterates to zero */
if(--host_blocked == 0) {
if(--SHpnt->host_blocked == 0) {
printk("scsi%d unblocking host at zero depth\n", SHpnt->host_no);
} else {
blk_plug_device(q);
break;
}
}
if(SDpnt->device_busy == 0 && SDpnt->device_blocked) {
/* unblock after device_blocked iterates to zero */
if(--SDpnt->device_blocked == 0) {
printk("scsi%d (%d:%d) unblocking device at zero depth\n", SHpnt->host_no, SDpnt->id, SDpnt->lun);
} else {
blk_plug_device(q);
break;
}
}
/*
* If the device cannot accept another request, then quit.
*/
......
......@@ -1461,6 +1461,10 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
if (*bflags & BLIST_SINGLELUN)
sdev->single_lun = 1;
/* if the device needs this changing, it may do so in the detect
* function */
sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->detect)
sdev->attached += (*sdt->detect) (sdev);
......
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