diff options
| author | Jens Axboe <axboe@suse.de> | 2004-02-23 20:26:03 -0800 |
|---|---|---|
| committer | Jens Axboe <axboe@suse.de> | 2004-02-23 20:26:03 -0800 |
| commit | 15680951df03078a16edc9cec55310a5f526398c (patch) | |
| tree | 209e6fd758a7b0c0ae28b44953c5ad9f060e3f97 | |
| parent | 8dfb4dc9f89a8dc3ddb662251f77df524c2d85be (diff) | |
[PATCH] fix SCSI non-sector bio backed IO
This fixes the SCSI layer to handle non-sector-aligned requests from
SG_IO (and potentially anything else producing these requests) that
could stall the machine and cause all sorts of funnies depending on the
low level driver used.
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 35 | ||||
| -rw-r--r-- | drivers/scsi/sd.c | 16 | ||||
| -rw-r--r-- | drivers/scsi/sr.c | 18 | ||||
| -rw-r--r-- | drivers/scsi/st.c | 2 | ||||
| -rw-r--r-- | include/scsi/scsi_cmnd.h | 2 |
5 files changed, 41 insertions, 32 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4da1f434ae1f..0e79779aceff 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -493,7 +493,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost) * at some point during this call. */ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, - int sectors, int requeue) + int bytes, int requeue) { request_queue_t *q = cmd->device->request_queue; struct request *req = cmd->request; @@ -503,12 +503,15 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, * If there are blocks left over at the end, set up the command * to queue the remainder of them. */ - if (end_that_request_first(req, uptodate, sectors)) { - int leftover = req->hard_nr_sectors - sectors; + if (end_that_request_chunk(req, uptodate, bytes)) { + int leftover = (req->hard_nr_sectors << 9) - bytes; + + if (blk_pc_request(req)) + leftover = req->data_len - bytes; /* kill remainder if no retrys */ if (!uptodate && blk_noretry_request(req)) - end_that_request_first(req, 0, leftover); + end_that_request_chunk(req, 0, leftover); else { if (requeue) /* @@ -649,11 +652,11 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) * b) We can just use scsi_requeue_command() here. This would * be used if we just wanted to retry, for example. */ -void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, - int block_sectors) +void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, + unsigned int block_bytes) { int result = cmd->result; - int this_count = cmd->bufflen >> 9; + int this_count = cmd->bufflen; request_queue_t *q = cmd->device->request_queue; struct request *req = cmd->request; int clear_errors = 1; @@ -705,9 +708,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, * Next deal with any sectors which we were able to correctly * handle. */ - if (good_sectors >= 0) { - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d sectors done.\n", - req->nr_sectors, good_sectors)); + if (good_bytes >= 0) { + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n", + req->nr_sectors, good_bytes)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); if (clear_errors) @@ -717,13 +720,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, * they will have been finished off by the first command. * If not, then we have a multi-buffer command. * - * If block_sectors != 0, it means we had a medium error + * If block_bytes != 0, it means we had a medium error * of some sort, and that we want to mark some number of * sectors as not uptodate. Thus we want to inhibit * requeueing right here - we will requeue down below * when we handle the bad sectors. */ - cmd = scsi_end_request(cmd, 1, good_sectors, result == 0); + cmd = scsi_end_request(cmd, 1, good_bytes, result == 0); /* * If the command completed without error, then either finish off the @@ -808,7 +811,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, (int) cmd->device->id, (int) cmd->device->lun); print_command(cmd->data_cmnd); print_sense("", cmd); - cmd = scsi_end_request(cmd, 0, block_sectors, 1); + cmd = scsi_end_request(cmd, 0, block_bytes, 1); return; default: break; @@ -837,8 +840,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, * We sometimes get this cruft in the event that a medium error * isn't properly reported. */ - cmd = scsi_end_request(cmd, 0, req->current_nr_sectors, 1); - return; + block_bytes = req->hard_cur_sectors << 9; + if (!block_bytes) + block_bytes = req->data_len; + cmd = scsi_end_request(cmd, 0, block_bytes, 1); } } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 04c6b03f2cd0..fd7242ea08eb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -661,8 +661,8 @@ static struct block_device_operations sd_fops = { static void sd_rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->bufflen >> 9; - int good_sectors = (result == 0 ? this_count : 0); + int this_count = SCpnt->bufflen; + int good_bytes = (result == 0 ? this_count : 0); sector_t block_sectors = 1; sector_t error_sector; #ifdef CONFIG_SCSI_LOGGING @@ -688,6 +688,8 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) case MEDIUM_ERROR: if (!(SCpnt->sense_buffer[0] & 0x80)) break; + if (!blk_fs_request(SCpnt->request)) + break; error_sector = (SCpnt->sense_buffer[3] << 24) | (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | @@ -718,9 +720,9 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) } error_sector &= ~(block_sectors - 1); - good_sectors = error_sector - SCpnt->request->sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; + good_bytes = (error_sector - SCpnt->request->sector) << 9; + if (good_bytes < 0 || good_bytes >= this_count) + good_bytes = 0; break; case RECOVERED_ERROR: @@ -732,7 +734,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) print_sense("sd", SCpnt); SCpnt->result = 0; SCpnt->sense_buffer[0] = 0x0; - good_sectors = this_count; + good_bytes = this_count; break; case ILLEGAL_REQUEST: @@ -755,7 +757,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) * how many actual sectors finished, and how many sectors we need * to say have failed. */ - scsi_io_completion(SCpnt, good_sectors, block_sectors); + scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); } static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index a07a69c0c5cf..b2f1699fa0a5 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -179,14 +179,14 @@ static inline struct scsi_cd *scsi_cd(struct gendisk *disk) static void rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->bufflen >> 9; - int good_sectors = (result == 0 ? this_count : 0); + int this_count = SCpnt->bufflen; + int good_bytes = (result == 0 ? this_count : 0); int block_sectors = 0; long error_sector; struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); #ifdef DEBUG - printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data); + printk("sr.c done: %x\n", result); #endif /* @@ -203,6 +203,8 @@ static void rw_intr(struct scsi_cmnd * SCpnt) case ILLEGAL_REQUEST: if (!(SCpnt->sense_buffer[0] & 0x90)) break; + if (!blk_fs_request(SCpnt->request)) + break; error_sector = (SCpnt->sense_buffer[3] << 24) | (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | @@ -215,9 +217,9 @@ static void rw_intr(struct scsi_cmnd * SCpnt) if (cd->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_sectors = error_sector - SCpnt->request->sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; + good_bytes = (error_sector - SCpnt->request->sector) << 9; + if (good_bytes < 0 || good_bytes >= this_count) + good_bytes = 0; /* * The SCSI specification allows for the value * returned by READ CAPACITY to be up to 75 2K @@ -241,7 +243,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) print_sense("sr", SCpnt); SCpnt->result = 0; SCpnt->sense_buffer[0] = 0x0; - good_sectors = this_count; + good_bytes = this_count; break; default: @@ -254,7 +256,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) * how many actual sectors finished, and how many sectors we need * to say have failed. */ - scsi_io_completion(SCpnt, good_sectors, block_sectors); + scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); } static int sr_init_command(struct scsi_cmnd * SCpnt) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index c96132f30e70..2cdf6f61b398 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4005,7 +4005,7 @@ static int st_remove(struct device *dev) static void st_intr(struct scsi_cmnd *SCpnt) { - scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen >> 9), 1); + scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1); } /* diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index e7511be54da2..751e7e81cf4a 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -158,6 +158,6 @@ struct scsi_cmnd { extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int); extern void scsi_put_command(struct scsi_cmnd *); -extern void scsi_io_completion(struct scsi_cmnd *, int, int); +extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); #endif /* _SCSI_SCSI_CMND_H */ |
