Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
[safe/jmp/linux-2.6] / drivers / block / swim3.c
index 5b09cf1..59ca2b7 100644 (file)
@@ -16,7 +16,6 @@
  * handle GCR disks
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -25,9 +24,9 @@
 #include <linux/fd.h>
 #include <linux/ioctl.h>
 #include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/prom.h>
@@ -176,6 +175,7 @@ struct swim3 {
 
 struct floppy_state {
        enum swim_state state;
+       spinlock_t lock;
        struct swim3 __iomem *swim3;    /* hardware registers */
        struct dbdma_regs __iomem *dma; /* DMA controller registers */
        int     swim3_intr;     /* interrupt number for SWIM3 */
@@ -200,7 +200,7 @@ struct floppy_state {
        int     ejected;
        wait_queue_head_t wait;
        int     wanted;
-       struct device_node*     media_bay; /* NULL when not in bay */
+       struct macio_dev *mdev;
        char    dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
 };
 
@@ -225,7 +225,7 @@ static unsigned short write_postamble[] = {
 static void swim3_select(struct floppy_state *fs, int sel);
 static void swim3_action(struct floppy_state *fs, int action);
 static int swim3_readbit(struct floppy_state *fs, int bit);
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
 static void start_request(struct floppy_state *fs);
 static void set_timeout(struct floppy_state *fs, int nticks,
                        void (*proc)(unsigned long));
@@ -238,24 +238,32 @@ static void scan_timeout(unsigned long data);
 static void seek_timeout(unsigned long data);
 static void settle_timeout(unsigned long data);
 static void xfer_timeout(unsigned long data);
-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
+static irqreturn_t swim3_interrupt(int irq, void *dev_id);
+/*static void fd_dma_interrupt(int irq, void *dev_id);*/
 static int grab_drive(struct floppy_state *fs, enum swim_state state,
                      int interruptible);
 static void release_drive(struct floppy_state *fs);
 static int fd_eject(struct floppy_state *fs);
-static int floppy_ioctl(struct inode *inode, struct file *filp,
+static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long param);
-static int floppy_open(struct inode *inode, struct file *filp);
-static int floppy_release(struct inode *inode, struct file *filp);
+static int floppy_open(struct block_device *bdev, fmode_t mode);
+static int floppy_release(struct gendisk *disk, fmode_t mode);
 static int floppy_check_change(struct gendisk *disk);
 static int floppy_revalidate(struct gendisk *disk);
-static int swim3_add_device(struct device_node *swims);
-int swim3_init(void);
 
-#ifndef CONFIG_PMAC_PBOOK
-#define check_media_bay(which, what)   1
-#endif
+static bool swim3_end_request(int err, unsigned int nr_bytes)
+{
+       if (__blk_end_request(fd_req, err, nr_bytes))
+               return true;
+
+       fd_req = NULL;
+       return false;
+}
+
+static bool swim3_end_request_cur(int err)
+{
+       return swim3_end_request(err, blk_rq_cur_bytes(fd_req));
+}
 
 static void swim3_select(struct floppy_state *fs, int sel)
 {
@@ -292,17 +300,17 @@ static int swim3_readbit(struct floppy_state *fs, int bit)
        return (stat & DATA) == 0;
 }
 
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
 {
        int i;
-       for(i=0;i<floppy_count;i++)
-       {
-               if (floppy_states[i].media_bay &&
-                       check_media_bay(floppy_states[i].media_bay, MB_FD))
+
+       for(i=0; i<floppy_count; i++) {
+               struct floppy_state *fs = &floppy_states[i];
+               if (fs->mdev->media_bay &&
+                   check_media_bay(fs->mdev->media_bay) != MB_FD)
                        continue;
-               start_request(&floppy_states[i]);
+               start_request(fs);
        }
-       sti();
 }
 
 static void start_request(struct floppy_state *fs)
@@ -315,25 +323,27 @@ static void start_request(struct floppy_state *fs)
                wake_up(&fs->wait);
                return;
        }
-       while (fs->state == idle && (req = elv_next_request(swim3_queue))) {
+       while (fs->state == idle) {
+               if (!fd_req) {
+                       fd_req = blk_fetch_request(swim3_queue);
+                       if (!fd_req)
+                               break;
+               }
+               req = fd_req;
 #if 0
-               printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+               printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
                       req->rq_disk->disk_name, req->cmd,
-                      (long)req->sector, req->nr_sectors, req->buffer);
-               printk("           rq_status=%d errors=%d current_nr_sectors=%ld\n",
-                      req->rq_status, req->errors, req->current_nr_sectors);
+                      (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
+               printk("           errors=%d current_nr_sectors=%u\n",
+                      req->errors, blk_rq_cur_sectors(req));
 #endif
 
-               if (req->sector < 0 || req->sector >= fs->total_secs) {
-                       end_request(req, 0);
-                       continue;
-               }
-               if (req->current_nr_sectors == 0) {
-                       end_request(req, 1);
+               if (blk_rq_pos(req) >= fs->total_secs) {
+                       swim3_end_request_cur(-EIO);
                        continue;
                }
                if (fs->ejected) {
-                       end_request(req, 0);
+                       swim3_end_request_cur(-EIO);
                        continue;
                }
 
@@ -341,18 +351,19 @@ static void start_request(struct floppy_state *fs)
                        if (fs->write_prot < 0)
                                fs->write_prot = swim3_readbit(fs, WRITE_PROT);
                        if (fs->write_prot) {
-                               end_request(req, 0);
+                               swim3_end_request_cur(-EIO);
                                continue;
                        }
                }
 
-               /* Do not remove the cast. req->sector is now a sector_t and
-                * can be 64 bits, but it will never go past 32 bits for this
-                * driver anyway, so we can safely cast it down and not have
-                * to do a 64/32 division
+               /* Do not remove the cast. blk_rq_pos(req) is now a
+                * sector_t and can be 64 bits, but it will never go
+                * past 32 bits for this driver anyway, so we can
+                * safely cast it down and not have to do a 64/32
+                * division
                 */
-               fs->req_cyl = ((long)req->sector) / fs->secpercyl;
-               x = ((long)req->sector) % fs->secpercyl;
+               fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
+               x = ((long)blk_rq_pos(req)) % fs->secpercyl;
                fs->head = x / fs->secpertrack;
                fs->req_sector = x % fs->secpertrack + 1;
                fd_req = req;
@@ -368,7 +379,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&fs->lock, flags);
        if (fs->timeout_pending)
                del_timer(&fs->timeout);
        fs->timeout.expires = jiffies + nticks;
@@ -376,7 +387,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
        fs->timeout.data = (unsigned long) fs;
        add_timer(&fs->timeout);
        fs->timeout_pending = 1;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
 }
 
 static inline void scan_track(struct floppy_state *fs)
@@ -429,7 +440,7 @@ static inline void setup_transfer(struct floppy_state *fs)
        struct dbdma_cmd *cp = fs->dma_cmd;
        struct dbdma_regs __iomem *dr = fs->dma;
 
-       if (fd_req->current_nr_sectors <= 0) {
+       if (blk_rq_cur_sectors(fd_req) <= 0) {
                printk(KERN_ERR "swim3: transfer 0 sectors?\n");
                return;
        }
@@ -437,8 +448,8 @@ static inline void setup_transfer(struct floppy_state *fs)
                n = 1;
        else {
                n = fs->secpertrack - fs->req_sector + 1;
-               if (n > fd_req->current_nr_sectors)
-                       n = fd_req->current_nr_sectors;
+               if (n > blk_rq_cur_sectors(fd_req))
+                       n = blk_rq_cur_sectors(fd_req);
        }
        fs->scount = n;
        swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
@@ -513,7 +524,7 @@ static void act(struct floppy_state *fs)
                case do_transfer:
                        if (fs->cur_cyl != fs->req_cyl) {
                                if (fs->retries > 5) {
-                                       end_request(fd_req, 0);
+                                       swim3_end_request_cur(-EIO);
                                        fs->state = idle;
                                        return;
                                }
@@ -545,7 +556,7 @@ static void scan_timeout(unsigned long data)
        out_8(&sw->intr_enable, 0);
        fs->cur_cyl = -1;
        if (fs->retries > 5) {
-               end_request(fd_req, 0);
+               swim3_end_request_cur(-EIO);
                fs->state = idle;
                start_request(fs);
        } else {
@@ -564,7 +575,7 @@ static void seek_timeout(unsigned long data)
        out_8(&sw->select, RELAX);
        out_8(&sw->intr_enable, 0);
        printk(KERN_ERR "swim3: seek timeout\n");
-       end_request(fd_req, 0);
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
@@ -588,7 +599,7 @@ static void settle_timeout(unsigned long data)
                return;
        }
        printk(KERN_ERR "swim3: seek settle timeout\n");
-       end_request(fd_req, 0);
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
@@ -598,8 +609,6 @@ static void xfer_timeout(unsigned long data)
        struct floppy_state *fs = (struct floppy_state *) data;
        struct swim3 __iomem *sw = fs->swim3;
        struct dbdma_regs __iomem *dr = fs->dma;
-       struct dbdma_cmd *cp = fs->dma_cmd;
-       unsigned long s;
        int n;
 
        fs->timeout_pending = 0;
@@ -610,22 +619,15 @@ static void xfer_timeout(unsigned long data)
        out_8(&sw->intr_enable, 0);
        out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
        out_8(&sw->select, RELAX);
-       if (rq_data_dir(fd_req) == WRITE)
-               ++cp;
-       if (ld_le16(&cp->xfer_status) != 0)
-               s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
-       else
-               s = 0;
-       fd_req->sector += s;
-       fd_req->current_nr_sectors -= s;
        printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
-              (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector);
-       end_request(fd_req, 0);
+              (rq_data_dir(fd_req)==WRITE? "writ": "read"),
+              (long)blk_rq_pos(fd_req));
+       swim3_end_request_cur(-EIO);
        fs->state = idle;
        start_request(fs);
 }
 
-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swim3_interrupt(int irq, void *dev_id)
 {
        struct floppy_state *fs = (struct floppy_state *) dev_id;
        struct swim3 __iomem *sw = fs->swim3;
@@ -637,7 +639,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        intr = in_8(&sw->intr);
        err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
        if ((intr & ERROR_INTR) && fs->state != do_transfer)
-               printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
+               printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n",
                       fs->state, rq_data_dir(fd_req), intr, err);
        switch (fs->state) {
        case locating:
@@ -651,7 +653,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
                                fs->cur_cyl = -1;
                                if (fs->retries > 5) {
-                                       end_request(fd_req, 0);
+                                       swim3_end_request_cur(-EIO);
                                        fs->state = idle;
                                        start_request(fs);
                                } else {
@@ -724,9 +726,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (intr & ERROR_INTR) {
                        n = fs->scount - 1 - resid / 512;
                        if (n > 0) {
-                               fd_req->sector += n;
-                               fd_req->current_nr_sectors -= n;
-                               fd_req->buffer += n * 512;
+                               blk_update_request(fd_req, 0, n << 9);
                                fs->req_sector += n;
                        }
                        if (fs->retries < 5) {
@@ -735,28 +735,22 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        } else {
                                printk("swim3: error %sing block %ld (err=%x)\n",
                                       rq_data_dir(fd_req) == WRITE? "writ": "read",
-                                      (long)fd_req->sector, err);
-                               end_request(fd_req, 0);
+                                      (long)blk_rq_pos(fd_req), err);
+                               swim3_end_request_cur(-EIO);
                                fs->state = idle;
                        }
                } else {
                        if ((stat & ACTIVE) == 0 || resid != 0) {
                                /* musta been an error */
                                printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
-                               printk(KERN_ERR "  state=%d, dir=%lx, intr=%x, err=%x\n",
+                               printk(KERN_ERR "  state=%d, dir=%x, intr=%x, err=%x\n",
                                       fs->state, rq_data_dir(fd_req), intr, err);
-                               end_request(fd_req, 0);
+                               swim3_end_request_cur(-EIO);
                                fs->state = idle;
                                start_request(fs);
                                break;
                        }
-                       fd_req->sector += fs->scount;
-                       fd_req->current_nr_sectors -= fs->scount;
-                       fd_req->buffer += fs->scount * 512;
-                       if (fd_req->current_nr_sectors <= 0) {
-                               end_request(fd_req, 1);
-                               fs->state = idle;
-                       } else {
+                       if (swim3_end_request(0, fs->scount << 9)) {
                                fs->req_sector += fs->scount;
                                if (fs->req_sector > fs->secpertrack) {
                                        fs->req_sector -= fs->secpertrack;
@@ -766,7 +760,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                        }
                                }
                                act(fs);
-                       }
+                       } else
+                               fs->state = idle;
                }
                if (fs->state == idle)
                        start_request(fs);
@@ -778,7 +773,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 /*
-static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void fd_dma_interrupt(int irq, void *dev_id)
 {
 }
 */
@@ -788,14 +783,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fs->lock, flags);
        if (fs->state != idle) {
                ++fs->wanted;
                while (fs->state != available) {
                        if (interruptible && signal_pending(current)) {
                                --fs->wanted;
-                               restore_flags(flags);
+                               spin_unlock_irqrestore(&fs->lock, flags);
                                return -EINTR;
                        }
                        interruptible_sleep_on(&fs->wait);
@@ -803,7 +797,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
                --fs->wanted;
        }
        fs->state = state;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
        return 0;
 }
 
@@ -811,11 +805,10 @@ static void release_drive(struct floppy_state *fs)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fs->lock, flags);
        fs->state = idle;
        start_request(fs);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
 }
 
 static int fd_eject(struct floppy_state *fs)
@@ -832,8 +825,7 @@ static int fd_eject(struct floppy_state *fs)
                        break;
                }
                swim3_select(fs, RELAX);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
+               schedule_timeout_interruptible(1);
                if (swim3_readbit(fs, DISK_IN) == 0)
                        break;
        }
@@ -847,16 +839,17 @@ static int fd_eject(struct floppy_state *fs)
 static struct floppy_struct floppy_type =
        { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };    /*  7 1.44MB 3.5"   */
 
-static int floppy_ioctl(struct inode *inode, struct file *filp,
+static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long param)
 {
-       struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+       struct floppy_state *fs = bdev->bd_disk->private_data;
        int err;
                
        if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
+       if (fs->mdev->media_bay &&
+           check_media_bay(fs->mdev->media_bay) != MB_FD)
                return -ENXIO;
 
        switch (cmd) {
@@ -874,14 +867,15 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
        return -ENOTTY;
 }
 
-static int floppy_open(struct inode *inode, struct file *filp)
+static int floppy_open(struct block_device *bdev, fmode_t mode)
 {
-       struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+       struct floppy_state *fs = bdev->bd_disk->private_data;
        struct swim3 __iomem *sw = fs->swim3;
        int n, err = 0;
 
        if (fs->ref_count == 0) {
-               if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
+               if (fs->mdev->media_bay &&
+                   check_media_bay(fs->mdev->media_bay) != MB_FD)
                        return -ENXIO;
                out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
                out_8(&sw->control_bic, 0xff);
@@ -900,8 +894,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
                                break;
                        }
                        swim3_select(fs, RELAX);
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(1);
+                       schedule_timeout_interruptible(1);
                }
                if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
                                 || swim3_readbit(fs, DISK_IN) == 0))
@@ -909,17 +902,17 @@ static int floppy_open(struct inode *inode, struct file *filp)
                swim3_action(fs, SETMFM);
                swim3_select(fs, RELAX);
 
-       } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+       } else if (fs->ref_count == -1 || mode & FMODE_EXCL)
                return -EBUSY;
 
-       if (err == 0 && (filp->f_flags & O_NDELAY) == 0
-           && (filp->f_mode & 3)) {
-               check_disk_change(inode->i_bdev);
+       if (err == 0 && (mode & FMODE_NDELAY) == 0
+           && (mode & (FMODE_READ|FMODE_WRITE))) {
+               check_disk_change(bdev);
                if (fs->ejected)
                        err = -ENXIO;
        }
 
-       if (err == 0 && (filp->f_mode & 2)) {
+       if (err == 0 && (mode & FMODE_WRITE)) {
                if (fs->write_prot < 0)
                        fs->write_prot = swim3_readbit(fs, WRITE_PROT);
                if (fs->write_prot)
@@ -935,7 +928,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
                return err;
        }
 
-       if (filp->f_flags & O_EXCL)
+       if (mode & FMODE_EXCL)
                fs->ref_count = -1;
        else
                ++fs->ref_count;
@@ -943,9 +936,9 @@ static int floppy_open(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int floppy_release(struct inode *inode, struct file *filp)
+static int floppy_release(struct gendisk *disk, fmode_t mode)
 {
-       struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
+       struct floppy_state *fs = disk->private_data;
        struct swim3 __iomem *sw = fs->swim3;
        if (fs->ref_count > 0 && --fs->ref_count == 0) {
                swim3_action(fs, MOTOR_OFF);
@@ -967,7 +960,8 @@ static int floppy_revalidate(struct gendisk *disk)
        struct swim3 __iomem *sw;
        int ret, n;
 
-       if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
+       if (fs->mdev->media_bay &&
+           check_media_bay(fs->mdev->media_bay) != MB_FD)
                return -ENXIO;
 
        sw = fs->swim3;
@@ -984,8 +978,7 @@ static int floppy_revalidate(struct gendisk *disk)
                if (signal_pending(current))
                        break;
                swim3_select(fs, RELAX);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
+               schedule_timeout_interruptible(1);
        }
        ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
                || swim3_readbit(fs, DISK_IN) == 0;
@@ -1001,122 +994,74 @@ static int floppy_revalidate(struct gendisk *disk)
        return ret;
 }
 
-static struct block_device_operations floppy_fops = {
+static const struct block_device_operations floppy_fops = {
        .open           = floppy_open,
        .release        = floppy_release,
-       .ioctl          = floppy_ioctl,
+       .locked_ioctl   = floppy_ioctl,
        .media_changed  = floppy_check_change,
        .revalidate_disk= floppy_revalidate,
 };
 
-int swim3_init(void)
+static int swim3_add_device(struct macio_dev *mdev, int index)
 {
-       struct device_node *swim;
-       int err = -ENOMEM;
-       int i;
-
-       devfs_mk_dir("floppy");
-
-       swim = find_devices("floppy");
-       while (swim && (floppy_count < MAX_FLOPPIES))
-       {
-               swim3_add_device(swim);
-               swim = swim->next;
-       }
-
-       swim = find_devices("swim3");
-       while (swim && (floppy_count < MAX_FLOPPIES))
-       {
-               swim3_add_device(swim);
-               swim = swim->next;
-       }
-
-       if (!floppy_count)
-               return -ENODEV;
-
-       for (i = 0; i < floppy_count; i++) {
-               disks[i] = alloc_disk(1);
-               if (!disks[i])
-                       goto out;
-       }
-
-       if (register_blkdev(FLOPPY_MAJOR, "fd")) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       swim3_queue = blk_init_queue(do_fd_request, &swim3_lock);
-       if (!swim3_queue) {
-               err = -ENOMEM;
-               goto out_queue;
+       struct device_node *swim = mdev->ofdev.node;
+       struct floppy_state *fs = &floppy_states[index];
+       int rc = -EBUSY;
+
+       /* Check & Request resources */
+       if (macio_resource_count(mdev) < 2) {
+               printk(KERN_WARNING "ifd%d: no address for %s\n",
+                      index, swim->full_name);
+               return -ENXIO;
        }
-
-       for (i = 0; i < floppy_count; i++) {
-               struct gendisk *disk = disks[i];
-               disk->major = FLOPPY_MAJOR;
-               disk->first_minor = i;
-               disk->fops = &floppy_fops;
-               disk->private_data = &floppy_states[i];
-               disk->queue = swim3_queue;
-               disk->flags |= GENHD_FL_REMOVABLE;
-               sprintf(disk->disk_name, "fd%d", i);
-               sprintf(disk->devfs_name, "floppy/%d", i);
-               set_capacity(disk, 2880);
-               add_disk(disk);
+       if (macio_irq_count(mdev) < 2) {
+               printk(KERN_WARNING "fd%d: no intrs for device %s\n",
+                       index, swim->full_name);
        }
-       return 0;
-
-out_queue:
-       unregister_blkdev(FLOPPY_MAJOR, "fd");
-out:
-       while (i--)
-               put_disk(disks[i]);
-       /* shouldn't we do something with results of swim_add_device()? */
-       return err;
-}
-
-static int swim3_add_device(struct device_node *swim)
-{
-       struct device_node *mediabay;
-       struct floppy_state *fs = &floppy_states[floppy_count];
-
-       if (swim->n_addrs < 2)
-       {
-               printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
-                      swim->n_addrs, swim->n_intrs);
-               return -EINVAL;
-       }
-
-       if (swim->n_intrs < 2)
-       {
-               printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
-                      swim->n_addrs, swim->n_intrs);
-               return -EINVAL;
+       if (macio_request_resource(mdev, 0, "swim3 (mmio)")) {
+               printk(KERN_ERR "fd%d: can't request mmio resource for %s\n",
+                      index, swim->full_name);
+               return -EBUSY;
        }
-
-       if (!request_OF_resource(swim, 0, NULL)) {
-               printk(KERN_INFO "swim3: can't request IO resource !\n");
-               return -EINVAL;
+       if (macio_request_resource(mdev, 1, "swim3 (dma)")) {
+               printk(KERN_ERR "fd%d: can't request dma resource for %s\n",
+                      index, swim->full_name);
+               macio_release_resource(mdev, 0);
+               return -EBUSY;
        }
+       dev_set_drvdata(&mdev->ofdev.dev, fs);
 
-       mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL;
-       if (mediabay == NULL)
+       if (mdev->media_bay == NULL)
                pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
        
        memset(fs, 0, sizeof(*fs));
+       spin_lock_init(&fs->lock);
        fs->state = idle;
        fs->swim3 = (struct swim3 __iomem *)
-               ioremap(swim->addrs[0].address, 0x200);
+               ioremap(macio_resource_start(mdev, 0), 0x200);
+       if (fs->swim3 == NULL) {
+               printk("fd%d: couldn't map registers for %s\n",
+                      index, swim->full_name);
+               rc = -ENOMEM;
+               goto out_release;
+       }
        fs->dma = (struct dbdma_regs __iomem *)
-               ioremap(swim->addrs[1].address, 0x200);
-       fs->swim3_intr = swim->intrs[0].line;
-       fs->dma_intr = swim->intrs[1].line;
+               ioremap(macio_resource_start(mdev, 1), 0x200);
+       if (fs->dma == NULL) {
+               printk("fd%d: couldn't map DMA for %s\n",
+                      index, swim->full_name);
+               iounmap(fs->swim3);
+               rc = -ENOMEM;
+               goto out_release;
+       }
+       fs->swim3_intr = macio_irq(mdev, 0);
+       fs->dma_intr = macio_irq(mdev, 1);
        fs->cur_cyl = -1;
        fs->cur_sector = -1;
        fs->secpercyl = 36;
        fs->secpertrack = 18;
        fs->total_secs = 2880;
-       fs->media_bay = mediabay;
+       fs->mdev = mdev;
        init_waitqueue_head(&fs->wait);
 
        fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
@@ -1124,15 +1069,16 @@ static int swim3_add_device(struct device_node *swim)
        st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
 
        if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
-               printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+               printk(KERN_ERR "fd%d: couldn't request irq %d for %s\n",
+                      index, fs->swim3_intr, swim->full_name);
                pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
+               goto out_unmap;
                return -EBUSY;
        }
 /*
        if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
                printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
                       fs->dma_intr);
-               pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
                return -EBUSY;
        }
 */
@@ -1140,10 +1086,92 @@ static int swim3_add_device(struct device_node *swim)
        init_timer(&fs->timeout);
 
        printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
-               mediabay ? "in media bay" : "");
+               mdev->media_bay ? "in media bay" : "");
 
-       floppy_count++;
-       
+       return 0;
+
+ out_unmap:
+       iounmap(fs->dma);
+       iounmap(fs->swim3);
+
+ out_release:
+       macio_release_resource(mdev, 0);
+       macio_release_resource(mdev, 1);
+
+       return rc;
+}
+
+static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+       int i, rc;
+       struct gendisk *disk;
+
+       /* Add the drive */
+       rc = swim3_add_device(mdev, floppy_count);
+       if (rc)
+               return rc;
+
+       /* Now create the queue if not there yet */
+       if (swim3_queue == NULL) {
+               /* If we failed, there isn't much we can do as the driver is still
+                * too dumb to remove the device, just bail out
+                */
+               if (register_blkdev(FLOPPY_MAJOR, "fd"))
+                       return 0;
+               swim3_queue = blk_init_queue(do_fd_request, &swim3_lock);
+               if (swim3_queue == NULL) {
+                       unregister_blkdev(FLOPPY_MAJOR, "fd");
+                       return 0;
+               }
+       }
+
+       /* Now register that disk. Same comment about failure handling */
+       i = floppy_count++;
+       disk = disks[i] = alloc_disk(1);
+       if (disk == NULL)
+               return 0;
+
+       disk->major = FLOPPY_MAJOR;
+       disk->first_minor = i;
+       disk->fops = &floppy_fops;
+       disk->private_data = &floppy_states[i];
+       disk->queue = swim3_queue;
+       disk->flags |= GENHD_FL_REMOVABLE;
+       sprintf(disk->disk_name, "fd%d", i);
+       set_capacity(disk, 2880);
+       add_disk(disk);
+
+       return 0;
+}
+
+static struct of_device_id swim3_match[] =
+{
+       {
+       .name           = "swim3",
+       },
+       {
+       .compatible     = "ohare-swim3"
+       },
+       {
+       .compatible     = "swim3"
+       },
+};
+
+static struct macio_driver swim3_driver =
+{
+       .name           = "swim3",
+       .match_table    = swim3_match,
+       .probe          = swim3_attach,
+#if 0
+       .suspend        = swim3_suspend,
+       .resume         = swim3_resume,
+#endif
+};
+
+
+int swim3_init(void)
+{
+       macio_register_driver(&swim3_driver);
        return 0;
 }