summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2004-02-23 20:26:03 -0800
committerJens Axboe <axboe@suse.de>2004-02-23 20:26:03 -0800
commit15680951df03078a16edc9cec55310a5f526398c (patch)
tree209e6fd758a7b0c0ae28b44953c5ad9f060e3f97
parent8dfb4dc9f89a8dc3ddb662251f77df524c2d85be (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.c35
-rw-r--r--drivers/scsi/sd.c16
-rw-r--r--drivers/scsi/sr.c18
-rw-r--r--drivers/scsi/st.c2
-rw-r--r--include/scsi/scsi_cmnd.h2
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 */