Commit 15680951 authored by Jens Axboe's avatar Jens Axboe

[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.
parent 8dfb4dc9
...@@ -493,7 +493,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost) ...@@ -493,7 +493,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
* at some point during this call. * at some point during this call.
*/ */
static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, 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; request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request; struct request *req = cmd->request;
...@@ -503,12 +503,15 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, ...@@ -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 * If there are blocks left over at the end, set up the command
* to queue the remainder of them. * to queue the remainder of them.
*/ */
if (end_that_request_first(req, uptodate, sectors)) { if (end_that_request_chunk(req, uptodate, bytes)) {
int leftover = req->hard_nr_sectors - sectors; int leftover = (req->hard_nr_sectors << 9) - bytes;
if (blk_pc_request(req))
leftover = req->data_len - bytes;
/* kill remainder if no retrys */ /* kill remainder if no retrys */
if (!uptodate && blk_noretry_request(req)) if (!uptodate && blk_noretry_request(req))
end_that_request_first(req, 0, leftover); end_that_request_chunk(req, 0, leftover);
else { else {
if (requeue) if (requeue)
/* /*
...@@ -649,11 +652,11 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) ...@@ -649,11 +652,11 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
* b) We can just use scsi_requeue_command() here. This would * b) We can just use scsi_requeue_command() here. This would
* be used if we just wanted to retry, for example. * be used if we just wanted to retry, for example.
*/ */
void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
int block_sectors) unsigned int block_bytes)
{ {
int result = cmd->result; int result = cmd->result;
int this_count = cmd->bufflen >> 9; 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; int clear_errors = 1;
...@@ -705,9 +708,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, ...@@ -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 * Next deal with any sectors which we were able to correctly
* handle. * handle.
*/ */
if (good_sectors >= 0) { if (good_bytes >= 0) {
SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d sectors done.\n", SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
req->nr_sectors, good_sectors)); 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) if (clear_errors)
...@@ -717,13 +720,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, ...@@ -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. * they will have been finished off by the first command.
* If not, then we have a multi-buffer 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 * of some sort, and that we want to mark some number of
* sectors as not uptodate. Thus we want to inhibit * sectors as not uptodate. Thus we want to inhibit
* requeueing right here - we will requeue down below * requeueing right here - we will requeue down below
* when we handle the bad sectors. * 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 * 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, ...@@ -808,7 +811,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
(int) cmd->device->id, (int) cmd->device->lun); (int) cmd->device->id, (int) cmd->device->lun);
print_command(cmd->data_cmnd); print_command(cmd->data_cmnd);
print_sense("", cmd); print_sense("", cmd);
cmd = scsi_end_request(cmd, 0, block_sectors, 1); cmd = scsi_end_request(cmd, 0, block_bytes, 1);
return; return;
default: default:
break; break;
...@@ -837,8 +840,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, ...@@ -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 * We sometimes get this cruft in the event that a medium error
* isn't properly reported. * isn't properly reported.
*/ */
cmd = scsi_end_request(cmd, 0, req->current_nr_sectors, 1); block_bytes = req->hard_cur_sectors << 9;
return; if (!block_bytes)
block_bytes = req->data_len;
cmd = scsi_end_request(cmd, 0, block_bytes, 1);
} }
} }
......
...@@ -661,8 +661,8 @@ static struct block_device_operations sd_fops = { ...@@ -661,8 +661,8 @@ static struct block_device_operations sd_fops = {
static void sd_rw_intr(struct scsi_cmnd * SCpnt) static void sd_rw_intr(struct scsi_cmnd * SCpnt)
{ {
int result = SCpnt->result; int result = SCpnt->result;
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen;
int good_sectors = (result == 0 ? this_count : 0); int good_bytes = (result == 0 ? this_count : 0);
sector_t block_sectors = 1; sector_t block_sectors = 1;
sector_t error_sector; sector_t error_sector;
#ifdef CONFIG_SCSI_LOGGING #ifdef CONFIG_SCSI_LOGGING
...@@ -688,6 +688,8 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -688,6 +688,8 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
case MEDIUM_ERROR: case MEDIUM_ERROR:
if (!(SCpnt->sense_buffer[0] & 0x80)) if (!(SCpnt->sense_buffer[0] & 0x80))
break; break;
if (!blk_fs_request(SCpnt->request))
break;
error_sector = (SCpnt->sense_buffer[3] << 24) | error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | (SCpnt->sense_buffer[5] << 8) |
...@@ -718,9 +720,9 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -718,9 +720,9 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
} }
error_sector &= ~(block_sectors - 1); error_sector &= ~(block_sectors - 1);
good_sectors = error_sector - SCpnt->request->sector; good_bytes = (error_sector - SCpnt->request->sector) << 9;
if (good_sectors < 0 || good_sectors >= this_count) if (good_bytes < 0 || good_bytes >= this_count)
good_sectors = 0; good_bytes = 0;
break; break;
case RECOVERED_ERROR: case RECOVERED_ERROR:
...@@ -732,7 +734,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -732,7 +734,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
print_sense("sd", SCpnt); print_sense("sd", SCpnt);
SCpnt->result = 0; SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0; SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count; good_bytes = this_count;
break; break;
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
...@@ -755,7 +757,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -755,7 +757,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
* how many actual sectors finished, and how many sectors we need * how many actual sectors finished, and how many sectors we need
* to say have failed. * 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) static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
......
...@@ -179,14 +179,14 @@ static inline struct scsi_cd *scsi_cd(struct gendisk *disk) ...@@ -179,14 +179,14 @@ static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
static void rw_intr(struct scsi_cmnd * SCpnt) static void rw_intr(struct scsi_cmnd * SCpnt)
{ {
int result = SCpnt->result; int result = SCpnt->result;
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen;
int good_sectors = (result == 0 ? this_count : 0); int good_bytes = (result == 0 ? this_count : 0);
int block_sectors = 0; int block_sectors = 0;
long error_sector; long error_sector;
struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
#ifdef DEBUG #ifdef DEBUG
printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data); printk("sr.c done: %x\n", result);
#endif #endif
/* /*
...@@ -203,6 +203,8 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -203,6 +203,8 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (!(SCpnt->sense_buffer[0] & 0x90)) if (!(SCpnt->sense_buffer[0] & 0x90))
break; break;
if (!blk_fs_request(SCpnt->request))
break;
error_sector = (SCpnt->sense_buffer[3] << 24) | error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | (SCpnt->sense_buffer[5] << 8) |
...@@ -215,9 +217,9 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -215,9 +217,9 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
if (cd->device->sector_size == 2048) if (cd->device->sector_size == 2048)
error_sector <<= 2; error_sector <<= 2;
error_sector &= ~(block_sectors - 1); error_sector &= ~(block_sectors - 1);
good_sectors = error_sector - SCpnt->request->sector; good_bytes = (error_sector - SCpnt->request->sector) << 9;
if (good_sectors < 0 || good_sectors >= this_count) if (good_bytes < 0 || good_bytes >= this_count)
good_sectors = 0; good_bytes = 0;
/* /*
* The SCSI specification allows for the value * The SCSI specification allows for the value
* returned by READ CAPACITY to be up to 75 2K * returned by READ CAPACITY to be up to 75 2K
...@@ -241,7 +243,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -241,7 +243,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
print_sense("sr", SCpnt); print_sense("sr", SCpnt);
SCpnt->result = 0; SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0; SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count; good_bytes = this_count;
break; break;
default: default:
...@@ -254,7 +256,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -254,7 +256,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
* how many actual sectors finished, and how many sectors we need * how many actual sectors finished, and how many sectors we need
* to say have failed. * 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) static int sr_init_command(struct scsi_cmnd * SCpnt)
......
...@@ -4005,7 +4005,7 @@ static int st_remove(struct device *dev) ...@@ -4005,7 +4005,7 @@ static int st_remove(struct device *dev)
static void st_intr(struct scsi_cmnd *SCpnt) 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);
} }
/* /*
......
...@@ -158,6 +158,6 @@ struct scsi_cmnd { ...@@ -158,6 +158,6 @@ struct scsi_cmnd {
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int); extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int);
extern void scsi_put_command(struct scsi_cmnd *); 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 */ #endif /* _SCSI_SCSI_CMND_H */
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