]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/scsi/sr.c
scsi: revert "[SCSI] Get rid of scsi_cmnd->done"
[linux-2.6.git] / drivers / scsi / sr.c
index 9e267c6d3a436d8581c6064faa6577b32a42550c..a0c4e13d4dabbbe70a962e103e78577ce71c6803 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
 #include <linux/string.h>
@@ -44,6 +43,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
 #include "sr.h"
 
 
+MODULE_DESCRIPTION("SCSI cdrom (sr) driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
+
 #define SR_DISKS       256
 
 #define MAX_RETRIES    3
 #define SR_CAPABILITIES \
        (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
         CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
-        CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
+        CDC_PLAY_AUDIO|CDC_RESET|CDC_DRIVE_STATUS| \
         CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \
         CDC_MRW|CDC_MRW_W|CDC_RAM)
 
 static int sr_probe(struct device *);
 static int sr_remove(struct device *);
-static int sr_init_command(struct scsi_cmnd *);
 
 static struct scsi_driver sr_template = {
        .owner                  = THIS_MODULE,
@@ -81,7 +86,6 @@ static struct scsi_driver sr_template = {
                .probe          = sr_probe,
                .remove         = sr_remove,
        },
-       .init_command           = sr_init_command,
 };
 
 static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
@@ -90,7 +94,7 @@ static DEFINE_SPINLOCK(sr_index_lock);
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * object after last put) */
-static DECLARE_MUTEX(sr_ref_sem);
+static DEFINE_MUTEX(sr_ref_mutex);
 
 static int sr_open(struct cdrom_device_info *, int);
 static void sr_release(struct cdrom_device_info *);
@@ -113,7 +117,6 @@ static struct cdrom_device_ops sr_dops = {
        .get_mcn                = sr_get_mcn,
        .reset                  = sr_reset,
        .audio_ioctl            = sr_audio_ioctl,
-       .dev_ioctl              = sr_dev_ioctl,
        .capability             = SR_CAPABILITIES,
        .generic_packet         = sr_packet,
 };
@@ -133,7 +136,7 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
 {
        struct scsi_cd *cd = NULL;
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        if (disk->private_data == NULL)
                goto out;
        cd = scsi_cd(disk);
@@ -146,18 +149,18 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
        kref_put(&cd->kref, sr_kref_release);
        cd = NULL;
  out:
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
        return cd;
 }
 
-static inline void scsi_cd_put(struct scsi_cd *cd)
+static void scsi_cd_put(struct scsi_cd *cd)
 {
        struct scsi_device *sdev = cd->device;
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        kref_put(&cd->kref, sr_kref_release);
        scsi_device_put(sdev);
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
 }
 
 /*
@@ -170,7 +173,7 @@ static inline void scsi_cd_put(struct scsi_cd *cd)
  * an inode for that to work, and we do not always have one.
  */
 
-int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
        struct scsi_cd *cd = cdi->handle;
        int retval;
@@ -213,7 +216,7 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot)
 static void rw_intr(struct scsi_cmnd * SCpnt)
 {
        int result = SCpnt->result;
-       int this_count = SCpnt->bufflen;
+       int this_count = SCpnt->request_bufflen;
        int good_bytes = (result == 0 ? this_count : 0);
        int block_sectors = 0;
        long error_sector;
@@ -237,8 +240,6 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
                case ILLEGAL_REQUEST:
                        if (!(SCpnt->sense_buffer[0] & 0x90))
                                break;
-                       if (!blk_fs_request(SCpnt->request))
-                               break;
                        error_sector = (SCpnt->sense_buffer[3] << 24) |
                                (SCpnt->sense_buffer[4] << 16) |
                                (SCpnt->sense_buffer[5] << 8) |
@@ -290,22 +291,42 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
         * how many actual sectors finished, and how many sectors we need
         * to say have failed.
         */
-       scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+       scsi_io_completion(SCpnt, good_bytes);
 }
 
-static int sr_init_command(struct scsi_cmnd * SCpnt)
+static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
        int block=0, this_count, s_size, timeout = SR_TIMEOUT;
-       struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+       struct scsi_cd *cd;
+       struct scsi_cmnd *SCpnt;
+       struct scsi_device *sdp = q->queuedata;
+       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;
+       cd = scsi_cd(rq->rq_disk);
+
+       /* from here on until we're complete, any goto out
+        * is used for a killable error condition */
+       ret = BLKPREP_KILL;
 
        SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
                                cd->disk->disk_name, block));
 
        if (!cd->device || !scsi_device_online(cd->device)) {
                SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
-                                       SCpnt->request->nr_sectors));
+                                       rq->nr_sectors));
                SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
-               return 0;
+               goto out;
        }
 
        if (cd->device->changed) {
@@ -313,38 +334,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
                 * quietly refuse to do anything to a changed disc until the
                 * changed bit has been reset
                 */
-               return 0;
-       }
-
-       /*
-        * these are already setup, just copy cdb basically
-        */
-       if (SCpnt->request->flags & REQ_BLOCK_PC) {
-               struct request *rq = SCpnt->request;
-
-               if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
-                       return 0;
-
-               memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
-               SCpnt->cmd_len = rq->cmd_len;
-               if (!rq->data_len)
-                       SCpnt->sc_data_direction = DMA_NONE;
-               else if (rq_data_dir(rq) == WRITE)
-                       SCpnt->sc_data_direction = DMA_TO_DEVICE;
-               else
-                       SCpnt->sc_data_direction = DMA_FROM_DEVICE;
-
-               this_count = rq->data_len;
-               if (rq->timeout)
-                       timeout = rq->timeout;
-
-               SCpnt->transfersize = rq->data_len;
-               goto queue;
-       }
-
-       if (!(SCpnt->request->flags & REQ_CMD)) {
-               blk_dump_rq_flags(SCpnt->request, "sr unsup command");
-               return 0;
+               goto out;
        }
 
        /*
@@ -360,22 +350,22 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
        }
 
        if (s_size != 512 && s_size != 1024 && s_size != 2048) {
-               sdev_printk(KERN_ERR, SCpnt->device, "bad sector size %d\n", s_size);
-               return 0;
+               scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size);
+               goto out;
        }
 
-       if (rq_data_dir(SCpnt->request) == WRITE) {
+       if (rq_data_dir(rq) == WRITE) {
                if (!cd->device->writeable)
-                       return 0;
+                       goto out;
                SCpnt->cmnd[0] = WRITE_10;
                SCpnt->sc_data_direction = DMA_TO_DEVICE;
                cd->cdi.media_written = 1;
-       } else if (rq_data_dir(SCpnt->request) == READ) {
+       } else if (rq_data_dir(rq) == READ) {
                SCpnt->cmnd[0] = READ_10;
                SCpnt->sc_data_direction = DMA_FROM_DEVICE;
        } else {
-               blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
-               return 0;
+               blk_dump_rq_flags(rq, "Unknown sr command");
+               goto out;
        }
 
        {
@@ -385,21 +375,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
                        size += sg[i].length;
 
                if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
-                       sdev_printk(KERN_ERR, SCpnt->device,
-                                   "mismatch count %d, bytes %d\n",
-                                   size, SCpnt->request_bufflen);
+                       scmd_printk(KERN_ERR, SCpnt,
+                               "mismatch count %d, bytes %d\n",
+                               size, SCpnt->request_bufflen);
                        if (SCpnt->request_bufflen > size)
-                               SCpnt->request_bufflen = SCpnt->bufflen = size;
+                               SCpnt->request_bufflen = size;
                }
        }
 
        /*
         * request doesn't start on hw block boundary, add scatter pads
         */
-       if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+       if (((unsigned int)rq->sector % (s_size >> 9)) ||
            (SCpnt->request_bufflen % s_size)) {
-               sdev_printk(KERN_NOTICE, SCpnt->device, "unaligned transfer\n");
-               return 0;
+               scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
+               goto out;
        }
 
        this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
@@ -407,17 +397,16 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
 
        SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
                                cd->cdi.name,
-                               (rq_data_dir(SCpnt->request) == WRITE) ?
+                               (rq_data_dir(rq) == WRITE) ?
                                        "writing" : "reading",
-                               this_count, SCpnt->request->nr_sectors));
+                               this_count, rq->nr_sectors));
 
        SCpnt->cmnd[1] = 0;
-       block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+       block = (unsigned int)rq->sector / (s_size >> 9);
 
        if (this_count > 0xffff) {
                this_count = 0xffff;
-               SCpnt->request_bufflen = SCpnt->bufflen =
-                               this_count * s_size;
+               SCpnt->request_bufflen = this_count * s_size;
        }
 
        SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
@@ -435,8 +424,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
         */
        SCpnt->transfersize = cd->device->sector_size;
        SCpnt->underflow = this_count << 9;
-
-queue:
        SCpnt->allowed = MAX_RETRIES;
        SCpnt->timeout_per_command = timeout;
 
@@ -450,13 +437,15 @@ queue:
         * 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);
 }
 
 static int sr_block_open(struct inode *inode, struct file *file)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+       struct scsi_cd *cd;
        int ret = 0;
 
        if(!(cd = scsi_cd_get(disk)))
@@ -486,17 +475,33 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
 {
        struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
        struct scsi_device *sdev = cd->device;
+       void __user *argp = (void __user *)arg;
+       int ret;
 
-        /*
-         * Send SCSI addressing ioctls directly to mid level, send other
-         * ioctls to cdrom/block level.
-         */
-        switch (cmd) {
-                case SCSI_IOCTL_GET_IDLUN:
-                case SCSI_IOCTL_GET_BUS_NUMBER:
-                        return scsi_ioctl(sdev, cmd, (void __user *)arg);
+       /*
+        * Send SCSI addressing ioctls directly to mid level, send other
+        * ioctls to cdrom/block level.
+        */
+       switch (cmd) {
+       case SCSI_IOCTL_GET_IDLUN:
+       case SCSI_IOCTL_GET_BUS_NUMBER:
+               return scsi_ioctl(sdev, cmd, argp);
        }
-       return cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
+
+       ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
+       if (ret != -ENOSYS)
+               return ret;
+
+       /*
+        * ENODEV means that we didn't recognise the ioctl, or that we
+        * cannot execute it in the current device state.  In either
+        * case fall through to scsi_ioctl, which will return ENDOEV again
+        * if it doesn't recognise the ioctl
+        */
+       ret = scsi_nonblockable_ioctl(sdev, cmd, argp, NULL);
+       if (ret != -ENODEV)
+               return ret;
+       return scsi_ioctl(sdev, cmd, argp);
 }
 
 static int sr_block_media_changed(struct gendisk *disk)
@@ -559,10 +564,9 @@ static int sr_probe(struct device *dev)
                goto fail;
 
        error = -ENOMEM;
-       cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+       cd = kzalloc(sizeof(*cd), GFP_KERNEL);
        if (!cd)
                goto fail;
-       memset(cd, 0, sizeof(*cd));
 
        kref_init(&cd->kref);
 
@@ -606,10 +610,9 @@ static int sr_probe(struct device *dev)
 
        /* FIXME: need to handle a get_capabilities failure properly ?? */
        get_capabilities(cd);
+       blk_queue_prep_rq(sdev->request_queue, sr_prep_fn);
        sr_vendor_init(cd);
 
-       snprintf(disk->devfs_name, sizeof(disk->devfs_name),
-                       "%s/cd", sdev->devfs_name);
        disk->driverfs_dev = &sdev->sdev_gendev;
        set_capacity(disk, cd->capacity);
        disk->private_data = &cd->driver;
@@ -642,7 +645,7 @@ static void get_sectorsize(struct scsi_cd *cd)
        unsigned char *buffer;
        int the_result, retries = 3;
        int sector_size;
-       request_queue_t *queue;
+       struct request_queue *queue;
 
        buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
        if (!buffer)
@@ -730,7 +733,7 @@ static void get_capabilities(struct scsi_cd *cd)
        unsigned int the_result;
        int retries, rc, n;
 
-       static char *loadmech[] =
+       static const char *loadmech[] =
        {
                "caddy",
                "tray",
@@ -776,8 +779,9 @@ static void get_capabilities(struct scsi_cd *cd)
                /* failed, drive doesn't have capabilities mode page */
                cd->cdi.speed = 1;
                cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
-                                        CDC_DVD | CDC_DVD_RAM |
-                                        CDC_SELECT_DISC | CDC_SELECT_SPEED);
+                                CDC_DVD | CDC_DVD_RAM |
+                                CDC_SELECT_DISC | CDC_SELECT_SPEED |
+                                CDC_MRW | CDC_MRW_W | CDC_RAM);
                kfree(buffer);
                printk("%s: scsi-1 drive\n", cd->cdi.name);
                return;
@@ -859,7 +863,7 @@ static int sr_packet(struct cdrom_device_info *cdi,
  *     sr_kref_release - Called to free the scsi_cd structure
  *     @kref: pointer to embedded kref
  *
- *     sr_ref_sem must be held entering this routine.  Because it is
+ *     sr_ref_mutex must be held entering this routine.  Because it is
  *     called on last put, you should always use the scsi_cd_get()
  *     scsi_cd_put() helpers which manipulate the semaphore directly
  *     and never do a direct kref_put().
@@ -888,9 +892,9 @@ static int sr_remove(struct device *dev)
 
        del_gendisk(cd->disk);
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        kref_put(&cd->kref, sr_kref_release);
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
 
        return 0;
 }
@@ -902,7 +906,11 @@ static int __init init_sr(void)
        rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
        if (rc)
                return rc;
-       return scsi_register_driver(&sr_template.gendrv);
+       rc = scsi_register_driver(&sr_template.gendrv);
+       if (rc)
+               unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+
+       return rc;
 }
 
 static void __exit exit_sr(void)