X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-floppy.c;h=c949e98df4b6da35da013d26ddb1b2d979cb36b4;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=56fec5ca18792bef7f61e6b0c6c634e79edae007;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 56fec5ca1..c949e98df 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -97,13 +97,13 @@ #include #include #include +#include #include #include #include #include #include -#include /* * The following are used to debug the driver. @@ -274,8 +274,11 @@ typedef struct { * driver due to an interrupt or a timer event is stored in a variable * of type idefloppy_floppy_t, defined below. */ -typedef struct { - ide_drive_t *drive; +typedef struct ide_floppy_obj { + ide_drive_t *drive; + ide_driver_t *driver; + struct gendisk *disk; + struct kref kref; /* Current packet command */ idefloppy_pc_t *pc; @@ -514,6 +517,34 @@ typedef struct { u8 reserved[4]; } idefloppy_mode_parameter_header_t; +static DECLARE_MUTEX(idefloppy_ref_sem); + +#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref) + +#define ide_floppy_g(disk) \ + container_of((disk)->private_data, struct ide_floppy_obj, driver) + +static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk) +{ + struct ide_floppy_obj *floppy = NULL; + + down(&idefloppy_ref_sem); + floppy = ide_floppy_g(disk); + if (floppy) + kref_get(&floppy->kref); + up(&idefloppy_ref_sem); + return floppy; +} + +static void ide_floppy_release(struct kref *); + +static void ide_floppy_put(struct ide_floppy_obj *floppy) +{ + down(&idefloppy_ref_sem); + kref_put(&floppy->kref, ide_floppy_release); + up(&idefloppy_ref_sem); +} + /* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. @@ -585,7 +616,7 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); - atapi_input_bytes(drive, data, count); + drive->hwif->atapi_input_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; @@ -619,7 +650,7 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); - atapi_output_bytes(drive, data, count); + drive->hwif->atapi_output_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; @@ -652,9 +683,12 @@ static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc) */ static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq) { + struct ide_floppy_obj *floppy = drive->driver_data; + ide_init_drive_cmd(rq); rq->buffer = (char *) pc; rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ; + rq->rq_disk = floppy->disk; (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -989,12 +1023,27 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive) return ide_started; } +/** + * idefloppy_should_report_error() + * + * Supresses error messages resulting from Medium not present + */ +static inline int idefloppy_should_report_error(idefloppy_floppy_t *floppy) +{ + if (floppy->sense_key == 0x02 && + floppy->asc == 0x3a && + floppy->ascq == 0x00) + return 0; + return 1; +} + /* * Issue a packet command */ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) { idefloppy_floppy_t *floppy = drive->driver_data; + ide_hwif_t *hwif = drive->hwif; atapi_feature_t feature; atapi_bcount_t bcount; ide_handler_t *pkt_xfer_routine; @@ -1021,12 +1070,13 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p */ if (!test_bit(PC_ABORT, &pc->flags)) { if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) { - printk(KERN_ERR "ide-floppy: %s: I/O error, " - "pc = %2x, key = %2x, " - "asc = %2x, ascq = %2x\n", - drive->name, pc->c[0], - floppy->sense_key, - floppy->asc, floppy->ascq); + if (idefloppy_should_report_error(floppy)) + printk(KERN_ERR "ide-floppy: %s: I/O error, " + "pc = %2x, key = %2x, " + "asc = %2x, ascq = %2x\n", + drive->name, pc->c[0], + floppy->sense_key, + floppy->asc, floppy->ascq); } /* Giving up */ pc->error = IDEFLOPPY_ERROR_GENERAL; @@ -1049,13 +1099,8 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p } feature.all = 0; - if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) { - if (test_bit(PC_WRITING, &pc->flags)) { - feature.b.dma = !HWIF(drive)->ide_dma_write(drive); - } else { - feature.b.dma = !HWIF(drive)->ide_dma_read(drive); - } - } + if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) + feature.b.dma = !hwif->dma_setup(drive); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -1067,7 +1112,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); - (void) (HWIF(drive)->ide_dma_begin(drive)); + hwif->dma_start(drive); } /* Can we transfer the packet when we get the interrupt or wait? */ @@ -1235,18 +1280,21 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request unsigned long block = (unsigned long)block_s; debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n", - rq->rq_status, rq->rq_disk->disk_name, + rq->rq_status, + rq->rq_disk ? rq->rq_disk->disk_name ? "?", rq->flags, rq->errors); debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, " "current_nr_sectors: %d\n", (long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); if (rq->errors >= ERROR_MAX) { - if (floppy->failed_pc != NULL) - printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x," - " key = %2x, asc = %2x, ascq = %2x\n", - drive->name, floppy->failed_pc->c[0], - floppy->sense_key, floppy->asc, floppy->ascq); + if (floppy->failed_pc != NULL) { + if (idefloppy_should_report_error(floppy)) + printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x," + " key = %2x, asc = %2x, ascq = %2x\n", + drive->name, floppy->failed_pc->c[0], + floppy->sense_key, floppy->asc, floppy->ascq); + } else printk(KERN_ERR "ide-floppy: %s: I/O error\n", drive->name); @@ -1288,11 +1336,13 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request */ static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc) { + struct ide_floppy_obj *floppy = drive->driver_data; struct request rq; ide_init_drive_cmd (&rq); rq.buffer = (char *) pc; rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ; + rq.rq_disk = floppy->disk; return ide_do_drive_cmd(drive, &rq, ide_wait); } @@ -1317,7 +1367,7 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive) } header = (idefloppy_mode_parameter_header_t *) pc.buffer; floppy->wp = header->wp; - set_disk_ro(drive->disk, floppy->wp); + set_disk_ro(floppy->disk, floppy->wp); page = (idefloppy_flexible_disk_page_t *) (header + 1); page->transfer_rate = ntohs(page->transfer_rate); @@ -1383,7 +1433,7 @@ static int idefloppy_get_capacity (ide_drive_t *drive) drive->bios_cyl = 0; drive->bios_head = drive->bios_sect = 0; floppy->blocks = floppy->bs_factor = 0; - set_capacity(drive->disk, 0); + set_capacity(floppy->disk, 0); idefloppy_create_read_capacity_cmd(&pc); if (idefloppy_queue_pc_tail(drive, &pc)) { @@ -1457,7 +1507,7 @@ static int idefloppy_get_capacity (ide_drive_t *drive) (void) idefloppy_get_flexible_disk_page(drive); } - set_capacity(drive->disk, floppy->blocks * floppy->bs_factor); + set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor); return rc; } @@ -1627,7 +1677,7 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg) } /* - * Return the current floppy capacity to ide.c. + * Return the current floppy capacity. */ static sector_t idefloppy_capacity (ide_drive_t *drive) { @@ -1779,10 +1829,6 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) struct idefloppy_id_gcw gcw; *((u16 *) &gcw) = drive->id->config; - drive->driver_data = floppy; - drive->ready_stat = 0; - memset(floppy, 0, sizeof(idefloppy_floppy_t)); - floppy->drive = drive; floppy->pc = floppy->pc_stack; if (gcw.drq_type == 1) set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags); @@ -1819,23 +1865,47 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) idefloppy_add_settings(drive); } -static int idefloppy_cleanup (ide_drive_t *drive) +static int ide_floppy_remove(struct device *dev) { + ide_drive_t *drive = to_ide_device(dev); idefloppy_floppy_t *floppy = drive->driver_data; - struct gendisk *g = drive->disk; + struct gendisk *g = floppy->disk; + + ide_unregister_subdriver(drive, floppy->driver); - if (ide_unregister_subdriver(drive)) - return 1; - drive->driver_data = NULL; - kfree(floppy); del_gendisk(g); - g->fops = ide_fops; + + ide_floppy_put(floppy); + return 0; } +static void ide_floppy_release(struct kref *kref) +{ + struct ide_floppy_obj *floppy = to_ide_floppy(kref); + ide_drive_t *drive = floppy->drive; + struct gendisk *g = floppy->disk; + + drive->driver_data = NULL; + g->private_data = NULL; + put_disk(g); + kfree(floppy); +} + #ifdef CONFIG_PROC_FS +static int proc_idefloppy_read_capacity + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t*drive = (ide_drive_t *)data; + int len; + + len = sprintf(page,"%llu\n", (long long)idefloppy_capacity(drive)); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static ide_proc_entry_t idefloppy_proc[] = { + { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL }, { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL }, { NULL, 0, NULL, NULL } }; @@ -1846,37 +1916,43 @@ static ide_proc_entry_t idefloppy_proc[] = { #endif /* CONFIG_PROC_FS */ -static int idefloppy_attach(ide_drive_t *drive); +static int ide_floppy_probe(struct device *); -/* - * IDE subdriver functions, registered with ide.c - */ static ide_driver_t idefloppy_driver = { .owner = THIS_MODULE, - .name = "ide-floppy", + .gen_driver = { + .name = "ide-floppy", + .bus = &ide_bus_type, + .probe = ide_floppy_probe, + .remove = ide_floppy_remove, + }, .version = IDEFLOPPY_VERSION, .media = ide_floppy, - .busy = 0, .supports_dsc_overlap = 0, - .cleanup = idefloppy_cleanup, .do_request = idefloppy_do_request, .end_request = idefloppy_do_end_request, - .capacity = idefloppy_capacity, + .error = __ide_error, + .abort = __ide_abort, .proc = idefloppy_proc, - .attach = idefloppy_attach, - .drives = LIST_HEAD_INIT(idefloppy_driver.drives), }; static int idefloppy_open(struct inode *inode, struct file *filp) { - ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; - idefloppy_floppy_t *floppy = drive->driver_data; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_floppy_obj *floppy; + ide_drive_t *drive; idefloppy_pc_t pc; + int ret = 0; - drive->usage++; - debug_log(KERN_INFO "Reached idefloppy_open\n"); + if (!(floppy = ide_floppy_get(disk))) + return -ENXIO; + + drive = floppy->drive; + + drive->usage++; + if (drive->usage == 1) { clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); /* Just in case */ @@ -1896,13 +1972,15 @@ static int idefloppy_open(struct inode *inode, struct file *filp) */ ) { drive->usage--; - return -EIO; + ret = -EIO; + goto out_put_floppy; } if (floppy->wp && (filp->f_mode & 2)) { drive->usage--; - return -EROFS; - } + ret = -EROFS; + goto out_put_floppy; + } set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags); /* IOMEGA Clik! drives do not support lock/unlock commands */ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { @@ -1912,21 +1990,26 @@ static int idefloppy_open(struct inode *inode, struct file *filp) check_disk_change(inode->i_bdev); } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) { drive->usage--; - return -EBUSY; + ret = -EBUSY; + goto out_put_floppy; } return 0; + +out_put_floppy: + ide_floppy_put(floppy); + return ret; } static int idefloppy_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_floppy_obj *floppy = ide_floppy_g(disk); + ide_drive_t *drive = floppy->drive; idefloppy_pc_t pc; debug_log(KERN_INFO "Reached idefloppy_release\n"); if (drive->usage == 1) { - idefloppy_floppy_t *floppy = drive->driver_data; - /* IOMEGA Clik! drives do not support lock/unlock commands */ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd(&pc, 0); @@ -1936,6 +2019,9 @@ static int idefloppy_release(struct inode *inode, struct file *filp) clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); } drive->usage--; + + ide_floppy_put(floppy); + return 0; } @@ -1943,10 +2029,10 @@ static int idefloppy_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; - idefloppy_floppy_t *floppy = drive->driver_data; + struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); + ide_drive_t *drive = floppy->drive; void __user *argp = (void __user *)arg; - int err = generic_ide_ioctl(bdev, cmd, arg); + int err = generic_ide_ioctl(drive, file, bdev, cmd, arg); int prevent = (arg) ? 1 : 0; idefloppy_pc_t pc; if (err != -EINVAL) @@ -2007,8 +2093,8 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file, static int idefloppy_media_changed(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; - idefloppy_floppy_t *floppy = drive->driver_data; + struct ide_floppy_obj *floppy = ide_floppy_g(disk); + ide_drive_t *drive = floppy->drive; /* do not scan partitions twice if this is a removable device */ if (drive->attach) { @@ -2020,8 +2106,8 @@ static int idefloppy_media_changed(struct gendisk *disk) static int idefloppy_revalidate_disk(struct gendisk *disk) { - ide_drive_t *drive = disk->private_data; - set_capacity(disk, current_capacity(drive)); + struct ide_floppy_obj *floppy = ide_floppy_g(disk); + set_capacity(disk, idefloppy_capacity(floppy->drive)); return 0; } @@ -2034,10 +2120,12 @@ static struct block_device_operations idefloppy_ops = { .revalidate_disk= idefloppy_revalidate_disk }; -static int idefloppy_attach (ide_drive_t *drive) +static int ide_floppy_probe(struct device *dev) { + ide_drive_t *drive = to_ide_device(dev); idefloppy_floppy_t *floppy; - struct gendisk *g = drive->disk; + struct gendisk *g; + if (!strstr("ide-floppy", drive->driver_req)) goto failed; if (!drive->present) @@ -2056,14 +2144,29 @@ static int idefloppy_attach (ide_drive_t *drive) printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); goto failed; } - if (ide_register_subdriver(drive, &idefloppy_driver)) { - printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (floppy); - goto failed; - } - DRIVER(drive)->busy++; + + g = alloc_disk(1 << PARTN_BITS); + if (!g) + goto out_free_floppy; + + ide_init_disk(g, drive); + + ide_register_subdriver(drive, &idefloppy_driver); + + memset(floppy, 0, sizeof(*floppy)); + + kref_init(&floppy->kref); + + floppy->drive = drive; + floppy->driver = &idefloppy_driver; + floppy->disk = g; + + g->private_data = &floppy->driver; + + drive->driver_data = floppy; + idefloppy_setup (drive, floppy); - DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; g->driverfs_dev = &drive->gendev; strcpy(g->devfs_name, drive->devfs_name); @@ -2072,15 +2175,18 @@ static int idefloppy_attach (ide_drive_t *drive) drive->attach = 1; add_disk(g); return 0; + +out_free_floppy: + kfree(floppy); failed: - return 1; + return -ENODEV; } MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); static void __exit idefloppy_exit (void) { - ide_unregister_driver(&idefloppy_driver); + driver_unregister(&idefloppy_driver.gen_driver); } /* @@ -2089,8 +2195,7 @@ static void __exit idefloppy_exit (void) static int idefloppy_init (void) { printk("ide-floppy driver " IDEFLOPPY_VERSION "\n"); - ide_register_driver(&idefloppy_driver); - return 0; + return driver_register(&idefloppy_driver.gen_driver); } module_init(idefloppy_init);