summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-02-02 16:06:23 -0600
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-25 16:14:06 -0800
commit9ec6dbd16425a0a7c8c112908d24564edb0868cb (patch)
tree3f21f7c41d8a4d893e6726e7c4390c4b01d96367
parent4b30c359ac5e24782a1c908e7ba392bec9b4ff34 (diff)
SCSI: sd: handle bad lba in sense information
patch 366c246de9cec909c5eba4f784c92d1e75b4dc38 in mainline. Some devices report medium error locations incorrectly. Add guards to make sure the reported bad lba is actually in the request that caused it. Additionally remove the large case statment for sector sizes and replace it with the proper u64 divisions. Tested-by: Mike Snitzer <snitzer@gmail.com> Cc: Stable Tree <stable@kernel.org> Cc: Tony Battersby <tonyb@cybernetics.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/scsi/sd.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116fd4578..2b28a2465ea4 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -901,6 +901,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
unsigned int xfer_size = SCpnt->request_bufflen;
unsigned int good_bytes = result ? 0 : xfer_size;
u64 start_lba = SCpnt->request->sector;
+ u64 end_lba = SCpnt->request->sector + (xfer_size / 512);
u64 bad_lba;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
@@ -939,26 +940,23 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
goto out;
if (xfer_size <= SCpnt->device->sector_size)
goto out;
- switch (SCpnt->device->sector_size) {
- case 256:
+ if (SCpnt->device->sector_size < 512) {
+ /* only legitimate sector_size here is 256 */
start_lba <<= 1;
- break;
- case 512:
- break;
- case 1024:
- start_lba >>= 1;
- break;
- case 2048:
- start_lba >>= 2;
- break;
- case 4096:
- start_lba >>= 3;
- break;
- default:
- /* Print something here with limiting frequency. */
- goto out;
- break;
+ end_lba <<= 1;
+ } else {
+ /* be careful ... don't want any overflows */
+ u64 factor = SCpnt->device->sector_size / 512;
+ do_div(start_lba, factor);
+ do_div(end_lba, factor);
}
+
+ if (bad_lba < start_lba || bad_lba >= end_lba)
+ /* the bad lba was reported incorrectly, we have
+ * no idea where the error is
+ */
+ goto out;
+
/* This computation should always be done in terms of
* the resolution of the device's medium.
*/