diff options
-rw-r--r-- | drivers/scsi/sd.c | 21 | ||||
-rw-r--r-- | drivers/scsi/sd.h | 6 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 3 |
3 files changed, 23 insertions, 7 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8e08d51a0f05..e5e7d7856454 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -375,6 +375,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
375 | struct gendisk *disk = rq->rq_disk; | 375 | struct gendisk *disk = rq->rq_disk; |
376 | struct scsi_disk *sdkp; | 376 | struct scsi_disk *sdkp; |
377 | sector_t block = rq->sector; | 377 | sector_t block = rq->sector; |
378 | sector_t threshold; | ||
378 | unsigned int this_count = rq->nr_sectors; | 379 | unsigned int this_count = rq->nr_sectors; |
379 | unsigned int timeout = sdp->timeout; | 380 | unsigned int timeout = sdp->timeout; |
380 | int ret; | 381 | int ret; |
@@ -422,13 +423,21 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
422 | } | 423 | } |
423 | 424 | ||
424 | /* | 425 | /* |
425 | * Some devices (some sdcards for one) don't like it if the | 426 | * Some SD card readers can't handle multi-sector accesses which touch |
426 | * last sector gets read in a larger then 1 sector read. | 427 | * the last one or two hardware sectors. Split accesses as needed. |
427 | */ | 428 | */ |
428 | if (unlikely(sdp->last_sector_bug && | 429 | threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS * |
429 | rq->nr_sectors > sdp->sector_size / 512 && | 430 | (sdp->sector_size / 512); |
430 | block + this_count == get_capacity(disk))) | 431 | |
431 | this_count -= sdp->sector_size / 512; | 432 | if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) { |
433 | if (block < threshold) { | ||
434 | /* Access up to the threshold but not beyond */ | ||
435 | this_count = threshold - block; | ||
436 | } else { | ||
437 | /* Access only a single hardware sector */ | ||
438 | this_count = sdp->sector_size / 512; | ||
439 | } | ||
440 | } | ||
432 | 441 | ||
433 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", | 442 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", |
434 | (unsigned long long)block)); | 443 | (unsigned long long)block)); |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 550b2f70a1f8..95b9f06534d5 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
@@ -31,6 +31,12 @@ | |||
31 | */ | 31 | */ |
32 | #define SD_BUF_SIZE 512 | 32 | #define SD_BUF_SIZE 512 |
33 | 33 | ||
34 | /* | ||
35 | * Number of sectors at the end of the device to avoid multi-sector | ||
36 | * accesses to in the case of last_sector_bug | ||
37 | */ | ||
38 | #define SD_LAST_BUGGY_SECTORS 8 | ||
39 | |||
34 | struct scsi_disk { | 40 | struct scsi_disk { |
35 | struct scsi_driver *driver; /* always &sd_template */ | 41 | struct scsi_driver *driver; /* always &sd_template */ |
36 | struct scsi_device *device; | 42 | struct scsi_device *device; |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9cecc409f0f8..291d56a19167 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -140,7 +140,8 @@ struct scsi_device { | |||
140 | unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ | 140 | unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ |
141 | unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ | 141 | unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ |
142 | unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ | 142 | unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ |
143 | unsigned last_sector_bug:1; /* Always read last sector in a 1 sector read */ | 143 | unsigned last_sector_bug:1; /* do not use multisector accesses on |
144 | SD_LAST_BUGGY_SECTORS */ | ||
144 | 145 | ||
145 | DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ | 146 | DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ |
146 | struct list_head event_list; /* asserted events */ | 147 | struct list_head event_list; /* asserted events */ |