VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / block / cciss.c
index 0d45b81..5509e56 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/init.h> 
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
+#include <linux/compat.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -479,6 +480,145 @@ static int cciss_release(struct inode *inode, struct file *filep)
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */
+extern long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern int
+register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int,
+      unsigned int, unsigned long, struct file *));
+extern int unregister_ioctl32_conversion(unsigned int cmd);
+
+static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file);
+static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+       struct file *file);
+
+typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *);
+
+static struct ioctl32_map {
+       unsigned int cmd;
+       handler_type handler;
+       int registered;
+} cciss_ioctl32_map[] = {
+       { CCISS_GETPCIINFO,     (handler_type) sys_ioctl, 0 },
+       { CCISS_GETINTINFO,     (handler_type) sys_ioctl, 0 },
+       { CCISS_SETINTINFO,     (handler_type) sys_ioctl, 0 },
+       { CCISS_GETNODENAME,    (handler_type) sys_ioctl, 0 },
+       { CCISS_SETNODENAME,    (handler_type) sys_ioctl, 0 },
+       { CCISS_GETHEARTBEAT,   (handler_type) sys_ioctl, 0 },
+       { CCISS_GETBUSTYPES,    (handler_type) sys_ioctl, 0 },
+       { CCISS_GETFIRMVER,     (handler_type) sys_ioctl, 0 },
+       { CCISS_GETDRIVVER,     (handler_type) sys_ioctl, 0 },
+       { CCISS_REVALIDVOLS,    (handler_type) sys_ioctl, 0 },
+       { CCISS_PASSTHRU32,     cciss_ioctl32_passthru, 0 },
+       { CCISS_DEREGDISK,      (handler_type) sys_ioctl, 0 },
+       { CCISS_REGNEWDISK,     (handler_type) sys_ioctl, 0 },
+       { CCISS_REGNEWD,        (handler_type) sys_ioctl, 0 },
+       { CCISS_RESCANDISK,     (handler_type) sys_ioctl, 0 },
+       { CCISS_GETLUNINFO,     (handler_type) sys_ioctl, 0 },
+       { CCISS_BIG_PASSTHRU32, cciss_ioctl32_big_passthru, 0 },
+};
+#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0]))
+static void register_cciss_ioctl32(void)
+{
+       int i, rc;
+
+       for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+               rc = register_ioctl32_conversion(
+                       cciss_ioctl32_map[i].cmd,
+                       cciss_ioctl32_map[i].handler);
+               if (rc != 0) {
+                       printk(KERN_WARNING "cciss: failed to register "
+                               "32 bit compatible ioctl 0x%08x\n",
+                               cciss_ioctl32_map[i].cmd);
+                       cciss_ioctl32_map[i].registered = 0;
+               } else
+                       cciss_ioctl32_map[i].registered = 1;
+       }
+}
+static void unregister_cciss_ioctl32(void)
+{
+       int i, rc;
+
+       for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+               if (!cciss_ioctl32_map[i].registered)
+                       continue;
+               rc = unregister_ioctl32_conversion(
+                       cciss_ioctl32_map[i].cmd);
+               if (rc == 0) {
+                       cciss_ioctl32_map[i].registered = 0;
+                       continue;
+               }
+               printk(KERN_WARNING "cciss: failed to unregister "
+                       "32 bit compatible ioctl 0x%08x\n",
+                       cciss_ioctl32_map[i].cmd);
+       }
+}
+int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+       struct file *file)
+{
+       IOCTL32_Command_struct __user *arg32 =
+               (IOCTL32_Command_struct __user *) arg;
+       IOCTL_Command_struct arg64;
+       IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+       int err;
+       u32 cp;
+
+       err = 0;
+       err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+       err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+       err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+       err |= get_user(arg64.buf_size, &arg32->buf_size);
+       err |= get_user(cp, &arg32->buf);
+       arg64.buf = compat_ptr(cp);
+       err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+       if (err)
+               return -EFAULT;
+
+       err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p);
+       if (err)
+               return err;
+       err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info));
+       if (err)
+               return -EFAULT;
+       return err;
+}
+
+int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+       struct file *file)
+{
+       BIG_IOCTL32_Command_struct __user *arg32 =
+               (BIG_IOCTL32_Command_struct __user *) arg;
+       BIG_IOCTL_Command_struct arg64;
+       BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+       int err;
+       u32 cp;
+
+       err = 0;
+       err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+       err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+       err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+       err |= get_user(arg64.buf_size, &arg32->buf_size);
+       err |= get_user(arg64.malloc_size, &arg32->malloc_size);
+       err |= get_user(cp, &arg32->buf);
+       arg64.buf = compat_ptr(cp);
+       err |= copy_to_user(p, &arg64, sizeof(arg64));
+
+       if (err)
+                return -EFAULT;
+
+       err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p);
+       if (err)
+               return err;
+       err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(&arg32->error_info));
+       if (err)
+               return -EFAULT;
+       return err;
+}
+#else
+static inline void register_cciss_ioctl32(void) {}
+static inline void unregister_cciss_ioctl32(void) {}
+#endif
 /*
  * ioctl 
  */
@@ -2728,6 +2868,7 @@ int __init cciss_init(void)
 
 static int __init init_cciss_module(void)
 {
+       register_cciss_ioctl32();
        return ( cciss_init());
 }
 
@@ -2735,6 +2876,7 @@ static void __exit cleanup_cciss_module(void)
 {
        int i;
 
+       unregister_cciss_ioctl32();
        pci_unregister_driver(&cciss_pci_driver);
        /* double check that all controller entrys have been removed */
        for (i=0; i< MAX_CTLR; i++)