[SCSI] aha152x: Close narrow race in release
[safe/jmp/linux-2.6] / drivers / scsi / sd.c
index 2c6116f..38a4141 100644 (file)
@@ -240,7 +240,6 @@ static struct scsi_driver sd_template = {
                .shutdown       = sd_shutdown,
        },
        .rescan                 = sd_rescan,
-       .init_command           = sd_init_command,
 };
 
 /*
@@ -331,14 +330,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
  *
  *     Returns 1 if successful and 0 if error (or cannot be done now).
  **/
-static int sd_init_command(struct scsi_cmnd * SCpnt)
+static int sd_prep_fn(struct request_queue *q, struct request *rq)
 {
-       struct scsi_device *sdp = SCpnt->device;
-       struct request *rq = SCpnt->request;
+       struct scsi_cmnd *SCpnt;
+       struct scsi_device *sdp = q->queuedata;
        struct gendisk *disk = rq->rq_disk;
        sector_t block = rq->sector;
-       unsigned int this_count = SCpnt->request_bufflen >> 9;
+       unsigned int this_count = rq->nr_sectors;
        unsigned int timeout = sdp->timeout;
+       int ret;
+
+       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+               ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+               goto out;
+       } else if (rq->cmd_type != REQ_TYPE_FS) {
+               ret = BLKPREP_KILL;
+               goto out;
+       }
+       ret = scsi_setup_fs_cmnd(sdp, rq);
+       if (ret != BLKPREP_OK)
+               goto out;
+       SCpnt = rq->special;
+
+       /* from here on until we're complete, any goto out
+        * is used for a killable error condition */
+       ret = BLKPREP_KILL;
 
        SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
                                        "sd_init_command: block=%llu, "
@@ -353,7 +369,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                                                rq->nr_sectors));
                SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
                                                "Retry with 0x%p\n", SCpnt));
-               return 0;
+               goto out;
        }
 
        if (sdp->changed) {
@@ -362,8 +378,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                 * the changed bit has been reset
                 */
                /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
-               return 0;
+               goto out;
        }
+
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
                                        (unsigned long long)block));
 
@@ -382,7 +399,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 1) || (rq->nr_sectors & 1)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 1;
                        this_count = this_count >> 1;
@@ -392,7 +409,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 3) || (rq->nr_sectors & 3)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 2;
                        this_count = this_count >> 2;
@@ -402,7 +419,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                if ((block & 7) || (rq->nr_sectors & 7)) {
                        scmd_printk(KERN_ERR, SCpnt,
                                    "Bad block number requested\n");
-                       return 0;
+                       goto out;
                } else {
                        block = block >> 3;
                        this_count = this_count >> 3;
@@ -410,7 +427,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
        }
        if (rq_data_dir(rq) == WRITE) {
                if (!sdp->writeable) {
-                       return 0;
+                       goto out;
                }
                SCpnt->cmnd[0] = WRITE_6;
                SCpnt->sc_data_direction = DMA_TO_DEVICE;
@@ -419,7 +436,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                SCpnt->sc_data_direction = DMA_FROM_DEVICE;
        } else {
                scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
-               return 0;
+               goto out;
        }
 
        SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
@@ -470,7 +487,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
                         */
                        scmd_printk(KERN_ERR, SCpnt,
                                    "FUA write on READ/WRITE(6) drive\n");
-                       return 0;
+                       goto out;
                }
 
                SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
@@ -501,7 +518,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
         * This indicates that the command is ready from our end to be
         * queued.
         */
-       return 1;
+       ret = BLKPREP_OK;
+ out:
+       return scsi_prep_return(q, rq, ret);
 }
 
 /**
@@ -1669,6 +1688,7 @@ static int sd_probe(struct device *dev)
 
        sd_revalidate_disk(gd);
 
+       blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
        blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
 
        gd->driverfs_dev = &sdp->sdev_gendev;