Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / ide / ide-tape.c
index 7603f6a..f04791a 100644 (file)
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/major.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/errno.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
-#include <asm/bitops.h>
 
 /*
  * partition
@@ -530,7 +532,6 @@ typedef struct os_dat_s {
  */
 #define IDETAPE_DEBUG_INFO             0
 #define IDETAPE_DEBUG_LOG              0
-#define IDETAPE_DEBUG_LOG_VERBOSE      0
 #define IDETAPE_DEBUG_BUGS             1
 
 /*
@@ -782,8 +783,12 @@ typedef struct {
  *     driver due to an interrupt or a timer event is stored in a variable
  *     of type idetape_tape_t, defined below.
  */
-typedef struct {
-       ide_drive_t *drive;
+typedef struct ide_tape_obj {
+       ide_drive_t     *drive;
+       ide_driver_t    *driver;
+       struct gendisk  *disk;
+       struct kref     kref;
+
        /*
         *      Since a typical character device operation requires more
         *      than one packet command, we provide here enough memory
@@ -1008,6 +1013,36 @@ typedef struct {
          int debug_level; 
 } idetape_tape_t;
 
+static DEFINE_MUTEX(idetape_ref_mutex);
+
+static struct class *idetape_sysfs_class;
+
+#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
+
+#define ide_tape_g(disk) \
+       container_of((disk)->private_data, struct ide_tape_obj, driver)
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+       struct ide_tape_obj *tape = NULL;
+
+       mutex_lock(&idetape_ref_mutex);
+       tape = ide_tape_g(disk);
+       if (tape)
+               kref_get(&tape->kref);
+       mutex_unlock(&idetape_ref_mutex);
+       return tape;
+}
+
+static void ide_tape_release(struct kref *);
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+       mutex_lock(&idetape_ref_mutex);
+       kref_put(&tape->kref, ide_tape_release);
+       mutex_unlock(&idetape_ref_mutex);
+}
+
 /*
  *     Tape door status
  */
@@ -1093,15 +1128,6 @@ enum {
 #define        IDETAPE_ERROR_FILEMARK          102
 #define        IDETAPE_ERROR_EOD               103
 
-/*
- *     idetape_chrdev_t provides the link between out character device
- *     interface and our block device interface and the corresponding
- *     ide_drive_t structure.
- */
-typedef struct {
-       ide_drive_t *drive;
-} idetape_chrdev_t;
-
 /*
  *     The following is used to format the general configuration word of
  *     the ATAPI IDENTIFY DEVICE command.
@@ -1258,71 +1284,21 @@ typedef struct {
  *     The variables below are used for the character device interface.
  *     Additional state variables are defined in our ide_drive_t structure.
  */
-static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
 
-#if IDETAPE_DEBUG_LOG_VERBOSE
+#define ide_tape_f(file) ((file)->private_data)
 
-/*
- * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
- */
-
-char *idetape_sense_key_verbose(u8 idetape_sense_key)
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
 {
-       switch (idetape_sense_key) {
-               default: {
-                       char buf[22];
-                       sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
-                       return(buf);
-               }
-
-       }
-}
-
-char *idetape_command_key_verbose(u8 idetape_command_key)
-{
-       switch (idetape_command_key) {
-               case IDETAPE_TEST_UNIT_READY_CMD:
-                       return("TEST_UNIT_READY_CMD");
-               case IDETAPE_REWIND_CMD:
-                       return("REWIND_CMD");
-               case IDETAPE_REQUEST_SENSE_CMD:
-                       return("REQUEST_SENSE_CMD");
-               case IDETAPE_READ_CMD:
-                       return("READ_CMD");
-               case IDETAPE_WRITE_CMD:
-                       return("WRITE_CMD");
-               case IDETAPE_WRITE_FILEMARK_CMD:
-                       return("WRITE_FILEMARK_CMD");
-               case IDETAPE_SPACE_CMD:
-                       return("SPACE_CMD");
-               case IDETAPE_INQUIRY_CMD:
-                       return("INQUIRY_CMD");
-               case IDETAPE_ERASE_CMD:
-                       return("ERASE_CMD");
-               case IDETAPE_MODE_SENSE_CMD:
-                       return("MODE_SENSE_CMD");
-               case IDETAPE_MODE_SELECT_CMD:
-                       return("MODE_SELECT_CMD");
-               case IDETAPE_LOAD_UNLOAD_CMD:
-                       return("LOAD_UNLOAD_CMD");
-               case IDETAPE_PREVENT_CMD:
-                       return("PREVENT_CMD");
-               case IDETAPE_LOCATE_CMD:
-                       return("LOCATE_CMD");
-               case IDETAPE_READ_POSITION_CMD:
-                       return("READ_POSITION_CMD");
-               case IDETAPE_READ_BUFFER_CMD:
-                       return("READ_BUFFER_CMD");
-               case IDETAPE_SET_SPEED_CMD:
-                       return("SET_SPEED_CMD");
-               default: {
-                               char buf[20];
-                               sprintf(buf, "CMD (0x%02x)", idetape_command_key);
-                               return(buf);
-                       }
-       }
+       struct ide_tape_obj *tape = NULL;
+
+       mutex_lock(&idetape_ref_mutex);
+       tape = idetape_devs[i];
+       if (tape)
+               kref_get(&tape->kref);
+       mutex_unlock(&idetape_ref_mutex);
+       return tape;
 }
-#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 
 /*
  *      Function declarations
@@ -1507,15 +1483,6 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res
                        "asc = %x, ascq = %x\n",
                        pc->c[0], result->sense_key,
                        result->asc, result->ascq);
-#if IDETAPE_DEBUG_LOG_VERBOSE
-       if (tape->debug_level >= 1)
-               printk(KERN_INFO "ide-tape: pc = %s, sense key = %x, "
-                       "asc = %x, ascq = %x\n",
-                       idetape_command_key_verbose((byte) pc->c[0]),
-                       result->sense_key,
-                       result->asc,
-                       result->ascq);
-#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
        /*
@@ -1583,6 +1550,7 @@ static void idetape_active_next_stage (ide_drive_t *drive)
        }
 #endif /* IDETAPE_DEBUG_BUGS */        
 
+       rq->rq_disk = tape->disk;
        rq->buffer = NULL;
        rq->special = (void *)stage->bh;
        tape->active_data_request = rq;
@@ -1835,8 +1803,11 @@ static void idetape_init_rq(struct request *rq, u8 cmd)
  */
 static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
 {
+       struct ide_tape_obj *tape = drive->driver_data;
+
        idetape_init_rq(rq, REQ_IDETAPE_PC1);
        rq->buffer = (char *) pc;
+       rq->rq_disk = tape->disk;
        (void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -2141,7 +2112,7 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 #ifdef CONFIG_BLK_DEV_IDEDMA
        /* Begin DMA, if necessary */
        if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
-               (void) (HWIF(drive)->ide_dma_begin(drive));
+               hwif->dma_start(drive);
 #endif
        /* Send the actual packet */
        HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
@@ -2209,12 +2180,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
                                "reverting to PIO\n");
                (void)__ide_dma_off(drive);
        }
-       if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
-               if (test_bit(PC_WRITING, &pc->flags))
-                       dma_ok = !HWIF(drive)->ide_dma_write(drive);
-               else
-                       dma_ok = !HWIF(drive)->ide_dma_read(drive);
-       }
+       if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+               dma_ok = !hwif->dma_setup(drive);
 
        if (IDE_CONTROL_REG)
                hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
@@ -2370,7 +2337,7 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
        }
        if (time_after(jiffies, tape->insert_time))
                tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-       if (jiffies - tape->avg_time >= HZ) {
+       if (time_after_eq(jiffies, tape->avg_time + HZ)) {
                tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
                tape->avg_size = 0;
                tape->avg_time = jiffies;
@@ -2506,6 +2473,11 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
                set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
+       if (drive->post_reset == 1) {
+               set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+               drive->post_reset = 0;
+       }
+
        if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
                tape->measure_insert_time = 1;
        if (time_after(jiffies, tape->insert_time))
@@ -2517,7 +2489,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
                        tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
-               } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
+               } else if (time_after(jiffies, tape->dsc_timeout)) {
                        printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
                                tape->name);
                        if (rq->cmd[0] & REQ_IDETAPE_PC2) {
@@ -2526,7 +2498,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        } else {
                                return ide_do_reset(drive);
                        }
-               } else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
+               } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
                        tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
                idetape_postpone_request(drive);
                return ide_stopped;
@@ -2674,7 +2646,7 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
        return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
+static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
@@ -2701,7 +2673,7 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
        tape->bh = bh;
 }
 
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
+static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
@@ -2798,6 +2770,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
        }
 #endif /* IDETAPE_DEBUG_BUGS */
        rq->waiting = &wait;
+       rq->end_io = blk_end_sync_rq;
        spin_unlock_irq(&tape->spinlock);
        wait_for_completion(&wait);
        /* The stage and its struct request have been deallocated */
@@ -2890,10 +2863,12 @@ static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
  */
 static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 {
+       struct ide_tape_obj *tape = drive->driver_data;
        struct request rq;
 
        idetape_init_rq(&rq, REQ_IDETAPE_PC1);
        rq.buffer = (char *) pc;
+       rq.rq_disk = tape->disk;
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
@@ -2932,8 +2907,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
                } else if (!(tape->sense_key == 2 && tape->asc == 4 &&
                             (tape->ascq == 1 || tape->ascq == 8)))
                        return -EIO;
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ / 10);
+               msleep(100);
        }
        return -EIO;
 }
@@ -3117,6 +3091,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct
 #endif /* IDETAPE_DEBUG_BUGS */        
 
        idetape_init_rq(&rq, cmd);
+       rq.rq_disk = tape->disk;
        rq.special = (void *)bh;
        rq.sector = tape->first_frame_position;
        rq.nr_sectors = rq.current_nr_sectors = blocks;
@@ -3610,6 +3585,7 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_config_t config;
+       void __user *argp = (void __user *)arg;
 
 #if IDETAPE_DEBUG_LOG  
        if (tape->debug_level >= 4)
@@ -3617,7 +3593,7 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l
 #endif /* IDETAPE_DEBUG_LOG */
        switch (cmd) {
                case 0x0340:
-                       if (copy_from_user ((char *) &config, (char *) arg, sizeof (idetape_config_t)))
+                       if (copy_from_user(&config, argp, sizeof (idetape_config_t)))
                                return -EFAULT;
                        tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
                        tape->max_stages = config.nr_stages;
@@ -3625,7 +3601,7 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l
                case 0x0350:
                        config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
                        config.nr_stages = tape->max_stages; 
-                       if (copy_to_user((char *) arg, (char *) &config, sizeof (idetape_config_t)))
+                       if (copy_to_user(argp, &config, sizeof (idetape_config_t)))
                                return -EFAULT;
                        break;
                default:
@@ -3634,16 +3610,6 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l
        return 0;
 }
 
-/*
- *     idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
-static void idetape_pre_reset (ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       if (tape != NULL)
-               set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-}
-
 /*
  *     idetape_space_over_filemarks is now a bit more complicated than just
  *     passing the command to the tape since we may have crossed some
@@ -3747,17 +3713,13 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
  *     will no longer hit performance.
  *      This is not applicable to Onstream.
  */
-static ssize_t idetape_chrdev_read (struct file *file, char *buf,
+static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                                    size_t count, loff_t *ppos)
 {
-       ide_drive_t *drive = file->private_data;
-       idetape_tape_t *tape = drive->driver_data;
+       struct ide_tape_obj *tape = ide_tape_f(file);
+       ide_drive_t *drive = tape->drive;
        ssize_t bytes_read,temp, actually_read = 0, rc;
 
-       if (ppos != &file->f_pos) {
-               /* "A request was outside the capabilities of the device." */
-               return -ENXIO;
-       }
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 3)
                printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
@@ -3810,18 +3772,13 @@ finish:
        return actually_read;
 }
 
-static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
+static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                                     size_t count, loff_t *ppos)
 {
-       ide_drive_t *drive = file->private_data;
-       idetape_tape_t *tape = drive->driver_data;
+       struct ide_tape_obj *tape = ide_tape_f(file);
+       ide_drive_t *drive = tape->drive;
        ssize_t retval, actually_written = 0;
 
-       if (ppos != &file->f_pos) {
-               /* "A request was outside the capabilities of the device." */
-               return -ENXIO;
-       }
-
        /* The drive is write protected. */
        if (tape->write_prot)
                return -EACCES;
@@ -4121,12 +4078,13 @@ static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       ide_drive_t *drive = file->private_data;
-       idetape_tape_t *tape = drive->driver_data;
+       struct ide_tape_obj *tape = ide_tape_f(file);
+       ide_drive_t *drive = tape->drive;
        struct mtop mtop;
        struct mtget mtget;
        struct mtpos mtpos;
        int block_offset = 0, position = tape->first_frame_position;
+       void __user *argp = (void __user *)arg;
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 3)
@@ -4146,7 +4104,7 @@ static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigne
        }
        switch (cmd) {
                case MTIOCTOP:
-                       if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+                       if (copy_from_user(&mtop, argp, sizeof (struct mtop)))
                                return -EFAULT;
                        return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
                case MTIOCGET:
@@ -4157,12 +4115,12 @@ static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigne
                        if (tape->drv_write_prot) {
                                mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
                        }
-                       if (copy_to_user((char *) arg,(char *) &mtget, sizeof(struct mtget)))
+                       if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
                                return -EFAULT;
                        return 0;
                case MTIOCPOS:
                        mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
-                       if (copy_to_user((char *) arg,(char *) &mtpos, sizeof(struct mtpos)))
+                       if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
                                return -EFAULT;
                        return 0;
                default:
@@ -4185,23 +4143,37 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
        idetape_pc_t pc;
        int retval;
 
+       /*
+        * We really want to do nonseekable_open(inode, filp); here, but some
+        * versions of tar incorrectly call lseek on tapes and bail out if that
+        * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+        */
+       filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
 #if IDETAPE_DEBUG_LOG
        printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
        
        if (i >= MAX_HWIFS * MAX_DRIVES)
                return -ENXIO;
-       drive = idetape_chrdevs[i].drive;
-       tape = drive->driver_data;
-       filp->private_data = drive;
 
-       if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
-               return -EBUSY;
+       if (!(tape = ide_tape_chrdev_get(i)))
+               return -ENXIO;
+
+       drive = tape->drive;
+
+       filp->private_data = tape;
+
+       if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) {
+               retval = -EBUSY;
+               goto out_put_tape;
+       }
+
        retval = idetape_wait_ready(drive, 60 * HZ);
        if (retval) {
                clear_bit(IDETAPE_BUSY, &tape->flags);
                printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
-               return retval;
+               goto out_put_tape;
        }
 
        idetape_read_position(drive);
@@ -4225,7 +4197,8 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
                if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
                    (filp->f_flags & O_ACCMODE) == O_RDWR) {
                        clear_bit(IDETAPE_BUSY, &tape->flags);
-                       return -EROFS;
+                       retval = -EROFS;
+                       goto out_put_tape;
                }
        }
 
@@ -4243,6 +4216,10 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
        idetape_restart_speed_control(drive);
        tape->restart_speed_control_req = 0;
        return 0;
+
+out_put_tape:
+       ide_tape_put(tape);
+       return retval;
 }
 
 static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
@@ -4266,8 +4243,8 @@ static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-       ide_drive_t *drive = filp->private_data;
-       idetape_tape_t *tape;
+       struct ide_tape_obj *tape = ide_tape_f(filp);
+       ide_drive_t *drive = tape->drive;
        idetape_pc_t pc;
        unsigned int minor = iminor(inode);
 
@@ -4301,6 +4278,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
                }
        }
        clear_bit(IDETAPE_BUSY, &tape->flags);
+       ide_tape_put(tape);
        unlock_kernel();
        return 0;
 }
@@ -4611,11 +4589,7 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        int stage_size;
        struct sysinfo si;
 
-       memset(tape, 0, sizeof (idetape_tape_t));
        spin_lock_init(&tape->spinlock);
-       drive->driver_data = tape;
-       /* An ATAPI device ignores DRDY */
-       drive->ready_stat = 0;
        drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
        if (HWIF(drive)->pci_dev != NULL) {
@@ -4633,7 +4607,6 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        /* Seagate Travan drives do not support DSC overlap. */
        if (strstr(drive->id->model, "Seagate STT3401"))
                drive->dsc_overlap = 0;
-       tape->drive = drive;
        tape->minor = minor;
        tape->name[0] = 'h';
        tape->name[1] = 't';
@@ -4711,29 +4684,38 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        idetape_add_settings(drive);
 }
 
-static int idetape_cleanup (ide_drive_t *drive)
+static void ide_tape_remove(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
-       int minor = tape->minor;
-       unsigned long flags;
 
-       spin_lock_irqsave(&ide_lock, flags);
-       if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
-           tape->first_stage != NULL || tape->merge_stage_size) {
-               spin_unlock_irqrestore(&ide_lock, flags);
-               return 1;
-       }
-       idetape_chrdevs[minor].drive = NULL;
-       spin_unlock_irqrestore(&ide_lock, flags);
-       DRIVER(drive)->busy = 0;
-       (void) ide_unregister_subdriver(drive);
+       ide_unregister_subdriver(drive, tape->driver);
+
+       ide_unregister_region(tape->disk);
+
+       ide_tape_put(tape);
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+       struct ide_tape_obj *tape = to_ide_tape(kref);
+       ide_drive_t *drive = tape->drive;
+       struct gendisk *g = tape->disk;
+
+       BUG_ON(tape->first_stage != NULL || tape->merge_stage_size);
+
+       drive->dsc_overlap = 0;
        drive->driver_data = NULL;
+       class_device_destroy(idetape_sysfs_class,
+                       MKDEV(IDETAPE_MAJOR, tape->minor));
+       class_device_destroy(idetape_sysfs_class,
+                       MKDEV(IDETAPE_MAJOR, tape->minor + 128));
        devfs_remove("%s/mt", drive->devfs_name);
        devfs_remove("%s/mtn", drive->devfs_name);
-       devfs_unregister_tape(drive->disk->number);
-       kfree (tape);
-       drive->disk->fops = ide_fops;
-       return 0;
+       devfs_unregister_tape(g->number);
+       idetape_devs[tape->minor] = NULL;
+       g->private_data = NULL;
+       put_disk(g);
+       kfree(tape);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -4751,6 +4733,7 @@ static int proc_idetape_read_name
 }
 
 static ide_proc_entry_t idetape_proc[] = {
+       { "capacity",   S_IFREG|S_IRUGO,        proc_ide_read_capacity, NULL },
        { "name",       S_IFREG|S_IRUGO,        proc_idetape_read_name, NULL },
        { NULL, 0, NULL, NULL }
 };
@@ -4761,25 +4744,24 @@ static ide_proc_entry_t idetape_proc[] = {
 
 #endif
 
-static int idetape_attach(ide_drive_t *drive);
+static int ide_tape_probe(ide_drive_t *);
 
-/*
- *     IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idetape_driver = {
-       .owner                  = THIS_MODULE,
-       .name                   = "ide-tape",
+       .gen_driver = {
+               .owner          = THIS_MODULE,
+               .name           = "ide-tape",
+               .bus            = &ide_bus_type,
+       },
+       .probe                  = ide_tape_probe,
+       .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
        .media                  = ide_tape,
-       .busy                   = 1,
        .supports_dsc_overlap   = 1,
-       .cleanup                = idetape_cleanup,
        .do_request             = idetape_do_request,
        .end_request            = idetape_end_request,
-       .pre_reset              = idetape_pre_reset,
+       .error                  = __ide_error,
+       .abort                  = __ide_abort,
        .proc                   = idetape_proc,
-       .attach                 = idetape_attach,
-       .drives                 = LIST_HEAD_INIT(idetape_driver.drives),
 };
 
 /*
@@ -4796,15 +4778,30 @@ static struct file_operations idetape_fops = {
 
 static int idetape_open(struct inode *inode, struct file *filp)
 {
-       ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ide_tape_obj *tape;
+       ide_drive_t *drive;
+
+       if (!(tape = ide_tape_get(disk)))
+               return -ENXIO;
+
+       drive = tape->drive;
+
        drive->usage++;
+
        return 0;
 }
 
 static int idetape_release(struct inode *inode, struct file *filp)
 {
-       ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ide_tape_obj *tape = ide_tape_g(disk);
+       ide_drive_t *drive = tape->drive;
+
        drive->usage--;
+
+       ide_tape_put(tape);
+
        return 0;
 }
 
@@ -4812,8 +4809,9 @@ static int idetape_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
-       ide_drive_t *drive = bdev->bd_disk->private_data;
-       int err = generic_ide_ioctl(bdev, cmd, arg);
+       struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+       ide_drive_t *drive = tape->drive;
+       int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
        if (err == -EINVAL)
                err = idetape_blkdev_ioctl(drive, cmd, arg);
        return err;
@@ -4826,9 +4824,10 @@ static struct block_device_operations idetape_block_ops = {
        .ioctl          = idetape_ioctl,
 };
 
-static int idetape_attach (ide_drive_t *drive)
+static int ide_tape_probe(ide_drive_t *drive)
 {
        idetape_tape_t *tape;
+       struct gendisk *g;
        int minor;
 
        if (!strstr("ide-tape", drive->driver_req))
@@ -4849,20 +4848,42 @@ static int idetape_attach (ide_drive_t *drive)
                printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
                printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
        }
-       tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+       tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL);
        if (tape == NULL) {
                printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
                goto failed;
        }
-       if (ide_register_subdriver(drive, &idetape_driver)) {
-               printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-               kfree(tape);
-               goto failed;
-       }
-       for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++)
+
+       g = alloc_disk(1 << PARTN_BITS);
+       if (!g)
+               goto out_free_tape;
+
+       ide_init_disk(g, drive);
+
+       ide_register_subdriver(drive, &idetape_driver);
+
+       kref_init(&tape->kref);
+
+       tape->drive = drive;
+       tape->driver = &idetape_driver;
+       tape->disk = g;
+
+       g->private_data = &tape->driver;
+
+       drive->driver_data = tape;
+
+       mutex_lock(&idetape_ref_mutex);
+       for (minor = 0; idetape_devs[minor]; minor++)
                ;
+       idetape_devs[minor] = tape;
+       mutex_unlock(&idetape_ref_mutex);
+
        idetape_setup(drive, tape, minor);
-       idetape_chrdevs[minor].drive = drive;
+
+       class_device_create(idetape_sysfs_class, NULL,
+                       MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
+       class_device_create(idetape_sysfs_class, NULL,
+                       MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
 
        devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
                        S_IFCHR | S_IRUGO | S_IWUGO,
@@ -4871,11 +4892,16 @@ static int idetape_attach (ide_drive_t *drive)
                        S_IFCHR | S_IRUGO | S_IWUGO,
                        "%s/mtn", drive->devfs_name);
 
-       drive->disk->number = devfs_register_tape(drive->devfs_name);
-       drive->disk->fops = &idetape_block_ops;
+       g->number = devfs_register_tape(drive->devfs_name);
+       g->fops = &idetape_block_ops;
+       ide_register_region(g);
+
        return 0;
+
+out_free_tape:
+       kfree(tape);
 failed:
-       return 1;
+       return -ENODEV;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -4883,23 +4909,43 @@ MODULE_LICENSE("GPL");
 
 static void __exit idetape_exit (void)
 {
-       ide_unregister_driver(&idetape_driver);
+       driver_unregister(&idetape_driver.gen_driver);
+       class_destroy(idetape_sysfs_class);
        unregister_chrdev(IDETAPE_MAJOR, "ht");
 }
 
-/*
- *     idetape_init will register the driver for each tape.
- */
-static int idetape_init (void)
+static int __init idetape_init(void)
 {
+       int error = 1;
+       idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
+       if (IS_ERR(idetape_sysfs_class)) {
+               idetape_sysfs_class = NULL;
+               printk(KERN_ERR "Unable to create sysfs class for ide tapes\n");
+               error = -EBUSY;
+               goto out;
+       }
+
        if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
                printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
-               return -EBUSY;
+               error = -EBUSY;
+               goto out_free_class;
        }
-       ide_register_driver(&idetape_driver);
+
+       error = driver_register(&idetape_driver.gen_driver);
+       if (error)
+               goto out_free_driver;
+
        return 0;
+
+out_free_driver:
+       driver_unregister(&idetape_driver.gen_driver);
+out_free_class:
+       class_destroy(idetape_sysfs_class);
+out:
+       return error;
 }
 
+MODULE_ALIAS("ide:*m-tape*");
 module_init(idetape_init);
 module_exit(idetape_exit);
 MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);