USB: cdc_acm: Fix memory leak after hangup
[safe/jmp/linux-2.6] / drivers / block / floppy.c
index 77cfd69..5c01f74 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 1993, 1994  Alain Knaff
  *  Copyright (C) 1998 Alan Cox
  */
+
 /*
  * 02.12.91 - Changed to static variables to indicate need for reset
  * and recalibrate. This makes some things easier (output_byte reset
 #define REALLY_SLOW_IO
 
 #define DEBUGT 2
-#define DCL_DEBUG              /* debug disk change line */
+#define DCL_DEBUG      /* debug disk change line */
 
 /* do print messages for unexpected interrupts */
 static int print_unex = 1;
@@ -161,24 +162,24 @@ static int print_unex = 1;
 #include <linux/workqueue.h>
 #define FDPATCHES
 #include <linux/fdreg.h>
-
 #include <linux/fd.h>
 #include <linux/hdreg.h>
-
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
 #include <linux/string.h>
+#include <linux/jiffies.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h> /* CMOS defines */
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
 #include <linux/buffer_head.h> /* for invalidate_buffers() */
+#include <linux/mutex.h>
 
 /*
  * PS/2 floppies have much slower step rates than regular floppies.
@@ -217,12 +218,10 @@ static int use_virtual_dma;
  */
 
 static DEFINE_SPINLOCK(floppy_lock);
-static struct completion device_release;
 
 static unsigned short virtual_dma_port = 0x3f0;
-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t floppy_interrupt(int irq, void *dev_id);
 static int set_dor(int fdc, char mask, char data);
-static void register_devfs_entries(int drive) __init;
 
 #define K_64   0x10000         /* 64KB */
 
@@ -242,7 +241,6 @@ static int allowed_drive_mask = 0x33;
 
 static int irqdma_allocated;
 
-#define LOCAL_END_REQUEST
 #define DEVICE_NAME "floppy"
 
 #include <linux/blkdev.h>
@@ -252,7 +250,7 @@ static int irqdma_allocated;
 
 static struct request *current_req;
 static struct request_queue *floppy_queue;
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
 
 #ifndef fd_get_dma_residue
 #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -275,8 +273,7 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
                return;         /* we have the memory */
        if (can_use_virtual_dma != 2)
                return;         /* no fallback allowed */
-       printk
-           ("DMA memory shortage. Temporarily falling back on virtual DMA\n");
+       printk("DMA memory shortage. Temporarily falling back on virtual DMA\n");
        *addr = (char *)nodma_mem_alloc(l);
 #else
        return;
@@ -292,23 +289,23 @@ static int initialising = 1;
 #define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
 #define UNIT(x) ((x) & 0x03)   /* drive on fdc */
 #define FDC(x) (((x) & 0x04) >> 2)     /* fdc of drive */
+       /* reverse mapping from unit and fdc to drive */
 #define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
-                               /* reverse mapping from unit and fdc to drive */
 #define DP (&drive_params[current_drive])
 #define DRS (&drive_state[current_drive])
 #define DRWE (&write_errors[current_drive])
 #define FDCS (&fdc_state[fdc])
-#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
-#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
-#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
+#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
+#define SETF(x) set_bit(x##_BIT, &DRS->flags)
+#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
 
 #define UDP (&drive_params[drive])
 #define UDRS (&drive_state[drive])
 #define UDRWE (&write_errors[drive])
 #define UFDCS (&fdc_state[FDC(drive)])
-#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
-#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
-#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
+#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
+#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
+#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
 
 #define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
 
@@ -357,7 +354,6 @@ static int inr;                     /* size of reply buffer, when called from interrupt */
 #define R_HEAD (reply_buffer[4])
 #define R_SECTOR (reply_buffer[5])
 #define R_SIZECODE (reply_buffer[6])
-
 #define SEL_DLY (2*HZ/100)
 
 /*
@@ -414,7 +410,7 @@ static struct floppy_write_errors write_errors[N_DRIVE];
 static struct timer_list motor_off_timer[N_DRIVE];
 static struct gendisk *disks[N_DRIVE];
 static struct block_device *opened_bdev[N_DRIVE];
-static DECLARE_MUTEX(open_lock);
+static DEFINE_MUTEX(open_lock);
 static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
 
 /*
@@ -428,8 +424,15 @@ static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
  * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
  * side 0 is on physical side 0 (but with the misnamed sector IDs).
  * 'stretch' should probably be renamed to something more general, like
- * 'options'.  Other parameters should be self-explanatory (see also
- * setfdprm(8)).
+ * 'options'.
+ *
+ * Bits 2 through 9 of 'stretch' tell the number of the first sector.
+ * The LSB (bit 2) is flipped. For most disks, the first sector
+ * is 1 (represented by 0x00<<2).  For some CP/M and music sampler
+ * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
+ * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
+ *
+ * Other parameters should be self-explanatory (see also setfdprm(8)).
  */
 /*
            Size
@@ -473,13 +476,12 @@ static struct floppy_struct floppy_type[32] = {
        { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */
        { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */
        { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */
-
        { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */
+
        { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  }, /* 30 800KB 3.5"    */
        { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
 };
 
-#define        NUMBER(x)       (sizeof(x) / sizeof(*(x)))
 #define SECTSIZE (_FD_SECTSIZE(*floppy))
 
 /* Auto-detection: Disk type used until the next media change occurs. */
@@ -541,12 +543,12 @@ static char *floppy_track_buffer;
 static int max_buffer_sectors;
 
 static int *errors;
-typedef void (*done_f) (int);
+typedef void (*done_f)(int);
 static struct cont_t {
-       void (*interrupt) (void);       /* this is called after the interrupt of the
+       void (*interrupt)(void);        /* this is called after the interrupt of the
                                         * main command */
-       void (*redo) (void);    /* this is called to retry the operation */
-       void (*error) (void);   /* this is called to tally an error */
+       void (*redo)(void);     /* this is called to retry the operation */
+       void (*error)(void);    /* this is called to tally an error */
        done_f done;            /* this is called to say if the operation has
                                 * succeeded/failed */
 } *cont;
@@ -557,6 +559,8 @@ static void process_fd_request(void);
 static void recalibrate_floppy(void);
 static void floppy_shutdown(unsigned long);
 
+static int floppy_request_regions(int);
+static void floppy_release_regions(int);
 static int floppy_grab_irq_and_dma(void);
 static void floppy_release_irq_and_dma(void);
 
@@ -672,7 +676,7 @@ static void __reschedule_timeout(int drive, const char *message, int marg)
        if (drive == current_reqD)
                drive = current_drive;
        del_timer(&fd_timeout);
-       if (drive < 0 || drive > N_DRIVE) {
+       if (drive < 0 || drive >= N_DRIVE) {
                fd_timeout.expires = jiffies + 20UL * HZ;
                drive = 0;
        } else
@@ -696,7 +700,6 @@ static void reschedule_timeout(int drive, const char *message, int marg)
 }
 
 #define INFBOUND(a,b) (a)=max_t(int, a, b)
-
 #define SUPBOUND(a,b) (a)=min_t(int, a, b)
 
 /*
@@ -735,8 +738,9 @@ static void reschedule_timeout(int drive, const char *message, int marg)
 static int disk_change(int drive)
 {
        int fdc = FDC(drive);
+
 #ifdef FLOPPY_SANITY_CHECK
-       if (jiffies - UDRS->select_date < UDP->select_delay)
+       if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
                DPRINT("WARNING disk change called early\n");
        if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
            (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
@@ -773,7 +777,6 @@ static int disk_change(int drive)
                        floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
                }
 
-               /*USETF(FD_DISK_NEWCHANGE); */
                return 1;
        } else {
                UDRS->last_checked = jiffies;
@@ -789,7 +792,10 @@ static inline int is_selected(int dor, int unit)
 
 static int set_dor(int fdc, char mask, char data)
 {
-       register unsigned char drive, unit, newdor, olddor;
+       unsigned char unit;
+       unsigned char drive;
+       unsigned char newdor;
+       unsigned char olddor;
 
        if (FDCS->address == -1)
                return -1;
@@ -816,15 +822,6 @@ static int set_dor(int fdc, char mask, char data)
                        UDRS->select_date = jiffies;
                }
        }
-       /*
-        *      We should propagate failures to grab the resources back
-        *      nicely from here. Actually we ought to rewrite the fd
-        *      driver some day too.
-        */
-       if (newdor & FLOPPY_MOTOR_MASK)
-               floppy_grab_irq_and_dma();
-       if (olddor & FLOPPY_MOTOR_MASK)
-               floppy_release_irq_and_dma();
        return olddor;
 }
 
@@ -882,8 +879,6 @@ static int _lock_fdc(int drive, int interruptible, int line)
                       line);
                return -1;
        }
-       if (floppy_grab_irq_and_dma() == -1)
-               return -EBUSY;
 
        if (test_and_set_bit(0, &fdc_busy)) {
                DECLARE_WAITQUEUE(wait, current);
@@ -905,6 +900,7 @@ static int _lock_fdc(int drive, int interruptible, int line)
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&fdc_wait, &wait);
+               flush_scheduled_work();
        }
        command_status = FD_COMMAND_NONE;
 
@@ -935,10 +931,9 @@ static inline void unlock_fdc(void)
        del_timer(&fd_timeout);
        cont = NULL;
        clear_bit(0, &fdc_busy);
-       if (elv_next_request(floppy_queue))
+       if (current_req || blk_peek_request(floppy_queue))
                do_fd_request(floppy_queue);
        spin_unlock_irqrestore(&floppy_lock, flags);
-       floppy_release_irq_and_dma();
        wake_up(&fdc_wait);
 }
 
@@ -954,7 +949,7 @@ static void motor_off_callback(unsigned long nr)
 static void floppy_off(unsigned int drive)
 {
        unsigned long volatile delta;
-       register int fdc = FDC(drive);
+       int fdc = FDC(drive);
 
        if (!(FDCS->dor & (0x10 << UNIT(drive))))
                return;
@@ -980,7 +975,9 @@ static void floppy_off(unsigned int drive)
  */
 static void scandrives(void)
 {
-       int i, drive, saved_drive;
+       int i;
+       int drive;
+       int saved_drive;
 
        if (DP->select_delay)
                return;
@@ -1004,11 +1001,11 @@ static void empty(void)
 {
 }
 
-static DECLARE_WORK(floppy_work, NULL, NULL);
+static DECLARE_WORK(floppy_work, NULL);
 
 static void schedule_bh(void (*handler) (void))
 {
-       PREPARE_WORK(&floppy_work, (void (*)(void *))handler, NULL);
+       PREPARE_WORK(&floppy_work, (work_func_t)handler);
        schedule_work(&floppy_work);
 }
 
@@ -1020,7 +1017,7 @@ static void cancel_activity(void)
 
        spin_lock_irqsave(&floppy_lock, flags);
        do_floppy = NULL;
-       PREPARE_WORK(&floppy_work, (void *)empty, NULL);
+       PREPARE_WORK(&floppy_work, (work_func_t)empty);
        del_timer(&fd_timer);
        spin_unlock_irqrestore(&floppy_lock, flags);
 }
@@ -1064,7 +1061,7 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
                return 1;
        }
 
-       if ((signed)(jiffies - delay) < 0) {
+       if (time_before(jiffies, delay)) {
                del_timer(&fd_timer);
                fd_timer.function = function;
                fd_timer.expires = delay;
@@ -1158,7 +1155,9 @@ static void show_floppy(void);
 /* waits until the fdc becomes ready */
 static int wait_til_ready(void)
 {
-       int counter, status;
+       int status;
+       int counter;
+
        if (FDCS->reset)
                return -1;
        for (counter = 0; counter < 10000; counter++) {
@@ -1205,7 +1204,8 @@ static int output_byte(char byte)
 /* gets the response from the fdc */
 static int result(void)
 {
-       int i, status = 0;
+       int i;
+       int status = 0;
 
        for (i = 0; i < MAX_REPLIES; i++) {
                if ((status = wait_til_ready()) < 0)
@@ -1238,6 +1238,7 @@ static int result(void)
 static int need_more_output(void)
 {
        int status;
+
        if ((status = wait_til_ready()) < 0)
                return -1;
        if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
@@ -1321,8 +1322,11 @@ static int fdc_configure(void)
  */
 static void fdc_specify(void)
 {
-       unsigned char spec1, spec2;
-       unsigned long srt, hlt, hut;
+       unsigned char spec1;
+       unsigned char spec2;
+       unsigned long srt;
+       unsigned long hlt;
+       unsigned long hut;
        unsigned long dtr = NOMINAL_DTR;
        unsigned long scale_dtr = NOMINAL_DTR;
        int hlt_max_code = 0x7f;
@@ -1331,7 +1335,6 @@ static void fdc_specify(void)
        if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
                fdc_configure();
                FDCS->need_configure = 0;
-               /*DPRINT("FIFO enabled\n"); */
        }
 
        switch (raw_cmd->rate & 0x03) {
@@ -1362,20 +1365,20 @@ static void fdc_specify(void)
        }
 
        /* Convert step rate from microseconds to milliseconds and 4 bits */
-       srt = 16 - (DP->srt * scale_dtr / 1000 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+       srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
        if (slow_floppy) {
                srt = srt / 4;
        }
        SUPBOUND(srt, 0xf);
        INFBOUND(srt, 0);
 
-       hlt = (DP->hlt * scale_dtr / 2 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+       hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
        if (hlt < 0x01)
                hlt = 0x01;
        else if (hlt > 0x7f)
                hlt = hlt_max_code;
 
-       hut = (DP->hut * scale_dtr / 16 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+       hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
        if (hut < 0x1)
                hut = 0x1;
        else if (hut > 0xf)
@@ -1484,7 +1487,6 @@ static int interpret_errors(void)
                                tell_sector();
                        }
                        printk("\n");
-
                }
                if (ST2 & ST2_WC || ST2 & ST2_BC)
                        /* wrong cylinder => recal */
@@ -1510,7 +1512,10 @@ static int interpret_errors(void)
  */
 static void setup_rw_floppy(void)
 {
-       int i, r, flags, dflags;
+       int i;
+       int r;
+       int flags;
+       int dflags;
        unsigned long ready_date;
        timeout_fn function;
 
@@ -1524,7 +1529,7 @@ static void setup_rw_floppy(void)
                 * again just before spinup completion. Beware that
                 * after scandrives, we must again wait for selection.
                 */
-               if ((signed)(ready_date - jiffies) > DP->select_delay) {
+               if (time_after(ready_date, jiffies + DP->select_delay)) {
                        ready_date -= DP->select_delay;
                        function = (timeout_fn) floppy_start;
                } else
@@ -1738,11 +1743,11 @@ static void print_result(char *message, int inr)
 }
 
 /* interrupt handler. Note that this can be called externally on the Sparc */
-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t floppy_interrupt(int irq, void *dev_id)
 {
-       void (*handler) (void) = do_floppy;
        int do_print;
        unsigned long f;
+       void (*handler)(void) = do_floppy;
 
        lasthandler = handler;
        interruptjiffies = jiffies;
@@ -1880,7 +1885,7 @@ static void show_floppy(void)
        printk("fdc_busy=%lu\n", fdc_busy);
        if (do_floppy)
                printk("do_floppy=%p\n", do_floppy);
-       if (floppy_work.pending)
+       if (work_pending(&floppy_work))
                printk("floppy_work.func=%p\n", floppy_work.func);
        if (timer_pending(&fd_timer))
                printk("fd_timer.function=%p\n", fd_timer.function);
@@ -1924,12 +1929,11 @@ static void floppy_shutdown(unsigned long data)
        is_alive("floppy shutdown");
 }
 
-/*typedef void (*timeout_fn)(unsigned long);*/
-
 /* start motor, check media-changed condition and write protection */
-static int start_motor(void (*function) (void))
+static int start_motor(void (*function)(void))
 {
-       int mask, data;
+       int mask;
+       int data;
 
        mask = 0xfc;
        data = UNIT(current_drive);
@@ -2032,17 +2036,17 @@ static struct cont_t wakeup_cont = {
        .interrupt      = empty,
        .redo           = do_wakeup,
        .error          = empty,
-       .done           = (done_f) empty
+       .done           = (done_f)empty
 };
 
 static struct cont_t intr_cont = {
        .interrupt      = empty,
        .redo           = process_fd_request,
        .error          = empty,
-       .done           = (done_f) empty
+       .done           = (done_f)empty
 };
 
-static int wait_til_done(void (*handler) (void), int interruptible)
+static int wait_til_done(void (*handler)(void), int interruptible)
 {
        int ret;
 
@@ -2061,7 +2065,6 @@ static int wait_til_done(void (*handler) (void), int interruptible)
                                break;
 
                        is_alive("wait_til_done");
-
                        schedule();
                }
 
@@ -2153,6 +2156,7 @@ static void bad_flp_intr(void)
 static void set_floppy(int drive)
 {
        int type = ITYPE(UDRS->fd_device);
+
        if (type)
                _floppy = floppy_type + type;
        else
@@ -2181,11 +2185,14 @@ static void format_interrupt(void)
 #define CT(x) ((x) | 0xc0)
 static void setup_format_params(int track)
 {
+       int n;
+       int il;
+       int count;
+       int head_shift;
+       int track_shift;
        struct fparm {
                unsigned char track, head, sect, size;
        } *here = (struct fparm *)floppy_track_buffer;
-       int il, n;
-       int count, head_shift, track_shift;
 
        raw_cmd = &default_raw_cmd;
        raw_cmd->track = track;
@@ -2239,9 +2246,9 @@ static void setup_format_params(int track)
                        }
                }
        }
-       if (_floppy->stretch & FD_ZEROBASED) {
+       if (_floppy->stretch & FD_SECTBASEMASK) {
                for (count = 0; count < F_SECT_PER_TRACK; count++)
-                       here[count].sect--;
+                       here[count].sect += FD_SECTBASE(_floppy) - 1;
        }
 }
 
@@ -2289,21 +2296,19 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
  * =============================
  */
 
-static void floppy_end_request(struct request *req, int uptodate)
+static void floppy_end_request(struct request *req, int error)
 {
        unsigned int nr_sectors = current_count_sectors;
+       unsigned int drive = (unsigned long)req->rq_disk->private_data;
 
        /* current_count_sectors can be zero if transfer failed */
-       if (!uptodate)
-               nr_sectors = req->current_nr_sectors;
-       if (end_that_request_first(req, uptodate, nr_sectors))
+       if (error)
+               nr_sectors = blk_rq_cur_sectors(req);
+       if (__blk_end_request(req, error, nr_sectors << 9))
                return;
-       add_disk_randomness(req->rq_disk);
-       floppy_off((long)req->rq_disk->private_data);
-       blkdev_dequeue_request(req);
-       end_that_request_last(req);
 
        /* We're done with the request */
+       floppy_off(drive);
        current_req = NULL;
 }
 
@@ -2327,28 +2332,28 @@ static void request_done(int uptodate)
        if (uptodate) {
                /* maintain values for invalidation on geometry
                 * change */
-               block = current_count_sectors + req->sector;
+               block = current_count_sectors + blk_rq_pos(req);
                INFBOUND(DRS->maxblock, block);
                if (block > _floppy->sect)
                        DRS->maxtrack = 1;
 
                /* unlock chained buffers */
                spin_lock_irqsave(q->queue_lock, flags);
-               floppy_end_request(req, 1);
+               floppy_end_request(req, 0);
                spin_unlock_irqrestore(q->queue_lock, flags);
        } else {
                if (rq_data_dir(req) == WRITE) {
                        /* record write error information */
                        DRWE->write_errors++;
                        if (DRWE->write_errors == 1) {
-                               DRWE->first_error_sector = req->sector;
+                               DRWE->first_error_sector = blk_rq_pos(req);
                                DRWE->first_error_generation = DRS->generation;
                        }
-                       DRWE->last_error_sector = req->sector;
+                       DRWE->last_error_sector = blk_rq_pos(req);
                        DRWE->last_error_generation = DRS->generation;
                }
                spin_lock_irqsave(q->queue_lock, flags);
-               floppy_end_request(req, 0);
+               floppy_end_request(req, -EIO);
                spin_unlock_irqrestore(q->queue_lock, flags);
        }
 }
@@ -2356,7 +2361,10 @@ static void request_done(int uptodate)
 /* Interrupt handler evaluating the result of the r/w operation */
 static void rw_interrupt(void)
 {
-       int nr_sectors, ssize, eoc, heads;
+       int eoc;
+       int ssize;
+       int heads;
+       int nr_sectors;
 
        if (R_HEAD >= 2) {
                /* some Toshiba floppy controllers occasionnally seem to
@@ -2387,7 +2395,7 @@ static void rw_interrupt(void)
 
 #ifdef FLOPPY_SANITY_CHECK
        if (nr_sectors / ssize >
-           (in_sector_offset + current_count_sectors + ssize - 1) / ssize) {
+           DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
                DPRINT("long rw: %x instead of %lx\n",
                       nr_sectors, current_count_sectors);
                printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
@@ -2449,22 +2457,19 @@ static void rw_interrupt(void)
 /* Compute maximal contiguous buffer size. */
 static int buffer_chain_size(void)
 {
-       struct bio *bio;
        struct bio_vec *bv;
-       int size, i;
+       int size;
+       struct req_iterator iter;
        char *base;
 
        base = bio_data(current_req->bio);
        size = 0;
 
-       rq_for_each_bio(bio, current_req) {
-               bio_for_each_segment(bv, bio, i) {
-                       if (page_address(bv->bv_page) + bv->bv_offset !=
-                           base + size)
-                               break;
+       rq_for_each_segment(bv, current_req, iter) {
+               if (page_address(bv->bv_page) + bv->bv_offset != base + size)
+                       break;
 
-                       size += bv->bv_len;
-               }
+               size += bv->bv_len;
        }
 
        return size >> 9;
@@ -2491,30 +2496,30 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 {
        int remaining;          /* number of transferred 512-byte sectors */
        struct bio_vec *bv;
-       struct bio *bio;
-       char *buffer, *dma_buffer;
-       int size, i;
+       char *buffer;
+       char *dma_buffer;
+       int size;
+       struct req_iterator iter;
 
        max_sector = transfer_size(ssize,
                                   min(max_sector, max_sector_2),
-                                  current_req->nr_sectors);
+                                  blk_rq_sectors(current_req));
 
        if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
-           buffer_max > fsector_t + current_req->nr_sectors)
+           buffer_max > fsector_t + blk_rq_sectors(current_req))
                current_count_sectors = min_t(int, buffer_max - fsector_t,
-                                             current_req->nr_sectors);
+                                             blk_rq_sectors(current_req));
 
        remaining = current_count_sectors << 9;
 #ifdef FLOPPY_SANITY_CHECK
-       if ((remaining >> 9) > current_req->nr_sectors &&
-           CT(COMMAND) == FD_WRITE) {
+       if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
                DPRINT("in copy buffer\n");
                printk("current_count_sectors=%ld\n", current_count_sectors);
                printk("remaining=%d\n", remaining >> 9);
-               printk("current_req->nr_sectors=%ld\n",
-                      current_req->nr_sectors);
+               printk("current_req->nr_sectors=%u\n",
+                      blk_rq_sectors(current_req));
                printk("current_req->current_nr_sectors=%u\n",
-                      current_req->current_nr_sectors);
+                      blk_rq_cur_sectors(current_req));
                printk("max_sector=%d\n", max_sector);
                printk("ssize=%d\n", ssize);
        }
@@ -2524,45 +2529,43 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 
        dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
 
-       size = current_req->current_nr_sectors << 9;
+       size = blk_rq_cur_bytes(current_req);
 
-       rq_for_each_bio(bio, current_req) {
-               bio_for_each_segment(bv, bio, i) {
-                       if (!remaining)
-                               break;
+       rq_for_each_segment(bv, current_req, iter) {
+               if (!remaining)
+                       break;
 
-                       size = bv->bv_len;
-                       SUPBOUND(size, remaining);
+               size = bv->bv_len;
+               SUPBOUND(size, remaining);
 
-                       buffer = page_address(bv->bv_page) + bv->bv_offset;
+               buffer = page_address(bv->bv_page) + bv->bv_offset;
 #ifdef FLOPPY_SANITY_CHECK
-                       if (dma_buffer + size >
-                           floppy_track_buffer + (max_buffer_sectors << 10) ||
-                           dma_buffer < floppy_track_buffer) {
-                               DPRINT("buffer overrun in copy buffer %d\n",
-                                      (int)((floppy_track_buffer -
-                                             dma_buffer) >> 9));
-                               printk("fsector_t=%d buffer_min=%d\n",
-                                      fsector_t, buffer_min);
-                               printk("current_count_sectors=%ld\n",
-                                      current_count_sectors);
-                               if (CT(COMMAND) == FD_READ)
-                                       printk("read\n");
-                               if (CT(COMMAND) == FD_WRITE)
-                                       printk("write\n");
-                               break;
-                       }
-                       if (((unsigned long)buffer) % 512)
-                               DPRINT("%p buffer not aligned\n", buffer);
-#endif
+               if (dma_buffer + size >
+                   floppy_track_buffer + (max_buffer_sectors << 10) ||
+                   dma_buffer < floppy_track_buffer) {
+                       DPRINT("buffer overrun in copy buffer %d\n",
+                              (int)((floppy_track_buffer -
+                                     dma_buffer) >> 9));
+                       printk("fsector_t=%d buffer_min=%d\n",
+                              fsector_t, buffer_min);
+                       printk("current_count_sectors=%ld\n",
+                              current_count_sectors);
                        if (CT(COMMAND) == FD_READ)
-                               memcpy(buffer, dma_buffer, size);
-                       else
-                               memcpy(dma_buffer, buffer, size);
-
-                       remaining -= size;
-                       dma_buffer += size;
+                               printk("read\n");
+                       if (CT(COMMAND) == FD_WRITE)
+                               printk("write\n");
+                       break;
                }
+               if (((unsigned long)buffer) % 512)
+                       DPRINT("%p buffer not aligned\n", buffer);
+#endif
+               if (CT(COMMAND) == FD_READ)
+                       memcpy(buffer, dma_buffer, size);
+               else
+                       memcpy(dma_buffer, buffer, size);
+
+               remaining -= size;
+               dma_buffer += size;
        }
 #ifdef FLOPPY_SANITY_CHECK
        if (remaining) {
@@ -2573,19 +2576,6 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 #endif
 }
 
-#if 0
-static inline int check_dma_crossing(char *start,
-                                    unsigned long length, char *message)
-{
-       if (CROSS_64KB(start, length)) {
-               printk("DMA xfer crosses 64KB boundary in %s %p-%p\n",
-                      message, start, start + length);
-               return 1;
-       } else
-               return 0;
-}
-#endif
-
 /* work around a bug in pseudo DMA
  * (on some FDCs) pseudo DMA does not stop when the CPU stops
  * sending data.  Hence we need a different way to signal the
@@ -2595,7 +2585,8 @@ static inline int check_dma_crossing(char *start,
  */
 static void virtualdmabug_workaround(void)
 {
-       int hard_sectors, end_sector;
+       int hard_sectors;
+       int end_sector;
 
        if (CT(COMMAND) == FD_WRITE) {
                COMMAND &= ~0x80;       /* switch off multiple track mode */
@@ -2627,7 +2618,10 @@ static void virtualdmabug_workaround(void)
 static int make_raw_rw_request(void)
 {
        int aligned_sector_t;
-       int max_sector, max_size, tracksize, ssize;
+       int max_sector;
+       int max_size;
+       int tracksize;
+       int ssize;
 
        if (max_buffer_sectors == 0) {
                printk("VFS: Block I/O scheduled on unopened device\n");
@@ -2653,10 +2647,10 @@ static int make_raw_rw_request(void)
 
        max_sector = _floppy->sect * _floppy->head;
 
-       TRACK = (int)current_req->sector / max_sector;
-       fsector_t = (int)current_req->sector % max_sector;
+       TRACK = (int)blk_rq_pos(current_req) / max_sector;
+       fsector_t = (int)blk_rq_pos(current_req) % max_sector;
        if (_floppy->track && TRACK >= _floppy->track) {
-               if (current_req->current_nr_sectors & 1) {
+               if (blk_rq_cur_sectors(current_req) & 1) {
                        current_count_sectors = 1;
                        return 1;
                } else
@@ -2664,7 +2658,7 @@ static int make_raw_rw_request(void)
        }
        HEAD = fsector_t / _floppy->sect;
 
-       if (((_floppy->stretch & (FD_SWAPSIDES | FD_ZEROBASED)) ||
+       if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
             TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
                max_sector = _floppy->sect;
 
@@ -2674,7 +2668,7 @@ static int make_raw_rw_request(void)
                if (fsector_t >= max_sector) {
                        current_count_sectors =
                            min_t(int, _floppy->sect - fsector_t,
-                                 current_req->nr_sectors);
+                                 blk_rq_sectors(current_req));
                        return 1;
                }
                SIZECODE = 2;
@@ -2694,7 +2688,7 @@ static int make_raw_rw_request(void)
        CODE2SIZE;
        SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
        SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
-           ((_floppy->stretch & FD_ZEROBASED) ? 0 : 1);
+           FD_SECTBASE(_floppy);
 
        /* tracksize describes the size which can be filled up with sectors
         * of size ssize.
@@ -2725,7 +2719,7 @@ static int make_raw_rw_request(void)
 
        in_sector_offset = (fsector_t % _floppy->sect) % ssize;
        aligned_sector_t = fsector_t - in_sector_offset;
-       max_size = current_req->nr_sectors;
+       max_size = blk_rq_sectors(current_req);
        if ((raw_cmd->track == buffer_track) &&
            (current_drive == buffer_drive) &&
            (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
@@ -2734,10 +2728,10 @@ static int make_raw_rw_request(void)
                        copy_buffer(1, max_sector, buffer_max);
                        return 1;
                }
-       } else if (in_sector_offset || current_req->nr_sectors < ssize) {
+       } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
                if (CT(COMMAND) == FD_WRITE) {
-                       if (fsector_t + current_req->nr_sectors > ssize &&
-                           fsector_t + current_req->nr_sectors < ssize + ssize)
+                       if (fsector_t + blk_rq_sectors(current_req) > ssize &&
+                           fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
                                max_size = ssize + ssize;
                        else
                                max_size = ssize;
@@ -2779,11 +2773,9 @@ static int make_raw_rw_request(void)
                 */
                if (!direct ||
                    (indirect * 2 > direct * 3 &&
-                    *errors < DP->max_errors.read_track &&
-                    /*!TESTF(FD_NEED_TWADDLE) && */
-                    ((!probing
+                    *errors < DP->max_errors.read_track && ((!probing
                       || (DP->read_track & (1 << DRS->probed_format)))))) {
-                       max_size = current_req->nr_sectors;
+                       max_size = blk_rq_sectors(current_req);
                } else {
                        raw_cmd->kernel_data = current_req->buffer;
                        raw_cmd->length = current_count_sectors << 9;
@@ -2794,10 +2786,6 @@ static int make_raw_rw_request(void)
                                       indirect, direct, fsector_t);
                                return 0;
                        }
-/*                     check_dma_crossing(raw_cmd->kernel_data, 
-                                          raw_cmd->length, 
-                                          "end of make_raw_request [1]");*/
-
                        virtualdmabug_workaround();
                        return 2;
                }
@@ -2812,7 +2800,7 @@ static int make_raw_rw_request(void)
            fsector_t > buffer_max ||
            fsector_t < buffer_min ||
            ((CT(COMMAND) == FD_READ ||
-             (!in_sector_offset && current_req->nr_sectors >= ssize)) &&
+             (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
             max_sector > 2 * max_buffer_sectors + buffer_min &&
             max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
            /* not enough space */
@@ -2847,8 +2835,6 @@ static int make_raw_rw_request(void)
        raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
        raw_cmd->length <<= 9;
 #ifdef FLOPPY_SANITY_CHECK
-       /*check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, 
-          "end of make_raw_request"); */
        if ((raw_cmd->length < current_count_sectors << 9) ||
            (raw_cmd->kernel_data != current_req->buffer &&
             CT(COMMAND) == FD_WRITE &&
@@ -2892,8 +2878,8 @@ static int make_raw_rw_request(void)
                                printk("write\n");
                        return 0;
                }
-       } else if (raw_cmd->length > current_req->nr_sectors << 9 ||
-                  current_count_sectors > current_req->nr_sectors) {
+       } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
+                  current_count_sectors > blk_rq_sectors(current_req)) {
                DPRINT("buffer overrun in direct transfer\n");
                return 0;
        } else if (raw_cmd->length < current_count_sectors << 9) {
@@ -2926,7 +2912,7 @@ static void redo_fd_request(void)
                        struct request *req;
 
                        spin_lock_irq(floppy_queue->queue_lock);
-                       req = elv_next_request(floppy_queue);
+                       req = blk_fetch_request(floppy_queue);
                        spin_unlock_irq(floppy_queue->queue_lock);
                        if (!req) {
                                do_floppy = NULL;
@@ -2993,7 +2979,7 @@ static void process_fd_request(void)
        schedule_bh(redo_fd_request);
 }
 
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
 {
        if (max_buffer_sectors == 0) {
                printk("VFS: do_fd_request called on non-open device\n");
@@ -3003,8 +2989,9 @@ static void do_fd_request(request_queue_t * q)
        if (usage_count == 0) {
                printk("warning: usage count=0, current_req=%p exiting\n",
                       current_req);
-               printk("sect=%ld flags=%lx\n", (long)current_req->sector,
-                      current_req->flags);
+               printk("sect=%ld type=%x flags=%x\n",
+                      (long)blk_rq_pos(current_req), current_req->cmd_type,
+                      current_req->cmd_flags);
                return;
        }
        if (test_bit(0, &fdc_busy)) {
@@ -3028,6 +3015,7 @@ static struct cont_t poll_cont = {
 static int poll_drive(int interruptible, int flag)
 {
        int ret;
+
        /* no auto-sense, just clear dcl */
        raw_cmd = &default_raw_cmd;
        raw_cmd->flags = flag;
@@ -3190,7 +3178,8 @@ static inline int raw_cmd_copyout(int cmd, char __user *param,
 
 static void raw_cmd_free(struct floppy_raw_cmd **ptr)
 {
-       struct floppy_raw_cmd *next, *this;
+       struct floppy_raw_cmd *next;
+       struct floppy_raw_cmd *this;
 
        this = *ptr;
        *ptr = NULL;
@@ -3262,8 +3251,10 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
 
 static int raw_cmd_ioctl(int cmd, void __user *param)
 {
-       int drive, ret, ret2;
        struct floppy_raw_cmd *my_raw_cmd;
+       int drive;
+       int ret2;
+       int ret;
 
        if (FDCS->rawcmd <= 1)
                FDCS->rawcmd = 1;
@@ -3330,13 +3321,16 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
            g->head <= 0 ||
            g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
            /* check if reserved bits are set */
-           (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_ZEROBASED)) != 0)
+           (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
                return -EINVAL;
        if (type) {
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               down(&open_lock);
-               LOCK_FDC(drive, 1);
+               mutex_lock(&open_lock);
+               if (lock_fdc(drive, 1)) {
+                       mutex_unlock(&open_lock);
+                       return -EINTR;
+               }
                floppy_type[type] = *g;
                floppy_type[type].name = "user format";
                for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
@@ -3349,7 +3343,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                                continue;
                        __invalidate_device(bdev);
                }
-               up(&open_lock);
+               mutex_unlock(&open_lock);
        } else {
                int oldStretch;
                LOCK_FDC(drive, 1);
@@ -3375,7 +3369,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                if (DRS->maxblock > user_params[drive].sect ||
                    DRS->maxtrack ||
                    ((user_params[drive].sect ^ oldStretch) &
-                    (FD_SWAPSIDES | FD_ZEROBASED)))
+                    (FD_SWAPSIDES | FD_SECTBASEMASK)))
                        invalidate_drive(bdev);
                else
                        process_fd_request();
@@ -3445,15 +3439,33 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
        return 0;
 }
 
-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       int drive = (long)bdev->bd_disk->private_data;
+       int type = ITYPE(drive_state[drive].fd_device);
+       struct floppy_struct *g;
+       int ret;
+
+       ret = get_floppy_geometry(drive, type, &g);
+       if (ret)
+               return ret;
+
+       geo->heads = g->head;
+       geo->sectors = g->sect;
+       geo->cylinders = g->track;
+       return 0;
+}
+
+static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                    unsigned long param)
 {
-#define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data)
+#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
 #define OUT(c,x) case c: outparam = (const char *) (x); break
 #define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
 
-       int drive = (long)inode->i_bdev->bd_disk->private_data;
-       int i, type = ITYPE(UDRS->fd_device);
+       int drive = (long)bdev->bd_disk->private_data;
+       int type = ITYPE(UDRS->fd_device);
+       int i;
        int ret;
        int size;
        union inparam {
@@ -3474,23 +3486,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                cmd = FDEJECT;
        }
 
-       /* generic block device ioctls */
-       switch (cmd) {
-               /* the following have been inspired by the corresponding
-                * code for other block devices. */
-               struct floppy_struct *g;
-       case HDIO_GETGEO:
-               {
-                       struct hd_geometry loc;
-                       ECALL(get_floppy_geometry(drive, type, &g));
-                       loc.heads = g->head;
-                       loc.sectors = g->sect;
-                       loc.cylinders = g->track;
-                       loc.start = 0;
-                       return _COPYOUT(loc);
-               }
-       }
-
        /* convert the old style command into a new style command */
        if ((cmd & 0xff00) == 0x0200) {
                ECALL(normalize_ioctl(&cmd, &size));
@@ -3527,11 +3522,11 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        current_type[drive] = NULL;
                        floppy_sizes[drive] = MAX_DISK_SIZE << 1;
                        UDRS->keep_data = 0;
-                       return invalidate_drive(inode->i_bdev);
+                       return invalidate_drive(bdev);
                case FDSETPRM:
                case FDDEFPRM:
                        return set_geometry(cmd, &inparam.g,
-                                           drive, type, inode->i_bdev);
+                                           drive, type, bdev);
                case FDGETPRM:
                        ECALL(get_floppy_geometry(drive, type,
                                                  (struct floppy_struct **)
@@ -3562,7 +3557,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                case FDFMTEND:
                case FDFLUSH:
                        LOCK_FDC(drive, 1);
-                       return invalidate_drive(inode->i_bdev);
+                       return invalidate_drive(bdev);
 
                case FDSETEMSGTRESH:
                        UDP->max_errors.reporting =
@@ -3636,8 +3631,7 @@ static void __init config_types(void)
        if (!UDP->cmos && FLOPPY1_TYPE)
                UDP->cmos = FLOPPY1_TYPE;
 
-       /* XXX */
-       /* additional physical CMOS drive detection should go here */
+       /* FIXME: additional physical CMOS drive detection should go here */
 
        for (drive = 0; drive < N_DRIVE; drive++) {
                unsigned int type = UDP->cmos;
@@ -3645,7 +3639,7 @@ static void __init config_types(void)
                const char *name = NULL;
                static char temparea[32];
 
-               if (type < NUMBER(default_drive_params)) {
+               if (type < ARRAY_SIZE(default_drive_params)) {
                        params = &default_drive_params[type].params;
                        if (type) {
                                name = default_drive_params[type].name;
@@ -3664,7 +3658,6 @@ static void __init config_types(void)
                                first = 0;
                        }
                        printk("%s fd%d is %s", prepend, drive, name);
-                       register_devfs_entries(drive);
                }
                *UDP = *params;
        }
@@ -3672,11 +3665,11 @@ static void __init config_types(void)
                printk("\n");
 }
 
-static int floppy_release(struct inode *inode, struct file *filp)
+static int floppy_release(struct gendisk *disk, fmode_t mode)
 {
-       int drive = (long)inode->i_bdev->bd_disk->private_data;
+       int drive = (long)disk->private_data;
 
-       down(&open_lock);
+       mutex_lock(&open_lock);
        if (UDRS->fd_ref < 0)
                UDRS->fd_ref = 0;
        else if (!UDRS->fd_ref--) {
@@ -3685,8 +3678,8 @@ static int floppy_release(struct inode *inode, struct file *filp)
        }
        if (!UDRS->fd_ref)
                opened_bdev[drive] = NULL;
-       floppy_release_irq_and_dma();
-       up(&open_lock);
+       mutex_unlock(&open_lock);
+
        return 0;
 }
 
@@ -3695,18 +3688,17 @@ static int floppy_release(struct inode *inode, struct file *filp)
  * /dev/PS0 etc), and disallows simultaneous access to the same
  * drive with different device numbers.
  */
-static int floppy_open(struct inode *inode, struct file *filp)
+static int floppy_open(struct block_device *bdev, fmode_t mode)
 {
-       int drive = (long)inode->i_bdev->bd_disk->private_data;
-       int old_dev;
+       int drive = (long)bdev->bd_disk->private_data;
+       int old_dev, new_dev;
        int try;
        int res = -EBUSY;
        char *tmp;
 
-       filp->private_data = (void *)0;
-       down(&open_lock);
+       mutex_lock(&open_lock);
        old_dev = UDRS->fd_device;
-       if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev)
+       if (opened_bdev[drive] && opened_bdev[drive] != bdev)
                goto out2;
 
        if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
@@ -3714,18 +3706,15 @@ static int floppy_open(struct inode *inode, struct file *filp)
                USETF(FD_VERIFY);
        }
 
-       if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
-               goto out2;
-
-       if (floppy_grab_irq_and_dma())
+       if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
                goto out2;
 
-       if (filp->f_flags & O_EXCL)
+       if (mode & FMODE_EXCL)
                UDRS->fd_ref = -1;
        else
                UDRS->fd_ref++;
 
-       opened_bdev[drive] = inode->i_bdev;
+       opened_bdev[drive] = bdev;
 
        res = -ENXIO;
 
@@ -3760,35 +3749,29 @@ static int floppy_open(struct inode *inode, struct file *filp)
                }
        }
 
-       UDRS->fd_device = iminor(inode);
-       set_capacity(disks[drive], floppy_sizes[iminor(inode)]);
-       if (old_dev != -1 && old_dev != iminor(inode)) {
+       new_dev = MINOR(bdev->bd_dev);
+       UDRS->fd_device = new_dev;
+       set_capacity(disks[drive], floppy_sizes[new_dev]);
+       if (old_dev != -1 && old_dev != new_dev) {
                if (buffer_drive == drive)
                        buffer_track = -1;
        }
 
-       /* Allow ioctls if we have write-permissions even if read-only open.
-        * Needed so that programs such as fdrawcmd still can work on write
-        * protected disks */
-       if (filp->f_mode & 2
-           || permission(filp->f_dentry->d_inode, 2, NULL) == 0)
-               filp->private_data = (void *)8;
-
        if (UFDCS->rawcmd == 1)
                UFDCS->rawcmd = 2;
 
-       if (!(filp->f_flags & O_NDELAY)) {
-               if (filp->f_mode & 3) {
+       if (!(mode & FMODE_NDELAY)) {
+               if (mode & (FMODE_READ|FMODE_WRITE)) {
                        UDRS->last_checked = 0;
-                       check_disk_change(inode->i_bdev);
+                       check_disk_change(bdev);
                        if (UTESTF(FD_DISK_CHANGED))
                                goto out;
                }
                res = -EROFS;
-               if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
+               if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
                        goto out;
        }
-       up(&open_lock);
+       mutex_unlock(&open_lock);
        return 0;
 out:
        if (UDRS->fd_ref < 0)
@@ -3797,9 +3780,8 @@ out:
                UDRS->fd_ref--;
        if (!UDRS->fd_ref)
                opened_bdev[drive] = NULL;
-       floppy_release_irq_and_dma();
 out2:
-       up(&open_lock);
+       mutex_unlock(&open_lock);
        return res;
 }
 
@@ -3813,15 +3795,10 @@ static int check_floppy_change(struct gendisk *disk)
        if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
                return 1;
 
-       if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
-               if (floppy_grab_irq_and_dma()) {
-                       return 1;
-               }
-
+       if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
                lock_fdc(drive, 0);
                poll_drive(0, 0);
                process_fd_request();
-               floppy_release_irq_and_dma();
        }
 
        if (UTESTF(FD_DISK_CHANGED) ||
@@ -3838,14 +3815,10 @@ static int check_floppy_change(struct gendisk *disk)
  * a disk in the drive, and whether that disk is writable.
  */
 
-static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done,
+static void floppy_rb0_complete(struct bio *bio,
                               int err)
 {
-       if (bio->bi_size)
-               return 1;
-
        complete((struct completion *)bio->bi_private);
-       return 0;
 }
 
 static int __floppy_read_block_0(struct block_device *bdev)
@@ -3934,45 +3907,15 @@ static int floppy_revalidate(struct gendisk *disk)
        return res;
 }
 
-static struct block_device_operations floppy_fops = {
-       .owner          = THIS_MODULE,
-       .open           = floppy_open,
-       .release        = floppy_release,
-       .ioctl          = fd_ioctl,
-       .media_changed  = check_floppy_change,
-       .revalidate_disk = floppy_revalidate,
-};
-static char *table[] = {
-       "", "d360", "h1200", "u360", "u720", "h360", "h720",
-       "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
-       "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
-       "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
-       "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
-       NULL
+static const struct block_device_operations floppy_fops = {
+       .owner                  = THIS_MODULE,
+       .open                   = floppy_open,
+       .release                = floppy_release,
+       .locked_ioctl           = fd_ioctl,
+       .getgeo                 = fd_getgeo,
+       .media_changed          = check_floppy_change,
+       .revalidate_disk        = floppy_revalidate,
 };
-static int t360[] = { 1, 0 },
-       t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 },
-       t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13,
-                       17, 21, 22, 30, 0 };
-static int *table_sup[] =
-    { NULL, t360, t1200, t3in + 5 + 8, t3in + 5, t3in, t3in };
-
-static void __init register_devfs_entries(int drive)
-{
-       int base_minor = (drive < 4) ? drive : (124 + drive);
-
-       if (UDP->cmos < NUMBER(default_drive_params)) {
-               int i = 0;
-               do {
-                       int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
-
-                       devfs_mk_bdev(MKDEV(FLOPPY_MAJOR, minor),
-                                     S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
-                                     S_IWGRP, "floppy/%d%s", drive,
-                                     table[table_sup[UDP->cmos][i]]);
-               } while (table_sup[UDP->cmos][i++]);
-       }
-}
 
 /*
  * Floppy Driver initialization
@@ -4187,7 +4130,7 @@ static int __init floppy_setup(char *str)
                printk("\n");
        } else
                DPRINT("botched floppy option\n");
-       DPRINT("Read Documentation/floppy.txt\n");
+       DPRINT("Read Documentation/blockdev/floppy.txt\n");
        return 0;
 }
 
@@ -4196,10 +4139,9 @@ static int have_no_fdc = -ENODEV;
 static ssize_t floppy_cmos_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct platform_device *p;
+       struct platform_device *p = to_platform_device(dev);
        int drive;
 
-       p = container_of(dev, struct platform_device,dev);
        drive = p->id;
        return sprintf(buf, "%X\n", UDP->cmos);
 }
@@ -4207,9 +4149,31 @@ DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
 
 static void floppy_device_release(struct device *dev)
 {
-       complete(&device_release);
 }
 
+static int floppy_resume(struct device *dev)
+{
+       int fdc;
+
+       for (fdc = 0; fdc < N_FDC; fdc++)
+               if (FDCS->address != -1)
+                       user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
+
+       return 0;
+}
+
+static struct dev_pm_ops floppy_pm_ops = {
+       .resume = floppy_resume,
+       .restore = floppy_resume,
+};
+
+static struct platform_driver floppy_driver = {
+       .driver = {
+               .name = "floppy",
+               .pm = &floppy_pm_ops,
+       },
+};
+
 static struct platform_device floppy_device[N_DRIVE];
 
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
@@ -4219,7 +4183,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
            !(allowed_drive_mask & (1 << drive)) ||
            fdc_state[FDC(drive)].version == FDC_NONE)
                return NULL;
-       if (((*part >> 2) & 0x1f) >= NUMBER(floppy_type))
+       if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
                return NULL;
        *part = 0;
        return get_disk(disks[drive]);
@@ -4230,6 +4194,11 @@ static int __init floppy_init(void)
        int i, unit, drive;
        int err, dr;
 
+#if defined(CONFIG_PPC)
+       if (check_legacy_ioport(FDC1))
+               return -ENODEV;
+#endif
+
        raw_cmd = NULL;
 
        for (dr = 0; dr < N_DRIVE; dr++) {
@@ -4249,16 +4218,18 @@ static int __init floppy_init(void)
                motor_off_timer[dr].function = motor_off_callback;
        }
 
-       devfs_mk_dir("floppy");
-
        err = register_blkdev(FLOPPY_MAJOR, "fd");
        if (err)
-               goto out_devfs_remove;
+               goto out_put_disk;
+
+       err = platform_driver_register(&floppy_driver);
+       if (err)
+               goto out_unreg_blkdev;
 
        floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
        if (!floppy_queue) {
                err = -ENOMEM;
-               goto out_unreg_blkdev;
+               goto out_unreg_driver;
        }
        blk_queue_max_sectors(floppy_queue, 64);
 
@@ -4289,13 +4260,6 @@ static int __init floppy_init(void)
        }
 
        use_virtual_dma = can_use_virtual_dma & 1;
-#if defined(CONFIG_PPC64)
-       if (check_legacy_ioport(FDC1)) {
-               del_timer(&fd_timeout);
-               err = -ENODEV;
-               goto out_unreg_region;
-       }
-#endif
        fdc_state[0].address = FDC1;
        if (fdc_state[0].address == -1) {
                del_timer(&fd_timeout);
@@ -4342,8 +4306,7 @@ static int __init floppy_init(void)
                FDCS->rawcmd = 2;
                if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
+                       floppy_release_regions(fdc);
                        FDCS->address = -1;
                        FDCS->version = FDC_NONE;
                        continue;
@@ -4352,8 +4315,7 @@ static int __init floppy_init(void)
                FDCS->version = get_fdc_version();
                if (FDCS->version == FDC_NONE) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
+                       floppy_release_regions(fdc);
                        FDCS->address = -1;
                        continue;
                }
@@ -4370,7 +4332,6 @@ static int __init floppy_init(void)
        fdc = 0;
        del_timer(&fd_timeout);
        current_drive = 0;
-       floppy_release_irq_and_dma();
        initialising = 0;
        if (have_no_fdc) {
                DPRINT("no floppy controllers found\n");
@@ -4392,7 +4353,10 @@ static int __init floppy_init(void)
                if (err)
                        goto out_flush_work;
 
-               device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+               err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+               if (err)
+                       goto out_unreg_platform_dev;
+
                /* to be cleaned up... */
                disks[drive]->private_data = (void *)(long)drive;
                disks[drive]->queue = floppy_queue;
@@ -4403,6 +4367,8 @@ static int __init floppy_init(void)
 
        return 0;
 
+out_unreg_platform_dev:
+       platform_device_unregister(&floppy_device[drive]);
 out_flush_work:
        flush_scheduled_work();
        if (usage_count)
@@ -4410,10 +4376,10 @@ out_flush_work:
 out_unreg_region:
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        blk_cleanup_queue(floppy_queue);
+out_unreg_driver:
+       platform_driver_unregister(&floppy_driver);
 out_unreg_blkdev:
        unregister_blkdev(FLOPPY_MAJOR, "fd");
-out_devfs_remove:
-       devfs_remove("floppy");
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
@@ -4424,6 +4390,47 @@ out_put_disk:
 
 static DEFINE_SPINLOCK(floppy_usage_lock);
 
+static const struct io_region {
+       int offset;
+       int size;
+} io_regions[] = {
+       { 2, 1 },
+       /* address + 3 is sometimes reserved by pnp bios for motherboard */
+       { 4, 2 },
+       /* address + 6 is reserved, and may be taken by IDE.
+        * Unfortunately, Adaptec doesn't know this :-(, */
+       { 7, 1 },
+};
+
+static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
+{
+       while (p != io_regions) {
+               p--;
+               release_region(FDCS->address + p->offset, p->size);
+       }
+}
+
+#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
+
+static int floppy_request_regions(int fdc)
+{
+       const struct io_region *p;
+
+       for (p = io_regions; p < ARRAY_END(io_regions); p++) {
+               if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
+                       DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
+                       floppy_release_allocated_regions(fdc, p);
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+static void floppy_release_regions(int fdc)
+{
+       floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
+}
+
 static int floppy_grab_irq_and_dma(void)
 {
        unsigned long flags;
@@ -4434,6 +4441,13 @@ static int floppy_grab_irq_and_dma(void)
                return 0;
        }
        spin_unlock_irqrestore(&floppy_usage_lock, flags);
+
+       /*
+        * We might have scheduled a free_irq(), wait it to
+        * drain first:
+        */
+       flush_scheduled_work();
+
        if (fd_request_irq()) {
                DPRINT("Unable to grab IRQ%d for the floppy driver\n",
                       FLOPPY_IRQ);
@@ -4445,27 +4459,21 @@ static int floppy_grab_irq_and_dma(void)
        if (fd_request_dma()) {
                DPRINT("Unable to grab DMA%d for the floppy driver\n",
                       FLOPPY_DMA);
-               fd_free_irq();
-               spin_lock_irqsave(&floppy_usage_lock, flags);
-               usage_count--;
-               spin_unlock_irqrestore(&floppy_usage_lock, flags);
-               return -1;
+               if (can_use_virtual_dma & 2)
+                       use_virtual_dma = can_use_virtual_dma = 1;
+               if (!(can_use_virtual_dma & 1)) {
+                       fd_free_irq();
+                       spin_lock_irqsave(&floppy_usage_lock, flags);
+                       usage_count--;
+                       spin_unlock_irqrestore(&floppy_usage_lock, flags);
+                       return -1;
+               }
        }
 
        for (fdc = 0; fdc < N_FDC; fdc++) {
                if (FDCS->address != -1) {
-                       if (!request_region(FDCS->address + 2, 4, "floppy")) {
-                               DPRINT("Floppy io-port 0x%04lx in use\n",
-                                      FDCS->address + 2);
-                               goto cleanup1;
-                       }
-                       if (!request_region(FDCS->address + 7, 1, "floppy DIR")) {
-                               DPRINT("Floppy io-port 0x%04lx in use\n",
-                                      FDCS->address + 7);
-                               goto cleanup2;
-                       }
-                       /* address + 6 is reserved, and may be taken by IDE.
-                        * Unfortunately, Adaptec doesn't know this :-(, */
+                       if (floppy_request_regions(fdc))
+                               goto cleanup;
                }
        }
        for (fdc = 0; fdc < N_FDC; fdc++) {
@@ -4481,21 +4489,17 @@ static int floppy_grab_irq_and_dma(void)
                if (FDCS->address != -1)
                        fd_outb(FDCS->dor, FD_DOR);
        /*
-        *      The driver will try and free resources and relies on us
-        *      to know if they were allocated or not.
+        * The driver will try and free resources and relies on us
+        * to know if they were allocated or not.
         */
        fdc = 0;
        irqdma_allocated = 1;
        return 0;
-cleanup2:
-       release_region(FDCS->address + 2, 4);
-cleanup1:
+cleanup:
        fd_free_irq();
        fd_free_dma();
-       while (--fdc >= 0) {
-               release_region(FDCS->address + 2, 4);
-               release_region(FDCS->address + 7, 1);
-       }
+       while (--fdc >= 0)
+               floppy_release_regions(fdc);
        spin_lock_irqsave(&floppy_usage_lock, flags);
        usage_count--;
        spin_unlock_irqrestore(&floppy_usage_lock, flags);
@@ -4551,15 +4555,13 @@ static void floppy_release_irq_and_dma(void)
                printk("floppy timer still active:%s\n", timeout_message);
        if (timer_pending(&fd_timer))
                printk("auxiliary floppy timer still active\n");
-       if (floppy_work.pending)
+       if (work_pending(&floppy_work))
                printk("work still pending\n");
 #endif
        old_fdc = fdc;
        for (fdc = 0; fdc < N_FDC; fdc++)
-               if (FDCS->address != -1) {
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
-               }
+               if (FDCS->address != -1)
+                       floppy_release_regions(fdc);
        fdc = old_fdc;
 }
 
@@ -4567,19 +4569,6 @@ static void floppy_release_irq_and_dma(void)
 
 static char *floppy;
 
-static void unregister_devfs_entries(int drive)
-{
-       int i;
-
-       if (UDP->cmos < NUMBER(default_drive_params)) {
-               i = 0;
-               do {
-                       devfs_remove("floppy/%d%s", drive,
-                                    table[table_sup[UDP->cmos][i]]);
-               } while (table_sup[UDP->cmos][i++]);
-       }
-}
-
 static void __init parse_floppy_cfg_string(char *cfg)
 {
        char *ptr;
@@ -4595,20 +4584,21 @@ static void __init parse_floppy_cfg_string(char *cfg)
        }
 }
 
-int init_module(void)
+static int __init floppy_module_init(void)
 {
        if (floppy)
                parse_floppy_cfg_string(floppy);
        return floppy_init();
 }
+module_init(floppy_module_init);
 
-void cleanup_module(void)
+static void __exit floppy_module_exit(void)
 {
        int drive;
 
-       init_completion(&device_release);
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        unregister_blkdev(FLOPPY_MAJOR, "fd");
+       platform_driver_unregister(&floppy_driver);
 
        for (drive = 0; drive < N_DRIVE; drive++) {
                del_timer_sync(&motor_off_timer[drive]);
@@ -4616,13 +4606,11 @@ void cleanup_module(void)
                if ((allowed_drive_mask & (1 << drive)) &&
                    fdc_state[FDC(drive)].version != FDC_NONE) {
                        del_gendisk(disks[drive]);
-                       unregister_devfs_entries(drive);
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
                put_disk(disks[drive]);
        }
-       devfs_remove("floppy");
 
        del_timer_sync(&fd_timeout);
        del_timer_sync(&fd_timer);
@@ -4633,9 +4621,8 @@ void cleanup_module(void)
 
        /* eject disk, if any */
        fd_eject(0);
-
-       wait_for_completion(&device_release);
 }
+module_exit(floppy_module_exit);
 
 module_param(floppy, charp, 0);
 module_param(FLOPPY_IRQ, int, 0);
@@ -4644,6 +4631,13 @@ MODULE_AUTHOR("Alain L. Knaff");
 MODULE_SUPPORTED_DEVICE("fd");
 MODULE_LICENSE("GPL");
 
+/* This doesn't actually get used other than for module information */
+static const struct pnp_device_id floppy_pnpids[] = {
+       { "PNP0700", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
+
 #else
 
 __setup("floppy=", floppy_setup);