Commit c65c692d authored by Douglas Gilbert's avatar Douglas Gilbert Committed by James Bottomley

[PATCH] streamline block SG_IO error processing

   - cleanup scsi_end_request() documentation
   - shorten path for block SG_IO through scsi_io_completion()
   - for non-SG_IO sense processing in scsi_io_completion():
      - ignore deferred errors (report + retry should suffice)
      - consolidate into a cleaner switch statement
Signed-off-by: default avatarDouglas Gilbert <dougg@torque.net>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent d47d2299
...@@ -498,19 +498,17 @@ void scsi_run_host_queues(struct Scsi_Host *shost) ...@@ -498,19 +498,17 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
/* /*
* Function: scsi_end_request() * Function: scsi_end_request()
* *
* Purpose: Post-processing of completed commands called from interrupt * Purpose: Post-processing of completed commands (usually invoked at end
* handler or a bottom-half handler. * of upper level post-processing and scsi_io_completion).
* *
* Arguments: cmd - command that is complete. * Arguments: cmd - command that is complete.
* uptodate - 1 if I/O indicates success, 0 for I/O error. * uptodate - 1 if I/O indicates success, <= 0 for I/O error.
* sectors - number of sectors we want to mark. * bytes - number of bytes of completed I/O
* requeue - indicates whether we should requeue leftovers. * requeue - indicates whether we should requeue leftovers.
* frequeue - indicates that if we release the command block
* that the queue request function should be called.
* *
* Lock status: Assumed that lock is not held upon entry. * Lock status: Assumed that lock is not held upon entry.
* *
* Returns: Nothing * Returns: cmd if requeue done or required, NULL otherwise
* *
* Notes: This is called for block device requests in order to * Notes: This is called for block device requests in order to
* mark some number of sectors as complete. * mark some number of sectors as complete.
...@@ -694,8 +692,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -694,8 +692,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
int this_count = cmd->bufflen; int this_count = cmd->bufflen;
request_queue_t *q = cmd->device->request_queue; request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request; struct request *req = cmd->request;
int clear_errors = 1;
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
/* /*
* Free up any indirection buffers we allocated for DMA purposes. * Free up any indirection buffers we allocated for DMA purposes.
...@@ -714,11 +713,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -714,11 +713,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
kfree(cmd->buffer); kfree(cmd->buffer);
} }
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result; req->errors = result;
if (result) { if (result) {
clear_errors = 0; if (sense_valid) {
if (scsi_command_normalize_sense(cmd, &sshdr)) {
/* /*
* SG_IO wants current and deferred errors * SG_IO wants current and deferred errors
*/ */
...@@ -742,6 +745,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -742,6 +745,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
cmd->request_buffer = NULL; cmd->request_buffer = NULL;
cmd->request_bufflen = 0; cmd->request_bufflen = 0;
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
scsi_end_request(cmd, 1, good_bytes, 0);
return;
}
/* /*
* Next deal with any sectors which we were able to correctly * Next deal with any sectors which we were able to correctly
* handle. * handle.
...@@ -751,8 +759,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -751,8 +759,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
req->nr_sectors, good_bytes)); req->nr_sectors, good_bytes));
SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
if (clear_errors) req->errors = 0;
req->errors = 0;
/* /*
* If multiple sectors are requested in one buffer, then * If multiple sectors are requested in one buffer, then
* they will have been finished off by the first command. * they will have been finished off by the first command.
...@@ -779,52 +786,37 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -779,52 +786,37 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
* sense buffer. We can extract information from this, so we * sense buffer. We can extract information from this, so we
* can choose a block to remap, etc. * can choose a block to remap, etc.
*/ */
if (driver_byte(result) != 0) { if (sense_valid && (! sense_deferred)) {
if (scsi_command_normalize_sense(cmd, &sshdr) && switch (sshdr.sense_key) {
!scsi_sense_is_deferred(&sshdr)) { case UNIT_ATTENTION:
/* if (cmd->device->removable) {
* If the device is in the process of becoming ready, /* detected disc change. set a bit
* retry. * and quietly refuse further access.
*/ */
if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { cmd->device->changed = 1;
cmd = scsi_end_request(cmd, 0,
this_count, 1);
return;
} else {
/*
* Must have been a power glitch, or a
* bus reset. Could not have been a
* media change, so we just retry the
* request and see what happens.
*/
scsi_requeue_command(q, cmd); scsi_requeue_command(q, cmd);
return; return;
} }
if (sshdr.sense_key == UNIT_ATTENTION) { break;
if (cmd->device->removable) {
/* detected disc change. set a bit
* and quietly refuse further access.
*/
cmd->device->changed = 1;
cmd = scsi_end_request(cmd, 0,
this_count, 1);
return;
} else {
/*
* Must have been a power glitch, or a
* bus reset. Could not have been a
* media change, so we just retry the
* request and see what happens.
*/
scsi_requeue_command(q, cmd);
return;
}
}
}
/*
* If we had an ILLEGAL REQUEST returned, then we may have
* performed an unsupported command. The only thing this
* should be would be a ten byte read where only a six byte
* read was supported. Also, on a system where READ CAPACITY
* failed, we may have read past the end of the disk.
*/
/*
* XXX: Following is probably broken since deferred errors
* fall through [dpg 20040827]
*/
switch (sshdr.sense_key) {
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
/*
* If we had an ILLEGAL REQUEST returned, then we may
* have performed an unsupported command. The only
* thing this should be would be a ten byte read where
* only a six byte read was supported. Also, on a
* system where READ CAPACITY failed, we may have read
* past the end of the disk.
*/
if (cmd->device->use_10_for_rw && if (cmd->device->use_10_for_rw &&
(cmd->cmnd[0] == READ_10 || (cmd->cmnd[0] == READ_10 ||
cmd->cmnd[0] == WRITE_10)) { cmd->cmnd[0] == WRITE_10)) {
...@@ -841,6 +833,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, ...@@ -841,6 +833,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
} }
break; break;
case NOT_READY: case NOT_READY:
/*
* If the device is in the process of becoming ready,
* retry.
*/
if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) {
scsi_requeue_command(q, cmd);
return;
}
printk(KERN_INFO "Device %s not ready.\n", printk(KERN_INFO "Device %s not ready.\n",
req->rq_disk ? req->rq_disk->disk_name : ""); req->rq_disk ? req->rq_disk->disk_name : "");
cmd = scsi_end_request(cmd, 0, this_count, 1); cmd = scsi_end_request(cmd, 0, this_count, 1);
......
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