X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-tape.c;h=f04791a58df0b0784e3e754cad9a0275034f0712;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=9d19fab9cc8abe1f53dd134051237ef68f824f6a;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 9d19fab9c..f04791a58 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -433,6 +433,7 @@ #include #include #include +#include #include #include #include @@ -442,13 +443,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include /* * partition @@ -781,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 @@ -1007,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 */ @@ -1092,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. @@ -1257,7 +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]; + +#define ide_tape_f(file) ((file)->private_data) + +static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) +{ + 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; +} /* * Function declarations @@ -1509,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; @@ -1761,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); } @@ -2067,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); @@ -2135,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); @@ -2296,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; @@ -2432,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)) @@ -2443,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) { @@ -2452,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; @@ -2724,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 */ @@ -2816,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); } @@ -2858,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; } @@ -3043,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; @@ -3561,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 @@ -3677,8 +3716,8 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c 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 IDETAPE_DEBUG_LOG @@ -3736,8 +3775,8 @@ finish: 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; /* The drive is write protected. */ @@ -4039,8 +4078,8 @@ 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; @@ -4104,24 +4143,37 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) idetape_pc_t pc; int retval; - nonseekable_open(inode, filp); + /* + * 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); @@ -4145,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; } } @@ -4163,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) @@ -4186,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); @@ -4221,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; } @@ -4531,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) { @@ -4553,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'; @@ -4631,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 @@ -4671,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 } }; @@ -4681,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), }; /* @@ -4716,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; } @@ -4732,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(file, 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; @@ -4746,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)) @@ -4769,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, @@ -4791,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"); @@ -4803,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);