Merge branch 'for-2.6.38/drivers' of git://git.kernel.dk/linux-2.6-block
[~shefty/rdma-dev.git] / drivers / block / floppy.c
index 709e69c6d0226f5c0c807cf39b22e9827f2655a7..b9ba04fc2b34eb0845cf0c724b64151e53b05c65 100644 (file)
@@ -178,7 +178,6 @@ static int print_unex = 1;
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <linux/fcntl.h>
@@ -199,6 +198,7 @@ static int print_unex = 1;
  * It's been recommended that take about 1/4 of the default speed
  * in some more extreme cases.
  */
+static DEFINE_MUTEX(floppy_mutex);
 static int slow_floppy;
 
 #include <asm/dma.h>
@@ -258,8 +258,8 @@ static int irqdma_allocated;
 #include <linux/completion.h>
 
 static struct request *current_req;
-static struct request_queue *floppy_queue;
 static void do_fd_request(struct request_queue *q);
+static int set_next_request(void);
 
 #ifndef fd_get_dma_residue
 #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -413,6 +413,7 @@ static struct gendisk *disks[N_DRIVE];
 static struct block_device *opened_bdev[N_DRIVE];
 static DEFINE_MUTEX(open_lock);
 static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
+static int fdc_queue;
 
 /*
  * This struct defines the different floppy types.
@@ -895,8 +896,8 @@ static void unlock_fdc(void)
        del_timer(&fd_timeout);
        cont = NULL;
        clear_bit(0, &fdc_busy);
-       if (current_req || blk_peek_request(floppy_queue))
-               do_fd_request(floppy_queue);
+       if (current_req || set_next_request())
+               do_fd_request(current_req->q);
        spin_unlock_irqrestore(&floppy_lock, flags);
        wake_up(&fdc_wait);
 }
@@ -2248,8 +2249,8 @@ static void floppy_end_request(struct request *req, int error)
  * logical buffer */
 static void request_done(int uptodate)
 {
-       struct request_queue *q = floppy_queue;
        struct request *req = current_req;
+       struct request_queue *q;
        unsigned long flags;
        int block;
        char msg[sizeof("request done ") + sizeof(int) * 3];
@@ -2263,6 +2264,8 @@ static void request_done(int uptodate)
                return;
        }
 
+       q = req->q;
+
        if (uptodate) {
                /* maintain values for invalidation on geometry
                 * change */
@@ -2816,6 +2819,28 @@ static int make_raw_rw_request(void)
        return 2;
 }
 
+/*
+ * Round-robin between our available drives, doing one request from each
+ */
+static int set_next_request(void)
+{
+       struct request_queue *q;
+       int old_pos = fdc_queue;
+
+       do {
+               q = disks[fdc_queue]->queue;
+               if (++fdc_queue == N_DRIVE)
+                       fdc_queue = 0;
+               if (q) {
+                       current_req = blk_fetch_request(q);
+                       if (current_req)
+                               break;
+               }
+       } while (fdc_queue != old_pos);
+
+       return current_req != NULL;
+}
+
 static void redo_fd_request(void)
 {
        int drive;
@@ -2827,17 +2852,17 @@ static void redo_fd_request(void)
 
 do_request:
        if (!current_req) {
-               struct request *req;
+               int pending;
+
+               spin_lock_irq(&floppy_lock);
+               pending = set_next_request();
+               spin_unlock_irq(&floppy_lock);
 
-               spin_lock_irq(floppy_queue->queue_lock);
-               req = blk_fetch_request(floppy_queue);
-               spin_unlock_irq(floppy_queue->queue_lock);
-               if (!req) {
+               if (!pending) {
                        do_floppy = NULL;
                        unlock_fdc();
                        return;
                }
-               current_req = req;
        }
        drive = (long)current_req->rq_disk->private_data;
        set_fdc(drive);
@@ -3558,9 +3583,9 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&floppy_mutex);
        ret = fd_locked_ioctl(bdev, mode, cmd, param);
-       unlock_kernel();
+       mutex_unlock(&floppy_mutex);
 
        return ret;
 }
@@ -3621,7 +3646,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
 {
        int drive = (long)disk->private_data;
 
-       lock_kernel();
+       mutex_lock(&floppy_mutex);
        mutex_lock(&open_lock);
        if (UDRS->fd_ref < 0)
                UDRS->fd_ref = 0;
@@ -3632,7 +3657,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
        if (!UDRS->fd_ref)
                opened_bdev[drive] = NULL;
        mutex_unlock(&open_lock);
-       unlock_kernel();
+       mutex_unlock(&floppy_mutex);
 
        return 0;
 }
@@ -3650,7 +3675,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        int res = -EBUSY;
        char *tmp;
 
-       lock_kernel();
+       mutex_lock(&floppy_mutex);
        mutex_lock(&open_lock);
        old_dev = UDRS->fd_device;
        if (opened_bdev[drive] && opened_bdev[drive] != bdev)
@@ -3727,7 +3752,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
                        goto out;
        }
        mutex_unlock(&open_lock);
-       unlock_kernel();
+       mutex_unlock(&floppy_mutex);
        return 0;
 out:
        if (UDRS->fd_ref < 0)
@@ -3738,7 +3763,7 @@ out:
                opened_bdev[drive] = NULL;
 out2:
        mutex_unlock(&open_lock);
-       unlock_kernel();
+       mutex_unlock(&floppy_mutex);
        return res;
 }
 
@@ -4170,6 +4195,13 @@ static int __init floppy_init(void)
                        goto out_put_disk;
                }
 
+               disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
+               if (!disks[dr]->queue) {
+                       err = -ENOMEM;
+                       goto out_put_disk;
+               }
+
+               blk_queue_max_hw_sectors(disks[dr]->queue, 64);
                disks[dr]->major = FLOPPY_MAJOR;
                disks[dr]->first_minor = TOMINOR(dr);
                disks[dr]->fops = &floppy_fops;
@@ -4188,13 +4220,6 @@ static int __init floppy_init(void)
        if (err)
                goto out_unreg_blkdev;
 
-       floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
-       if (!floppy_queue) {
-               err = -ENOMEM;
-               goto out_unreg_driver;
-       }
-       blk_queue_max_hw_sectors(floppy_queue, 64);
-
        blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
                            floppy_find, NULL, NULL);
 
@@ -4322,7 +4347,6 @@ static int __init floppy_init(void)
 
                /* to be cleaned up... */
                disks[drive]->private_data = (void *)(long)drive;
-               disks[drive]->queue = floppy_queue;
                disks[drive]->flags |= GENHD_FL_REMOVABLE;
                disks[drive]->driverfs_dev = &floppy_device[drive].dev;
                add_disk(disks[drive]);
@@ -4333,19 +4357,19 @@ static int __init floppy_init(void)
 out_unreg_platform_dev:
        platform_device_unregister(&floppy_device[drive]);
 out_flush_work:
-       flush_scheduled_work();
+       flush_work_sync(&floppy_work);
        if (atomic_read(&usage_count))
                floppy_release_irq_and_dma();
 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_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
+               if (disks[dr]->queue)
+                       blk_cleanup_queue(disks[dr]->queue);
                put_disk(disks[dr]);
        }
        return err;
@@ -4403,7 +4427,7 @@ static int floppy_grab_irq_and_dma(void)
         * We might have scheduled a free_irq(), wait it to
         * drain first:
         */
-       flush_scheduled_work();
+       flush_work_sync(&floppy_work);
 
        if (fd_request_irq()) {
                DPRINT("Unable to grab IRQ%d for the floppy driver\n",
@@ -4554,12 +4578,12 @@ static void __exit floppy_module_exit(void)
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
+               blk_cleanup_queue(disks[drive]->queue);
                put_disk(disks[drive]);
        }
 
        del_timer_sync(&fd_timeout);
        del_timer_sync(&fd_timer);
-       blk_cleanup_queue(floppy_queue);
 
        if (atomic_read(&usage_count))
                floppy_release_irq_and_dma();