]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/sd.c
[PATCH] atyfb: Fix interlaced modes
[linux-2.6-omap-h63xx.git] / drivers / scsi / sd.c
index d651150ee76de53bf91a5a62bc326672c00cd39f..4c5127ed379c6560dd22e17e0aa408b7b51979f8 100644 (file)
@@ -102,6 +102,7 @@ struct scsi_disk {
        u8              write_prot;
        unsigned        WCE : 1;        /* state of disk WCE bit */
        unsigned        RCD : 1;        /* state of disk RCD bit, unused */
+       unsigned        DPOFUA : 1;     /* state of disk DPOFUA bit */
 };
 
 static DEFINE_IDR(sd_index_idr);
@@ -121,8 +122,7 @@ static void sd_shutdown(struct device *dev);
 static void sd_rescan(struct device *);
 static int sd_init_command(struct scsi_cmnd *);
 static int sd_issue_flush(struct device *, sector_t *);
-static void sd_end_flush(request_queue_t *, struct request *);
-static int sd_prepare_flush(request_queue_t *, struct request *);
+static void sd_prepare_flush(request_queue_t *, struct request *);
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
                             unsigned char *buffer);
 
@@ -137,8 +137,6 @@ static struct scsi_driver sd_template = {
        .rescan                 = sd_rescan,
        .init_command           = sd_init_command,
        .issue_flush            = sd_issue_flush,
-       .prepare_flush          = sd_prepare_flush,
-       .end_flush              = sd_end_flush,
 };
 
 /*
@@ -346,6 +344,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
        
        if (block > 0xffffffff) {
                SCpnt->cmnd[0] += READ_16 - READ_6;
+               SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
                SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
                SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
                SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
@@ -365,6 +364,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                        this_count = 0xffff;
 
                SCpnt->cmnd[0] += READ_10 - READ_6;
+               SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
                SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
                SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
                SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
@@ -373,6 +373,17 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
                SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
        } else {
+               if (unlikely(blk_fua_rq(rq))) {
+                       /*
+                        * This happens only if this drive failed
+                        * 10byte rw command with ILLEGAL_REQUEST
+                        * during operation and thus turned off
+                        * use_10_for_rw.
+                        */
+                       printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n");
+                       return 0;
+               }
+
                SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
                SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
                SCpnt->cmnd[3] = (unsigned char) block & 0xff;
@@ -516,7 +527,7 @@ static int sd_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc)
+static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
        struct scsi_device *sdp = sdkp->device;
@@ -534,15 +545,9 @@ static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *
        else
                scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
 
-       if (put_user(diskinfo[0], &loc->heads))
-               return -EFAULT;
-       if (put_user(diskinfo[1], &loc->sectors))
-               return -EFAULT;
-       if (put_user(diskinfo[2], &loc->cylinders))
-               return -EFAULT;
-       if (put_user((unsigned)get_start_sect(bdev),
-                    (unsigned long __user *)&loc->start))
-               return -EFAULT;
+       geo->heads = diskinfo[0];
+       geo->sectors = diskinfo[1];
+       geo->cylinders = diskinfo[2];
        return 0;
 }
 
@@ -582,12 +587,6 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
        if (!scsi_block_when_processing_errors(sdp) || !error)
                return error;
 
-       if (cmd == HDIO_GETGEO) {
-               if (!arg)
-                       return -EINVAL;
-               return sd_hdio_getgeo(bdev, p);
-       }
-
        /*
         * Send SCSI addressing ioctls directly to mid level, send other
         * ioctls to block level and then onto mid level if they can't be
@@ -729,42 +728,13 @@ static int sd_issue_flush(struct device *dev, sector_t *error_sector)
        return ret;
 }
 
-static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
+static void sd_prepare_flush(request_queue_t *q, struct request *rq)
 {
-       struct request *rq = flush_rq->end_io_data;
-       struct scsi_cmnd *cmd = rq->special;
-       unsigned int bytes = rq->hard_nr_sectors << 9;
-
-       if (!flush_rq->errors) {
-               spin_unlock(q->queue_lock);
-               scsi_io_completion(cmd, bytes, 0);
-               spin_lock(q->queue_lock);
-       } else if (blk_barrier_postflush(rq)) {
-               spin_unlock(q->queue_lock);
-               scsi_io_completion(cmd, 0, bytes);
-               spin_lock(q->queue_lock);
-       } else {
-               /*
-                * force journal abort of barriers
-                */
-               end_that_request_first(rq, -EOPNOTSUPP, rq->hard_nr_sectors);
-               end_that_request_last(rq, -EOPNOTSUPP);
-       }
-}
-
-static int sd_prepare_flush(request_queue_t *q, struct request *rq)
-{
-       struct scsi_device *sdev = q->queuedata;
-       struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
-
-       if (!sdkp || !sdkp->WCE)
-               return 0;
-
        memset(rq->cmd, 0, sizeof(rq->cmd));
-       rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+       rq->flags |= REQ_BLOCK_PC;
        rq->timeout = SD_TIMEOUT;
        rq->cmd[0] = SYNCHRONIZE_CACHE;
-       return 1;
+       rq->cmd_len = 10;
 }
 
 static void sd_rescan(struct device *dev)
@@ -818,6 +788,7 @@ static struct block_device_operations sd_fops = {
        .open                   = sd_open,
        .release                = sd_release,
        .ioctl                  = sd_ioctl,
+       .getgeo                 = sd_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl           = sd_compat_ioctl,
 #endif
@@ -1427,10 +1398,18 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
                        sdkp->RCD = 0;
                }
 
+               sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
+               if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
+                       printk(KERN_NOTICE "SCSI device %s: uses "
+                              "READ/WRITE(6), disabling FUA\n", diskname);
+                       sdkp->DPOFUA = 0;
+               }
+
                ct =  sdkp->RCD + 2*sdkp->WCE;
 
-               printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n",
-                      diskname, types[ct]);
+               printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n",
+                      diskname, types[ct],
+                      sdkp->DPOFUA ? " w/ FUA" : "");
 
                return;
        }
@@ -1462,6 +1441,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
        struct scsi_disk *sdkp = scsi_disk(disk);
        struct scsi_device *sdp = sdkp->device;
        unsigned char *buffer;
+       unsigned ordered;
 
        SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
 
@@ -1498,7 +1478,21 @@ static int sd_revalidate_disk(struct gendisk *disk)
                sd_read_write_protect_flag(sdkp, disk->disk_name, buffer);
                sd_read_cache_type(sdkp, disk->disk_name, buffer);
        }
-               
+
+       /*
+        * We now have all cache related info, determine how we deal
+        * with ordered requests.  Note that as the current SCSI
+        * dispatch function can alter request order, we cannot use
+        * QUEUE_ORDERED_TAG_* even when ordered tag is supported.
+        */
+       if (sdkp->WCE)
+               ordered = sdkp->DPOFUA
+                       ? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH;
+       else
+               ordered = QUEUE_ORDERED_DRAIN;
+
+       blk_queue_ordered(sdkp->disk->queue, ordered, sd_prepare_flush);
+
        set_capacity(disk, sdkp->capacity);
        kfree(buffer);
 
@@ -1598,6 +1592,7 @@ static int sd_probe(struct device *dev)
        strcpy(gd->devfs_name, sdp->devfs_name);
 
        gd->private_data = &sdkp->driver;
+       gd->queue = sdkp->device->request_queue;
 
        sd_revalidate_disk(gd);
 
@@ -1605,7 +1600,6 @@ static int sd_probe(struct device *dev)
        gd->flags = GENHD_FL_DRIVERFS;
        if (sdp->removable)
                gd->flags |= GENHD_FL_REMOVABLE;
-       gd->queue = sdkp->device->request_queue;
 
        dev_set_drvdata(dev, sdkp);
        add_disk(gd);