X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-tape.c;h=9cfc2d7ce22d015ee27ca877a45d451e6483c317;hb=e0ff8aa1acd079b70e796571917ae0449b7c465b;hp=7603f6a56e5b894d5d9b8930ba95d39851f5196b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7603f6a56..9cfc2d7ce 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -424,7 +424,6 @@ #define IDETAPE_VERSION "1.19" -#include #include #include #include @@ -433,8 +432,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -442,13 +441,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include /* * partition @@ -530,7 +530,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 +781,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 +1011,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 +1126,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 +1282,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 +1481,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 +1548,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 +1801,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 +2110,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 +2178,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 +2335,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 +2471,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 +2487,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 +2496,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,21 +2644,23 @@ 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 int 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; + int ret = 0; while (n) { #if IDETAPE_DEBUG_BUGS if (bh == NULL) { printk(KERN_ERR "ide-tape: bh == NULL in " "idetape_copy_stage_from_user\n"); - return; + return 1; } #endif /* IDETAPE_DEBUG_BUGS */ count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n); - copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count); + if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count)) + ret = 1; n -= count; atomic_add(count, &bh->b_count); buf += count; @@ -2699,23 +2671,26 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t } } tape->bh = bh; + return ret; } -static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n) +static int 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; + int ret = 0; while (n) { #if IDETAPE_DEBUG_BUGS if (bh == NULL) { printk(KERN_ERR "ide-tape: bh == NULL in " "idetape_copy_stage_to_user\n"); - return; + return 1; } #endif /* IDETAPE_DEBUG_BUGS */ count = min(tape->b_count, n); - copy_to_user(buf, tape->b_data, count); + if (copy_to_user(buf, tape->b_data, count)) + ret = 1; n -= count; tape->b_data += count; tape->b_count -= count; @@ -2728,6 +2703,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape } } } + return ret; } static void idetape_init_merge_stage (idetape_tape_t *tape) @@ -2788,7 +2764,7 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) */ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) { - DECLARE_COMPLETION(wait); + DECLARE_COMPLETION_ONSTACK(wait); idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS @@ -2798,6 +2774,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 +2867,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 +2911,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 +3095,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 +3589,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 +3597,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 +3605,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 +3614,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 +3717,14 @@ 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; + ssize_t ret = 0; - 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); @@ -3775,7 +3742,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf, return (0); if (tape->merge_stage_size) { actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count); - idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read); + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read)) + ret = -EFAULT; buf += actually_read; tape->merge_stage_size -= actually_read; count -= actually_read; @@ -3784,7 +3752,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf, bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl); if (bytes_read <= 0) goto finish; - idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read); + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read)) + ret = -EFAULT; buf += bytes_read; count -= bytes_read; actually_read += bytes_read; @@ -3794,7 +3763,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char *buf, if (bytes_read <= 0) goto finish; temp = min((unsigned long)count, (unsigned long)bytes_read); - idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp); + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp)) + ret = -EFAULT; actually_read += temp; tape->merge_stage_size = bytes_read-temp; } @@ -3807,20 +3777,17 @@ finish: idetape_space_over_filemarks(drive, MTFSF, 1); return 0; } - return actually_read; + + return (ret) ? ret : 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; - ssize_t retval, actually_written = 0; - - if (ppos != &file->f_pos) { - /* "A request was outside the capabilities of the device." */ - return -ENXIO; - } + struct ide_tape_obj *tape = ide_tape_f(file); + ide_drive_t *drive = tape->drive; + ssize_t actually_written = 0; + ssize_t ret = 0; /* The drive is write protected. */ if (tape->write_prot) @@ -3856,7 +3823,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf, * some drives (Seagate STT3401A) will return an error. */ if (drive->dsc_overlap) { - retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); + ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); if (retval < 0) { __idetape_kfree_stage(tape->merge_stage); tape->merge_stage = NULL; @@ -3877,12 +3844,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf, } #endif /* IDETAPE_DEBUG_BUGS */ actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count); - idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written); + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written)) + ret = -EFAULT; buf += actually_written; tape->merge_stage_size += actually_written; count -= actually_written; if (tape->merge_stage_size == tape->stage_size) { + ssize_t retval; tape->merge_stage_size = 0; retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl); if (retval <= 0) @@ -3890,7 +3859,9 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf, } } while (count >= tape->stage_size) { - idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size); + ssize_t retval; + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size)) + ret = -EFAULT; buf += tape->stage_size; count -= tape->stage_size; retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl); @@ -3900,10 +3871,11 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf, } if (count) { actually_written += count; - idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count); + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count)) + ret = -EFAULT; tape->merge_stage_size += count; } - return (actually_written); + return (ret) ? ret : actually_written; } static int idetape_write_filemark (ide_drive_t *drive) @@ -4121,12 +4093,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 +4119,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 +4130,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 +4158,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 +4212,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 +4231,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 +4258,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 +4293,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 +4604,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 +4622,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 +4699,35 @@ 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; - 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; + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor)); + class_device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor + 128)); + idetape_devs[tape->minor] = NULL; + g->private_data = NULL; + put_disk(g); + kfree(tape); } #ifdef CONFIG_PROC_FS @@ -4751,6 +4745,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 +4756,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 +4790,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 +4821,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 +4836,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,33 +4860,52 @@ 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; - devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt", drive->devfs_name); - devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mtn", drive->devfs_name); + 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); + + g->fops = &idetape_block_ops; + ide_register_region(g); - drive->disk->number = devfs_register_tape(drive->devfs_name); - drive->disk->fops = &idetape_block_ops; return 0; + +out_free_tape: + kfree(tape); failed: - return 1; + return -ENODEV; } MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); @@ -4883,23 +4913,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);