Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[pandora-kernel.git] / drivers / scsi / sd.c
index 8e08d51..2a2bc89 100644 (file)
@@ -375,6 +375,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
        struct gendisk *disk = rq->rq_disk;
        struct scsi_disk *sdkp;
        sector_t block = rq->sector;
+       sector_t threshold;
        unsigned int this_count = rq->nr_sectors;
        unsigned int timeout = sdp->timeout;
        int ret;
@@ -422,13 +423,21 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
        }
 
        /*
-        * Some devices (some sdcards for one) don't like it if the
-        * last sector gets read in a larger then 1 sector read.
+        * Some SD card readers can't handle multi-sector accesses which touch
+        * the last one or two hardware sectors.  Split accesses as needed.
         */
-       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;
+       threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS *
+               (sdp->sector_size / 512);
+
+       if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) {
+               if (block < threshold) {
+                       /* Access up to the threshold but not beyond */
+                       this_count = threshold - block;
+               } else {
+                       /* Access only a single hardware sector */
+                       this_count = sdp->sector_size / 512;
+               }
+       }
 
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
                                        (unsigned long long)block));
@@ -1866,6 +1875,7 @@ static int sd_probe(struct device *dev)
 
        dev_set_drvdata(dev, sdkp);
        add_disk(gd);
+       blk_register_filter(gd);
        sd_dif_config_host(sdkp);
 
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
@@ -1899,6 +1909,7 @@ static int sd_remove(struct device *dev)
        struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
        device_del(&sdkp->dev);
+       blk_unregister_filter(sdkp->disk);
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);