diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a69b155f39a2..24eba3118b5a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) goto out; } + /* + * Some devices (some sdcards for one) don't like it if the + * last sector gets read in a larger then 1 sector read. + */ + if (unlikely(sdp->last_sector_bug && + rq->nr_sectors > sdp->sector_size / 512 && + block + this_count == get_capacity(disk))) + this_count -= sdp->sector_size / 512; + SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", (unsigned long long)block)); @@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; + struct scsi_sense_hdr *sshdr = NULL; int retval; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); @@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk) * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ - if (!scsi_device_online(sdp)) - goto not_present; + if (!scsi_device_online(sdp)) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * Using TEST_UNIT_READY enables differentiation between drive with @@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk) * sd_revalidate() is called. */ retval = -ENODEV; - if (scsi_block_when_processing_errors(sdp)) - retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); + + if (scsi_block_when_processing_errors(sdp)) { + sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); + retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES, + sshdr); + } /* * Unable to test, unit probably not ready. This usually @@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk) * and we will figure it out later once the drive is * available again. */ - if (retval) - goto not_present; + if (retval || (scsi_sense_valid(sshdr) && + /* 0x3a is medium not present */ + sshdr->asc == 0x3a)) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * For removable scsi disk we have to recognise the presence @@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk) retval = sdp->changed; sdp->changed = 0; - +out: + if (retval != sdkp->previous_state) + sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); + sdkp->previous_state = retval; + kfree(sshdr); return retval; - -not_present: - set_media_not_present(sdkp); - return 1; } static int sd_sync_cache(struct scsi_disk *sdkp) |