+#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