fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / message / i2o / i2o_config.c
index 4c24010..e33d446 100644 (file)
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
-#include <linux/ioctl32.h>
 #include <linux/compat.h>
-#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
-#include <asm/io.h>
 
-extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+#include "core.h"
 
-static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
-struct wait_queue *i2o_wait_queue;
+#define SG_TABLESIZE           30
+
+static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
+                        unsigned long);
+
+static spinlock_t i2o_config_lock;
 
 #define MODINC(x,y) ((x) = ((x) + 1) % (y))
 
@@ -74,122 +66,22 @@ struct i2o_cfg_info {
 static struct i2o_cfg_info *open_files = NULL;
 static ulong i2o_cfg_info_id = 0;
 
-#if 0
-/*
- *     This is the callback for any message we have posted. The message itself
- *     will be returned to the message pool when we return from the IRQ
- *
- *     This runs in irq context so be short and sweet.
- */
-static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c,
-                         struct i2o_message *m)
-{
-       u32 *msg = (u32 *) m;
-
-       if (msg[0] & MSG_FAIL) {
-               u32 *preserved_msg = (u32 *) (c->msg_virt + msg[7]);
-
-               printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
-
-               /* Release the preserved msg frame by resubmitting it as a NOP */
-
-               preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
-               preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
-               preserved_msg[2] = 0;
-               i2o_post_message(c, msg[7]);
-       }
-
-       if (msg[4] >> 24)       // ReqStatus != SUCCESS
-               i2o_report_status(KERN_INFO, "i2o_config", msg);
-
-       if (m->function == I2O_CMD_UTIL_EVT_REGISTER) {
-               struct i2o_cfg_info *inf;
-
-               for (inf = open_files; inf; inf = inf->next)
-                       if (inf->q_id == i2o_cntxt_list_get(c, msg[3]))
-                               break;
-
-               //
-               // If this is the case, it means that we're getting
-               // events for a file descriptor that's been close()'d
-               // w/o the user unregistering for events first.
-               // The code currently assumes that the user will
-               // take care of unregistering for events before closing
-               // a file.
-               //
-               // TODO:
-               // Should we track event registartion and deregister
-               // for events when a file is close()'d so this doesn't
-               // happen? That would get rid of the search through
-               // the linked list since file->private_data could point
-               // directly to the i2o_config_info data structure...but
-               // it would mean having all sorts of tables to track
-               // what each file is registered for...I think the
-               // current method is simpler. - DS
-               //
-               if (!inf)
-                       return;
-
-               inf->event_q[inf->q_in].id.iop = c->unit;
-               inf->event_q[inf->q_in].id.tid = m->target_tid;
-               inf->event_q[inf->q_in].id.evt_mask = msg[4];
-
-               //
-               // Data size = msg size - reply header
-               //
-               inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
-               if (inf->event_q[inf->q_in].data_size)
-                       memcpy(inf->event_q[inf->q_in].evt_data,
-                              (unsigned char *)(msg + 5),
-                              inf->event_q[inf->q_in].data_size);
-
-               spin_lock(&i2o_config_lock);
-               MODINC(inf->q_in, I2O_EVT_Q_LEN);
-               if (inf->q_len == I2O_EVT_Q_LEN) {
-                       MODINC(inf->q_out, I2O_EVT_Q_LEN);
-                       inf->q_lost++;
-               } else {
-                       // Keep I2OEVTGET on another CPU from touching this
-                       inf->q_len++;
-               }
-               spin_unlock(&i2o_config_lock);
-
-//              printk(KERN_INFO "File %p w/id %d has %d events\n",
-//                      inf->fp, inf->q_id, inf->q_len);
-
-               kill_fasync(&inf->fasync, SIGIO, POLL_IN);
-       }
-
-       return;
-}
-#endif
-
-/*
- *     Each of these describes an i2o message handler. They are
- *     multiplexed by the i2o_core code
- */
-
-struct i2o_driver i2o_config_driver = {
-       .name = "Config-OSM"
-};
-
 static int i2o_cfg_getiops(unsigned long arg)
 {
        struct i2o_controller *c;
        u8 __user *user_iop_table = (void __user *)arg;
        u8 tmp[MAX_I2O_CONTROLLERS];
+       int ret = 0;
 
        memset(tmp, 0, MAX_I2O_CONTROLLERS);
 
-       if (!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS))
-               return -EFAULT;
-
        list_for_each_entry(c, &i2o_controllers, list)
            tmp[c->unit] = 1;
 
-       __copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS);
+       if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS))
+               ret = -EFAULT;
 
-       return 0;
+       return ret;
 };
 
 static int i2o_cfg_gethrt(unsigned long arg)
@@ -294,7 +186,7 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
        if (!dev)
                return -ENXIO;
 
-       ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL);
+       ops = kmalloc(kcmd.oplen, GFP_KERNEL);
        if (!ops)
                return -ENOMEM;
 
@@ -307,7 +199,7 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
         * It's possible to have a _very_ large table
         * and that the user asks for all of it at once...
         */
-       res = (u8 *) kmalloc(65536, GFP_KERNEL);
+       res = kmalloc(65536, GFP_KERNEL);
        if (!res) {
                kfree(ops);
                return -ENOMEM;
@@ -339,7 +231,6 @@ static int i2o_cfg_swdl(unsigned long arg)
        unsigned char maxfrag = 0, curfrag = 1;
        struct i2o_dma buffer;
        struct i2o_message *msg;
-       u32 m;
        unsigned int status = 0, swlen = 0, fragsize = 8192;
        struct i2o_controller *c;
 
@@ -365,31 +256,38 @@ static int i2o_cfg_swdl(unsigned long arg)
        if (!c)
                return -ENXIO;
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -EBUSY;
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
        if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
-               i2o_msg_nop(c, m);
+               i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
 
-       __copy_from_user(buffer.virt, kxfer.buf, fragsize);
-
-       writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
-       writel(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 | ADAPTER_TID,
-              &msg->u.head[1]);
-       writel(i2o_config_driver.context, &msg->u.head[2]);
-       writel(0, &msg->u.head[3]);
-       writel((((u32) kxfer.flags) << 24) | (((u32) kxfer.sw_type) << 16) |
-              (((u32) maxfrag) << 8) | (((u32) curfrag)), &msg->body[0]);
-       writel(swlen, &msg->body[1]);
-       writel(kxfer.sw_id, &msg->body[2]);
-       writel(0xD0000000 | fragsize, &msg->body[3]);
-       writel(buffer.phys, &msg->body[4]);
+       if (__copy_from_user(buffer.virt, kxfer.buf, fragsize)) {
+               i2o_msg_nop(c, msg);
+               i2o_dma_free(&c->pdev->dev, &buffer);
+               return -EFAULT;
+       }
 
-//      printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-       status = i2o_msg_post_wait_mem(c, m, 60, &buffer);
+       msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);
+       msg->u.head[1] =
+           cpu_to_le32(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 |
+                       ADAPTER_TID);
+       msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
+       msg->u.head[3] = cpu_to_le32(0);
+       msg->body[0] =
+           cpu_to_le32((((u32) kxfer.flags) << 24) | (((u32) kxfer.
+                                                       sw_type) << 16) |
+                       (((u32) maxfrag) << 8) | (((u32) curfrag)));
+       msg->body[1] = cpu_to_le32(swlen);
+       msg->body[2] = cpu_to_le32(kxfer.sw_id);
+       msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);
+       msg->body[4] = cpu_to_le32(buffer.phys);
+
+       osm_debug("swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+       status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);
 
        if (status != -ETIMEDOUT)
                i2o_dma_free(&c->pdev->dev, &buffer);
@@ -397,9 +295,7 @@ static int i2o_cfg_swdl(unsigned long arg)
        if (status != I2O_POST_WAIT_OK) {
                // it fails if you try and send frags out of order
                // and for some yet unknown reasons too
-               printk(KERN_INFO
-                      "i2o_config: swdl failed, DetailedStatus = %d\n",
-                      status);
+               osm_info("swdl failed, DetailedStatus = %d\n", status);
                return status;
        }
 
@@ -413,71 +309,75 @@ static int i2o_cfg_swul(unsigned long arg)
        unsigned char maxfrag = 0, curfrag = 1;
        struct i2o_dma buffer;
        struct i2o_message *msg;
-       u32 m;
        unsigned int status = 0, swlen = 0, fragsize = 8192;
        struct i2o_controller *c;
+       int ret = 0;
 
        if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-               return -EFAULT;
+               goto return_fault;
 
        if (get_user(swlen, kxfer.swlen) < 0)
-               return -EFAULT;
+               goto return_fault;
 
        if (get_user(maxfrag, kxfer.maxfrag) < 0)
-               return -EFAULT;
+               goto return_fault;
 
        if (get_user(curfrag, kxfer.curfrag) < 0)
-               return -EFAULT;
+               goto return_fault;
 
        if (curfrag == maxfrag)
                fragsize = swlen - (maxfrag - 1) * 8192;
 
-       if (!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize))
-               return -EFAULT;
+       if (!kxfer.buf)
+               goto return_fault;
 
        c = i2o_find_iop(kxfer.iop);
        if (!c)
                return -ENXIO;
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -EBUSY;
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
        if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
-               i2o_msg_nop(c, m);
+               i2o_msg_nop(c, msg);
                return -ENOMEM;
        }
 
-       writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
-       writel(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID,
-              &msg->u.head[1]);
-       writel(i2o_config_driver.context, &msg->u.head[2]);
-       writel(0, &msg->u.head[3]);
-       writel((u32) kxfer.flags << 24 | (u32) kxfer.
-              sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag,
-              &msg->body[0]);
-       writel(swlen, &msg->body[1]);
-       writel(kxfer.sw_id, &msg->body[2]);
-       writel(0xD0000000 | fragsize, &msg->body[3]);
-       writel(buffer.phys, &msg->body[4]);
-
-//      printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-       status = i2o_msg_post_wait_mem(c, m, 60, &buffer);
+       msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);
+       msg->u.head[1] =
+           cpu_to_le32(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID);
+       msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
+       msg->u.head[3] = cpu_to_le32(0);
+       msg->body[0] =
+           cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.
+                       sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag);
+       msg->body[1] = cpu_to_le32(swlen);
+       msg->body[2] = cpu_to_le32(kxfer.sw_id);
+       msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);
+       msg->body[4] = cpu_to_le32(buffer.phys);
+
+       osm_debug("swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+       status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);
 
        if (status != I2O_POST_WAIT_OK) {
                if (status != -ETIMEDOUT)
                        i2o_dma_free(&c->pdev->dev, &buffer);
 
-               printk(KERN_INFO
-                      "i2o_config: swul failed, DetailedStatus = %d\n",
-                      status);
+               osm_info("swul failed, DetailedStatus = %d\n", status);
                return status;
        }
 
-       __copy_to_user(kxfer.buf, buffer.virt, fragsize);
+       if (copy_to_user(kxfer.buf, buffer.virt, fragsize))
+               ret = -EFAULT;
+
        i2o_dma_free(&c->pdev->dev, &buffer);
 
-       return 0;
+      return_ret:
+       return ret;
+      return_fault:
+       ret = -EFAULT;
+       goto return_ret;
 };
 
 static int i2o_cfg_swdel(unsigned long arg)
@@ -486,7 +386,6 @@ static int i2o_cfg_swdel(unsigned long arg)
        struct i2o_sw_xfer kxfer;
        struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;
        struct i2o_message *msg;
-       u32 m;
        unsigned int swlen;
        int token;
 
@@ -500,26 +399,24 @@ static int i2o_cfg_swdel(unsigned long arg)
        if (!c)
                return -ENXIO;
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -EBUSY;
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
-       writel(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
-       writel(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID,
-              &msg->u.head[1]);
-       writel(i2o_config_driver.context, &msg->u.head[2]);
-       writel(0, &msg->u.head[3]);
-       writel((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16,
-              &msg->body[0]);
-       writel(swlen, &msg->body[1]);
-       writel(kxfer.sw_id, &msg->body[2]);
+       msg->u.head[0] = cpu_to_le32(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0);
+       msg->u.head[1] =
+           cpu_to_le32(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID);
+       msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
+       msg->u.head[3] = cpu_to_le32(0);
+       msg->body[0] =
+           cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16);
+       msg->body[1] = cpu_to_le32(swlen);
+       msg->body[2] = cpu_to_le32(kxfer.sw_id);
 
-       token = i2o_msg_post_wait(c, m, 10);
+       token = i2o_msg_post_wait(c, msg, 10);
 
        if (token != I2O_POST_WAIT_OK) {
-               printk(KERN_INFO
-                      "i2o_config: swdel failed, DetailedStatus = %d\n",
-                      token);
+               osm_info("swdel failed, DetailedStatus = %d\n", token);
                return -ETIMEDOUT;
        }
 
@@ -531,28 +428,27 @@ static int i2o_cfg_validate(unsigned long arg)
        int token;
        int iop = (int)arg;
        struct i2o_message *msg;
-       u32 m;
        struct i2o_controller *c;
 
        c = i2o_find_iop(iop);
        if (!c)
                return -ENXIO;
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -EBUSY;
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
-       writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
-       writel(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop,
-              &msg->u.head[1]);
-       writel(i2o_config_driver.context, &msg->u.head[2]);
-       writel(0, &msg->u.head[3]);
+       msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+       msg->u.head[1] =
+           cpu_to_le32(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop);
+       msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
+       msg->u.head[3] = cpu_to_le32(0);
 
-       token = i2o_msg_post_wait(c, m, 10);
+       token = i2o_msg_post_wait(c, msg, 10);
 
        if (token != I2O_POST_WAIT_OK) {
-               printk(KERN_INFO "Can't validate configuration, ErrorStatus = "
-                      "%d\n", token);
+               osm_info("Can't validate configuration, ErrorStatus = %d\n",
+                        token);
                return -ETIMEDOUT;
        }
 
@@ -562,7 +458,6 @@ static int i2o_cfg_validate(unsigned long arg)
 static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp)
 {
        struct i2o_message *msg;
-       u32 m;
        struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg;
        struct i2o_evt_id kdesc;
        struct i2o_controller *c;
@@ -581,18 +476,19 @@ static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp)
        if (!d)
                return -ENODEV;
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
-       if (m == I2O_QUEUE_EMPTY)
-               return -EBUSY;
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
-       writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
-       writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | kdesc.tid,
-              &msg->u.head[1]);
-       writel(i2o_config_driver.context, &msg->u.head[2]);
-       writel(i2o_cntxt_list_add(c, fp->private_data), &msg->u.head[3]);
-       writel(kdesc.evt_mask, &msg->body[0]);
+       msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+       msg->u.head[1] =
+           cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 |
+                       kdesc.tid);
+       msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
+       msg->u.head[3] = cpu_to_le32(i2o_cntxt_list_add(c, fp->private_data));
+       msg->body[0] = cpu_to_le32(kdesc.evt_mask);
 
-       i2o_msg_post(c, m);
+       i2o_msg_post(c, msg);
 
        return 0;
 }
@@ -625,8 +521,8 @@ static int i2o_cfg_evt_get(unsigned long arg, struct file *fp)
 }
 
 #ifdef CONFIG_COMPAT
-static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
-                             struct file *file)
+static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
+                             unsigned long arg)
 {
        struct i2o_cmd_passthru32 __user *cmd;
        struct i2o_controller *c;
@@ -640,9 +536,9 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
        u32 sg_offset = 0;
        u32 sg_count = 0;
        u32 i = 0;
+       u32 sg_index = 0;
        i2o_status_block *sb;
        struct i2o_message *msg;
-       u32 m;
        unsigned int iop;
 
        cmd = (struct i2o_cmd_passthru32 __user *)arg;
@@ -654,22 +550,22 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
 
        c = i2o_find_iop(iop);
        if (!c) {
-               pr_debug("controller %d not found\n", iop);
+               osm_debug("controller %d not found\n", iop);
                return -ENXIO;
        }
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
 
        sb = c->status_block.virt;
 
        if (get_user(size, &user_msg[0])) {
-               printk(KERN_WARNING "unable to get size!\n");
+               osm_warn("unable to get size!\n");
                return -EFAULT;
        }
        size = size >> 16;
 
        if (size > sb->inbound_frame_size) {
-               pr_debug("size of message > inbound_frame_size");
+               osm_warn("size of message > inbound_frame_size");
                return -EFAULT;
        }
 
@@ -679,7 +575,7 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
 
        /* Copy in the user's I2O command */
        if (copy_from_user(msg, user_msg, size)) {
-               printk(KERN_WARNING "unable to copy user message\n");
+               osm_warn("unable to copy user message\n");
                return -EFAULT;
        }
        i2o_dump_message(msg);
@@ -690,19 +586,15 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
        reply_size >>= 16;
        reply_size <<= 2;
 
-       reply = kmalloc(reply_size, GFP_KERNEL);
+       reply = kzalloc(reply_size, GFP_KERNEL);
        if (!reply) {
                printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
                       c->name);
                return -ENOMEM;
        }
-       memset(reply, 0, reply_size);
 
        sg_offset = (msg->u.head[0] >> 4) & 0x0f;
 
-       writel(i2o_config_driver.context, &msg->u.s.icntxt);
-       writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt);
-
        memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
        if (sg_offset) {
                struct sg_simple_element *sg;
@@ -719,8 +611,8 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                if (sg_count > SG_TABLESIZE) {
                        printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
                               c->name, sg_count);
-                       kfree(reply);
-                       return -EINVAL;
+                       rcode = -EINVAL;
+                       goto cleanup;
                }
 
                for (i = 0; i < sg_count; i++) {
@@ -736,7 +628,7 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                                goto cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
-                       p = &(sg_list[i]);
+                       p = &(sg_list[sg_index]);
                        /* Allocate memory for the transfer */
                        if (i2o_dma_alloc
                            (&c->pdev->dev, p, sg_size,
@@ -745,20 +637,22 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
+                       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->virt, (void __user *)(unsigned long)sg[i].addr_bus,
-                                    sg_size)) {
+                                   (p->virt,
+                                    (void __user *)(unsigned long)sg[i].
+                                    addr_bus, sg_size)) {
                                        printk(KERN_DEBUG
                                               "%s: Could not copy SG buf %d FROM user\n",
                                               c->name, i);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                        //TODO 64bit fix
@@ -766,32 +660,33 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                }
        }
 
-       rcode = i2o_msg_post_wait(c, m, 60);
-       if (rcode)
-               goto cleanup;
+       rcode = i2o_msg_post_wait(c, msg, 60);
+       if (rcode) {
+               reply[4] = ((u32) rcode) << 24;
+               goto sg_list_cleanup;
+       }
 
        if (sg_offset) {
-               u32 msg[128];
+               u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE];
                /* Copy back the Scatter Gather buffers back to user space */
                u32 j;
                // TODO 64bit fix
                struct sg_simple_element *sg;
                int sg_size;
-               printk(KERN_INFO "sg_offset\n");
 
                // re-acquire the original message to handle correctly the sg copy operation
-               memset(&msg, 0, MSG_FRAME_SIZE * 4);
+               memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
                // get user msg size in u32s
                if (get_user(size, &user_msg[0])) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                size = size >> 16;
                size *= 4;
                /* Copy in the user's I2O command */
                if (copy_from_user(msg, user_msg, size)) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                sg_count =
                    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -813,21 +708,22 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                                               c->name, sg_list[j].virt,
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                }
        }
 
+      sg_list_cleanup:
        /* Copy back the reply to user space */
        if (reply_size) {
                // we wrote our own values for context - now restore the user supplied ones
-               printk(KERN_INFO "reply_size\n");
                if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {
                        printk(KERN_WARNING
                               "%s: Could not copy message context FROM user\n",
                               c->name);
                        rcode = -EFAULT;
+                       goto sg_list_cleanup;
                }
                if (copy_to_user(user_reply, reply, reply_size)) {
                        printk(KERN_WARNING
@@ -836,14 +732,37 @@ static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg,
                }
        }
 
+       for (i = 0; i < sg_index; i++)
+               i2o_dma_free(&c->pdev->dev, &sg_list[i]);
+
       cleanup:
        kfree(reply);
-       printk(KERN_INFO "rcode: %d\n", rcode);
        return rcode;
 }
 
-#else
+static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
+                                unsigned long arg)
+{
+       int ret;
+       lock_kernel();
+       switch (cmd) {
+       case I2OGETIOPS:
+               ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
+               break;
+       case I2OPASSTHRU32:
+               ret = i2o_cfg_passthru32(file, cmd, arg);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+       unlock_kernel();
+       return ret;
+}
+
+#endif
 
+#ifdef CONFIG_I2O_EXT_ADAPTEC
 static int i2o_cfg_passthru(unsigned long arg)
 {
        struct i2o_cmd_passthru __user *cmd =
@@ -863,7 +782,6 @@ static int i2o_cfg_passthru(unsigned long arg)
        void *p = NULL;
        i2o_status_block *sb;
        struct i2o_message *msg;
-       u32 m;
        unsigned int iop;
 
        if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg))
@@ -871,11 +789,11 @@ static int i2o_cfg_passthru(unsigned long arg)
 
        c = i2o_find_iop(iop);
        if (!c) {
-               pr_debug("controller %d not found\n", iop);
+               osm_warn("controller %d not found\n", iop);
                return -ENXIO;
        }
 
-       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
 
        sb = c->status_block.virt;
 
@@ -884,7 +802,7 @@ static int i2o_cfg_passthru(unsigned long arg)
        size = size >> 16;
 
        if (size > sb->inbound_frame_size) {
-               pr_debug("size of message > inbound_frame_size");
+               osm_warn("size of message > inbound_frame_size");
                return -EFAULT;
        }
 
@@ -902,19 +820,15 @@ static int i2o_cfg_passthru(unsigned long arg)
        reply_size >>= 16;
        reply_size <<= 2;
 
-       reply = kmalloc(reply_size, GFP_KERNEL);
+       reply = kzalloc(reply_size, GFP_KERNEL);
        if (!reply) {
                printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
                       c->name);
                return -ENOMEM;
        }
-       memset(reply, 0, reply_size);
 
        sg_offset = (msg->u.head[0] >> 4) & 0x0f;
 
-       writel(i2o_config_driver.context, &msg->u.s.icntxt);
-       writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt);
-
        memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
        if (sg_offset) {
                struct sg_simple_element *sg;
@@ -931,8 +845,8 @@ static int i2o_cfg_passthru(unsigned long arg)
                if (sg_count > SG_TABLESIZE) {
                        printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
                               c->name, sg_count);
-                       kfree(reply);
-                       return -EINVAL;
+                       rcode = -EINVAL;
+                       goto cleanup;
                }
 
                for (i = 0; i < sg_count; i++) {
@@ -944,7 +858,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                       "%s:Bad SG element %d - not simple (%x)\n",
                                       c->name, i, sg[i].flag_count);
                                rcode = -EINVAL;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
                        sg_size = sg[i].flag_count & 0xffffff;
                        /* Allocate memory for the transfer */
@@ -954,7 +868,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                       c->name, sg_size, i, sg_count);
                                rcode = -ENOMEM;
-                               goto cleanup;
+                               goto sg_list_cleanup;
                        }
                        sg_list[sg_index++] = p;        // sglist indexed with input frame, not our internal frame.
                        /* Copy in the user's SG buffer if necessary */
@@ -968,7 +882,7 @@ static int i2o_cfg_passthru(unsigned long arg)
                                               "%s: Could not copy SG buf %d FROM user\n",
                                               c->name, i);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                        //TODO 64bit fix
@@ -976,9 +890,11 @@ static int i2o_cfg_passthru(unsigned long arg)
                }
        }
 
-       rcode = i2o_msg_post_wait(c, m, 60);
-       if (rcode)
-               goto cleanup;
+       rcode = i2o_msg_post_wait(c, msg, 60);
+       if (rcode) {
+               reply[4] = ((u32) rcode) << 24;
+               goto sg_list_cleanup;
+       }
 
        if (sg_offset) {
                u32 msg[128];
@@ -987,21 +903,20 @@ static int i2o_cfg_passthru(unsigned long arg)
                // TODO 64bit fix
                struct sg_simple_element *sg;
                int sg_size;
-               printk(KERN_INFO "sg_offset\n");
 
                // re-acquire the original message to handle correctly the sg copy operation
-               memset(&msg, 0, MSG_FRAME_SIZE * 4);
+               memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
                // get user msg size in u32s
                if (get_user(size, &user_msg[0])) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                size = size >> 16;
                size *= 4;
                /* Copy in the user's I2O command */
                if (copy_from_user(msg, user_msg, size)) {
                        rcode = -EFAULT;
-                       goto cleanup;
+                       goto sg_list_cleanup;
                }
                sg_count =
                    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -1023,16 +938,16 @@ static int i2o_cfg_passthru(unsigned long arg)
                                               c->name, sg_list[j],
                                               sg[j].addr_bus);
                                        rcode = -EFAULT;
-                                       goto cleanup;
+                                       goto sg_list_cleanup;
                                }
                        }
                }
        }
 
+      sg_list_cleanup:
        /* Copy back the reply to user space */
        if (reply_size) {
                // we wrote our own values for context - now restore the user supplied ones
-               printk(KERN_INFO "reply_size\n");
                if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {
                        printk(KERN_WARNING
                               "%s: Could not copy message context FROM user\n",
@@ -1046,6 +961,9 @@ static int i2o_cfg_passthru(unsigned long arg)
                }
        }
 
+       for (i = 0; i < sg_index; i++)
+               kfree(sg_list[i]);
+
       cleanup:
        kfree(reply);
        return rcode;
@@ -1105,14 +1023,14 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
                ret = i2o_cfg_evt_get(arg, fp);
                break;
 
-#ifndef CONFIG_COMPAT
+#ifdef CONFIG_I2O_EXT_ADAPTEC
        case I2OPASSTHRU:
                ret = i2o_cfg_passthru(arg);
                break;
 #endif
 
        default:
-               pr_debug("i2o_config: unknown ioctl called!\n");
+               osm_debug("unknown ioctl called!\n");
                ret = -EINVAL;
        }
 
@@ -1197,6 +1115,9 @@ static struct file_operations config_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .ioctl = i2o_cfg_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = i2o_cfg_compat_ioctl,
+#endif
        .open = cfg_open,
        .release = cfg_release,
        .fasync = cfg_fasync,
@@ -1208,43 +1129,21 @@ static struct miscdevice i2o_miscdev = {
        &config_fops
 };
 
-static int __init i2o_config_init(void)
+static int __init i2o_config_old_init(void)
 {
-       printk(KERN_INFO "I2O configuration manager v 0.04.\n");
-       printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software\n");
+       spin_lock_init(&i2o_config_lock);
 
        if (misc_register(&i2o_miscdev) < 0) {
-               printk(KERN_ERR "i2o_config: can't register device.\n");
-               return -EBUSY;
-       }
-       /*
-        *      Install our handler
-        */
-       if (i2o_driver_register(&i2o_config_driver)) {
-               printk(KERN_ERR "i2o_config: handler register failed.\n");
-               misc_deregister(&i2o_miscdev);
+               osm_err("can't register device.\n");
                return -EBUSY;
        }
-#ifdef CONFIG_COMPAT
-       register_ioctl32_conversion(I2OPASSTHRU32, i2o_cfg_passthru32);
-       register_ioctl32_conversion(I2OGETIOPS, (void *)sys_ioctl);
-#endif
+
        return 0;
 }
 
-static void i2o_config_exit(void)
+static void i2o_config_old_exit(void)
 {
-#ifdef CONFIG_COMPAT
-       unregister_ioctl32_conversion(I2OPASSTHRU32);
-       unregister_ioctl32_conversion(I2OGETIOPS);
-#endif
        misc_deregister(&i2o_miscdev);
-       i2o_driver_unregister(&i2o_config_driver);
 }
 
 MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O Configuration");
-MODULE_LICENSE("GPL");
-
-module_init(i2o_config_init);
-module_exit(i2o_config_exit);