linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
       [not found] <20030507104008$12ba@gated-at.bofh.it>
@ 2003-05-07 11:51 ` Arnd Bergmann
  2003-05-07 12:41   ` Pavel Machek
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 11:51 UTC (permalink / raw)
  To: Pavel Machek, linux-kernel

Pavel Machek wrote:

> Only change *needed* in each architecture is moving A() macros into
> compat.h, so that generic code can use it. Please apply,

Please don't use A() in new code, we now have compat_ptr() and
compat_uptr_t for this.

        Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 11:51 ` ioctl cleanups: enable sg_io and serial stuff to be shared Arnd Bergmann
@ 2003-05-07 12:41   ` Pavel Machek
  2003-05-07 12:56     ` Christoph Hellwig
  2003-05-07 13:18     ` Arnd Bergmann
  0 siblings, 2 replies; 39+ messages in thread
From: Pavel Machek @ 2003-05-07 12:41 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel

Hi!

> > Only change *needed* in each architecture is moving A() macros into
> > compat.h, so that generic code can use it. Please apply,
> 
> Please don't use A() in new code, we now have compat_ptr() and
> compat_uptr_t for this.

Fixed now.
								Pavel

--- linux.clean/arch/x86_64/ia32/ia32_ioctl.c	2003-05-05 15:53:57.000000000 -0700
+++ linux/arch/x86_64/ia32/ia32_ioctl.c	2003-05-07 07:01:29.000000000 -0700
@@ -1333,235 +1333,6 @@
 	return err;
 }
 
-
-typedef struct sg_io_hdr32 {
-	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
-	s32 dxfer_direction;	/* [i] data transfer direction  */
-	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
-	u8  mx_sb_len;		/* [i] max length to write to sbp */
-	u16 iovec_count;	/* [i] 0 implies no scatter gather */
-	u32 dxfer_len;		/* [i] byte count of data transfer */
-	u32 dxferp;		/* [i], [*io] points to data transfer memory
-					      or scatter gather list */
-	u32 cmdp;		/* [i], [*i] points to command to perform */
-	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
-	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
-	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
-	s32 pack_id;		/* [i->o] unused internally (normally) */
-	u32 usr_ptr;		/* [i->o] unused internally */
-	u8  status;		/* [o] scsi status */
-	u8  masked_status;	/* [o] shifted, masked scsi status */
-	u8  msg_status;		/* [o] messaging level data (optional) */
-	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
-	u16 host_status;	/* [o] errors from host adapter */
-	u16 driver_status;	/* [o] errors from software driver */
-	s32 resid;		/* [o] dxfer_len - actual_transferred */
-	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
-	u32 info;		/* [o] auxiliary information */
-} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
-
-typedef struct sg_iovec32 {
-	u32 iov_base;
-	u32 iov_len;
-} sg_iovec32_t;
-
-static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov;
-	int i;
-
-	sgp->dxferp = kmalloc(sgp->iovec_count *
-			      sizeof(sg_iovec_t), GFP_KERNEL);
-	if (!sgp->dxferp)
-		return -ENOMEM;
-	memset(sgp->dxferp, 0,
-	       sgp->iovec_count * sizeof(sg_iovec_t));
-
-	kiov = (sg_iovec_t *) sgp->dxferp;
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-		if (__get_user(iov_base32, &uiov->iov_base) ||
-		    __get_user(kiov->iov_len, &uiov->iov_len))
-			return -EFAULT;
-
-		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
-		if (!kiov->iov_base)
-			return -ENOMEM;
-		if (copy_from_user(kiov->iov_base,
-				   (void *) A(iov_base32),
-				   kiov->iov_len))
-			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-
-		if (__get_user(iov_base32, &uiov->iov_base))
-			return -EFAULT;
-
-		if (copy_to_user((void *) A(iov_base32),
-				 kiov->iov_base,
-				 kiov->iov_len))
-			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static void free_sg_iovec(sg_io_hdr_t *sgp)
-{
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		if (kiov->iov_base) {
-			kfree(kiov->iov_base);
-			kiov->iov_base = NULL;
-		}
-		kiov++;
-	}
-	kfree(sgp->dxferp);
-	sgp->dxferp = NULL;
-}
-
-static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	sg_io_hdr32_t *sg_io32;
-	sg_io_hdr_t sg_io64;
-	u32 dxferp32, cmdp32, sbp32;
-	mm_segment_t old_fs;
-	int err = 0;
-
-	sg_io32 = (sg_io_hdr32_t *)arg;
-	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
-	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
-	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
-	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
-	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
-	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
-	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
-	err |= __get_user(sg_io64.flags, &sg_io32->flags);
-	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
-
-	sg_io64.dxferp = NULL;
-	sg_io64.cmdp = NULL;
-	sg_io64.sbp = NULL;
-
-	err |= __get_user(cmdp32, &sg_io32->cmdp);
-	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
-	if (!sg_io64.cmdp) {
-		err = -ENOMEM;
-		goto out;
-	}
-	if (copy_from_user(sg_io64.cmdp,
-			   (void *) A(cmdp32),
-			   sg_io64.cmd_len)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	err |= __get_user(sbp32, &sg_io32->sbp);
-	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
-	if (!sg_io64.sbp) {
-		err = -ENOMEM;
-		goto out;
-	}
-	if (copy_from_user(sg_io64.sbp,
-			   (void *) A(sbp32),
-			   sg_io64.mx_sb_len)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	err |= __get_user(dxferp32, &sg_io32->dxferp);
-	if (sg_io64.iovec_count) {
-		int ret;
-
-		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
-			err = ret;
-			goto out;
-		}
-	} else {
-		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
-		if (!sg_io64.dxferp) {
-			err = -ENOMEM;
-			goto out;
-		}
-		if (copy_from_user(sg_io64.dxferp,
-				   (void *) A(dxferp32),
-				   sg_io64.dxfer_len)) {
-			err = -EFAULT;
-			goto out;
-		}
-	}
-
-	/* Unused internally, do not even bother to copy it over. */
-	sg_io64.usr_ptr = NULL;
-
-	if (err)
-		return -EFAULT;
-
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
-	set_fs (old_fs);
-
-	if (err < 0)
-		goto out;
-
-	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
-	err |= __put_user(sg_io64.status, &sg_io32->status);
-	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
-	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
-	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
-	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
-	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
-	err |= __put_user(sg_io64.resid, &sg_io32->resid);
-	err |= __put_user(sg_io64.duration, &sg_io32->duration);
-	err |= __put_user(sg_io64.info, &sg_io32->info);
-	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
-	if (sg_io64.dxferp) {
-		if (sg_io64.iovec_count)
-			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
-		else
-			err |= copy_to_user((void *)A(dxferp32),
-					    sg_io64.dxferp,
-					    sg_io64.dxfer_len);
-	}
-	if (err)
-		err = -EFAULT;
-
-out:
-	if (sg_io64.cmdp)
-		kfree(sg_io64.cmdp);
-	if (sg_io64.sbp)
-		kfree(sg_io64.sbp);
-	if (sg_io64.dxferp) {
-		if (sg_io64.iovec_count) {
-			free_sg_iovec(&sg_io64);
-		} else {
-			kfree(sg_io64.dxferp);
-		}
-	}
-	return err;
-}
-
 struct sock_fprog32 {
 	__u16	len;
 	__u32	filter;
@@ -3190,8 +2961,6 @@
 
 /* And these ioctls need translation */
 HANDLE_IOCTL(TIOCGDEV, tiocgdev)
-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 #ifdef CONFIG_NET
@@ -3274,7 +3043,6 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
-HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
--- linux.clean/drivers/block/Makefile	2003-05-05 15:49:42.000000000 -0700
+++ linux/drivers/block/Makefile	2003-05-06 13:53:24.000000000 -0700
@@ -25,7 +25,7 @@
 obj-$(CONFIG_BLK_DEV_PS2)	+= ps2esdi.o
 obj-$(CONFIG_BLK_DEV_XD)	+= xd.o
 obj-$(CONFIG_BLK_CPQ_DA)	+= cpqarray.o
-obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.o
+obj-$(CONFIG_BLK_CPQ_CISS_DA)	+= cciss.o
 obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o
 
 obj-$(CONFIG_BLK_DEV_UMEM)	+= umem.o
--- linux.clean/drivers/block/scsi_ioctl.c	2003-05-05 15:49:42.000000000 -0700
+++ linux/drivers/block/scsi_ioctl.c	2003-05-07 07:03:24.000000000 -0700
@@ -15,6 +15,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
  *
+ * Changes:
+ * Pavel Machek <pavel@suse.cz> 05/2003
+ * - move ioctl32 emulation here [this patch is dedicated to johanka@root.cz]
  */
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -25,12 +28,14 @@
 #include <linux/cdrom.h>
 #include <linux/slab.h>
 #include <linux/bio.h>
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 
-
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size[8] =
 {
@@ -294,6 +299,213 @@
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+#define EMU_SG_MAX 128
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) compat_ptr(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	if (sgp->iovec_count > EMU_SG_MAX)
+		return -EINVAL;
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+		if (verify_area(VERIFY_WRITE, (void *)compat_ptr(iov_base32), kiov->iov_len))
+			return -EFAULT;
+		kiov->iov_base = (void *)compat_ptr(iov_base32);
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *f)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) compat_ptr(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) compat_ptr(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		if (sg_io64.dxfer_len > 4*PAGE_SIZE) { 
+			err = -EINVAL;
+			goto out;
+		}
+
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) compat_ptr(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)compat_ptr(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			;
+		else
+			err |= copy_to_user((void *)compat_ptr(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
+static int __init init_compat(void)
+{
+	register_ioctl32_conversion(SG_IO, sg_ioctl_trans);
+	return 0;
+}
+
+__initcall(init_compat);
+#endif
+
 #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
 #define START_STOP_TIMEOUT		(60 * HZ)
 #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
--- linux.clean/drivers/serial/core.c	2003-05-05 15:50:12.000000000 -0700
+++ linux/drivers/serial/core.c	2003-05-06 14:17:08.000000000 -0700
@@ -32,6 +32,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+#include <linux/ioctl32.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -1147,6 +1148,67 @@
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+struct serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	__u32 iomem_base;
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
+
+static int serial_struct_ioctl(unsigned fd, unsigned cmd, unsigned long ptr, struct file *f) 
+{
+	typedef struct serial_struct SS;
+	struct serial_struct32 *ss32 = (void *) ptr; 
+	int err;
+	struct serial_struct ss; 
+	mm_segment_t oldseg = get_fs(); 
+	if (cmd == TIOCSSERIAL) { 
+		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
+			return -EFAULT;
+		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
+			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
+		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
+	}
+	set_fs(KERNEL_DS);
+		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+	set_fs(oldseg);
+	if (cmd == TIOCGSERIAL && err >= 0) { 
+		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
+		    __put_user((unsigned long)ss.iomem_base  >> 32 ? 
+			       0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
+			       &ss32->iomem_base) ||
+		    __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
+		    __put_user(ss.port_high, &ss32->port_high))
+			return -EFAULT;
+	} 
+	return err;	
+}
+
+static int __init init_compat(void)
+{
+	register_ioctl32_conversion(TIOCGSERIAL, serial_struct_ioctl);
+	register_ioctl32_conversion(TIOCSSERIAL, serial_struct_ioctl);
+	return 0;
+}
+
+__initcall(init_compat);
+#endif
+
 static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	struct uart_state *state = tty->driver_data;
--- linux.clean/include/linux/ioctl32.h	2003-05-05 15:53:04.000000000 -0700
+++ linux/include/linux/ioctl32.h	2003-05-06 13:58:57.000000000 -0700
@@ -2,9 +2,9 @@
 #define IOCTL32_H 1
 
 struct file;
-
 extern long sys_ioctl(unsigned int, unsigned int, unsigned long);
 
+
 /* 
  * Register an 32bit ioctl translation handler for ioctl cmd.
  *
@@ -14,12 +14,15 @@
  *                        arg: ioctl argument
  *                        struct file *file: file descriptor pointer.
  */ 
+typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
 
 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);
 
-typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
+/* FIXME: several conversions make sense for one cmd depending on
+ * device being used (don't complain, its ioctl, its supposed to be
+ * ugly). Therefore unregisters needs *handler, too.
+ */
 
 struct ioctl_trans {
 	unsigned long cmd;


-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 12:41   ` Pavel Machek
@ 2003-05-07 12:56     ` Christoph Hellwig
  2003-05-07 14:39       ` David S. Miller
  2003-05-07 15:28       ` Pavel Machek
  2003-05-07 13:18     ` Arnd Bergmann
  1 sibling, 2 replies; 39+ messages in thread
From: Christoph Hellwig @ 2003-05-07 12:56 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Arnd Bergmann, linux-kernel

On Wed, May 07, 2003 at 02:41:14PM +0200, Pavel Machek wrote:
> Hi!
> 
> > > Only change *needed* in each architecture is moving A() macros into
> > > compat.h, so that generic code can use it. Please apply,
> > 
> > Please don't use A() in new code, we now have compat_ptr() and
> > compat_uptr_t for this.
> 
> Fixed now.

Btw, if you really want to move all the 32bit ioctl compat code to the
drivers a ->ioctl32 file operation might be the better choice..


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 12:41   ` Pavel Machek
  2003-05-07 12:56     ` Christoph Hellwig
@ 2003-05-07 13:18     ` Arnd Bergmann
  2003-05-07 14:01       ` Carl-Daniel Hailfinger
  2003-05-07 15:16       ` Pavel Machek
  1 sibling, 2 replies; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 13:18 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-kernel

On Wednesday 07 May 2003 14:41, Pavel Machek wrote:
> Hi!
>
> > > Only change *needed* in each architecture is moving A() macros into
> > > compat.h, so that generic code can use it. Please apply,
> >
> > Please don't use A() in new code, we now have compat_ptr() and
> > compat_uptr_t for this.
>
> Fixed now.

Ok. I now noticed there are some more problems that I did not see
at first:

> --- linux.clean/drivers/block/Makefile	2003-05-05 15:49:42.000000000 -0700
> +++ linux/drivers/block/Makefile	2003-05-06 13:53:24.000000000 -0700
> @@ -25,7 +25,7 @@
>  obj-$(CONFIG_BLK_DEV_PS2)	+= ps2esdi.o
>  obj-$(CONFIG_BLK_DEV_XD)	+= xd.o
>  obj-$(CONFIG_BLK_CPQ_DA)	+= cpqarray.o
> -obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.o
> +obj-$(CONFIG_BLK_CPQ_CISS_DA)	+= cciss.o
>  obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o

huh?

> +typedef struct sg_io_hdr32 {
> +	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
> +	s32 dxfer_direction;	/* [i] data transfer direction  */
> +	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
> +	u8  mx_sb_len;		/* [i] max length to write to sbp */
> +	u16 iovec_count;	/* [i] 0 implies no scatter gather */
> +	u32 dxfer_len;		/* [i] byte count of data transfer */
> +	u32 dxferp;		/* [i], [*io] points to data transfer memory
> +					      or scatter gather list */
> +	u32 cmdp;		/* [i], [*i] points to command to perform */
> +	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
> +	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
> +	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
> +	s32 pack_id;		/* [i->o] unused internally (normally) */
> +	u32 usr_ptr;		/* [i->o] unused internally */
> +	u8  status;		/* [o] scsi status */
> +	u8  masked_status;	/* [o] shifted, masked scsi status */
> +	u8  msg_status;		/* [o] messaging level data (optional) */
> +	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
> +	u16 host_status;	/* [o] errors from host adapter */
> +	u16 driver_status;	/* [o] errors from software driver */
> +	s32 resid;		/* [o] dxfer_len - actual_transferred */
> +	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
> +	u32 info;		/* [o] auxiliary information */
> +} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
> +
> +typedef struct sg_iovec32 {
> +	u32 iov_base;
> +	u32 iov_len;
> +} sg_iovec32_t;

These should better be expressed with compat_uptr_t, compat_ulong_t etc.


> +	sg_iovec32_t *uiov = (sg_iovec32_t *) compat_ptr(uptr32);

> +		if (verify_area(VERIFY_WRITE, (void *)compat_ptr(iov_base32),
> kiov->iov_len)) +			return -EFAULT;
> +		kiov->iov_base = (void *)compat_ptr(iov_base32);

You don't need to cast to a pointer when using compat_ptr.


> +static int __init init_compat(void)
> +{
> +	register_ioctl32_conversion(SG_IO, sg_ioctl_trans);
> +	return 0;
> +}
> +
> +__initcall(init_compat);
> +#endif
> +
>  #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
>  #define START_STOP_TIMEOUT		(60 * HZ)
>  #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)

Has anyone solved the register_ioctl32_conversion() from module problem
yet? The patch will break if you build scsi as a module because you
never unregister the conversion helper on unload.
Even if you do the unregister from a module_exit() function, there
will still be a small race against running ioctl handlers. I suppose
we have to add an 'owner' field to struct ioctl_trans in order to
get it right.

> +#ifdef CONFIG_COMPAT
> +struct serial_struct32 {
> +	int	type;
> +	int	line;
> +	unsigned int	port;
> +	int	irq;
> +	int	flags;
> +	int	xmit_fifo_size;
> +	int	custom_divisor;
> +	int	baud_base;
> +	unsigned short	close_delay;
> +	char	io_type;
> +	char	reserved_char[1];
> +	int	hub6;
> +	unsigned short	closing_wait; /* time to wait before closing */
> +	unsigned short	closing_wait2; /* no longer used... */
> +	__u32 iomem_base;
> +	unsigned short	iomem_reg_shift;
> +	unsigned int	port_high;
> +	int	reserved[1];
> +};
see above.

> +		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
you need compat_ptr() for iomem_base as well

> +
> +static int __init init_compat(void)
> +{
> +	register_ioctl32_conversion(TIOCGSERIAL, serial_struct_ioctl);
> +	register_ioctl32_conversion(TIOCSSERIAL, serial_struct_ioctl);
> +	return 0;
> +}
> +
> +__initcall(init_compat);
see above.

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 13:18     ` Arnd Bergmann
@ 2003-05-07 14:01       ` Carl-Daniel Hailfinger
  2003-05-07 15:16       ` Pavel Machek
  1 sibling, 0 replies; 39+ messages in thread
From: Carl-Daniel Hailfinger @ 2003-05-07 14:01 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Pavel Machek, linux-kernel

Arnd Bergmann wrote:
> On Wednesday 07 May 2003 14:41, Pavel Machek wrote:
> 
> Ok. I now noticed there are some more problems that I did not see
> at first:
> 
> 
>>--- linux.clean/drivers/block/Makefile	2003-05-05 15:49:42.000000000 -0700
>>+++ linux/drivers/block/Makefile	2003-05-06 13:53:24.000000000 -0700
>>@@ -25,7 +25,7 @@
>> obj-$(CONFIG_BLK_DEV_PS2)	+= ps2esdi.o
>> obj-$(CONFIG_BLK_DEV_XD)	+= xd.o
>> obj-$(CONFIG_BLK_CPQ_DA)	+= cpqarray.o
>>-obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.o
>>+obj-$(CONFIG_BLK_CPQ_CISS_DA)	+= cciss.o
>> obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o
> 
> 
> huh?

Tab vs. spaces


Carl-Daniel


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 15:12         ` Jeff Garzik
@ 2003-05-07 14:07           ` David S. Miller
  0 siblings, 0 replies; 39+ messages in thread
From: David S. Miller @ 2003-05-07 14:07 UTC (permalink / raw)
  To: jgarzik; +Cc: hch, pavel, arnd, linux-kernel

   From: Jeff Garzik <jgarzik@pobox.com>
   Date: Wed, 7 May 2003 11:12:03 -0400

   On Wed, May 07, 2003 at 07:39:00AM -0700, David S. Miller wrote:
   > On Wed, 2003-05-07 at 05:56, Christoph Hellwig wrote:
   > > Btw, if you really want to move all the 32bit ioctl compat code to the
   > > drivers a ->ioctl32 file operation might be the better choice..
   > 
   > I can't believe I never thought of that. :-)
   
   Likewise.  That's a good idea...
   
But, of course, name it compat_ioctl() not ioctl32.  The compat layer
is not only about 32-bit compatibility even though that is all that it
is used for currently.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 12:56     ` Christoph Hellwig
@ 2003-05-07 14:39       ` David S. Miller
  2003-05-07 15:12         ` Jeff Garzik
                           ` (3 more replies)
  2003-05-07 15:28       ` Pavel Machek
  1 sibling, 4 replies; 39+ messages in thread
From: David S. Miller @ 2003-05-07 14:39 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Pavel Machek, Arnd Bergmann, linux-kernel

On Wed, 2003-05-07 at 05:56, Christoph Hellwig wrote:
> Btw, if you really want to move all the 32bit ioctl compat code to the
> drivers a ->ioctl32 file operation might be the better choice..

I can't believe I never thought of that. :-)

-- 
David S. Miller <davem@redhat.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 14:39       ` David S. Miller
@ 2003-05-07 15:12         ` Jeff Garzik
  2003-05-07 14:07           ` David S. Miller
  2003-05-08 10:46         ` Gerd Knorr
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2003-05-07 15:12 UTC (permalink / raw)
  To: David S. Miller
  Cc: Christoph Hellwig, Pavel Machek, Arnd Bergmann, linux-kernel

On Wed, May 07, 2003 at 07:39:00AM -0700, David S. Miller wrote:
> On Wed, 2003-05-07 at 05:56, Christoph Hellwig wrote:
> > Btw, if you really want to move all the 32bit ioctl compat code to the
> > drivers a ->ioctl32 file operation might be the better choice..
> 
> I can't believe I never thought of that. :-)

Likewise.  That's a good idea...

	Jeff




^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 13:18     ` Arnd Bergmann
  2003-05-07 14:01       ` Carl-Daniel Hailfinger
@ 2003-05-07 15:16       ` Pavel Machek
  2003-05-07 15:46         ` Arnd Bergmann
  1 sibling, 1 reply; 39+ messages in thread
From: Pavel Machek @ 2003-05-07 15:16 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel

Hi!

> > +typedef struct sg_io_hdr32 {
> > +	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
> > +	s32 dxfer_direction;	/* [i] data transfer direction  */
> > +	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
> > +	u8  mx_sb_len;		/* [i] max length to write to sbp */
> > +	u16 iovec_count;	/* [i] 0 implies no scatter gather */
> > +	u32 dxfer_len;		/* [i] byte count of data transfer */
> > +	u32 dxferp;		/* [i], [*io] points to data transfer memory
> > +					      or scatter gather list */
> > +	u32 cmdp;		/* [i], [*i] points to command to perform */
> > +	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
> > +	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
> > +	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
> > +	s32 pack_id;		/* [i->o] unused internally (normally) */
> > +	u32 usr_ptr;		/* [i->o] unused internally */
> > +	u8  status;		/* [o] scsi status */
> > +	u8  masked_status;	/* [o] shifted, masked scsi status */
> > +	u8  msg_status;		/* [o] messaging level data (optional) */
> > +	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
> > +	u16 host_status;	/* [o] errors from host adapter */
> > +	u16 driver_status;	/* [o] errors from software driver */
> > +	s32 resid;		/* [o] dxfer_len - actual_transferred */
> > +	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
> > +	u32 info;		/* [o] auxiliary information */
> > +} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
> > +
> > +typedef struct sg_iovec32 {
> > +	u32 iov_base;
> > +	u32 iov_len;
> > +} sg_iovec32_t;
> 
> These should better be expressed with compat_uptr_t, compat_ulong_t etc.
> 
> 
> > +	sg_iovec32_t *uiov = (sg_iovec32_t *) compat_ptr(uptr32);
> 
> > +		if (verify_area(VERIFY_WRITE, (void *)compat_ptr(iov_base32),
> > kiov->iov_len)) +			return -EFAULT;
> > +		kiov->iov_base = (void *)compat_ptr(iov_base32);
> 
> You don't need to cast to a pointer when using compat_ptr.

I thought so. I originally wanted as clean move as possible. I'll fix it.

> > +static int __init init_compat(void)
> > +{
> > +	register_ioctl32_conversion(SG_IO, sg_ioctl_trans);
> > +	return 0;
> > +}
> > +
> > +__initcall(init_compat);
> > +#endif
> > +
> >  #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
> >  #define START_STOP_TIMEOUT		(60 * HZ)
> >  #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
> 
> Has anyone solved the register_ioctl32_conversion() from module problem
> yet? The patch will break if you build scsi as a module because you
> never unregister the conversion helper on unload.
> Even if you do the unregister from a module_exit() function, there
> will still be a small race against running ioctl handlers. I suppose
> we have to add an 'owner' field to struct ioctl_trans in order to
> get it right.

Its in drivers/block/scsi_ioctl.c. AFAICS, its always compiled in, so
I'm not hitting that problem *yet*.

> > +#ifdef CONFIG_COMPAT
> > +struct serial_struct32 {
> > +	int	type;
> > +	int	line;
> > +	unsigned int	port;
> > +	int	irq;
> > +	int	flags;
> > +	int	xmit_fifo_size;
> > +	int	custom_divisor;
> > +	int	baud_base;
> > +	unsigned short	close_delay;
> > +	char	io_type;
> > +	char	reserved_char[1];
> > +	int	hub6;
> > +	unsigned short	closing_wait; /* time to wait before closing */
> > +	unsigned short	closing_wait2; /* no longer used... */
> > +	__u32 iomem_base;
> > +	unsigned short	iomem_reg_shift;
> > +	unsigned int	port_high;
> > +	int	reserved[1];
> > +};
> see above.
> 
> > +		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
> you need compat_ptr() for iomem_base as well

Its not pointer, AFAICS (at least it can not be dereferenced by
userspace).
								Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 12:56     ` Christoph Hellwig
  2003-05-07 14:39       ` David S. Miller
@ 2003-05-07 15:28       ` Pavel Machek
  2003-05-07 16:04         ` David S. Miller
  1 sibling, 1 reply; 39+ messages in thread
From: Pavel Machek @ 2003-05-07 15:28 UTC (permalink / raw)
  To: Christoph Hellwig, Pavel Machek, Arnd Bergmann, linux-kernel

Hi!

> > > > Only change *needed* in each architecture is moving A() macros into
> > > > compat.h, so that generic code can use it. Please apply,
> > > 
> > > Please don't use A() in new code, we now have compat_ptr() and
> > > compat_uptr_t for this.
> > 
> > Fixed now.
> 
> Btw, if you really want to move all the 32bit ioctl compat code to the
> drivers a ->ioctl32 file operation might be the better choice..

Not sure if we are not too close to stable release to do that? And I
see no incremental way how to get there. Moving compatibility stuff
closer to drivers can be done close to stable release...

OTOH it forces pain where it belongs, and when someone invents stupid
ioctl, it puts pain on him... I like that.

								Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 15:16       ` Pavel Machek
@ 2003-05-07 15:46         ` Arnd Bergmann
  2003-05-07 16:07           ` Jens Axboe
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 15:46 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-kernel

On Wednesday 07 May 2003 17:16, Pavel Machek wrote:

> > Has anyone solved the register_ioctl32_conversion() from module problem
> > yet? The patch will break if you build scsi as a module because you
> > never unregister the conversion helper on unload.
> > Even if you do the unregister from a module_exit() function, there
> > will still be a small race against running ioctl handlers. I suppose
> > we have to add an 'owner' field to struct ioctl_trans in order to
> > get it right.
>
> Its in drivers/block/scsi_ioctl.c. AFAICS, its always compiled in, so
> I'm not hitting that problem *yet*.

No, it has indeed been possible to build scsi as a module for a long
time and in that case, scsi_ioctl becomes part of that module. The same 
problem also exists for any user of register_ioctl32_conversion(), e.g.
ieee1394.

> > > +		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
> >
> > you need compat_ptr() for iomem_base as well
>
> Its not pointer, AFAICS (at least it can not be dereferenced by
> userspace).

Right, it appears to be a physical address, which therefore would require
a new mapping macro to be really correct. If this were used on s390, that
macro would be the same as compat_ptr(), the other architectures probably 
need a simple cast (again, like compat_ptr()). Either of 1. new macro, 2.
compat_ptr() or 3. the existing code works correctly here, so just do
whichever you prefer. Maybe somebody else has a strong opinion on it.

	Arnd <><



^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 15:28       ` Pavel Machek
@ 2003-05-07 16:04         ` David S. Miller
  2003-05-07 19:13           ` Arnd Bergmann
  2003-05-08 20:33           ` Pavel Machek
  0 siblings, 2 replies; 39+ messages in thread
From: David S. Miller @ 2003-05-07 16:04 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Christoph Hellwig, Arnd Bergmann, linux-kernel

On Wed, 2003-05-07 at 08:28, Pavel Machek wrote:
> Not sure if we are not too close to stable release to do that? And I
> see no incremental way how to get there. Moving compatibility stuff
> closer to drivers can be done close to stable release...

You can define it as follows:

1) If entry exists in COMPAT or TRANSLATE table, invoke
   fops->ioctl(), else

2) If ->compat_ioctl() exists, invoke that, else

3) Fail.

The COMPAT tables are sort of valuable, in that it eliminates
the need to duplicate code when all of a drivers ioctls need
no translation.

BTW, need to extend this to netdev->do_ioctl as well for the
handling of SIOCDEVPRIVATE based stuff.  Oh goody, we can finally
fix up that crap :))))

-- 
David S. Miller <davem@redhat.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 15:46         ` Arnd Bergmann
@ 2003-05-07 16:07           ` Jens Axboe
  2003-05-07 16:20             ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Jens Axboe @ 2003-05-07 16:07 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Pavel Machek, linux-kernel

On Wed, May 07 2003, Arnd Bergmann wrote:
> On Wednesday 07 May 2003 17:16, Pavel Machek wrote:
> 
> > > Has anyone solved the register_ioctl32_conversion() from module problem
> > > yet? The patch will break if you build scsi as a module because you
> > > never unregister the conversion helper on unload.
> > > Even if you do the unregister from a module_exit() function, there
> > > will still be a small race against running ioctl handlers. I suppose
> > > we have to add an 'owner' field to struct ioctl_trans in order to
> > > get it right.
> >
> > Its in drivers/block/scsi_ioctl.c. AFAICS, its always compiled in, so
> > I'm not hitting that problem *yet*.
> 
> No, it has indeed been possible to build scsi as a module for a long
> time and in that case, scsi_ioctl becomes part of that module. The same 
> problem also exists for any user of register_ioctl32_conversion(), e.g.
> ieee1394.

drivers/block/scsi_ioctl.c is not part of the scsi layer, it provides
generic SG_IO functionality for scsi-like block drivers.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 16:07           ` Jens Axboe
@ 2003-05-07 16:20             ` Arnd Bergmann
  0 siblings, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 16:20 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Pavel Machek, linux-kernel

On Wednesday 07 May 2003 18:07, Jens Axboe wrote:
> On Wed, May 07 2003, Arnd Bergmann wrote:
> > No, it has indeed been possible to build scsi as a module for a long
> > time and in that case, scsi_ioctl becomes part of that module. The same
> > problem also exists for any user of register_ioctl32_conversion(), e.g.
> > ieee1394.
>
> drivers/block/scsi_ioctl.c is not part of the scsi layer, it provides
> generic SG_IO functionality for scsi-like block drivers.

Ok, sorry about the confusion. I was thinking of drivers/scsi/scsi_ioctl.c
all the time. However, the problem I meant is still present in the patch
for drivers/serial/core.c, which does get built as a module, and potentially
in any other module. Note that the whole purpose of
register_ioctl32_conversion() is to be able to put the wrappers in modules:
If you put your wrapper function in a file that is never a module, you
can simply put HANDLE_IOCTL(FOO, compat_foo) in include/linux/compat_ioctl.h.

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 19:13           ` Arnd Bergmann
@ 2003-05-07 18:12             ` David S. Miller
  2003-05-07 23:50               ` Arnd Bergmann
  2003-05-07 22:20             ` Alan Cox
  1 sibling, 1 reply; 39+ messages in thread
From: David S. Miller @ 2003-05-07 18:12 UTC (permalink / raw)
  To: arnd; +Cc: pavel, hch, linux-kernel

   From: Arnd Bergmann <arnd@arndb.de>
   Date: Wed, 7 May 2003 21:13:07 +0200

   Btw: is there any bit in the ioctl number definition that can
   be (ab)used for compat_ioctl?

Unfortunately no.  All the bits are used in order to allow
the size field of the encoding to be as large as possible.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 16:04         ` David S. Miller
@ 2003-05-07 19:13           ` Arnd Bergmann
  2003-05-07 18:12             ` David S. Miller
  2003-05-07 22:20             ` Alan Cox
  2003-05-08 20:33           ` Pavel Machek
  1 sibling, 2 replies; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 19:13 UTC (permalink / raw)
  To: David S. Miller, Pavel Machek; +Cc: Christoph Hellwig, linux-kernel

On Wednesday 07 May 2003 18:04, David S. Miller wrote:
> You can define it as follows:
>
> 1) If entry exists in COMPAT or TRANSLATE table, invoke
>    fops->ioctl(), else
>
> 2) If ->compat_ioctl() exists, invoke that, else
>
> 3) Fail.

Another solution could be to use the tables only if
->compat_ioctl() is undefined or returned -ENOTTY. That
would save the hash table lookup in many cases and makes
it possible for a driver to override a generic handler
with its more specialized version (e.g. CIODEVPRIVATE).

> The COMPAT tables are sort of valuable, in that it eliminates
> the need to duplicate code when all of a drivers ioctls need
> no translation.

Right. Of course you can just as well do 

	.ioctl = &foo_ioctl,
	.compat_ioctl = &foo_ioctl,

in that case.

Btw: is there any bit in the ioctl number definition that can
be (ab)used for compat_ioctl? Maybe we don't even need another
callback if the compatibility mode can be encoded in the
number itself (simplified):

long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
	unsigned long arg)
{
	long err = sys_ioctl(fd, cmd | _IOC_COMPAT, arg);
	if (err == -ENOTTY) /* use ioctl_trans table */
		err = compat_do_ioctl(fd, cmd, arg);
	return err;
}
...
long foo_ioctl(struct inode * inode, struct file * filp,
		unsigned int cmd, unsigned long arg)
{
	switch(cmd) {
	case SOMEIOCTL:
		return do_something(inode, arg);
	case SOMEIOCTL | _IOC_COMPAT:
		return compat_do_something(inode, arg);
	case ANOTHERIOCTL:
	case ANOTHERIOCTL | _IOC_COMPAT:	
		return do_something_else(inode, arg);
	}
	return -ENOTTY;
}

	Arnd <><	

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 19:13           ` Arnd Bergmann
  2003-05-07 18:12             ` David S. Miller
@ 2003-05-07 22:20             ` Alan Cox
  1 sibling, 0 replies; 39+ messages in thread
From: Alan Cox @ 2003-05-07 22:20 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: David S. Miller, Pavel Machek, Christoph Hellwig,
	Linux Kernel Mailing List

On Mer, 2003-05-07 at 20:13, Arnd Bergmann wrote:
> Another solution could be to use the tables only if
> ->compat_ioctl() is undefined or returned -ENOTTY. That

We have magic -ENOIOCTLCMD type returns never meant for user space to
handle that ambiguity


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 18:12             ` David S. Miller
@ 2003-05-07 23:50               ` Arnd Bergmann
  2003-05-08 10:35                 ` David S. Miller
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-07 23:50 UTC (permalink / raw)
  To: David S. Miller; +Cc: pavel, hch, linux-kernel

On Wednesday 07 May 2003 20:12, David S. Miller wrote:
>    From: Arnd Bergmann <arnd@arndb.de>
>    Date: Wed, 7 May 2003 21:13:07 +0200
>
>    Btw: is there any bit in the ioctl number definition that can
>    be (ab)used for compat_ioctl?
>
> Unfortunately no.  All the bits are used in order to allow
> the size field of the encoding to be as large as possible.

I checked the numbers that are in arch/sparc64/kernel/ioctl32.o
and found none that uses more than 9 bits for the size field,
while every architecture has at least 13 bits space. There may
of course be other ioctls that can not live with 12 bit size
fields and it's probably a bad idea to require special-casing
these in the compat code.

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 23:50               ` Arnd Bergmann
@ 2003-05-08 10:35                 ` David S. Miller
  0 siblings, 0 replies; 39+ messages in thread
From: David S. Miller @ 2003-05-08 10:35 UTC (permalink / raw)
  To: arnd; +Cc: pavel, hch, linux-kernel

   From: Arnd Bergmann <arnd@arndb.de>
   Date: Thu, 8 May 2003 01:50:10 +0200
   
   I checked the numbers that are in arch/sparc64/kernel/ioctl32.o
   and found none that uses more than 9 bits for the size field,

I know that we had to change our sparc ioctl macro definitions a few
months ago to accomodate some ioctl that wanted more bits.

It isn't a theoretical problem.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 14:39       ` David S. Miller
  2003-05-07 15:12         ` Jeff Garzik
@ 2003-05-08 10:46         ` Gerd Knorr
  2003-05-08 15:16         ` Ben Collins
  2003-05-08 15:23         ` Arnd Bergmann
  3 siblings, 0 replies; 39+ messages in thread
From: Gerd Knorr @ 2003-05-08 10:46 UTC (permalink / raw)
  To: linux-kernel

"David S. Miller" <davem@redhat.com> writes:

> On Wed, 2003-05-07 at 05:56, Christoph Hellwig wrote:
> > Btw, if you really want to move all the 32bit ioctl compat code to the
> > drivers a ->ioctl32 file operation might be the better choice..
> 
> I can't believe I never thought of that. :-)

Why ->ioctl32()?  Wouldn't ->ioctl() work equally well?  That assumes
that ioctls which need translation have different numbers through.
Not sure whenever this is a problem, but most ioctls which need
translation need this due to different field sizes.  Thus the total
ioctl struct size and the ioctl number (which has the size encoded)
should end up being different too.  Anyone aware of corner cases where
this isn't going to work?

I ran into this compat issue while porting my scsi media changer
driver to 2.5 and I decided to register the one ioctl which needs
translation as "compatible" and handle the issue within the ->ioctl
handler of the driver.  Patch below, untested, grep for
"CONFIG_COMPAT" to find the intresting places.  Comments welcome.

Oh, and maybe move the ioctl compat lists stuff into modutils?  So you
just have some magic macros (like EXPORT_SYMBOL + friends) where you
list your drivers ioctls and they will be registered/unregistered
automagically at boot/insmod/rmmod time?

  Gerd

diff -u linux-2.5.69/Documentation/scsi-changer.txt linux/Documentation/scsi-changer.txt
--- linux-2.5.69/Documentation/scsi-changer.txt	2003-05-08 11:03:21.000000000 +0200
+++ linux/Documentation/scsi-changer.txt	2003-05-08 11:03:21.000000000 +0200
@@ -0,0 +1,184 @@
+
+README for the SCSI media changer driver
+========================================
+
+This is a driver for SCSI Medium Changer devices, which are listed
+with "Type: Medium Changer" in /proc/scsi/scsi.
+
+This is for *real* Jukeboxes.  It is *not* supported to work with
+common small CD-ROM changers, neither one-lun-per-slot SCSI changers
+nor IDE drives.
+
+Userland tools available from: http://bytesex.org/changer.html
+
+
+General Information
+-------------------
+
+First some words about how changers work: A changer has 2 (possibly
+more) SCSI ID's. One for the changer device which controls the robot,
+and one for the device which actually reads and writes the data. The
+later may be anything, a MOD, a CD-ROM, a tape or whatever. For the
+changer device this is a "don't care", he *only* shuffles around the
+media, nothing else.
+
+
+The SCSI changer model is complex, compared to - for example - IDE-CD
+changers. But it allows to handle nearly all possible cases. It knows
+4 different types of changer elements:
+
+  media transport - this one shuffles around the media, i.e. the
+                    transport arm.  Also known as "picker".
+  storage         - a slot which can hold a media.
+  import/export   - the same as above, but is accessable from outside,
+                    i.e. there the operator (you !) can use this to
+                    fill in and remove media from the changer.
+		    Sometimes named "mailslot".
+  data transfer   - this is the device which reads/writes, i.e. the
+		    CD-ROM / Tape / whatever drive.
+
+None of these is limited to one: A huge Jukebox could have slots for
+123 CD-ROM's, 5 CD-ROM readers (and therefore 6 SCSI ID's: the changer
+and each CD-ROM) and 2 transport arms. No problem to handle.
+
+
+How it is implemented
+---------------------
+
+I implemented the driver as character device driver with a NetBSD-like
+ioctl interface. Just grabbed NetBSD's header file and one of the
+other linux SCSI device drivers as starting point. The interface
+should be source code compatible with NetBSD. So if there is any
+software (anybody knows ???) which supports a BSDish changer driver,
+it should work with this driver too.
+
+Over time a few more ioctls where added, volume tag support for example
+wasn't covered by the NetBSD ioctl API.
+
+
+Current State
+-------------
+
+Support for more than one transport arm is not implemented yet (and
+nobody asked for it so far...).
+
+I test and use the driver myself with a 35 slot cdrom jukebox from
+Grundig.  I got some reports telling it works ok with tape autoloaders
+(Exabyte, HP and DEC).  Some People use this driver with amanda.  It
+works fine with small (11 slots) and a huge (4 MOs, 88 slots)
+magneto-optical Jukebox.  Probably with lots of other changers too, most
+(but not all :-) people mail me only if it does *not* work...
+
+I don't have any device lists, neither black-list nor white-list.  Thus
+it is quite useless to ask me whenever a specific device is supported or
+not.  In theory every changer device which supports the SCSI-2 media
+changer command set should work out-of-the-box with this driver.  If it
+doesn't, it is a bug.  Either within the driver or within the firmware
+of the changer device.
+
+
+Using it
+--------
+
+This is a character device with major number is 86, so use
+"mknod /dev/sch0 c 86 0" to create the special file for the driver.
+
+If the module finds the changer, it prints some messages about the
+device [ try "dmesg" if you don't see anything ] and should show up in
+/proc/devices. If not....  some changers use ID ? / LUN 0 for the
+device and ID ? / LUN 1 for the robot mechanism. But Linux does *not*
+look for LUN's other than 0 as default, becauce there are to many
+broken devices. So you can try:
+
+  1) echo "scsi add-single-device 0 0 ID 1" > /proc/scsi/scsi
+     (replace ID with the SCSI-ID of the device)
+  2) boot the kernel with "max_scsi_luns=1" on the command line
+     (append="max_scsi_luns=1" in lilo.conf should do the trick)
+
+
+Trouble?
+--------
+
+If you insmod the driver with "insmod debug=1", it will be verbose and
+prints a lot of stuff to the syslog.  Compiling the kernel with
+CONFIG_SCSI_CONSTANTS=y improves the quality of the error messages alot
+because the kernel will translate the error codes into human-readable
+strings then.
+
+You can display these messages with the dmesg command (or check the
+logfiles).  If you email me some question becauce of a problem with the
+driver, please include these messages.
+
+
+Insmod options
+--------------
+
+debug=0/1
+	Enable debug messages (see above, default: 0).
+
+verbose=0/1
+	Be verbose (default: 1).
+
+init=0/1
+	Send INITIALIZE ELEMENT STATUS command to the changer
+	at insmod time (default: 1).
+
+check_busy=0/1
+	When moving media from/to data transfer elements, check
+	whenever the device is busy and refuse to move if so
+	(default: 1).
+
+timeout_init=<seconds>
+	timeout for the INITIALIZE ELEMENT STATUS command
+	(default: 3600).
+
+timeout_move=<seconds>
+	timeout for all other commands (default: 120).
+
+dt_id=<id1>,<id2>,...
+dt_lun=<lun1>,<lun2>,...
+	These two allow to specify the SCSI ID and LUN for the data
+	transfer elements.  You likely don't need this as the jukebox
+	should provide this information.  But some devices don't ...
+
+vendor_firsts=
+vendor_counts=
+vendor_labels=
+	These insmod options can be used to tell the driver that there
+	are some vendor-specific element types.  Grundig for example
+	does this.  Some jukeboxes have a printer to label fresh burned
+	CDs, which is addressed as element 0xc000 (type 5).  To tell the
+	driver about this vendor-specific element, use this:
+		$ insmod ch			\
+			vendor_firsts=0xc000	\
+			vendor_counts=1		\
+			vendor_labels=printer
+	All three insmod options accept up to four comma-separated
+	values, this way you can configure the element types 5-8.
+	You likely need the SCSI specs for the device in question to
+	find the correct values as they are not covered by the SCSI-2
+	standard.
+
+
+Credits
+-------
+
+I wrote this driver using the famous mailing-patches-around-the-world
+method.  With (more or less) help from:
+
+	Daniel Moehwald <moehwald@hdg.de>
+	Dane Jasper <dane@sonic.net>
+	R. Scott Bailey <sbailey@dsddi.eds.com>
+	Jonathan Corbet <corbet@atd.ucar.edu>
+
+Special thanks go to
+	Martin Kuehne <Martin.KUEHNE@GRUNDIG.com>
+for a old, second-hand (but full functional) cdrom jukebox which I use
+to develop/test driver and tools now.
+
+Have fun,
+
+   Gerd
+
+-- 
+Gerd Knorr <kraxel@bytesex.org>
diff -u linux-2.5.69/drivers/scsi/Kconfig linux/drivers/scsi/Kconfig
--- linux-2.5.69/drivers/scsi/Kconfig	2003-05-08 11:01:34.000000000 +0200
+++ linux/drivers/scsi/Kconfig	2003-05-08 11:03:21.000000000 +0200
@@ -111,6 +111,24 @@
 	  <file:Documentation/scsi/scsi.txt>. The module will be called sg.
 	  If unsure, say N.
 
+config CHR_DEV_SCH
+	tristate "SCSI media changer support"
+	depends on SCSI
+	---help---
+	  This is a driver for SCSI media changers.  Most common devices are
+	  tape libraries and MOD/CDROM jukeboxes.  *Real* jukeboxes, you
+	  don't need this for those tiny 6-slot cdrom changers.  Media
+	  changers are listed as "Type: Medium Changer" in /proc/scsi/scsi.
+	  If you have such hardware and want to use it with linux, say Y
+	  here.  Check <file:Documentation/scsi-changer.txt> for details.
+	
+	  If you want to compile this as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt> and
+	  <file:Documentation/scsi.txt>. The module will be called ch.o.
+	  If unsure, say N.
+	
+
 comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
 	depends on SCSI
 
diff -u linux-2.5.69/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux-2.5.69/drivers/scsi/Makefile	2003-05-08 11:01:30.000000000 +0200
+++ linux/drivers/scsi/Makefile	2003-05-08 11:03:21.000000000 +0200
@@ -121,6 +121,7 @@
 obj-$(CONFIG_BLK_DEV_SD)	+= sd_mod.o
 obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
+obj-$(CONFIG_CHR_DEV_SCH)	+= ch.o
 
 scsi_mod-y			+= scsi.o hosts.o scsi_ioctl.o constants.o \
 				   scsicam.o scsi_error.o scsi_lib.o \
diff -u linux-2.5.69/drivers/scsi/ch.c linux/drivers/scsi/ch.c
--- linux-2.5.69/drivers/scsi/ch.c	2003-05-08 11:03:21.000000000 +0200
+++ linux/drivers/scsi/ch.c	2003-05-08 12:07:25.000000000 +0200
@@ -0,0 +1,1097 @@
+/*
+ * SCSI Media Changer device driver for Linux 2.6
+ *
+ *     (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
+ *
+ */
+
+#define VERSION "0.22"
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/blk.h>
+#include <linux/completion.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ioctl32.h>
+#include <linux/compat.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/chio.h>			/* here are all the ioctls */
+
+#define MAJOR_NR	SCSI_CHANGER_MAJOR
+
+#define CH_DT_MAX       16
+#define CH_TYPES        8
+
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+
+MODULE_SUPPORTED_DEVICE("sch");
+MODULE_DESCRIPTION("device driver for scsi media changer devices");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
+MODULE_LICENSE("GPL");
+
+static int check_busy = 1;
+MODULE_PARM(check_busy,"i");
+MODULE_PARM_DESC(check_busy, \
+    "enable/disable busy check for data transfer elements (default: on)");
+
+static int init = 1;
+MODULE_PARM(init,"i");
+MODULE_PARM_DESC(init, \
+    "initialize element status on driver load (default: on)");
+
+static int timeout_move = 300;
+MODULE_PARM(timeout_move,"i");
+MODULE_PARM_DESC(timeout_move,"timeout for move commands "
+		 "(default: 300 seconds)");
+
+static int timeout_init = 3600;
+MODULE_PARM(timeout_init,"i");
+MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS "
+		 "(default: 3600 seconds)");
+
+static int verbose = 1;
+MODULE_PARM(verbose,"i");
+MODULE_PARM_DESC(verbose,"be verbose (default: on)");
+
+static int debug = 0;
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more "
+		 "detailed sense codes on scsi errors (default: off)");
+
+static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
+static int dt_lun[CH_DT_MAX];
+MODULE_PARM(dt_id,"1-" __MODULE_STRING(CH_DT_MAX) "i");
+MODULE_PARM(dt_lun,"1-" __MODULE_STRING(CH_DT_MAX) "i");
+
+/* tell the driver about vendor-specific slots */
+static int vendor_firsts[CH_TYPES-4];
+static int vendor_counts[CH_TYPES-4];
+static char *vendor_labels[CH_TYPES-4];
+MODULE_PARM(vendor_firsts,"1-4i");
+MODULE_PARM(vendor_counts,"1-4i");
+MODULE_PARM(vendor_labels,"1-4s");
+
+#define dprintk(fmt, arg...)    if (debug) \
+        printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg)
+#define vprintk(fmt, arg...)    if (verbose) \
+        printk(KERN_INFO "%s: " fmt, ch->name, ##arg)
+
+/* ------------------------------------------------------------------- */
+
+#define MAX_RETRIES   1
+
+static int  ch_attach(Scsi_Device *);
+static void ch_detach(Scsi_Device *);
+static int  ch_open(struct inode * inode, struct file * filp);
+static int  ch_release(struct inode * inode, struct file * filp);
+static int  ch_ioctl(struct inode * inode, struct file * filp,
+		     unsigned int cmd, unsigned long arg);
+
+typedef struct {
+	struct list_head    list;
+	int                 minor;
+	char                name[8];
+	Scsi_Device  	    *device;
+	Scsi_Device         **dt;        /* ptrs to data transfer elements */
+	u_int               firsts[CH_TYPES];
+	u_int               counts[CH_TYPES];
+	u_int               unit_attention;
+	u_int		    voltags;
+	struct semaphore    lock;
+} scsi_changer;
+
+static LIST_HEAD(ch_devlist);
+static spinlock_t ch_devlist_lock = SPIN_LOCK_UNLOCKED;
+static int ch_devcount;
+
+struct Scsi_Device_Template ch_template =
+{
+	.module     = THIS_MODULE,
+	.list       = LIST_HEAD_INIT(ch_template.list),
+	.name       = "media changer",
+	.scsi_type  = TYPE_MEDIUM_CHANGER,
+	.attach     = ch_attach,
+	.detach     = ch_detach,
+	.scsi_driverfs_driver = {
+		.name = "ch",
+	},
+};
+
+static struct file_operations changer_fops =
+{
+	.owner      = THIS_MODULE,
+	.open       = ch_open,
+	.release    = ch_release,
+	.ioctl      = ch_ioctl,
+};
+
+static struct {
+	unsigned char  sense;
+	unsigned char  asc;
+	unsigned char  ascq;
+	int	       errno;
+} err[] = {
+/* Just filled in what looks right. Hav'nt checked any standard paper for
+   these errno assignments, so they may be wrong... */
+	{
+		.sense  = ILLEGAL_REQUEST,
+		.asc    = 0x21,
+		.ascq   = 0x01,
+		.errno  = EBADSLT, /* Invalid element address */
+	},{
+		.sense  = ILLEGAL_REQUEST,
+		.asc    = 0x28,
+		.ascq   = 0x01,
+		.errno  = EBADE,   /* Import or export element accessed */
+	},{
+		.sense  = ILLEGAL_REQUEST,
+		.asc    = 0x3B,
+		.ascq   = 0x0D,
+		.errno  = EXFULL,  /* Medium destination element full */
+	},{
+		.sense  = ILLEGAL_REQUEST,
+		.asc    = 0x3B,
+		.ascq   = 0x0E,
+		.errno  = EBADE,   /* Medium source element empty */
+	},{
+		.sense  = ILLEGAL_REQUEST,
+		.asc    = 0x20,
+		.ascq   = 0x00,
+		.errno  = EBADRQC, /* Invalid command operation code */
+	},{
+	        /* end of list */
+	}
+};
+
+/* ------------------------------------------------------------------- */
+/* ioctl32 compat                                                      */
+
+#ifdef CONFIG_COMPAT
+
+struct changer_element_status32 {
+	int		ces_type;
+	compat_uptr_t	ces_data;
+};
+#define CHIOGSTATUS32  _IOW('c', 8,struct changer_element_status32)
+
+static struct {
+	unsigned int cmd;
+	int          reg;
+} ioctl32_cmds[] = {
+	{ .cmd = CHIOMOVE      },
+	{ .cmd = CHIOEXCHANGE  },
+	{ .cmd = CHIOPOSITION  },
+	{ .cmd = CHIOGPICKER   },
+	{ .cmd = CHIOSPICKER   },
+	{ .cmd = CHIOGPARAMS   },
+	{ .cmd = CHIOGELEM     },
+	{ .cmd = CHIOINITELEM  },
+	{ .cmd = CHIOSVOLTAG   },
+	{ .cmd = CHIOGVPARAMS  },
+	{ .cmd = CHIOGSTATUS32 },
+};
+
+static int ioctl32_register(void)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(ioctl32_cmds); i++) {
+		err = register_ioctl32_conversion(ioctl32_cmds[i].cmd,NULL);
+		if (err >= 0)
+			ioctl32_cmds[i].reg++;
+	}
+	return 0;
+}
+static int ioctl32_unregister(void)
+{
+	unsigned int i;
+	
+	for (i = 0; i < ARRAY_SIZE(ioctl32_cmds); i++) {
+		if (ioctl32_cmds[i].reg) {
+			unregister_ioctl32_conversion(ioctl32_cmds[i].cmd);
+			ioctl32_cmds[i].reg--;
+		}
+	}
+	return 0;
+}
+
+#else
+
+static int ioctl32_register(void)   { return 0; }
+static int ioctl32_unregister(void) { return 0; }
+
+#endif
+
+/* ------------------------------------------------------------------- */
+
+static int ch_find_errno(unsigned char *sense_buffer)
+{
+	int i,errno = 0;
+
+	/* Check to see if additional sense information is available */
+	if (sense_buffer[7]  > 5 &&
+	    sense_buffer[12] != 0) {
+		for (i = 0; err[i].errno != 0; i++) {
+			if (err[i].sense == sense_buffer[ 2] &&
+			    err[i].asc   == sense_buffer[12] &&
+			    err[i].ascq  == sense_buffer[13]) {
+				errno = -err[i].errno;
+				break;
+			}
+		}
+	}
+	if (errno == 0)
+		errno = -EIO;
+	return errno;
+}
+
+static void
+ch_request_done (Scsi_Cmnd * sc)
+{
+	sc->request->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
+        if (sc->request->waiting != NULL)
+		complete(sc->request->waiting);
+}
+
+static int
+ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
+	   void *buffer, unsigned buflength)
+{
+	int errno, retries = 0, timeout;
+	DECLARE_COMPLETION(wait);
+	Scsi_Request *sr;
+	
+	sr = scsi_allocate_request(ch->device);
+	if (NULL == sr)
+		return -ENOMEM;
+
+ retry:
+	errno = 0;
+	if (debug) {
+		dprintk("command: %s","");
+		print_command(cmd);
+	}
+
+	sr->sr_request->waiting = &wait;
+	timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
+		? timeout_init : timeout_move;
+	scsi_do_req(sr, cmd, buffer, buflength, ch_request_done,
+		    timeout * HZ, MAX_RETRIES);
+	wait_for_completion(&wait);
+	sr->sr_request->waiting = NULL;
+
+	dprintk("result: 0x%x\n",sr->sr_result);
+	if (driver_byte(sr->sr_result) != 0) {
+		if (debug)
+			print_req_sense(ch->name, sr);
+		errno = ch_find_errno(sr->sr_sense_buffer);
+
+		switch(sr->sr_sense_buffer[2] & 0xf) {
+		case UNIT_ATTENTION:
+			ch->unit_attention = 1;
+			if (retries++ < 3)
+				goto retry;
+			break;
+		}
+	}
+	scsi_release_request(sr);
+	return errno;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static Scsi_Device*
+find_device(struct Scsi_Host *host, u_char channel, u_char id, u_char lun)
+{
+	struct list_head *item;
+	Scsi_Device *device;
+
+	list_for_each(item,&host->my_devices) {
+		device = list_entry(item, Scsi_Device, siblings);
+		if (device->channel == channel &&
+		    device->id      == id      &&
+		    device->lun     == lun)
+			return device;
+	}
+	return NULL;
+}
+
+static int
+ch_elem_to_typecode(scsi_changer *ch, u_int elem)
+{
+	int i;
+	
+	for (i = 0; i < CH_TYPES; i++) {
+		if (elem >= ch->firsts[i]  &&
+		    elem <  ch->firsts[i] +
+	            ch->counts[i])
+			return i+1;
+	}
+	return 0;
+}
+
+static int
+ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
+{
+	u_char  cmd[12];
+	u_char  *buffer;
+	int     result;
+	
+	buffer = kmalloc(512, GFP_KERNEL);
+	if(!buffer)
+		return -ENOMEM;
+	
+ retry:
+	memset(cmd,0,sizeof(cmd));
+	cmd[0] = READ_ELEMENT_STATUS;
+	cmd[1] = (ch->device->lun << 5) | 
+		(ch->voltags ? 0x10 : 0) |
+		ch_elem_to_typecode(ch,elem);
+	cmd[2] = (elem >> 8) & 0xff;
+	cmd[3] = elem        & 0xff;
+	cmd[5] = 1;
+	cmd[9] = 255;
+	if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) {
+		if (((buffer[16] << 8) | buffer[17]) != elem) {
+			dprintk("asked for element 0x%02x, got 0x%02x\n",
+				elem,(buffer[16] << 8) | buffer[17]);
+			kfree(buffer);
+			return -EIO;
+		}
+		memcpy(data,buffer+16,16);
+	} else {
+		if (ch->voltags) {
+			ch->voltags = 0;
+			vprintk("device has no volume tag support%s\n","");
+			goto retry;
+		}
+		dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem);
+	}
+	kfree(buffer);
+	return result;
+}
+
+static int 
+ch_init_elem(scsi_changer *ch)
+{
+	int err;
+	u_char cmd[6];
+
+	vprintk("INITIALIZE ELEMENT STATUS, may take some time ...%s\n","");
+	memset(cmd,0,sizeof(cmd));
+	cmd[0] = INITIALIZE_ELEMENT_STATUS;
+	cmd[1] = ch->device->lun << 5;
+	err = ch_do_scsi(ch, cmd, NULL, 0);
+	vprintk("... finished%s\n","");
+	return err;
+}
+
+static int
+ch_readconfig(scsi_changer *ch)
+{
+	u_char  cmd[10], data[16];
+	u_char  *buffer;
+	int     result,id,lun,i;
+	u_int   elem;
+	
+	buffer = kmalloc(512, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	memset(buffer,0,512);
+	
+	memset(cmd,0,sizeof(cmd));
+	cmd[0] = MODE_SENSE;
+	cmd[1] = ch->device->lun << 5;
+	cmd[2] = 0x1d;
+	cmd[4] = 255;
+	result = ch_do_scsi(ch, cmd, buffer, 255);
+	if (0 != result) {
+		cmd[1] |= (1<<3);
+		result  = ch_do_scsi(ch, cmd, buffer, 255);
+	}
+	if (0 == result) {
+		ch->firsts[CHET_MT] =
+			(buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
+		ch->counts[CHET_MT] =
+			(buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
+		ch->firsts[CHET_ST] =
+			(buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
+		ch->counts[CHET_ST] =
+			(buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
+		ch->firsts[CHET_IE] =
+			(buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
+		ch->counts[CHET_IE] =
+			(buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
+		ch->firsts[CHET_DT] =
+			(buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
+		ch->counts[CHET_DT] =
+			(buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
+		vprintk("type #1 (mt): 0x%x+%d [medium transport]\n",
+			ch->firsts[CHET_MT],
+			ch->counts[CHET_MT]);
+		vprintk("type #2 (st): 0x%x+%d [storage]\n",
+			ch->firsts[CHET_ST],
+			ch->counts[CHET_ST]);
+		vprintk("type #3 (ie): 0x%x+%d [import/export]\n",
+			ch->firsts[CHET_IE],
+			ch->counts[CHET_IE]);
+		vprintk("type #4 (dt): 0x%x+%d [data transfer]\n",
+			ch->firsts[CHET_DT],
+			ch->counts[CHET_DT]);
+	} else {
+		vprintk("reading element address assigment page failed!%s\n",
+			"");
+	}
+	
+	/* vendor specific element types */
+	for (i = 0; i < 4; i++) {
+		if (0 == vendor_counts[i])
+			continue;
+		if (NULL == vendor_labels[i])
+			continue;
+		ch->firsts[CHET_V1+i] = vendor_firsts[i];
+		ch->counts[CHET_V1+i] = vendor_counts[i];
+		vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n",
+			i+5,i+1,vendor_firsts[i],vendor_counts[i],
+			vendor_labels[i]);
+	}
+
+	/* look up the devices of the data transfer elements */
+	ch->dt =
+		kmalloc(ch->counts[CHET_DT]*sizeof(Scsi_Device*),
+			GFP_ATOMIC);
+	for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
+		id  = -1;
+		lun = 0;
+		if (-1 != dt_id[elem]) {
+			id  = dt_id[elem];
+			lun = dt_lun[elem];
+			vprintk("dt 0x%x: [insmod option] ",
+				elem+ch->firsts[CHET_DT]);
+		} else if (0 != ch_read_element_status
+			   (ch,elem+ch->firsts[CHET_DT],data)) {
+			vprintk("dt 0x%x: READ ELEMENT STATUS failed\n",
+				elem+ch->firsts[CHET_DT]);
+		} else {
+			vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]);
+			if (data[6] & 0x80) {
+				if (verbose)
+					printk("not this SCSI bus\n");
+				ch->dt[elem] = NULL;
+			} else if (0 == (data[6] & 0x30)) {
+				if (verbose)
+					printk("ID/LUN unknown\n");
+				ch->dt[elem] = NULL;
+			} else {
+				id  = ch->device->id;
+				lun = 0;
+				if (data[6] & 0x20) id  = data[7];
+				if (data[6] & 0x10) lun = data[6] & 7;
+			}
+		}
+		if (-1 != id) {
+			if (verbose)
+				printk("ID %i, LUN %i, ",id,lun);
+			ch->dt[elem] =
+				find_device(ch->device->host,
+					    ch->device->channel,
+					    id,lun);
+			if (!ch->dt[elem]) {
+				/* should not happen */
+				if (verbose)
+					printk("Huh? device not found!\n");
+			} else {
+				if (verbose)
+					printk("name: %8.8s %16.16s %4.4s\n",
+					       ch->dt[elem]->vendor,
+					       ch->dt[elem]->model,
+					       ch->dt[elem]->rev);
+			}
+		}
+	}
+	ch->voltags = 1;
+	kfree(buffer);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int
+ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
+{
+	u_char  cmd[10];
+	
+	dprintk("position: 0x%x\n",elem);
+	if (0 == trans)
+		trans = ch->firsts[CHET_MT];
+	memset(cmd,0,sizeof(cmd));
+	cmd[0]  = POSITION_TO_ELEMENT;
+	cmd[1]  = ch->device->lun << 5;
+	cmd[2]  = (trans >> 8) & 0xff;
+	cmd[3]  =  trans       & 0xff;
+	cmd[4]  = (elem  >> 8) & 0xff;
+	cmd[5]  =  elem        & 0xff;
+	cmd[8]  = rotate ? 1 : 0;
+	return ch_do_scsi(ch, cmd, NULL,0);
+}
+
+static int
+ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
+{
+	u_char  cmd[12];
+	
+	dprintk("move: 0x%x => 0x%x\n",src,dest);
+	if (0 == trans)
+		trans = ch->firsts[CHET_MT];
+	memset(cmd,0,sizeof(cmd));
+	cmd[0]  = MOVE_MEDIUM;
+	cmd[1]  = ch->device->lun << 5;
+	cmd[2]  = (trans >> 8) & 0xff;
+	cmd[3]  =  trans       & 0xff;
+	cmd[4]  = (src   >> 8) & 0xff;
+	cmd[5]  =  src         & 0xff;
+	cmd[6]  = (dest  >> 8) & 0xff;
+	cmd[7]  =  dest        & 0xff;
+	cmd[10] = rotate ? 1 : 0;
+	return ch_do_scsi(ch, cmd, NULL,0);
+}
+
+static int
+ch_exchange(scsi_changer *ch, u_int trans, u_int src,
+	    u_int dest1, u_int dest2, int rotate1, int rotate2)
+{
+	u_char  cmd[12];
+	
+	dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
+		src,dest1,dest2);
+	if (0 == trans)
+		trans = ch->firsts[CHET_MT];
+	memset(cmd,0,sizeof(cmd));
+	cmd[0]  = EXCHANGE_MEDIUM;
+	cmd[1]  = ch->device->lun << 5;
+	cmd[2]  = (trans >> 8) & 0xff;
+	cmd[3]  =  trans       & 0xff;
+	cmd[4]  = (src   >> 8) & 0xff;
+	cmd[5]  =  src         & 0xff;
+	cmd[6]  = (dest1 >> 8) & 0xff;
+	cmd[7]  =  dest1       & 0xff;
+	cmd[8]  = (dest2 >> 8) & 0xff;
+	cmd[9]  =  dest2       & 0xff;
+	cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
+	
+	return ch_do_scsi(ch, cmd, NULL,0);
+}
+
+static void
+ch_check_voltag(char *tag)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		/* restrict to ascii */
+		if (tag[i] >= 0x7f || tag[i] < 0x20)
+			tag[i] = ' ';
+		/* don't allow search wildcards */
+		if (tag[i] == '?' ||
+		    tag[i] == '*')
+			tag[i] = ' ';
+	}
+}
+
+static int
+ch_set_voltag(scsi_changer *ch, u_int elem,
+	      int alternate, int clear, u_char *tag)
+{
+	u_char  cmd[12];
+	u_char  *buffer;
+	int result;
+
+	buffer = kmalloc(512, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	memset(buffer,0,512);
+
+	dprintk("%s %s voltag: 0x%x => \"%s\"\n",
+		clear     ? "clear"     : "set",
+		alternate ? "alternate" : "primary",
+		elem, tag);
+	memset(cmd,0,sizeof(cmd));
+	cmd[0]  = SEND_VOLUME_TAG;
+	cmd[1] = (ch->device->lun << 5) | 
+		ch_elem_to_typecode(ch,elem);
+	cmd[2] = (elem >> 8) & 0xff;
+	cmd[3] = elem        & 0xff;
+	cmd[5] = clear
+		? (alternate ? 0x0d : 0x0c)
+		: (alternate ? 0x0b : 0x0a);
+	
+	cmd[9] = 255;
+
+	memcpy(buffer,tag,32);
+	ch_check_voltag(buffer);
+
+	result = ch_do_scsi(ch, cmd, buffer, 256);
+	kfree(buffer);
+	return result;
+}
+
+static int ch_gstatus(scsi_changer *ch, int type, unsigned char *dest)
+{
+	int retval = 0;
+	u_char data[16];
+	unsigned int i;
+	
+	down(&ch->lock);
+	for (i = 0; i < ch->counts[type]; i++) {
+		if (0 != ch_read_element_status
+		    (ch, ch->firsts[type]+i,data)) {
+			retval = -EIO;
+			break;
+		}
+		put_user(data[2], dest+i);
+		if (data[2] & CESTATUS_EXCEPT)
+			vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n",
+				ch->firsts[type]+i,
+				(int)data[4],(int)data[5]);
+		retval = ch_read_element_status
+			(ch, ch->firsts[type]+i,data);
+		if (0 != retval)
+			break;
+	}
+	up(&ch->lock);
+	return retval;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int
+ch_release(struct inode *inode, struct file *file)
+{
+	scsi_changer *ch = file->private_data;
+
+	scsi_device_put(ch->device);
+	file->private_data = NULL;
+	return 0;
+}
+
+static int
+ch_open(struct inode *inode, struct file *file)
+{
+	struct list_head *item;
+	scsi_changer *tmp, *ch;
+	int minor = minor(inode->i_rdev);
+
+	spin_lock(&ch_devlist_lock);
+	ch = NULL;
+	list_for_each(item,&ch_devlist) {
+		tmp = list_entry(item, scsi_changer, list);
+		if (tmp->minor == minor)
+			ch = tmp;
+	}
+	if (NULL == ch || scsi_device_get(ch->device)) {
+		spin_unlock(&ch_devlist_lock);
+		return -ENXIO;
+	}
+	spin_unlock(&ch_devlist_lock);
+
+	file->private_data = ch;
+	return 0;
+}
+
+static int
+ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
+{
+	if (type >= CH_TYPES  ||  unit >= ch->counts[type])
+		return -1;
+	return 0;
+}
+
+/* for data transfer elements: check if they are busy */
+static int
+ch_is_busy(scsi_changer *ch, int type, int unit)
+{
+	if (!check_busy)
+		return 0;
+	if (type != CHET_DT)
+		return 0;
+	if (!ch->dt[unit])
+		return 0;
+	return ch->dt[unit]->access_count;
+}
+
+static int ch_ioctl(struct inode * inode, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	scsi_changer *ch = file->private_data;
+	int retval;
+	
+	switch (cmd) {
+	case CHIOGPARAMS:
+	{
+		struct changer_params params;
+		
+		params.cp_curpicker = 0;
+		params.cp_npickers  = ch->counts[CHET_MT];
+		params.cp_nslots    = ch->counts[CHET_ST];
+		params.cp_nportals  = ch->counts[CHET_IE];
+		params.cp_ndrives   = ch->counts[CHET_DT];
+		
+		if (copy_to_user((void *) arg, &params, sizeof(params)))
+			return -EFAULT;
+		return 0;
+	}
+	case CHIOGVPARAMS:
+	{
+		struct changer_vendor_params vparams;
+
+		memset(&vparams,0,sizeof(vparams));
+		if (ch->counts[CHET_V1]) {
+			vparams.cvp_n1  = ch->counts[CHET_V1];
+			strncpy(vparams.cvp_label1,vendor_labels[0],16);
+		}
+		if (ch->counts[CHET_V2]) {
+			vparams.cvp_n2  = ch->counts[CHET_V2];
+			strncpy(vparams.cvp_label2,vendor_labels[1],16);
+		}
+		if (ch->counts[CHET_V3]) {
+			vparams.cvp_n3  = ch->counts[CHET_V3];
+			strncpy(vparams.cvp_label3,vendor_labels[2],16);
+		}
+		if (ch->counts[CHET_V4]) {
+			vparams.cvp_n4  = ch->counts[CHET_V4];
+			strncpy(vparams.cvp_label4,vendor_labels[3],16);
+		}
+		if (copy_to_user((void *) arg, &vparams, sizeof(vparams)))
+			return -EFAULT;
+		return 0;
+	}
+	
+	case CHIOPOSITION:
+	{
+		struct changer_position pos;
+		
+		if (copy_from_user(&pos, (void*)arg, sizeof (pos)))
+			return -EFAULT;
+
+		if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
+			dprintk("CHIOPOSITION: invalid parameter%s\n","");
+			return -EBADSLT;
+		}
+		down(&ch->lock);
+		retval = ch_position(ch,0,
+				     ch->firsts[pos.cp_type] + pos.cp_unit,
+				     pos.cp_flags & CP_INVERT);
+		up(&ch->lock);
+		return retval;
+	}
+	
+	case CHIOMOVE:
+	{
+		struct changer_move mv;
+
+		if (copy_from_user(&mv, (void*)arg, sizeof (mv)))
+			return -EFAULT;
+
+		if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
+		    0 != ch_checkrange(ch, mv.cm_totype,   mv.cm_tounit  )) {
+			dprintk("CHIOMOVE: invalid parameter%s\n","");
+			return -EBADSLT;
+		}
+		if (ch_is_busy(ch, mv.cm_fromtype, mv.cm_fromunit) ||
+		    ch_is_busy(ch, mv.cm_totype,   mv.cm_tounit  ))
+			return -EBUSY;
+		
+		down(&ch->lock);
+		retval = ch_move(ch,0,
+				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
+				 ch->firsts[mv.cm_totype]   + mv.cm_tounit,
+				 mv.cm_flags & CM_INVERT);
+		up(&ch->lock);
+		return retval;
+	}
+
+	case CHIOEXCHANGE:
+	{
+		struct changer_exchange mv;
+		
+		if (copy_from_user(&mv, (void*)arg, sizeof (mv)))
+			return -EFAULT;
+
+		if (0 != ch_checkrange(ch, mv.ce_srctype,  mv.ce_srcunit ) ||
+		    0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
+		    0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
+			dprintk("CHIOEXCHANGE: invalid parameter%s\n","");
+			return -EBADSLT;
+		}
+		if (0 != ch_is_busy(ch, mv.ce_srctype,  mv.ce_srcunit ) ||
+		    0 != ch_is_busy(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
+		    0 != ch_is_busy(ch, mv.ce_sdsttype, mv.ce_sdstunit))
+			return -EBUSY;
+		
+		down(&ch->lock);
+		retval = ch_exchange
+			(ch,0,
+			 ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
+			 ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
+			 ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
+			 mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
+		up(&ch->lock);
+		return retval;
+	}
+
+	case CHIOGSTATUS:
+	{
+		struct changer_element_status ces;
+		
+		if (copy_from_user(&ces, (void*)arg, sizeof (ces)))
+			return -EFAULT;
+		if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
+			return -EINVAL;
+
+		return ch_gstatus(ch, ces.ces_type, ces.ces_data);
+	}
+
+#ifdef CONFIG_COMPAT
+	case CHIOGSTATUS32:
+	{
+		struct changer_element_status32 ces32;
+		unsigned char *data;
+		
+		if (copy_from_user(&ces32, (void*)arg, sizeof (ces32)))
+			return -EFAULT;
+		if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
+			return -EINVAL;
+
+		data = compat_ptr(ces32.ces_data);
+		return ch_gstatus(ch, ces32.ces_type, data);
+	}
+#endif
+    
+	case CHIOGELEM:
+	{
+		struct changer_get_element cge;
+		u_char  cmd[12];
+		u_char  *buffer;
+		unsigned int elem;
+		int     result,i;
+		
+		if (copy_from_user(&cge, (void*)arg, sizeof (cge)))
+			return -EFAULT;
+
+		if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
+			return -EINVAL;
+		elem = ch->firsts[cge.cge_type] + cge.cge_unit;
+		
+		buffer = kmalloc(512, GFP_KERNEL);
+		if (!buffer)
+			return -ENOMEM;
+		down(&ch->lock);
+		
+	voltag_retry:
+		memset(cmd,0,sizeof(cmd));
+		cmd[0] = READ_ELEMENT_STATUS;
+		cmd[1] = (ch->device->lun << 5) |
+			(ch->voltags ? 0x10 : 0) |
+			ch_elem_to_typecode(ch,elem);
+		cmd[2] = (elem >> 8) & 0xff;
+		cmd[3] = elem        & 0xff;
+		cmd[5] = 1;
+		cmd[9] = 255;
+		
+		if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256))) {
+			cge.cge_status = buffer[18];
+			cge.cge_flags = 0;
+			if (buffer[18] & CESTATUS_EXCEPT) {
+				/* FIXME: fill cge_errno */
+			}
+			if (buffer[25] & 0x80) {
+				cge.cge_flags |= CGE_SRC;
+				if (buffer[25] & 0x40)
+					cge.cge_flags |= CGE_INVERT;
+				elem = (buffer[26]<<8) | buffer[27];
+				for (i = 0; i < 4; i++) {
+					if (elem >= ch->firsts[i] &&
+					    elem <  ch->firsts[i] + ch->counts[i]) {
+						cge.cge_srctype = i;
+						cge.cge_srcunit = elem-ch->firsts[i];
+					}
+				}
+			}
+			if ((buffer[22] & 0x30) == 0x30) {
+				cge.cge_flags |= CGE_IDLUN;
+				cge.cge_id  = buffer[23];
+				cge.cge_lun = buffer[22] & 7;
+			}
+			if (buffer[9] & 0x80) {
+				cge.cge_flags |= CGE_PVOLTAG;
+				memcpy(cge.cge_pvoltag,buffer+28,36);
+			}
+			if (buffer[9] & 0x40) {
+				cge.cge_flags |= CGE_AVOLTAG;
+				memcpy(cge.cge_avoltag,buffer+64,36);
+			}
+		} else if (ch->voltags) {
+			ch->voltags = 0;
+			vprintk("device has no volume tag support%s\n","");
+			goto voltag_retry;
+		}
+		kfree(buffer);
+		up(&ch->lock);
+		
+		if (copy_to_user((void*)arg, &cge, sizeof (cge)))
+			return -EFAULT;
+		return result;
+	}
+
+	case CHIOINITELEM:
+	{
+		down(&ch->lock);
+		retval = ch_init_elem(ch);
+		up(&ch->lock);
+		return retval;
+	}
+		
+	case CHIOSVOLTAG:
+	{
+		struct changer_set_voltag csv;
+		int elem;
+
+		if (copy_from_user(&csv, (void*)arg, sizeof(csv)))
+			return -EFAULT;
+
+		if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
+			dprintk("CHIOSVOLTAG: invalid parameter%s\n","");
+			return -EBADSLT;
+		}
+		elem = ch->firsts[csv.csv_type] + csv.csv_unit;
+		down(&ch->lock);
+		retval = ch_set_voltag(ch, elem,
+				       csv.csv_flags & CSV_AVOLTAG,
+				       csv.csv_flags & CSV_CLEARTAG,
+				       csv.csv_voltag);
+		up(&ch->lock);
+		return retval;
+	}
+
+	default:
+		return scsi_ioctl(ch->device, cmd, (void*)arg);
+
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int ch_attach(Scsi_Device * sd)
+{
+	scsi_changer *ch;
+	
+	if (sd->type != TYPE_MEDIUM_CHANGER)
+		return 1;
+    
+	ch = kmalloc(sizeof(*ch), GFP_KERNEL);
+	if (NULL == ch)
+		return 1;
+
+	memset(ch,0,sizeof(*ch));
+	ch->minor = ch_devcount;
+	sprintf(ch->name,"ch%d",ch->minor);
+	init_MUTEX(&ch->lock);
+	ch->device = sd;
+	ch_readconfig(ch);
+	if (init)
+		ch_init_elem(ch);
+
+	devfs_register(NULL, ch->name, 0,
+		       MAJOR_NR, ch->minor,
+		       S_IFCHR | S_IRUGO | S_IWUGO,
+		       &changer_fops, NULL);
+
+	printk(KERN_INFO "Attached scsi changer %s "
+	       "at scsi%d, channel %d, id %d, lun %d\n", 
+	       ch->name, sd->host->host_no, sd->channel, sd->id, sd->lun);
+	
+	spin_lock(&ch_devlist_lock);
+	list_add_tail(&ch->list,&ch_devlist);
+	ch_devcount++;
+	spin_unlock(&ch_devlist_lock);
+	return 0;
+}
+
+static void ch_detach(Scsi_Device *sd)
+{
+	struct list_head *item;
+	scsi_changer *tmp, *ch;
+
+	spin_lock(&ch_devlist_lock);
+	ch = NULL;
+	list_for_each(item,&ch_devlist) {
+		tmp = list_entry(item, scsi_changer, list);
+		if (tmp->device == sd)
+			ch = tmp;
+	}
+	BUG_ON(NULL == ch);
+	list_del(&ch->list);
+	spin_unlock(&ch_devlist_lock);
+
+	devfs_remove(ch->name);
+	kfree(ch->dt);
+	kfree(ch);
+	ch_devcount--;
+	return;
+}
+
+static int __init init_ch_module(void)
+{
+	int rc;
+	
+	printk(KERN_INFO "SCSI Media Changer driver v" VERSION
+	       " for Linux " UTS_RELEASE "\n");
+	rc = register_chrdev(MAJOR_NR,"ch",&changer_fops);
+	if (rc < 0) {
+		printk("Unable to get major %d for SCSI-Changer\n",
+		       MAJOR_NR);
+		return rc;
+	}
+	ioctl32_register();
+	rc = scsi_register_device(&ch_template);
+	if (rc < 0)
+		goto fail1;
+	return 0;
+
+ fail1:
+	ioctl32_unregister();
+	unregister_chrdev(MAJOR_NR, "ch");
+	return rc;
+}
+
+static void __exit exit_ch_module(void) 
+{
+	scsi_unregister_device(&ch_template);
+	unregister_chrdev(MAJOR_NR, "ch");
+	ioctl32_unregister();
+}
+
+module_init(init_ch_module);
+module_exit(exit_ch_module);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u linux-2.5.69/include/linux/chio.h linux/include/linux/chio.h
--- linux-2.5.69/include/linux/chio.h	2003-05-08 11:03:21.000000000 +0200
+++ linux/include/linux/chio.h	2003-05-08 11:45:50.000000000 +0200
@@ -0,0 +1,168 @@
+/*
+ * ioctl interface for the scsi media changer driver
+ */
+
+/* changer element types */
+#define CHET_MT   0	/* media transport element (robot) */
+#define CHET_ST   1	/* storage element (media slots) */
+#define CHET_IE   2	/* import/export element */
+#define CHET_DT   3	/* data transfer element (tape/cdrom/whatever) */
+#define CHET_V1   4	/* vendor specific #1 */
+#define CHET_V2   5	/* vendor specific #2 */
+#define CHET_V3   6	/* vendor specific #3 */
+#define CHET_V4   7	/* vendor specific #4 */
+
+
+/*
+ * CHIOGPARAMS
+ *    query changer properties
+ *
+ * CHIOVGPARAMS
+ *    query vendor-specific element types
+ *
+ *    accessing elements works by specifing type and unit of the element.
+ *    for eample, storage elements are addressed with type = CHET_ST and
+ *    unit = 0 .. cp_nslots-1
+ *
+ */
+struct changer_params {
+	int cp_curpicker;  /* current transport element */
+	int cp_npickers;   /* number of transport elements      (CHET_MT) */
+	int cp_nslots;     /* number of storage elements        (CHET_ST) */
+	int cp_nportals;   /* number of import/export elements  (CHET_IE) */
+	int cp_ndrives;    /* number of data transfer elements  (CHET_DT) */
+};
+struct changer_vendor_params {
+	int  cvp_n1;       /* number of vendor specific elems   (CHET_V1) */
+	char cvp_label1[16];
+	int  cvp_n2;       /* number of vendor specific elems   (CHET_V2) */
+	char cvp_label2[16];
+	int  cvp_n3;       /* number of vendor specific elems   (CHET_V3) */
+	char cvp_label3[16];
+	int  cvp_n4;       /* number of vendor specific elems   (CHET_V4) */
+	char cvp_label4[16];
+	int  reserved[8];
+};
+
+
+/*
+ * CHIOMOVE
+ *    move a medium from one element to another
+ */
+struct changer_move {
+	int cm_fromtype;	/* type/unit of source element */
+	int cm_fromunit;	
+	int cm_totype;	/* type/unit of destination element */
+	int cm_tounit;
+	int cm_flags;
+};
+#define CM_INVERT   1   /* flag: rotate media (for double-sided like MOD) */
+
+
+/*
+ * CHIOEXCHANGE
+ *    move one medium from element #1 to element #2,
+ *    and another one from element #2 to element #3.
+ *    element #1 and #3 are allowed to be identical.
+ */
+struct changer_exchange {
+	int ce_srctype;	    /* type/unit of element #1 */
+	int ce_srcunit;
+	int ce_fdsttype;    /* type/unit of element #2 */
+	int ce_fdstunit;
+	int ce_sdsttype;    /* type/unit of element #3 */
+	int ce_sdstunit;
+	int ce_flags;
+};
+#define CE_INVERT1   1
+#define CE_INVERT2   2
+
+
+/*
+ * CHIOPOSITION
+ *    move the transport element (robot arm) to a specific element.
+ */
+struct changer_position {
+	int cp_type;
+	int cp_unit;
+	int cp_flags;
+};
+#define CP_INVERT   1
+
+
+/*
+ * CHIOGSTATUS
+ *    get element status for all elements of a specific type
+ */
+struct changer_element_status {
+	int             ces_type;
+	unsigned char   *ces_data;
+};
+#define CESTATUS_FULL     0x01 /* full */
+#define CESTATUS_IMPEXP   0x02	/* media was imported (inserted by sysop) */
+#define CESTATUS_EXCEPT   0x04	/* error condition */
+#define CESTATUS_ACCESS   0x08	/* access allowed */
+#define CESTATUS_EXENAB   0x10	/* element can export media */
+#define CESTATUS_INENAB   0x20	/* element can import media */
+
+
+/*
+ * CHIOGELEM
+ *    get more detailed status informtion for a single element
+ */
+struct changer_get_element {
+	int	cge_type;	 /* type/unit */
+	int	cge_unit;
+	int	cge_status;      /* status */
+	int     cge_errno;       /* errno */
+	int     cge_srctype;     /* source element of the last move/exchange */
+	int     cge_srcunit;
+	int     cge_id;          /* scsi id  (for data transfer elements) */
+	int     cge_lun;         /* scsi lun (for data transfer elements) */
+	char    cge_pvoltag[36]; /* primary volume tag */
+	char    cge_avoltag[36]; /* alternate volume tag */
+	int     cge_flags;
+};
+/* flags */
+#define CGE_ERRNO     0x01       /* errno available       */
+#define CGE_INVERT    0x02       /* media inverted        */
+#define CGE_SRC       0x04       /* media src available   */
+#define CGE_IDLUN     0x08       /* ID+LUN available      */
+#define CGE_PVOLTAG   0x10       /* primary volume tag available */
+#define CGE_AVOLTAG   0x20       /* alternate volume tag available */
+
+
+/*
+ * CHIOSVOLTAG
+ *    set volume tag
+ */
+struct changer_set_voltag {
+	int	csv_type;	 /* type/unit */
+	int	csv_unit;
+	char    csv_voltag[36];  /* volume tag */
+	int     csv_flags;
+};
+#define CSV_PVOLTAG   0x01       /* primary volume tag */
+#define CSV_AVOLTAG   0x02       /* alternate volume tag */
+#define CSV_CLEARTAG  0x04       /* clear volume tag */
+
+/* ioctls */
+#define CHIOMOVE       _IOW('c', 1,struct changer_move)
+#define CHIOEXCHANGE   _IOW('c', 2,struct changer_exchange)
+#define CHIOPOSITION   _IOW('c', 3,struct changer_position)
+#define CHIOGPICKER    _IOR('c', 4,int)                        /* not impl. */
+#define CHIOSPICKER    _IOW('c', 5,int)                        /* not impl. */
+#define CHIOGPARAMS    _IOR('c', 6,struct changer_params)
+#define CHIOGSTATUS    _IOW('c', 8,struct changer_element_status)
+#define CHIOGELEM      _IOW('c',16,struct changer_get_element)
+#define CHIOINITELEM   _IO('c',17)
+#define CHIOSVOLTAG    _IOW('c',18,struct changer_set_voltag)
+#define CHIOGVPARAMS   _IOR('c',19,struct changer_vendor_params)
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u linux-2.5.69/include/linux/major.h linux/include/linux/major.h
--- linux-2.5.69/include/linux/major.h	2003-05-08 11:00:15.000000000 +0200
+++ linux/include/linux/major.h	2003-05-08 11:03:21.000000000 +0200
@@ -100,6 +100,7 @@
 #define I2O_MAJOR		80	/* 80->87 */
 
 #define SHMIQ_MAJOR		85   /* Linux/mips, SGI /dev/shmiq */
+#define SCSI_CHANGER_MAJOR      86
 
 #define IDE6_MAJOR		88
 #define IDE7_MAJOR		89
diff -u linux-2.5.69/include/scsi/scsi.h linux/include/scsi/scsi.h
--- linux-2.5.69/include/scsi/scsi.h	2003-05-08 11:01:43.000000000 +0200
+++ linux/include/scsi/scsi.h	2003-05-08 11:03:21.000000000 +0200
@@ -31,6 +31,7 @@
 #define FORMAT_UNIT           0x04
 #define READ_BLOCK_LIMITS     0x05
 #define REASSIGN_BLOCKS       0x07
+#define INITIALIZE_ELEMENT_STATUS 0x07
 #define READ_6                0x08
 #define WRITE_6               0x0a
 #define SEEK_6                0x0b
@@ -55,6 +56,7 @@
 #define READ_10               0x28
 #define WRITE_10              0x2a
 #define SEEK_10               0x2b
+#define POSITION_TO_ELEMENT   0x2b
 #define WRITE_VERIFY          0x2e
 #define VERIFY                0x2f
 #define SEARCH_HIGH           0x30
@@ -87,6 +89,7 @@
 #define PERSISTENT_RESERVE_OUT 0x5f
 #define REPORT_LUNS           0xa0
 #define MOVE_MEDIUM           0xa5
+#define EXCHANGE_MEDIUM       0xa6
 #define READ_12               0xa8
 #define WRITE_12              0xaa
 #define WRITE_VERIFY_12       0xae


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 14:39       ` David S. Miller
  2003-05-07 15:12         ` Jeff Garzik
  2003-05-08 10:46         ` Gerd Knorr
@ 2003-05-08 15:16         ` Ben Collins
  2003-05-08 15:51           ` Christoph Hellwig
  2003-05-08 19:34           ` Pavel Machek
  2003-05-08 15:23         ` Arnd Bergmann
  3 siblings, 2 replies; 39+ messages in thread
From: Ben Collins @ 2003-05-08 15:16 UTC (permalink / raw)
  To: David S. Miller
  Cc: Christoph Hellwig, Pavel Machek, Arnd Bergmann, linux-kernel

On Wed, May 07, 2003 at 07:39:00AM -0700, David S. Miller wrote:
> On Wed, 2003-05-07 at 05:56, Christoph Hellwig wrote:
> > Btw, if you really want to move all the 32bit ioctl compat code to the
> > drivers a ->ioctl32 file operation might be the better choice..
> 
> I can't believe I never thought of that. :-)

How would the driver differentiate between .compat_ioctl == NULL being a
case where it should fail because there is no translation, or a case
where it should use the compatible .ioctl? Maybe there should be an
extra flag like use_compat_ioctl. So:

	.use_compat_ioctl	= 1;
	.ioctl			= my_ioctl;
	.compat_ioctl		= my_compat_ioctl;

Means use my_compat_ioctl() for translation. And just:

	.use_compat_ioctl	= 1;
	.ioctl			= my_ioctl;

Means that our standard my_ioctl is 32/64 compatible.

This would also solve the current problem where a module that is
compiled with compat ioctl's using register_ioctl32_conversion() is not
usable on a kernel compiled without CONFIG_COMPAT, even though it very
well should be.

-- 
Debian     - http://www.debian.org/
Linux 1394 - http://www.linux1394.org/
Subversion - http://subversion.tigris.org/
Deqo       - http://www.deqo.com/

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 14:39       ` David S. Miller
                           ` (2 preceding siblings ...)
  2003-05-08 15:16         ` Ben Collins
@ 2003-05-08 15:23         ` Arnd Bergmann
  3 siblings, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-08 15:23 UTC (permalink / raw)
  To: David S. Miller, Christoph Hellwig, Gerd Knorr; +Cc: Pavel Machek, linux-kernel

Gerd Knorr wrote:

> ioctl struct size and the ioctl number (which has the size encoded)
> should end up being different too.  Anyone aware of corner cases where
> this isn't going to work?

About half of the ioctls that need special care have fixed numbers 
instead of using _IOR() etc, see e.g. include/linux/sockios.h,
or they get the definition wrong in some way.

The way you do it in your patch could work for many cases, but it
won't be enough to eliminate HANDLE_IOCTL(), if that is desired.

Adding fops->compat_ioctl() makes it possible to eventually replace 
all HANDLE_IOCTL() and keep only COMPATIBLE_IOCTL(), which in turn
would become simpler to deal with.
If we don't add fops->compat_ioctl(), the ioctl handlers could
however look at (current_thread_info()->flags & _TIF_32BIT) to find
out if which user data structure they should expect. Is that reliable?
Do we already have a macro to do it?

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 15:51           ` Christoph Hellwig
@ 2003-05-08 15:37             ` Ben Collins
  0 siblings, 0 replies; 39+ messages in thread
From: Ben Collins @ 2003-05-08 15:37 UTC (permalink / raw)
  To: Christoph Hellwig, David S. Miller, Pavel Machek, Arnd Bergmann,
	linux-kernel

On Thu, May 08, 2003 at 04:51:18PM +0100, Christoph Hellwig wrote:
> On Thu, May 08, 2003 at 11:16:43AM -0400, Ben Collins wrote:
> > How would the driver differentiate between .compat_ioctl == NULL being a
> > case where it should fail because there is no translation, or a case
> > where it should use the compatible .ioctl? Maybe there should be an
> > extra flag like use_compat_ioctl. So:
> 
> .compat_ioctl == NULL:  fail
> .compat_ioctl == .ioctl: everythings fine, I read the docs

That makes sense aswell.

> > This would also solve the current problem where a module that is
> > compiled with compat ioctl's using register_ioctl32_conversion() is not
> > usable on a kernel compiled without CONFIG_COMPAT, even though it very
> > well should be.
> 
> You mean you want to load the same binary module in differently
> compiled kernels?  That's a flawed idea to start with..

I don't, but I don't see the point in it not working in this case.

-- 
Debian     - http://www.debian.org/
Linux 1394 - http://www.linux1394.org/
Subversion - http://subversion.tigris.org/
Deqo       - http://www.deqo.com/

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 15:16         ` Ben Collins
@ 2003-05-08 15:51           ` Christoph Hellwig
  2003-05-08 15:37             ` Ben Collins
  2003-05-08 19:34           ` Pavel Machek
  1 sibling, 1 reply; 39+ messages in thread
From: Christoph Hellwig @ 2003-05-08 15:51 UTC (permalink / raw)
  To: Ben Collins; +Cc: David S. Miller, Pavel Machek, Arnd Bergmann, linux-kernel

On Thu, May 08, 2003 at 11:16:43AM -0400, Ben Collins wrote:
> How would the driver differentiate between .compat_ioctl == NULL being a
> case where it should fail because there is no translation, or a case
> where it should use the compatible .ioctl? Maybe there should be an
> extra flag like use_compat_ioctl. So:

.compat_ioctl == NULL:  fail
.compat_ioctl == .ioctl: everythings fine, I read the docs

> This would also solve the current problem where a module that is
> compiled with compat ioctl's using register_ioctl32_conversion() is not
> usable on a kernel compiled without CONFIG_COMPAT, even though it very
> well should be.

You mean you want to load the same binary module in differently
compiled kernels?  That's a flawed idea to start with..


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 19:34           ` Pavel Machek
@ 2003-05-08 19:27             ` Ben Collins
  2003-05-08 20:06               ` Pavel Machek
  2003-05-08 20:26               ` David Mosberger
  0 siblings, 2 replies; 39+ messages in thread
From: Ben Collins @ 2003-05-08 19:27 UTC (permalink / raw)
  To: Pavel Machek
  Cc: David S. Miller, Christoph Hellwig, Arnd Bergmann, linux-kernel

On Thu, May 08, 2003 at 09:34:30PM +0200, Pavel Machek wrote:
> Hi!
> 
> > This would also solve the current problem where a module that is
> > compiled with compat ioctl's using register_ioctl32_conversion() is not
> > usable on a kernel compiled without CONFIG_COMPAT, even though it very
> > well should be.
> 
> CONFIG_COMPAT is pretty much constant depending only on
> architecture. I see no point in complicating this.

I don't think so. Sparc64 and ia64 I know allow you to disable 32bit
compatibility. I'd be surprised if the other 32/64 architectures didn't.

-- 
Debian     - http://www.debian.org/
Linux 1394 - http://www.linux1394.org/
Subversion - http://subversion.tigris.org/
Deqo       - http://www.deqo.com/

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 15:16         ` Ben Collins
  2003-05-08 15:51           ` Christoph Hellwig
@ 2003-05-08 19:34           ` Pavel Machek
  2003-05-08 19:27             ` Ben Collins
  1 sibling, 1 reply; 39+ messages in thread
From: Pavel Machek @ 2003-05-08 19:34 UTC (permalink / raw)
  To: Ben Collins
  Cc: David S. Miller, Christoph Hellwig, Pavel Machek, Arnd Bergmann,
	linux-kernel

Hi!

> This would also solve the current problem where a module that is
> compiled with compat ioctl's using register_ioctl32_conversion() is not
> usable on a kernel compiled without CONFIG_COMPAT, even though it very
> well should be.

CONFIG_COMPAT is pretty much constant depending only on
architecture. I see no point in complicating this.

								Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:06               ` Pavel Machek
@ 2003-05-08 19:47                 ` Ben Collins
  2003-05-08 20:09                 ` David S. Miller
  1 sibling, 0 replies; 39+ messages in thread
From: Ben Collins @ 2003-05-08 19:47 UTC (permalink / raw)
  To: Pavel Machek
  Cc: David S. Miller, Christoph Hellwig, Arnd Bergmann, linux-kernel

On Thu, May 08, 2003 at 10:06:30PM +0200, Pavel Machek wrote:
> > On Thu, May 08, 2003 at 09:34:30PM +0200, Pavel Machek wrote:
> > > Hi!
> > > 
> > > > This would also solve the current problem where a module that is
> > > > compiled with compat ioctl's using register_ioctl32_conversion() is not
> > > > usable on a kernel compiled without CONFIG_COMPAT, even though it very
> > > > well should be.
> > > 
> > > CONFIG_COMPAT is pretty much constant depending only on
> > > architecture. I see no point in complicating this.
> > 
> > I don't think so. Sparc64 and ia64 I know allow you to disable 32bit
> > compatibility. I'd be surprised if the other 32/64 architectures
> didn't.
> 
> 
> Really? I thought sparc64 has no real 64-bit userland?
> 
> Okay, it might make sense on x86-64, but I do not think savings are
> worth the trouble.

I never said it was worth just that effort. What I said was is that the
smarter change of using a compat_ioctl in the fops has the cool
side affect of allowing that to happen. Not that I ever thought it was
worth making huge changes to the infrastructure.

-- 
Debian     - http://www.debian.org/
Linux 1394 - http://www.linux1394.org/
Subversion - http://subversion.tigris.org/
Deqo       - http://www.deqo.com/

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 19:27             ` Ben Collins
@ 2003-05-08 20:06               ` Pavel Machek
  2003-05-08 19:47                 ` Ben Collins
  2003-05-08 20:09                 ` David S. Miller
  2003-05-08 20:26               ` David Mosberger
  1 sibling, 2 replies; 39+ messages in thread
From: Pavel Machek @ 2003-05-08 20:06 UTC (permalink / raw)
  To: Ben Collins
  Cc: Pavel Machek, David S. Miller, Christoph Hellwig, Arnd Bergmann,
	linux-kernel

> On Thu, May 08, 2003 at 09:34:30PM +0200, Pavel Machek wrote:
> > Hi!
> > 
> > > This would also solve the current problem where a module that is
> > > compiled with compat ioctl's using register_ioctl32_conversion() is not
> > > usable on a kernel compiled without CONFIG_COMPAT, even though it very
> > > well should be.
> > 
> > CONFIG_COMPAT is pretty much constant depending only on
> > architecture. I see no point in complicating this.
> 
> I don't think so. Sparc64 and ia64 I know allow you to disable 32bit
> compatibility. I'd be surprised if the other 32/64 architectures
didn't.


Really? I thought sparc64 has no real 64-bit userland?

Okay, it might make sense on x86-64, but I do not think savings are
worth the trouble.
					Pavel
> 

-- 
Horseback riding is like software...
...vgf orggre jura vgf serr.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:06               ` Pavel Machek
  2003-05-08 19:47                 ` Ben Collins
@ 2003-05-08 20:09                 ` David S. Miller
  1 sibling, 0 replies; 39+ messages in thread
From: David S. Miller @ 2003-05-08 20:09 UTC (permalink / raw)
  To: pavel; +Cc: bcollins, hch, arnd, linux-kernel

   From: Pavel Machek <pavel@ucw.cz>
   Date: Thu, 8 May 2003 22:06:30 +0200
   
   Really? I thought sparc64 has no real 64-bit userland?
   
Wrong.  We use 32-bit binaries by default because they're
more efficient.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 19:27             ` Ben Collins
  2003-05-08 20:06               ` Pavel Machek
@ 2003-05-08 20:26               ` David Mosberger
  2003-05-08 20:33                 ` Arjan van de Ven
  1 sibling, 1 reply; 39+ messages in thread
From: David Mosberger @ 2003-05-08 20:26 UTC (permalink / raw)
  To: Ben Collins
  Cc: Pavel Machek, David S. Miller, Christoph Hellwig, Arnd Bergmann,
	linux-kernel

>>>>> On Thu, 8 May 2003 15:27:30 -0400, Ben Collins <bcollins@debian.org> said:

  Ben> On Thu, May 08, 2003 at 09:34:30PM +0200, Pavel Machek wrote:
  >> Hi!

  >> > This would also solve the current problem where a module that
  >> is > compiled with compat ioctl's using
  >> register_ioctl32_conversion() is not > usable on a kernel
  >> compiled without CONFIG_COMPAT, even though it very > well should
  >> be.

  >> CONFIG_COMPAT is pretty much constant depending only on
  >> architecture. I see no point in complicating this.

  Ben> I don't think so. Sparc64 and ia64 I know allow you to disable
  Ben> 32bit compatibility. I'd be surprised if the other 32/64
  Ben> architectures didn't.

Definitely.  I turn it off on a regular basis and expect to use it
even less in the future.

	--david

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-07 16:04         ` David S. Miller
  2003-05-07 19:13           ` Arnd Bergmann
@ 2003-05-08 20:33           ` Pavel Machek
  2003-05-08 20:43             ` David S. Miller
  2003-05-08 22:48             ` Arnd Bergmann
  1 sibling, 2 replies; 39+ messages in thread
From: Pavel Machek @ 2003-05-08 20:33 UTC (permalink / raw)
  To: David S. Miller; +Cc: Christoph Hellwig, Arnd Bergmann, linux-kernel

Hi!

> > Not sure if we are not too close to stable release to do that? And I
> > see no incremental way how to get there. Moving compatibility stuff
> > closer to drivers can be done close to stable release...
> 
> You can define it as follows:
> 
> 1) If entry exists in COMPAT or TRANSLATE table, invoke
>    fops->ioctl(), else
> 
> 2) If ->compat_ioctl() exists, invoke that, else
> 
> 3) Fail.
> 
> The COMPAT tables are sort of valuable, in that it eliminates
> the need to duplicate code when all of a drivers ioctls need
> no translation.
> 
> BTW, need to extend this to netdev->do_ioctl as well for the
> handling of SIOCDEVPRIVATE based stuff.  Oh goody, we can finally
> fix up that crap :))))

There's a *lot* of structs that contain *ioctl:
pavel@amd:/usr/src/linux-test/include/linux$ grep "*ioctl" *
pavel@amd:/usr/src/linux-test/include/linux$ grep "*ioctl" *
atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
hdlc.h: int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
hdlcdrv.h:      int (*ioctl)(struct net_device *, struct ifreq *,
ide.h:  int             (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
if_bridge.h:extern void brioctl_set(int (*ioctl_hook)(unsigned long));
if_pppox.h:     int             (*ioctl)(struct socket *sock, unsigned int cmd,
ioctl32.h:typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
loop.h: int             (*ioctl)(struct loop_device *, int cmd,
loop.h: int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
net.h:  int             (*ioctl)     (struct socket *sock, unsigned int cmd,
ppp_channel.h:  int     (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
serial_core.h:  int             (*ioctl)(struct uart_port *, unsigned int, unsigned long);
tty_driver.h: * int  (*ioctl)(struct tty_struct *tty, struct file * file,
tty_driver.h:   int  (*ioctl)(struct tty_struct *tty, struct file * file,
tty_ldisc.h: * int      (*ioctl)(struct tty_struct * tty, struct file * file,
tty_ldisc.h:    int     (*ioctl)(struct tty_struct * tty, struct file * file,
usb.h:  int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
wanrouter.h:    int (*ioctl) (struct wan_device *wandev, unsigned cmd,
pavel@amd:/usr/src/linux-test/include/linux$

What about this one: redefine it to (*ioctl)( ...., unsigned *long*,
unsinged long). That means we can add 

#define IOCTL_COMPAT 0x1 0000 0000

and avoid adding new field to each such structure. Also I will not
have to duplicate lots of middle-level code (I will have to modify
unsigned int -> unsigned long, but no second copies of everything). It
means that architecture with CONFIG_COMPAT needs to have unsigned long
> 32 bits, but I guess we can live with that.

What do you think?
								Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:26               ` David Mosberger
@ 2003-05-08 20:33                 ` Arjan van de Ven
  2003-05-08 21:11                   ` David Mosberger
  0 siblings, 1 reply; 39+ messages in thread
From: Arjan van de Ven @ 2003-05-08 20:33 UTC (permalink / raw)
  To: davidm; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 136 bytes --]


> Definitely.  I turn it off on a regular basis and expect to use it
> even less in the future.

working on a qemu port to ia64 ?

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:33           ` Pavel Machek
@ 2003-05-08 20:43             ` David S. Miller
  2003-05-08 23:03               ` Pavel Machek
  2003-05-08 22:48             ` Arnd Bergmann
  1 sibling, 1 reply; 39+ messages in thread
From: David S. Miller @ 2003-05-08 20:43 UTC (permalink / raw)
  To: pavel; +Cc: hch, arnd, linux-kernel

   From: Pavel Machek <pavel@ucw.cz>
   Date: Thu, 8 May 2003 22:33:14 +0200

   What about this one: redefine it to (*ioctl)( ...., unsigned *long*,
   unsinged long). That means we can add 
   
   #define IOCTL_COMPAT 0x1 0000 0000

Bzzt!  Doesn't work on 32-bit.  COMPAT does not mean 64-bit-->32-bit
translations, stop thinking about the compat layer in this way.

It is a generic environment translation system.

Eventually we can use it for things like IBCS2 and stuff like that.

Suggest something sane like defining a macro such as
"compat_task(tsk)" that can be tested by various bits of
code.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:33                 ` Arjan van de Ven
@ 2003-05-08 21:11                   ` David Mosberger
  0 siblings, 0 replies; 39+ messages in thread
From: David Mosberger @ 2003-05-08 21:11 UTC (permalink / raw)
  To: arjanv; +Cc: linux-kernel

>>>>> On 08 May 2003 22:33:42 +0200, Arjan van de Ven <arjanv@redhat.com> said:

  >> Definitely.  I turn it off on a regular basis and expect to use it
  >> even less in the future.

  Arjan> working on a qemu port to ia64 ?

Who, me?  I know better than that.

Last time I worked on x86 emulation was on Alpha for BIOS emulation.
It wasn't fun then.

	--david

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:33           ` Pavel Machek
  2003-05-08 20:43             ` David S. Miller
@ 2003-05-08 22:48             ` Arnd Bergmann
  2003-05-08 23:22               ` Pavel Machek
  1 sibling, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-08 22:48 UTC (permalink / raw)
  To: Pavel Machek, David S. Miller; +Cc: Christoph Hellwig, linux-kernel

On Thursday 08 May 2003 22:33, Pavel Machek wrote:

> > BTW, need to extend this to netdev->do_ioctl as well for the
> > handling of SIOCDEVPRIVATE based stuff.  Oh goody, we can finally
> > fix up that crap :))))
>
> There's a *lot* of structs that contain *ioctl:

> atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
> atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
> fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
> fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 
> hdlc.h: int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); 
> ...

There are even some more that your grep did not catch. However, only 
few of them actually need to be changed if we add ->compat_ioctl(). 

For those subsystems that have a clearly defined set of ioctls that 
are implemented by the specific drivers, the compatibility code can
be put in a higher level ioctl handler, e.g. atm_ioctl() instead of
each of the atm drivers.
Finding out exactly which interfaces need to be extended can be done
in the process.

> What about this one: redefine it to (*ioctl)( ...., unsigned *long*,
> unsinged long). That means we can add
>
> #define IOCTL_COMPAT 0x1 0000 0000

I had the same idea before but in addition to the problem that davem
mentioned, this would require changing every single ioctl handler
in the kernel and in third party drivers to use 'long' numbers.
Not really something we want to do during the current freeze.

The three options that currently make sense to me are:

a) keep using register_ioctl32_conversion() for everything
b) add a compat_task() function that handlers may use to decide
   if they should use the compat data structures, list those ioctls
   as COMPATIBLE_IOCTL()
c) add ->compat_ioctl() to some interfaces, with HANDLE_IOCTL() as
   fallback

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 20:43             ` David S. Miller
@ 2003-05-08 23:03               ` Pavel Machek
  2003-05-08 23:35                 ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Pavel Machek @ 2003-05-08 23:03 UTC (permalink / raw)
  To: David S. Miller; +Cc: hch, arnd, linux-kernel

Hi!

>    From: Pavel Machek <pavel@ucw.cz>
>    Date: Thu, 8 May 2003 22:33:14 +0200
> 
>    What about this one: redefine it to (*ioctl)( ...., unsigned *long*,
>    unsinged long). That means we can add 
>    
>    #define IOCTL_COMPAT 0x1 0000 0000
> 
> Bzzt!  Doesn't work on 32-bit.  COMPAT does not mean 64-bit-->32-bit
> translations, stop thinking about the compat layer in this way.
> 
> It is a generic environment translation system.
> 
> Eventually we can use it for things like IBCS2 and stuff like that.

I... do not think so. 

You'd then need

.compat_linux32_ioctl
.compat_IBCS2_ioctl
...

I do not think that is doable.

> Suggest something sane like defining a macro such as
> "compat_task(tsk)" that can be tested by various bits of
> code.

That makes more sense. Unfortunately, that means that case "okay, it
is compatible" can not be told from "we did not bother to check
compat_task()". :-(. Nor do I see a transition phase.
								Pavel

-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 22:48             ` Arnd Bergmann
@ 2003-05-08 23:22               ` Pavel Machek
  0 siblings, 0 replies; 39+ messages in thread
From: Pavel Machek @ 2003-05-08 23:22 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: David S. Miller, Christoph Hellwig, linux-kernel

Hi!

> > > BTW, need to extend this to netdev->do_ioctl as well for the
> > > handling of SIOCDEVPRIVATE based stuff.  Oh goody, we can finally
> > > fix up that crap :))))
> >
> > There's a *lot* of structs that contain *ioctl:
> 
> > atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
> > atmdev.h:       int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
> > fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
> > fs.h:   int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 
> > hdlc.h: int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); 
> > ...
> 
> There are even some more that your grep did not catch. However, only 
> few of them actually need to be changed if we add ->compat_ioctl(). 

Having few structs with ->ioctl() and few with both ->ioctl() and
->compat_ioctl() seems pretty ugly to me...

> For those subsystems that have a clearly defined set of ioctls that 
> are implemented by the specific drivers, the compatibility code can
> be put in a higher level ioctl handler, e.g. atm_ioctl() instead of
> each of the atm drivers.

If it is clearly defined, it should not be an ioctl() in the first
place. Yep, you are right ioctl is probably abused for that at few
points... And finding out where it ->compat_ioctl() is going to be
"interesting".

> Finding out exactly which interfaces need to be extended can be done
> in the process.

> > What about this one: redefine it to (*ioctl)( ...., unsigned *long*,
> > unsinged long). That means we can add
> >
> > #define IOCTL_COMPAT 0x1 0000 0000
> 
> I had the same idea before but in addition to the problem that davem
> mentioned, this would require changing every single ioctl handler
> in the kernel and in third party drivers to use 'long' numbers.

Oops; yep, that's a showstopper.

> Not really something we want to do during the current freeze.
> 
> The three options that currently make sense to me are:
> 
> a) keep using register_ioctl32_conversion() for everything

I believe this makes sense: its too close to 2.6 to do anything else.

> b) add a compat_task() function that handlers may use to decide
>    if they should use the compat data structures, list those ioctls
>    as COMPATIBLE_IOCTL()

Unfortunately missing compat handler silently does the wrong thing in
this case.

> c) add ->compat_ioctl() to some interfaces, with HANDLE_IOCTL() as
>    fallback

Seems like too much rewriting to me...
								Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: ioctl cleanups: enable sg_io and serial stuff to be shared
  2003-05-08 23:03               ` Pavel Machek
@ 2003-05-08 23:35                 ` Arnd Bergmann
  0 siblings, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2003-05-08 23:35 UTC (permalink / raw)
  To: Pavel Machek, David S. Miller; +Cc: hch, linux-kernel

On Friday 09 May 2003 01:03, Pavel Machek wrote:

> > Suggest something sane like defining a macro such as
> > "compat_task(tsk)" that can be tested by various bits of
> > code.
>
> That makes more sense. Unfortunately, that means that case "okay, it
> is compatible" can not be told from "we did not bother to check
> compat_task()". :-(. Nor do I see a transition phase.

You still need to list them as COMPATIBLE_IOCTL() or call
register_ioctl32_conversion(IOCTLNO, 0) when the ioctl has been
made compatible. Unless we are sure that every single ioctl
has been made compatible (probably never), the default must
be to call sys_ioctl from compat_sys_ioctl only if the number
is explicitly listed. This should solve both problems you
mentioned.

One minor remaining problem is that if multiple files contain
handlers for the same ioctl number, they have to be converted
at the same time because the number can not both be compatible
and incompatible at the same time.

	Arnd <><

^ permalink raw reply	[flat|nested] 39+ messages in thread

* ioctl cleanups: enable sg_io and serial stuff to be shared
@ 2003-05-07 10:27 Pavel Machek
  0 siblings, 0 replies; 39+ messages in thread
From: Pavel Machek @ 2003-05-07 10:27 UTC (permalink / raw)
  To: kernel list, torvalds

Hi!

This enables sg_io stuff to be shared across architectures and makes
setserial support works on all architectures.

Only change *needed* in each architecture is moving A() macros into
compat.h, so that generic code can use it. Please apply,

								Pavel

--- linux.clean/arch/x86_64/ia32/ia32_ioctl.c	2003-05-05 15:53:57.000000000 -0700
+++ linux/arch/x86_64/ia32/ia32_ioctl.c	2003-05-06 14:16:12.000000000 -0700
@@ -108,10 +108,6 @@
 
 #include <asm/mtrr.h>
 
-
-#define A(__x) ((void *)(unsigned long)(__x))
-#define AA(__x)	A(__x)
-
 /* Aiee. Someone does not find a difference between int and long */
 #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
 #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
@@ -1333,235 +1329,6 @@
 	return err;
 }
 
-
-typedef struct sg_io_hdr32 {
-	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
-	s32 dxfer_direction;	/* [i] data transfer direction  */
-	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
-	u8  mx_sb_len;		/* [i] max length to write to sbp */
-	u16 iovec_count;	/* [i] 0 implies no scatter gather */
-	u32 dxfer_len;		/* [i] byte count of data transfer */
-	u32 dxferp;		/* [i], [*io] points to data transfer memory
-					      or scatter gather list */
-	u32 cmdp;		/* [i], [*i] points to command to perform */
-	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
-	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
-	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
-	s32 pack_id;		/* [i->o] unused internally (normally) */
-	u32 usr_ptr;		/* [i->o] unused internally */
-	u8  status;		/* [o] scsi status */
-	u8  masked_status;	/* [o] shifted, masked scsi status */
-	u8  msg_status;		/* [o] messaging level data (optional) */
-	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
-	u16 host_status;	/* [o] errors from host adapter */
-	u16 driver_status;	/* [o] errors from software driver */
-	s32 resid;		/* [o] dxfer_len - actual_transferred */
-	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
-	u32 info;		/* [o] auxiliary information */
-} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
-
-typedef struct sg_iovec32 {
-	u32 iov_base;
-	u32 iov_len;
-} sg_iovec32_t;
-
-static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov;
-	int i;
-
-	sgp->dxferp = kmalloc(sgp->iovec_count *
-			      sizeof(sg_iovec_t), GFP_KERNEL);
-	if (!sgp->dxferp)
-		return -ENOMEM;
-	memset(sgp->dxferp, 0,
-	       sgp->iovec_count * sizeof(sg_iovec_t));
-
-	kiov = (sg_iovec_t *) sgp->dxferp;
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-		if (__get_user(iov_base32, &uiov->iov_base) ||
-		    __get_user(kiov->iov_len, &uiov->iov_len))
-			return -EFAULT;
-
-		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
-		if (!kiov->iov_base)
-			return -ENOMEM;
-		if (copy_from_user(kiov->iov_base,
-				   (void *) A(iov_base32),
-				   kiov->iov_len))
-			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-
-		if (__get_user(iov_base32, &uiov->iov_base))
-			return -EFAULT;
-
-		if (copy_to_user((void *) A(iov_base32),
-				 kiov->iov_base,
-				 kiov->iov_len))
-			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static void free_sg_iovec(sg_io_hdr_t *sgp)
-{
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		if (kiov->iov_base) {
-			kfree(kiov->iov_base);
-			kiov->iov_base = NULL;
-		}
-		kiov++;
-	}
-	kfree(sgp->dxferp);
-	sgp->dxferp = NULL;
-}
-
-static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	sg_io_hdr32_t *sg_io32;
-	sg_io_hdr_t sg_io64;
-	u32 dxferp32, cmdp32, sbp32;
-	mm_segment_t old_fs;
-	int err = 0;
-
-	sg_io32 = (sg_io_hdr32_t *)arg;
-	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
-	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
-	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
-	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
-	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
-	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
-	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
-	err |= __get_user(sg_io64.flags, &sg_io32->flags);
-	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
-
-	sg_io64.dxferp = NULL;
-	sg_io64.cmdp = NULL;
-	sg_io64.sbp = NULL;
-
-	err |= __get_user(cmdp32, &sg_io32->cmdp);
-	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
-	if (!sg_io64.cmdp) {
-		err = -ENOMEM;
-		goto out;
-	}
-	if (copy_from_user(sg_io64.cmdp,
-			   (void *) A(cmdp32),
-			   sg_io64.cmd_len)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	err |= __get_user(sbp32, &sg_io32->sbp);
-	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
-	if (!sg_io64.sbp) {
-		err = -ENOMEM;
-		goto out;
-	}
-	if (copy_from_user(sg_io64.sbp,
-			   (void *) A(sbp32),
-			   sg_io64.mx_sb_len)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	err |= __get_user(dxferp32, &sg_io32->dxferp);
-	if (sg_io64.iovec_count) {
-		int ret;
-
-		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
-			err = ret;
-			goto out;
-		}
-	} else {
-		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
-		if (!sg_io64.dxferp) {
-			err = -ENOMEM;
-			goto out;
-		}
-		if (copy_from_user(sg_io64.dxferp,
-				   (void *) A(dxferp32),
-				   sg_io64.dxfer_len)) {
-			err = -EFAULT;
-			goto out;
-		}
-	}
-
-	/* Unused internally, do not even bother to copy it over. */
-	sg_io64.usr_ptr = NULL;
-
-	if (err)
-		return -EFAULT;
-
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
-	set_fs (old_fs);
-
-	if (err < 0)
-		goto out;
-
-	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
-	err |= __put_user(sg_io64.status, &sg_io32->status);
-	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
-	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
-	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
-	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
-	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
-	err |= __put_user(sg_io64.resid, &sg_io32->resid);
-	err |= __put_user(sg_io64.duration, &sg_io32->duration);
-	err |= __put_user(sg_io64.info, &sg_io32->info);
-	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
-	if (sg_io64.dxferp) {
-		if (sg_io64.iovec_count)
-			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
-		else
-			err |= copy_to_user((void *)A(dxferp32),
-					    sg_io64.dxferp,
-					    sg_io64.dxfer_len);
-	}
-	if (err)
-		err = -EFAULT;
-
-out:
-	if (sg_io64.cmdp)
-		kfree(sg_io64.cmdp);
-	if (sg_io64.sbp)
-		kfree(sg_io64.sbp);
-	if (sg_io64.dxferp) {
-		if (sg_io64.iovec_count) {
-			free_sg_iovec(&sg_io64);
-		} else {
-			kfree(sg_io64.dxferp);
-		}
-	}
-	return err;
-}
-
 struct sock_fprog32 {
 	__u16	len;
 	__u32	filter;
@@ -3190,8 +2957,6 @@
 
 /* And these ioctls need translation */
 HANDLE_IOCTL(TIOCGDEV, tiocgdev)
-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 #ifdef CONFIG_NET
@@ -3274,7 +3039,6 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
-HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
--- linux.clean/drivers/block/Makefile	2003-05-05 15:49:42.000000000 -0700
+++ linux/drivers/block/Makefile	2003-05-06 13:53:24.000000000 -0700
@@ -25,7 +25,7 @@
 obj-$(CONFIG_BLK_DEV_PS2)	+= ps2esdi.o
 obj-$(CONFIG_BLK_DEV_XD)	+= xd.o
 obj-$(CONFIG_BLK_CPQ_DA)	+= cpqarray.o
-obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.o
+obj-$(CONFIG_BLK_CPQ_CISS_DA)	+= cciss.o
 obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o
 
 obj-$(CONFIG_BLK_DEV_UMEM)	+= umem.o
--- linux.clean/drivers/block/scsi_ioctl.c	2003-05-05 15:49:42.000000000 -0700
+++ linux/drivers/block/scsi_ioctl.c	2003-05-07 04:51:52.000000000 -0700
@@ -15,6 +15,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
  *
+ * Changes:
+ * Pavel Machek <pavel@suse.cz> 05/2003
+ * - move ioctl32 emulation here [this patch is dedicated to johanka@root.cz]
  */
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -25,12 +28,14 @@
 #include <linux/cdrom.h>
 #include <linux/slab.h>
 #include <linux/bio.h>
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 
-
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size[8] =
 {
@@ -294,6 +299,213 @@
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+#define EMU_SG_MAX 128
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	if (sgp->iovec_count > EMU_SG_MAX)
+		return -EINVAL;
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+		if (verify_area(VERIFY_WRITE, (void *)A(iov_base32), kiov->iov_len))
+			return -EFAULT;
+		kiov->iov_base = (void *)A(iov_base32);
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *f)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		if (sg_io64.dxfer_len > 4*PAGE_SIZE) { 
+			err = -EINVAL;
+			goto out;
+		}
+
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			;
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
+static int __init init_compat(void)
+{
+	register_ioctl32_conversion(SG_IO, sg_ioctl_trans);
+	return 0;
+}
+
+__initcall(init_compat);
+#endif
+
 #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
 #define START_STOP_TIMEOUT		(60 * HZ)
 #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
--- linux.clean/drivers/scsi/scsi_ioctl.c	2003-04-08 04:20:20.000000000 -0700
+++ linux/drivers/scsi/scsi_ioctl.c	2003-05-06 14:24:19.000000000 -0700
@@ -24,12 +24,12 @@
 #include <scsi/scsi_ioctl.h>
 
 #define NORMAL_RETRIES			5
-#define IOCTL_NORMAL_TIMEOUT			(10 * HZ)
+#define IOCTL_NORMAL_TIMEOUT		(10 * HZ)
 #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
 #define START_STOP_TIMEOUT		(60 * HZ)
 #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
 #define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
-#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )  /* ZIP-250 on parallel port takes as long! */
+#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ)  /* ZIP-250 on parallel port takes as long! */
 
 #define MAX_BUF PAGE_SIZE
 
@@ -362,8 +362,6 @@
 error:
 	if (buf)
 		kfree(buf);
-
-
 	return result;
 #else
 	{
--- linux.clean/drivers/serial/core.c	2003-05-05 15:50:12.000000000 -0700
+++ linux/drivers/serial/core.c	2003-05-06 14:17:08.000000000 -0700
@@ -32,6 +32,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+#include <linux/ioctl32.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -1147,6 +1148,67 @@
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+struct serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	__u32 iomem_base;
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
+
+static int serial_struct_ioctl(unsigned fd, unsigned cmd, unsigned long ptr, struct file *f) 
+{
+	typedef struct serial_struct SS;
+	struct serial_struct32 *ss32 = (void *) ptr; 
+	int err;
+	struct serial_struct ss; 
+	mm_segment_t oldseg = get_fs(); 
+	if (cmd == TIOCSSERIAL) { 
+		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
+			return -EFAULT;
+		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
+			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
+		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
+	}
+	set_fs(KERNEL_DS);
+		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+	set_fs(oldseg);
+	if (cmd == TIOCGSERIAL && err >= 0) { 
+		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
+		    __put_user((unsigned long)ss.iomem_base  >> 32 ? 
+			       0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
+			       &ss32->iomem_base) ||
+		    __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
+		    __put_user(ss.port_high, &ss32->port_high))
+			return -EFAULT;
+	} 
+	return err;	
+}
+
+static int __init init_compat(void)
+{
+	register_ioctl32_conversion(TIOCGSERIAL, serial_struct_ioctl);
+	register_ioctl32_conversion(TIOCSSERIAL, serial_struct_ioctl);
+	return 0;
+}
+
+__initcall(init_compat);
+#endif
+
 static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	struct uart_state *state = tty->driver_data;
--- linux.clean/include/asm-x86_64/compat.h	2003-04-21 13:41:23.000000000 -0700
+++ linux/include/asm-x86_64/compat.h	2003-05-06 14:00:02.000000000 -0700
@@ -128,4 +128,8 @@
 	return (void *)(unsigned long)uptr;
 }
 
+/* For compat_ioctl handlers */
+#define A(__x) ((void *)(unsigned long)(__x))
+#define AA(__x)	A(__x)
+
 #endif /* _ASM_X86_64_COMPAT_H */
--- linux.clean/include/linux/ioctl32.h	2003-05-05 15:53:04.000000000 -0700
+++ linux/include/linux/ioctl32.h	2003-05-06 13:58:57.000000000 -0700
@@ -2,9 +2,9 @@
 #define IOCTL32_H 1
 
 struct file;
-
 extern long sys_ioctl(unsigned int, unsigned int, unsigned long);
 
+
 /* 
  * Register an 32bit ioctl translation handler for ioctl cmd.
  *
@@ -14,12 +14,15 @@
  *                        arg: ioctl argument
  *                        struct file *file: file descriptor pointer.
  */ 
+typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
 
 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);
 
-typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
+/* FIXME: several conversions make sense for one cmd depending on
+ * device being used (don't complain, its ioctl, its supposed to be
+ * ugly). Therefore unregisters needs *handler, too.
+ */
 
 struct ioctl_trans {
 	unsigned long cmd;

-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2003-05-08 23:27 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20030507104008$12ba@gated-at.bofh.it>
2003-05-07 11:51 ` ioctl cleanups: enable sg_io and serial stuff to be shared Arnd Bergmann
2003-05-07 12:41   ` Pavel Machek
2003-05-07 12:56     ` Christoph Hellwig
2003-05-07 14:39       ` David S. Miller
2003-05-07 15:12         ` Jeff Garzik
2003-05-07 14:07           ` David S. Miller
2003-05-08 10:46         ` Gerd Knorr
2003-05-08 15:16         ` Ben Collins
2003-05-08 15:51           ` Christoph Hellwig
2003-05-08 15:37             ` Ben Collins
2003-05-08 19:34           ` Pavel Machek
2003-05-08 19:27             ` Ben Collins
2003-05-08 20:06               ` Pavel Machek
2003-05-08 19:47                 ` Ben Collins
2003-05-08 20:09                 ` David S. Miller
2003-05-08 20:26               ` David Mosberger
2003-05-08 20:33                 ` Arjan van de Ven
2003-05-08 21:11                   ` David Mosberger
2003-05-08 15:23         ` Arnd Bergmann
2003-05-07 15:28       ` Pavel Machek
2003-05-07 16:04         ` David S. Miller
2003-05-07 19:13           ` Arnd Bergmann
2003-05-07 18:12             ` David S. Miller
2003-05-07 23:50               ` Arnd Bergmann
2003-05-08 10:35                 ` David S. Miller
2003-05-07 22:20             ` Alan Cox
2003-05-08 20:33           ` Pavel Machek
2003-05-08 20:43             ` David S. Miller
2003-05-08 23:03               ` Pavel Machek
2003-05-08 23:35                 ` Arnd Bergmann
2003-05-08 22:48             ` Arnd Bergmann
2003-05-08 23:22               ` Pavel Machek
2003-05-07 13:18     ` Arnd Bergmann
2003-05-07 14:01       ` Carl-Daniel Hailfinger
2003-05-07 15:16       ` Pavel Machek
2003-05-07 15:46         ` Arnd Bergmann
2003-05-07 16:07           ` Jens Axboe
2003-05-07 16:20             ` Arnd Bergmann
2003-05-07 10:27 Pavel Machek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).