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) ...@@ -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->ehandler = NULL; /* Initial value until the thing starts up. */
retval->eh_notify = NULL; /* Who we notify when we exit. */ 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_blocked = 0;
retval->host_self_blocked = FALSE; retval->host_self_blocked = FALSE;
......
...@@ -297,6 +297,19 @@ typedef struct SHT ...@@ -297,6 +297,19 @@ typedef struct SHT
*/ */
char *proc_name; 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; } Scsi_Host_Template;
/* /*
...@@ -418,12 +431,9 @@ struct Scsi_Host ...@@ -418,12 +431,9 @@ struct Scsi_Host
unsigned int host_blocked; unsigned int host_blocked;
/* /*
* Initial value for the blocking. If the queue is empty, host_blocked * Value host_blocked counts down from
* counts down in the request_fn until it restarts host operations as */
* zero is reached. unsigned int max_host_blocked;
*
* 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 *); void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
......
...@@ -622,19 +622,9 @@ static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) ...@@ -622,19 +622,9 @@ static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
* possibly work anyways. * possibly work anyways.
*/ */
if (reason == SCSI_MLQUEUE_HOST_BUSY) { if (reason == SCSI_MLQUEUE_HOST_BUSY) {
if (host->host_busy == 0) { host->host_blocked = host->max_host_blocked;
if (scsi_retry_command(cmd) == 0) {
return 0;
}
}
host->host_blocked = SCSI_START_HOST_BLOCKED;
} else { } else {
if (cmd->device->device_busy == 0) { cmd->device->device_blocked = cmd->device->max_device_blocked;
if (scsi_retry_command(cmd) == 0) {
return 0;
}
}
cmd->device->device_blocked = TRUE;
} }
/* /*
...@@ -793,7 +783,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) ...@@ -793,7 +783,7 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
spin_unlock_irqrestore(host->host_lock, flags); spin_unlock_irqrestore(host->host_lock, flags);
if (rtn != 0) { if (rtn != 0) {
scsi_delete_timer(SCpnt); 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, SCSI_LOG_MLQUEUE(3,
printk("queuecommand : request rejected\n")); printk("queuecommand : request rejected\n"));
} }
...@@ -1397,7 +1387,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt) ...@@ -1397,7 +1387,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* host full condition on the host. * host full condition on the host.
*/ */
host->host_blocked = 0; host->host_blocked = 0;
device->device_blocked = FALSE; device->device_blocked = 0;
/* /*
* If we have valid sense information, then some kind of recovery * If we have valid sense information, then some kind of recovery
......
...@@ -611,12 +611,18 @@ struct scsi_device { ...@@ -611,12 +611,18 @@ struct scsi_device {
* this device */ * this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */ * because we did a bus reset. */
unsigned device_blocked:1; /* Device returned QUEUE_FULL. */
unsigned ten:1; /* support ten byte read / write */ unsigned ten:1; /* support ten byte read / write */
unsigned remap:1; /* support remapping */ unsigned remap:1; /* support remapping */
unsigned starved:1; /* unable to process commands because unsigned starved:1; /* unable to process commands because
host busy */ 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 // Flag to allow revalidate to succeed in sd_open
int allow_revalidate; int allow_revalidate;
struct device sdev_driverfs_dev; struct device sdev_driverfs_dev;
......
...@@ -756,14 +756,22 @@ void scsi_request_fn(request_queue_t * q) ...@@ -756,14 +756,22 @@ void scsi_request_fn(request_queue_t * q)
if(SHpnt->host_busy == 0 && SHpnt->host_blocked) { if(SHpnt->host_busy == 0 && SHpnt->host_blocked) {
/* unblock after host_blocked iterates to zero */ /* 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); printk("scsi%d unblocking host at zero depth\n", SHpnt->host_no);
} else { } else {
blk_plug_device(q); blk_plug_device(q);
break; 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. * If the device cannot accept another request, then quit.
*/ */
......
...@@ -1461,6 +1461,10 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1461,6 +1461,10 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
if (*bflags & BLIST_SINGLELUN) if (*bflags & BLIST_SINGLELUN)
sdev->single_lun = 1; 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) for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->detect) if (sdt->detect)
sdev->attached += (*sdt->detect) (sdev); 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