fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide-floppy.c
index 7383f44..d33717c 100644 (file)
@@ -82,7 +82,6 @@
 
 #define IDEFLOPPY_VERSION "0.99.newide"
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/cdrom.h>
 #include <linux/ide.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>
 
 /*
  *     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;
@@ -314,7 +317,7 @@ typedef struct {
        unsigned long flags;
 } idefloppy_floppy_t;
 
-#define IDEFLOPPY_TICKS_DELAY  3       /* default delay for ZIP 100 */
+#define IDEFLOPPY_TICKS_DELAY  HZ/20   /* default delay for ZIP 100 (50ms) */
 
 /*
  *     Floppy flag bits values.
@@ -514,6 +517,34 @@ typedef struct {
        u8              reserved[4];
 } idefloppy_mode_parameter_header_t;
 
+static DEFINE_MUTEX(idefloppy_ref_mutex);
+
+#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;
+
+       mutex_lock(&idefloppy_ref_mutex);
+       floppy = ide_floppy_g(disk);
+       if (floppy)
+               kref_get(&floppy->kref);
+       mutex_unlock(&idefloppy_ref_mutex);
+       return floppy;
+}
+
+static void ide_floppy_release(struct kref *);
+
+static void ide_floppy_put(struct ide_floppy_obj *floppy)
+{
+       mutex_lock(&idefloppy_ref_mutex);
+       kref_put(&floppy->kref, ide_floppy_release);
+       mutex_unlock(&idefloppy_ref_mutex);
+}
+
 /*
  *     Too bad. The drive wants to send us data which we are not ready to accept.
  *     Just throw it away.
@@ -557,7 +588,7 @@ static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
        /* Why does this happen? */
        if (!rq)
                return 0;
-       if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+       if (!blk_special_request(rq)) {
                /* our real local end request function */
                ide_end_request(drive, uptodate, nsecs);
                return 0;
@@ -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;
@@ -630,10 +661,12 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un
 
        idefloppy_do_end_request(drive, 1, done >> 9);
 
+#if IDEFLOPPY_DEBUG_BUGS
        if (bcount) {
                printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
                idefloppy_write_zeros(drive, bcount);
        }
+#endif
 }
 
 static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
@@ -652,9 +685,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->cmd_type = REQ_TYPE_SPECIAL;
+       rq->rq_disk = floppy->disk;
        (void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -802,7 +838,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
                        "transferred\n", pc->actually_transferred);
                clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-               local_irq_enable();
+               local_irq_enable_in_hardirq();
 
                if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
                        /* Error detected */
@@ -861,8 +897,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
                                        "to send us more data than expected "
                                        "- discarding data\n");
                                idefloppy_discard_data(drive,bcount.all);
-                               if (HWGROUP(drive)->handler != NULL)
-                                       BUG();
+                               BUG_ON(HWGROUP(drive)->handler != NULL);
                                ide_set_handler(drive,
                                                &idefloppy_pc_intr,
                                                IDEFLOPPY_WAIT_CMD,
@@ -895,8 +930,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
        pc->actually_transferred += bcount.all;
        pc->current_position += bcount.all;
 
-       if (HWGROUP(drive)->handler != NULL)
-               BUG();
+       BUG_ON(HWGROUP(drive)->handler != NULL);
        ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);           /* And set the interrupt handler again */
        return ide_started;
 }
@@ -923,8 +957,7 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
                                "issuing a packet command\n");
                return ide_do_reset(drive);
        }
-       if (HWGROUP(drive)->handler != NULL)
-               BUG();
+       BUG_ON(HWGROUP(drive)->handler != NULL);
        /* Set the interrupt routine */
        ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
        /* Send the actual packet */
@@ -980,8 +1013,7 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
         * 40 and 50msec work well. idefloppy_pc_intr will not be actually
         * used until after the packet is moved in about 50 msec.
         */
-       if (HWGROUP(drive)->handler != NULL)
-               BUG();
+       BUG_ON(HWGROUP(drive)->handler != NULL);
        ide_set_handler(drive, 
          &idefloppy_pc_intr,           /* service routine for packet command */
          floppy->ticks,                /* wait this long before "failing" */
@@ -989,16 +1021,34 @@ 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;
 
+#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone
+         and have lived on another thread's stack; that stack may have become
+         unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */
 #if IDEFLOPPY_DEBUG_BUGS
        if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
            pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1006,6 +1056,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
                        "Two request sense in serial were issued\n");
        }
 #endif /* IDEFLOPPY_DEBUG_BUGS */
+#endif
 
        if (floppy->failed_pc == NULL &&
            pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
@@ -1021,12 +1072,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 +1101,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 +1114,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? */
@@ -1203,7 +1250,7 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t
        pc->callback = &idefloppy_rw_callback;
        pc->rq = rq;
        pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
-       if (rq->flags & REQ_RW)
+       if (rq->cmd_flags & REQ_RW)
                set_bit(PC_WRITING, &pc->flags);
        pc->buffer = NULL;
        pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
@@ -1234,26 +1281,28 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
        idefloppy_pc_t *pc;
        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,
+       debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n",
+                       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);
                idefloppy_do_end_request(drive, 0, 0);
                return ide_stopped;
        }
-       if (rq->flags & REQ_CMD) {
+       if (blk_fs_request(rq)) {
                if (((long)rq->sector % floppy->bs_factor) ||
                    (rq->nr_sectors % floppy->bs_factor)) {
                        printk("%s: unsupported r/w request size\n",
@@ -1263,9 +1312,9 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
                }
                pc = idefloppy_next_pc_storage(drive);
                idefloppy_create_rw_cmd(floppy, pc, rq, block);
-       } else if (rq->flags & REQ_SPECIAL) {
+       } else if (blk_special_request(rq)) {
                pc = (idefloppy_pc_t *) rq->buffer;
-       } else if (rq->flags & REQ_BLOCK_PC) {
+       } else if (blk_pc_request(rq)) {
                pc = idefloppy_next_pc_storage(drive);
                if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
                        idefloppy_do_end_request(drive, 0, 0);
@@ -1288,11 +1337,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.cmd_type = REQ_TYPE_SPECIAL;
+       rq.rq_disk = floppy->disk;
 
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1317,7 +1368,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 +1434,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 +1508,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;
 }
 
@@ -1584,7 +1635,7 @@ static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg)
 /*
 ** Get ATAPI_FORMAT_UNIT progress indication.
 **
-** Userland gives a pointer to an int.  The int is set to a progresss
+** Userland gives a pointer to an int.  The int is set to a progress
 ** indicator 0-65536, with 65536=100%.
 **
 ** If the drive does not support format progress indication, we just check
@@ -1627,7 +1678,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 +1830,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 +1866,44 @@ 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 void ide_floppy_remove(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
-       struct gendisk *g = drive->disk;
+       struct gendisk *g = floppy->disk;
+
+       ide_unregister_subdriver(drive, floppy->driver);
+
+       del_gendisk(g);
+
+       ide_floppy_put(floppy);
+}
+
+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;
 
-       if (ide_unregister_subdriver(drive))
-               return 1;
        drive->driver_data = NULL;
+       g->private_data = NULL;
+       put_disk(g);
        kfree(floppy);
-       del_gendisk(g);
-       g->fops = ide_fops;
-       return 0;
 }
 
 #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 +1914,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(ide_drive_t *);
 
-/*
- *     IDE subdriver functions, registered with ide.c
- */
 static ide_driver_t idefloppy_driver = {
-       .owner                  = THIS_MODULE,
-       .name                   = "ide-floppy",
+       .gen_driver = {
+               .owner          = THIS_MODULE,
+               .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 +1970,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 +1988,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 +2017,20 @@ 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;
+}
+
+static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+       ide_drive_t *drive = floppy->drive;
+
+       geo->heads = drive->bios_head;
+       geo->sectors = drive->bios_sect;
+       geo->cylinders = (u16)drive->bios_cyl; /* truncate */
        return 0;
 }
 
@@ -1943,14 +2038,12 @@ 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(file, bdev, cmd, arg);
+       int err;
        int prevent = (arg) ? 1 : 0;
        idefloppy_pc_t pc;
-       if (err != -EINVAL)
-               return err;
 
        switch (cmd) {
        case CDROMEJECT:
@@ -2002,13 +2095,13 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
        case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
                return idefloppy_get_format_progress(drive, argp);
        }
-       return -EINVAL;
+       return generic_ide_ioctl(drive, file, bdev, cmd, arg);
 }
 
 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 +2113,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;
 }
 
@@ -2030,14 +2123,16 @@ static struct block_device_operations idefloppy_ops = {
        .open           = idefloppy_open,
        .release        = idefloppy_release,
        .ioctl          = idefloppy_ioctl,
+       .getgeo         = idefloppy_getgeo,
        .media_changed  = idefloppy_media_changed,
        .revalidate_disk= idefloppy_revalidate_disk
 };
 
-static int idefloppy_attach (ide_drive_t *drive)
+static int ide_floppy_probe(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy;
-       struct gendisk *g = drive->disk;
+       struct gendisk *g;
+
        if (!strstr("ide-floppy", drive->driver_req))
                goto failed;
        if (!drive->present)
@@ -2052,47 +2147,59 @@ static int idefloppy_attach (ide_drive_t *drive)
                printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
                goto failed;
        }
-       if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+       if ((floppy = kzalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
                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);
+
+       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);
        g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
        g->fops = &idefloppy_ops;
        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);
 }
 
-/*
- *     idefloppy_init will register the driver for each floppy.
- */
-static int idefloppy_init (void)
+static int __init 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_ALIAS("ide:*m-floppy*");
 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
 MODULE_LICENSE("GPL");