| From 366c246de9cec909c5eba4f784c92d1e75b4dc38 Mon Sep 17 00:00:00 2001 |
| From: James Bottomley <James.Bottomley@HansenPartnership.com> |
| Date: Sat, 2 Feb 2008 16:06:23 -0600 |
| Subject: SCSI: sd: handle bad lba in sense information |
| |
| From: James Bottomley <James.Bottomley@HansenPartnership.com> |
| |
| 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> |
| |
| --- |
| drivers/scsi/sd.c | 34 ++++++++++++++++------------------ |
| 1 file changed, 16 insertions(+), 18 deletions(-) |
| |
| --- a/drivers/scsi/sd.c |
| +++ b/drivers/scsi/sd.c |
| @@ -901,6 +901,7 @@ static void sd_rw_intr(struct scsi_cmnd |
| 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 |
| 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. |
| */ |