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) | |||
395 | goto out; | 395 | goto out; |
396 | } | 396 | } |
397 | 397 | ||
398 | /* | ||
399 | * Some devices (some sdcards for one) don't like it if the | ||
400 | * last sector gets read in a larger then 1 sector read. | ||
401 | */ | ||
402 | if (unlikely(sdp->last_sector_bug && | ||
403 | rq->nr_sectors > sdp->sector_size / 512 && | ||
404 | block + this_count == get_capacity(disk))) | ||
405 | this_count -= sdp->sector_size / 512; | ||
406 | |||
398 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", | 407 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", |
399 | (unsigned long long)block)); | 408 | (unsigned long long)block)); |
400 | 409 | ||
@@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk) | |||
736 | { | 745 | { |
737 | struct scsi_disk *sdkp = scsi_disk(disk); | 746 | struct scsi_disk *sdkp = scsi_disk(disk); |
738 | struct scsi_device *sdp = sdkp->device; | 747 | struct scsi_device *sdp = sdkp->device; |
748 | struct scsi_sense_hdr *sshdr = NULL; | ||
739 | int retval; | 749 | int retval; |
740 | 750 | ||
741 | SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); | 751 | 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) | |||
749 | * can deal with it then. It is only because of unrecoverable errors | 759 | * can deal with it then. It is only because of unrecoverable errors |
750 | * that we would ever take a device offline in the first place. | 760 | * that we would ever take a device offline in the first place. |
751 | */ | 761 | */ |
752 | if (!scsi_device_online(sdp)) | 762 | if (!scsi_device_online(sdp)) { |
753 | goto not_present; | 763 | set_media_not_present(sdkp); |
764 | retval = 1; | ||
765 | goto out; | ||
766 | } | ||
754 | 767 | ||
755 | /* | 768 | /* |
756 | * Using TEST_UNIT_READY enables differentiation between drive with | 769 | * Using TEST_UNIT_READY enables differentiation between drive with |
@@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk) | |||
762 | * sd_revalidate() is called. | 775 | * sd_revalidate() is called. |
763 | */ | 776 | */ |
764 | retval = -ENODEV; | 777 | retval = -ENODEV; |
765 | if (scsi_block_when_processing_errors(sdp)) | 778 | |
766 | retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); | 779 | if (scsi_block_when_processing_errors(sdp)) { |
780 | sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); | ||
781 | retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES, | ||
782 | sshdr); | ||
783 | } | ||
767 | 784 | ||
768 | /* | 785 | /* |
769 | * Unable to test, unit probably not ready. This usually | 786 | * Unable to test, unit probably not ready. This usually |
@@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk) | |||
771 | * and we will figure it out later once the drive is | 788 | * and we will figure it out later once the drive is |
772 | * available again. | 789 | * available again. |
773 | */ | 790 | */ |
774 | if (retval) | 791 | if (retval || (scsi_sense_valid(sshdr) && |
775 | goto not_present; | 792 | /* 0x3a is medium not present */ |
793 | sshdr->asc == 0x3a)) { | ||
794 | set_media_not_present(sdkp); | ||
795 | retval = 1; | ||
796 | goto out; | ||
797 | } | ||
776 | 798 | ||
777 | /* | 799 | /* |
778 | * For removable scsi disk we have to recognise the presence | 800 | * For removable scsi disk we have to recognise the presence |
@@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk) | |||
783 | 805 | ||
784 | retval = sdp->changed; | 806 | retval = sdp->changed; |
785 | sdp->changed = 0; | 807 | sdp->changed = 0; |
786 | 808 | out: | |
809 | if (retval != sdkp->previous_state) | ||
810 | sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); | ||
811 | sdkp->previous_state = retval; | ||
812 | kfree(sshdr); | ||
787 | return retval; | 813 | return retval; |
788 | |||
789 | not_present: | ||
790 | set_media_not_present(sdkp); | ||
791 | return 1; | ||
792 | } | 814 | } |
793 | 815 | ||
794 | static int sd_sync_cache(struct scsi_disk *sdkp) | 816 | static int sd_sync_cache(struct scsi_disk *sdkp) |