drivers/message/i2o/i2o_config.c: use memdup_user
[linux-2.6.git] / drivers / message / i2o / i2o_config.c
index 84e046e..c4b117f 100644 (file)
  *             Added basic ioctl() support
  *     Deepak Saxena (06/07/1999):
  *             Added software download ioctl (still testing)
- *     Auvo Häkkinen (09/10/1999):
+ *     Auvo Häkkinen (09/10/1999):
  *             Changes to i2o_cfg_reply(), ioctl_parms()
  *             Added ioct_validate()
- *     Taneli Vähäkangas (09/30/1999):
+ *     Taneli Vähäkangas (09/30/1999):
  *             Fixed ioctl_swdl()
- *     Taneli Vähäkangas (10/04/1999):
+ *     Taneli Vähäkangas (10/04/1999):
  *             Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
  *     Deepak Saxena (11/18/1999):
  *             Added event managmenet support
- *     Alan Cox <alan@redhat.com>:
+ *     Alan Cox <alan@lxorguk.ukuu.org.uk>:
  *             2.4 rewrite ported to 2.5
  *     Markus Lidel <Markus.Lidel@shadowconnect.com>:
  *             Added pass-thru support for Adaptec's raidutils
@@ -33,6 +33,7 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/compat.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 
@@ -40,8 +41,7 @@
 
 #define SG_TABLESIZE           30
 
-static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
-                        unsigned long);
+static long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long);
 
 static spinlock_t i2o_config_lock;
 
@@ -186,14 +186,9 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
        if (!dev)
                return -ENXIO;
 
-       ops = kmalloc(kcmd.oplen, GFP_KERNEL);
-       if (!ops)
-               return -ENOMEM;
-
-       if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) {
-               kfree(ops);
-               return -EFAULT;
-       }
+       ops = memdup_user(kcmd.opbuf, kcmd.oplen);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
 
        /*
         * It's possible to have a _very_ large table
@@ -260,7 +255,7 @@ static int i2o_cfg_swdl(unsigned long arg)
        if (IS_ERR(msg))
                return PTR_ERR(msg);
 
-       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
                i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
@@ -314,22 +309,22 @@ static int i2o_cfg_swul(unsigned long arg)
        int ret = 0;
 
        if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-               goto return_fault;
+               return -EFAULT;
 
        if (get_user(swlen, kxfer.swlen) < 0)
-               goto return_fault;
+               return -EFAULT;
 
        if (get_user(maxfrag, kxfer.maxfrag) < 0)
-               goto return_fault;
+               return -EFAULT;
 
        if (get_user(curfrag, kxfer.curfrag) < 0)
-               goto return_fault;
+               return -EFAULT;
 
        if (curfrag == maxfrag)
                fragsize = swlen - (maxfrag - 1) * 8192;
 
        if (!kxfer.buf)
-               goto return_fault;
+               return -EFAULT;
 
        c = i2o_find_iop(kxfer.iop);
        if (!c)
@@ -339,7 +334,7 @@ static int i2o_cfg_swul(unsigned long arg)
        if (IS_ERR(msg))
                return PTR_ERR(msg);
 
-       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+       if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
                i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
@@ -373,12 +368,8 @@ static int i2o_cfg_swul(unsigned long arg)
 
        i2o_dma_free(&c->pdev->dev, &buffer);
 
-      return_ret:
        return ret;
-      return_fault:
-       ret = -EFAULT;
-       goto return_ret;
-};
+}
 
 static int i2o_cfg_swdel(unsigned long arg)
 {
@@ -634,9 +625,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
                        sg_size = sg[i].flag_count & 0xffffff;
                        p = &(sg_list[sg_index]);
                        /* Allocate memory for the transfer */
-                       if (i2o_dma_alloc
-                           (&c->pdev->dev, p, sg_size,
-                            PCI_DMA_BIDIRECTIONAL)) {
+                       if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
                                printk(KERN_DEBUG
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
@@ -753,7 +742,7 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
        lock_kernel();
        switch (cmd) {
        case I2OGETIOPS:
-               ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
+               ret = i2o_cfg_ioctl(file, cmd, arg);
                break;
        case I2OPASSTHRU32:
                ret = i2o_cfg_passthru32(file, cmd, arg);
@@ -780,12 +769,11 @@ static int i2o_cfg_passthru(unsigned long arg)
        u32 size = 0;
        u32 reply_size = 0;
        u32 rcode = 0;
-       void *sg_list[SG_TABLESIZE];
+       struct i2o_dma sg_list[SG_TABLESIZE];
        u32 sg_offset = 0;
        u32 sg_count = 0;
        int sg_index = 0;
        u32 i = 0;
-       void *p = NULL;
        i2o_status_block *sb;
        struct i2o_message *msg;
        unsigned int iop;
@@ -842,6 +830,7 @@ static int i2o_cfg_passthru(unsigned long arg)
        memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
        if (sg_offset) {
                struct sg_simple_element *sg;
+               struct i2o_dma *p;
 
                if (sg_offset * 4 >= size) {
                        rcode = -EFAULT;
@@ -871,22 +860,22 @@ static int i2o_cfg_passthru(unsigned long arg)
                                goto sg_list_cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
+                       p = &(sg_list[sg_index]);
+                       if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
                        /* Allocate memory for the transfer */
-                       p = kmalloc(sg_size, GFP_KERNEL);
-                       if (!p) {
                                printk(KERN_DEBUG
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
                                goto sg_list_cleanup;
                        }
-                       sg_list[sg_index++] = p;        // sglist indexed with input frame, not our internal frame.
+                       sg_index++;
                        /* Copy in the user's SG buffer if necessary */
                        if (sg[i].
                            flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
                                // TODO 64bit fix
                                if (copy_from_user
-                                   (p, (void __user *)sg[i].addr_bus,
+                                   (p->virt, (void __user *)sg[i].addr_bus,
                                     sg_size)) {
                                        printk(KERN_DEBUG
                                               "%s: Could not copy SG buf %d FROM user\n",
@@ -895,8 +884,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                        goto sg_list_cleanup;
                                }
                        }
-                       //TODO 64bit fix
-                       sg[i].addr_bus = virt_to_bus(p);
+                       sg[i].addr_bus = p->phys;
                }
        }
 
@@ -908,7 +896,7 @@ static int i2o_cfg_passthru(unsigned long arg)
        }
 
        if (sg_offset) {
-               u32 rmsg[128];
+               u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
                /* Copy back the Scatter Gather buffers back to user space */
                u32 j;
                // TODO 64bit fix
@@ -942,11 +930,11 @@ static int i2o_cfg_passthru(unsigned long arg)
                                sg_size = sg[j].flag_count & 0xffffff;
                                // TODO 64bit fix
                                if (copy_to_user
-                                   ((void __user *)sg[j].addr_bus, sg_list[j],
+                                   ((void __user *)sg[j].addr_bus, sg_list[j].virt,
                                     sg_size)) {
                                        printk(KERN_WARNING
                                               "%s: Could not copy %p TO user %x\n",
-                                              c->name, sg_list[j],
+                                              c->name, sg_list[j].virt,
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
                                        goto sg_list_cleanup;
@@ -973,7 +961,7 @@ sg_list_cleanup:
        }
 
        for (i = 0; i < sg_index; i++)
-               kfree(sg_list[i]);
+               i2o_dma_free(&c->pdev->dev, &sg_list[i]);
 
 cleanup:
        kfree(reply);
@@ -987,11 +975,11 @@ out:
 /*
  * IOCTL Handler
  */
-static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
-                        unsigned long arg)
+static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 {
        int ret;
 
+       lock_kernel();
        switch (cmd) {
        case I2OGETIOPS:
                ret = i2o_cfg_getiops(arg);
@@ -1047,7 +1035,7 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
                osm_debug("unknown ioctl called!\n");
                ret = -EINVAL;
        }
-
+       unlock_kernel();
        return ret;
 }
 
@@ -1061,6 +1049,7 @@ static int cfg_open(struct inode *inode, struct file *file)
        if (!tmp)
                return -ENOMEM;
 
+       lock_kernel();
        file->private_data = (void *)(i2o_cfg_info_id++);
        tmp->fp = file;
        tmp->fasync = NULL;
@@ -1074,6 +1063,7 @@ static int cfg_open(struct inode *inode, struct file *file)
        spin_lock_irqsave(&i2o_config_lock, flags);
        open_files = tmp;
        spin_unlock_irqrestore(&i2o_config_lock, flags);
+       unlock_kernel();
 
        return 0;
 }
@@ -1082,42 +1072,33 @@ static int cfg_fasync(int fd, struct file *fp, int on)
 {
        ulong id = (ulong) fp->private_data;
        struct i2o_cfg_info *p;
+       int ret = -EBADF;
 
+       lock_kernel();
        for (p = open_files; p; p = p->next)
                if (p->q_id == id)
                        break;
 
-       if (!p)
-               return -EBADF;
-
-       return fasync_helper(fd, fp, on, &p->fasync);
+       if (p)
+               ret = fasync_helper(fd, fp, on, &p->fasync);
+       unlock_kernel();
+       return ret;
 }
 
 static int cfg_release(struct inode *inode, struct file *file)
 {
        ulong id = (ulong) file->private_data;
-       struct i2o_cfg_info *p1, *p2;
+       struct i2o_cfg_info *p, **q;
        unsigned long flags;
 
        lock_kernel();
-       p1 = p2 = NULL;
-
        spin_lock_irqsave(&i2o_config_lock, flags);
-       for (p1 = open_files; p1;) {
-               if (p1->q_id == id) {
-
-                       if (p1->fasync)
-                               cfg_fasync(-1, file, 0);
-                       if (p2)
-                               p2->next = p1->next;
-                       else
-                               open_files = p1->next;
-
-                       kfree(p1);
+       for (q = &open_files; (p = *q) != NULL; q = &p->next) {
+               if (p->q_id == id) {
+                       *q = p->next;
+                       kfree(p);
                        break;
                }
-               p2 = p1;
-               p1 = p1->next;
        }
        spin_unlock_irqrestore(&i2o_config_lock, flags);
        unlock_kernel();
@@ -1128,7 +1109,7 @@ static int cfg_release(struct inode *inode, struct file *file)
 static const struct file_operations config_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
-       .ioctl = i2o_cfg_ioctl,
+       .unlocked_ioctl = i2o_cfg_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = i2o_cfg_compat_ioctl,
 #endif