diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d277e8620e3e..fcfeddc79331 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -1783,6 +1783,8 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1783 | { | 1783 | { |
1784 | int result = SCpnt->result; | 1784 | int result = SCpnt->result; |
1785 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); | 1785 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); |
1786 | unsigned int sector_size = SCpnt->device->sector_size; | ||
1787 | unsigned int resid; | ||
1786 | struct scsi_sense_hdr sshdr; | 1788 | struct scsi_sense_hdr sshdr; |
1787 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); | 1789 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); |
1788 | struct request *req = SCpnt->request; | 1790 | struct request *req = SCpnt->request; |
@@ -1813,6 +1815,21 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1813 | scsi_set_resid(SCpnt, blk_rq_bytes(req)); | 1815 | scsi_set_resid(SCpnt, blk_rq_bytes(req)); |
1814 | } | 1816 | } |
1815 | break; | 1817 | break; |
1818 | default: | ||
1819 | /* | ||
1820 | * In case of bogus fw or device, we could end up having | ||
1821 | * an unaligned partial completion. Check this here and force | ||
1822 | * alignment. | ||
1823 | */ | ||
1824 | resid = scsi_get_resid(SCpnt); | ||
1825 | if (resid & (sector_size - 1)) { | ||
1826 | sd_printk(KERN_INFO, sdkp, | ||
1827 | "Unaligned partial completion (resid=%u, sector_sz=%u)\n", | ||
1828 | resid, sector_size); | ||
1829 | resid = min(scsi_bufflen(SCpnt), | ||
1830 | round_up(resid, sector_size)); | ||
1831 | scsi_set_resid(SCpnt, resid); | ||
1832 | } | ||
1816 | } | 1833 | } |
1817 | 1834 | ||
1818 | if (result) { | 1835 | if (result) { |