svn commit: r266981 - in head/sys: cam/scsi compat/freebsd32 compat/linux

Alexander Motin mav at FreeBSD.org
Mon Jun 2 19:53:55 UTC 2014


Author: mav
Date: Mon Jun  2 19:53:53 2014
New Revision: 266981
URL: http://svnweb.freebsd.org/changeset/base/266981

Log:
  Overhaul CAM SG driver IOCTL interfaces.
  
  Make it really work for native FreeBSD programs.  Before this it was broken
  for years due to different number of pointer dereferences in Linux and
  FreeBSD IOCTL paths, permanently returning errors to FreeBSD programs.
  This change breaks the driver FreeBSD IOCTL ABI, making it more strict,
  but since it was not working any way -- who bother.
  
  Add shims for 32-bit programs on 64-bit host, translating the argument
  of the SG_IO IOCTL for both FreeBSD and Linux ABIs.
  
  With this change I was able to run 32-bit Linux sg3_utils tools and simple
  32 and 64-bit FreeBSD test tools on both 32 and 64-bit FreeBSD systems.
  
  MFC after:	1 month

Modified:
  head/sys/cam/scsi/scsi_sg.c
  head/sys/cam/scsi/scsi_sg.h
  head/sys/compat/freebsd32/freebsd32_ioctl.c
  head/sys/compat/freebsd32/freebsd32_ioctl.h
  head/sys/compat/linux/linux_ioctl.c

Modified: head/sys/cam/scsi/scsi_sg.c
==============================================================================
--- head/sys/cam/scsi/scsi_sg.c	Mon Jun  2 19:28:11 2014	(r266980)
+++ head/sys/cam/scsi/scsi_sg.c	Mon Jun  2 19:53:53 2014	(r266981)
@@ -494,7 +494,7 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 	struct ccb_scsiio *csio;
 	struct cam_periph *periph;
 	struct sg_softc *softc;
-	struct sg_io_hdr req;
+	struct sg_io_hdr *req;
 	int dir, error;
 
 	periph = (struct cam_periph *)dev->si_drv1;
@@ -507,40 +507,22 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 	error = 0;
 
 	switch (cmd) {
-	case LINUX_SCSI_GET_BUS_NUMBER: {
-		int busno;
-
-		busno = xpt_path_path_id(periph->path);
-		error = copyout(&busno, arg, sizeof(busno));
-		break;
-	}
-	case LINUX_SCSI_GET_IDLUN: {
-		struct scsi_idlun idlun;
-		struct cam_sim *sim;
+	case SG_GET_VERSION_NUM:
+	{
+		int *version = (int *)arg;
 
-		idlun.dev_id = xpt_path_target_id(periph->path);
-		sim = xpt_path_sim(periph->path);
-		idlun.host_unique_id = sim->unit_number;
-		error = copyout(&idlun, arg, sizeof(idlun));
+		*version = sg_version;
 		break;
 	}
-	case SG_GET_VERSION_NUM:
-	case LINUX_SG_GET_VERSION_NUM:
-		error = copyout(&sg_version, arg, sizeof(sg_version));
-		break;
 	case SG_SET_TIMEOUT:
-	case LINUX_SG_SET_TIMEOUT: {
-		u_int user_timeout;
+	{
+		u_int user_timeout = *(u_int *)arg;
 
-		error = copyin(arg, &user_timeout, sizeof(u_int));
-		if (error == 0) {
-			softc->sg_user_timeout = user_timeout;
-			softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
-		}
+		softc->sg_user_timeout = user_timeout;
+		softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
 		break;
 	}
 	case SG_GET_TIMEOUT:
-	case LINUX_SG_GET_TIMEOUT:
 		/*
 		 * The value is returned directly to the syscall.
 		 */
@@ -548,17 +530,14 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 		error = 0;
 		break;
 	case SG_IO:
-	case LINUX_SG_IO:
-		error = copyin(arg, &req, sizeof(req));
-		if (error)
-			break;
+		req = (struct sg_io_hdr *)arg;
 
-		if (req.cmd_len > IOCDBLEN) {
+		if (req->cmd_len > IOCDBLEN) {
 			error = EINVAL;
 			break;
 		}
 
-		if (req.iovec_count != 0) {
+		if (req->iovec_count != 0) {
 			error = EOPNOTSUPP;
 			break;
 		}
@@ -566,14 +545,14 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 		csio = &ccb->csio;
 
-		error = copyin(req.cmdp, &csio->cdb_io.cdb_bytes,
-		    req.cmd_len);
+		error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes,
+		    req->cmd_len);
 		if (error) {
 			xpt_release_ccb(ccb);
 			break;
 		}
 
-		switch(req.dxfer_direction) {
+		switch(req->dxfer_direction) {
 		case SG_DXFER_TO_DEV:
 			dir = CAM_DIR_OUT;
 			break;
@@ -594,62 +573,57 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 			      sgdone,
 			      dir|CAM_DEV_QFRZDIS,
 			      MSG_SIMPLE_Q_TAG,
-			      req.dxferp,
-			      req.dxfer_len,
-			      req.mx_sb_len,
-			      req.cmd_len,
-			      req.timeout);
+			      req->dxferp,
+			      req->dxfer_len,
+			      req->mx_sb_len,
+			      req->cmd_len,
+			      req->timeout);
 
 		error = sgsendccb(periph, ccb);
 		if (error) {
-			req.host_status = DID_ERROR;
-			req.driver_status = DRIVER_INVALID;
+			req->host_status = DID_ERROR;
+			req->driver_status = DRIVER_INVALID;
 			xpt_release_ccb(ccb);
 			break;
 		}
 
-		req.status = csio->scsi_status;
-		req.masked_status = (csio->scsi_status >> 1) & 0x7f;
-		sg_scsiio_status(csio, &req.host_status, &req.driver_status);
-		req.resid = csio->resid;
-		req.duration = csio->ccb_h.timeout;
-		req.info = 0;
-
-		error = copyout(&req, arg, sizeof(req));
-		if ((error == 0) && (csio->ccb_h.status & CAM_AUTOSNS_VALID)
-		    && (req.sbp != NULL)) {
-			req.sb_len_wr = req.mx_sb_len - csio->sense_resid;
-			error = copyout(&csio->sense_data, req.sbp,
-					req.sb_len_wr);
+		req->status = csio->scsi_status;
+		req->masked_status = (csio->scsi_status >> 1) & 0x7f;
+		sg_scsiio_status(csio, &req->host_status, &req->driver_status);
+		req->resid = csio->resid;
+		req->duration = csio->ccb_h.timeout;
+		req->info = 0;
+
+		if ((csio->ccb_h.status & CAM_AUTOSNS_VALID)
+		    && (req->sbp != NULL)) {
+			req->sb_len_wr = req->mx_sb_len - csio->sense_resid;
+			error = copyout(&csio->sense_data, req->sbp,
+					req->sb_len_wr);
 		}
 
 		xpt_release_ccb(ccb);
 		break;
 		
 	case SG_GET_RESERVED_SIZE:
-	case LINUX_SG_GET_RESERVED_SIZE: {
-		int size = 32768;
-
-		error = copyout(&size, arg, sizeof(size));
+	{
+		int *size = (int *)arg;
+		*size = DFLTPHYS;
 		break;
 	}
 
 	case SG_GET_SCSI_ID:
-	case LINUX_SG_GET_SCSI_ID:
 	{
-		struct sg_scsi_id id;
-
-		id.host_no = cam_sim_path(xpt_path_sim(periph->path));
-		id.channel = xpt_path_path_id(periph->path);
-		id.scsi_id = xpt_path_target_id(periph->path);
-		id.lun = xpt_path_lun_id(periph->path);
-		id.scsi_type = softc->pd_type;
-		id.h_cmd_per_lun = 1;
-		id.d_queue_depth = 1;
-		id.unused[0] = 0;
-		id.unused[1] = 0;
+		struct sg_scsi_id *id = (struct sg_scsi_id *)arg;
 
-		error = copyout(&id, arg, sizeof(id));
+		id->host_no = cam_sim_path(xpt_path_sim(periph->path));
+		id->channel = xpt_path_path_id(periph->path);
+		id->scsi_id = xpt_path_target_id(periph->path);
+		id->lun = xpt_path_lun_id(periph->path);
+		id->scsi_type = softc->pd_type;
+		id->h_cmd_per_lun = 1;
+		id->d_queue_depth = 1;
+		id->unused[0] = 0;
+		id->unused[1] = 0;
 		break;
 	}
 
@@ -672,25 +646,6 @@ sgioctl(struct cdev *dev, u_long cmd, ca
 	case SG_SET_COMMAND_Q:
 	case SG_SET_DEBUG:
 	case SG_NEXT_CMD_LEN:
-	case LINUX_SG_EMULATED_HOST:
-	case LINUX_SG_SET_TRANSFORM:
-	case LINUX_SG_GET_TRANSFORM:
-	case LINUX_SG_GET_NUM_WAITING:
-	case LINUX_SG_SCSI_RESET:
-	case LINUX_SG_GET_REQUEST_TABLE:
-	case LINUX_SG_SET_KEEP_ORPHAN:
-	case LINUX_SG_GET_KEEP_ORPHAN:
-	case LINUX_SG_GET_ACCESS_COUNT:
-	case LINUX_SG_SET_FORCE_LOW_DMA:
-	case LINUX_SG_GET_LOW_DMA:
-	case LINUX_SG_GET_SG_TABLESIZE:
-	case LINUX_SG_SET_FORCE_PACK_ID:
-	case LINUX_SG_GET_PACK_ID:
-	case LINUX_SG_SET_RESERVED_SIZE:
-	case LINUX_SG_GET_COMMAND_Q:
-	case LINUX_SG_SET_COMMAND_Q:
-	case LINUX_SG_SET_DEBUG:
-	case LINUX_SG_NEXT_CMD_LEN:
 	default:
 #ifdef CAMDEBUG
 		printf("sgioctl: rejecting cmd 0x%lx\n", cmd);

Modified: head/sys/cam/scsi/scsi_sg.h
==============================================================================
--- head/sys/cam/scsi/scsi_sg.h	Mon Jun  2 19:28:11 2014	(r266980)
+++ head/sys/cam/scsi/scsi_sg.h	Mon Jun  2 19:53:53 2014	(r266981)
@@ -8,31 +8,31 @@
 #define _SCSI_SG_H
 
 #define SGIOC	'"'
-#define SG_SET_TIMEOUT		_IO(SGIOC, 0x01)
+#define SG_SET_TIMEOUT		_IOW(SGIOC, 0x01, u_int)
 #define SG_GET_TIMEOUT		_IO(SGIOC, 0x02)
-#define SG_EMULATED_HOST	_IO(SGIOC, 0x03)
+#define SG_EMULATED_HOST	_IOR(SGIOC, 0x03, int)
 #define SG_SET_TRANSFORM	_IO(SGIOC, 0x04)
 #define SG_GET_TRANSFORM	_IO(SGIOC, 0x05)
-#define SG_GET_COMMAND_Q	_IO(SGIOC, 0x70)
-#define SG_SET_COMMAND_Q	_IO(SGIOC, 0x71)
-#define SG_GET_RESERVED_SIZE	_IO(SGIOC, 0x72)
-#define SG_SET_RESERVED_SIZE	_IO(SGIOC, 0x75)
-#define SG_GET_SCSI_ID		_IO(SGIOC, 0x76)
-#define SG_SET_FORCE_LOW_DMA	_IO(SGIOC, 0x79)
-#define SG_GET_LOW_DMA		_IO(SGIOC, 0x7a)
-#define SG_SET_FORCE_PACK_ID	_IO(SGIOC, 0x7b)
-#define SG_GET_PACK_ID		_IO(SGIOC, 0x7c)
-#define SG_GET_NUM_WAITING	_IO(SGIOC, 0x7d)
-#define SG_SET_DEBUG		_IO(SGIOC, 0x7e)
-#define SG_GET_SG_TABLESIZE	_IO(SGIOC, 0x7f)
-#define SG_GET_VERSION_NUM	_IO(SGIOC, 0x82)
-#define SG_NEXT_CMD_LEN		_IO(SGIOC, 0x83)
-#define SG_SCSI_RESET		_IO(SGIOC, 0x84)
-#define SG_IO			_IO(SGIOC, 0x85)
+#define SG_GET_COMMAND_Q	_IOW(SGIOC, 0x70, int)
+#define SG_SET_COMMAND_Q	_IOR(SGIOC, 0x71, int)
+#define SG_GET_RESERVED_SIZE	_IOR(SGIOC, 0x72, int)
+#define SG_SET_RESERVED_SIZE	_IOW(SGIOC, 0x75, int)
+#define SG_GET_SCSI_ID		_IOR(SGIOC, 0x76, struct sg_scsi_id)
+#define SG_SET_FORCE_LOW_DMA	_IOW(SGIOC, 0x79, int)
+#define SG_GET_LOW_DMA		_IOR(SGIOC, 0x7a, int)
+#define SG_SET_FORCE_PACK_ID	_IOW(SGIOC, 0x7b, int)
+#define SG_GET_PACK_ID		_IOR(SGIOC, 0x7c, int)
+#define SG_GET_NUM_WAITING	_IOR(SGIOC, 0x7d, int)
+#define SG_SET_DEBUG		_IOW(SGIOC, 0x7e, int)
+#define SG_GET_SG_TABLESIZE	_IOR(SGIOC, 0x7f, int)
+#define SG_GET_VERSION_NUM	_IOR(SGIOC, 0x82, int)
+#define SG_NEXT_CMD_LEN		_IOW(SGIOC, 0x83, int)
+#define SG_SCSI_RESET		_IOW(SGIOC, 0x84, int)
+#define SG_IO			_IOWR(SGIOC, 0x85, struct sg_io_hdr)
 #define SG_GET_REQUEST_TABLE	_IO(SGIOC, 0x86)
-#define SG_SET_KEEP_ORPHAN	_IO(SGIOC, 0x87)
-#define SG_GET_KEEP_ORPHAN	_IO(SGIOC, 0x88)
-#define SG_GET_ACCESS_COUNT	_IO(SGIOC, 0x89)
+#define SG_SET_KEEP_ORPHAN	_IOW(SGIOC, 0x87, int)
+#define SG_GET_KEEP_ORPHAN	_IOR(SGIOC, 0x88, int)
+#define SG_GET_ACCESS_COUNT	_IOR(SGIOC, 0x89, int)
 
 struct sg_io_hdr {
 	int		interface_id;
@@ -59,6 +59,31 @@ struct sg_io_hdr {
 	u_int		info;
 };
 
+struct sg_io_hdr32 {
+	int		interface_id;
+	int		dxfer_direction;
+	u_char		cmd_len;
+	u_char		mx_sb_len;
+	u_short		iovec_count;
+	u_int		dxfer_len;
+	uint32_t	dxferp;
+	uint32_t	cmdp;
+	uint32_t	sbp;
+	u_int		timeout;
+	u_int		flags;
+	int		pack_id;
+	uint32_t	usr_ptr;
+	u_char		status;
+	u_char		masked_status;
+	u_char		msg_status;
+	u_char		sb_len_wr;
+	u_short		host_status;
+	u_short		driver_status;
+	int		resid;
+	u_int		duration;
+	u_int		info;
+};
+
 #define SG_DXFER_NONE		-1
 #define SG_DXFER_TO_DEV		-2
 #define SG_DXFER_FROM_DEV	-3

Modified: head/sys/compat/freebsd32/freebsd32_ioctl.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_ioctl.c	Mon Jun  2 19:28:11 2014	(r266980)
+++ head/sys/compat/freebsd32/freebsd32_ioctl.c	Mon Jun  2 19:53:53 2014	(r266981)
@@ -344,6 +344,71 @@ cleanup:
 	return (error);
 }
 
+static int
+freebsd32_ioctl_sg(struct thread *td,
+    struct freebsd32_ioctl_args *uap, struct file *fp)
+{
+	struct sg_io_hdr io;
+	struct sg_io_hdr32 io32;
+	int error;
+
+	if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0)
+		return (error);
+
+	CP(io32, io, interface_id);
+	CP(io32, io, dxfer_direction);
+	CP(io32, io, cmd_len);
+	CP(io32, io, mx_sb_len);
+	CP(io32, io, iovec_count);
+	CP(io32, io, dxfer_len);
+	PTRIN_CP(io32, io, dxferp);
+	PTRIN_CP(io32, io, cmdp);
+	PTRIN_CP(io32, io, sbp);
+	CP(io32, io, timeout);
+	CP(io32, io, flags);
+	CP(io32, io, pack_id);
+	PTRIN_CP(io32, io, usr_ptr);
+	CP(io32, io, status);
+	CP(io32, io, masked_status);
+	CP(io32, io, msg_status);
+	CP(io32, io, sb_len_wr);
+	CP(io32, io, host_status);
+	CP(io32, io, driver_status);
+	CP(io32, io, resid);
+	CP(io32, io, duration);
+	CP(io32, io, info);
+
+	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
+		return (error);
+
+	CP(io, io32, interface_id);
+	CP(io, io32, dxfer_direction);
+	CP(io, io32, cmd_len);
+	CP(io, io32, mx_sb_len);
+	CP(io, io32, iovec_count);
+	CP(io, io32, dxfer_len);
+	PTROUT_CP(io, io32, dxferp);
+	PTROUT_CP(io, io32, cmdp);
+	PTROUT_CP(io, io32, sbp);
+	CP(io, io32, timeout);
+	CP(io, io32, flags);
+	CP(io, io32, pack_id);
+	PTROUT_CP(io, io32, usr_ptr);
+	CP(io, io32, status);
+	CP(io, io32, masked_status);
+	CP(io, io32, msg_status);
+	CP(io, io32, sb_len_wr);
+	CP(io, io32, host_status);
+	CP(io, io32, driver_status);
+	CP(io, io32, resid);
+	CP(io, io32, duration);
+	CP(io, io32, info);
+
+	error = copyout(&io32, uap->data, sizeof(io32));
+
+	return (error);
+}
+
 int
 freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
 {
@@ -393,6 +458,10 @@ freebsd32_ioctl(struct thread *td, struc
 		error = freebsd32_ioctl_pciocgetconf(td, uap, fp);
 		break;
 
+	case SG_IO_32:
+		error = freebsd32_ioctl_sg(td, uap, fp);
+		break;
+
 	default:
 		fdrop(fp, td);
 		ap.fd = uap->fd;

Modified: head/sys/compat/freebsd32/freebsd32_ioctl.h
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_ioctl.h	Mon Jun  2 19:28:11 2014	(r266980)
+++ head/sys/compat/freebsd32/freebsd32_ioctl.h	Mon Jun  2 19:53:53 2014	(r266981)
@@ -32,6 +32,8 @@
 #ifndef _COMPAT_FREEBSD32_IOCTL_H_
 #define	_COMPAT_FREEBSD32_IOCTL_H_
 
+#include <cam/scsi/scsi_sg.h>
+
 typedef __uint32_t caddr_t32;
 
 struct ioc_toc_header32 {
@@ -122,5 +124,6 @@ struct pci_conf_io32 {
 #define	MEMRANGE_GET32	_IOWR('m', 50, struct mem_range_op32)
 #define	MEMRANGE_SET32	_IOW('m', 51, struct mem_range_op32)
 #define	PCIOCGETCONF_32	_IOWR('p', 5, struct pci_conf_io32)
+#define	SG_IO_32	_IOWR(SGIOC, 0x85, struct sg_io_hdr32)
 
 #endif	/* _COMPAT_FREEBSD32_IOCTL_H_ */

Modified: head/sys/compat/linux/linux_ioctl.c
==============================================================================
--- head/sys/compat/linux/linux_ioctl.c	Mon Jun  2 19:28:11 2014	(r266980)
+++ head/sys/compat/linux/linux_ioctl.c	Mon Jun  2 19:53:53 2014	(r266981)
@@ -92,6 +92,8 @@ __FBSDID("$FreeBSD$");
 #include <contrib/v4l/videodev2.h>
 #include <compat/linux/linux_videodev2_compat.h>
 
+#include <cam/scsi/scsi_sg.h>
+
 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
 
 FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator");
@@ -1646,9 +1648,32 @@ linux_ioctl_cdrom(struct thread *td, str
 	}
 
 	case LINUX_SCSI_GET_BUS_NUMBER:
+	{
+		struct sg_scsi_id id;
+
+		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+		    td->td_ucred, td);
+		if (error)
+			break;
+		error = copyout(&id.channel, (void *)args->arg, sizeof(int));
+		break;
+	}
+
 	case LINUX_SCSI_GET_IDLUN:
-		error = linux_ioctl_sg(td, args);
+	{
+		struct sg_scsi_id id;
+		struct scsi_idlun idl;
+
+		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
+		    td->td_ucred, td);
+		if (error)
+			break;
+		idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
+		    ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
+		idl.host_unique_id = id.host_no;
+		error = copyout(&idl, (void *)args->arg, sizeof(idl));
 		break;
+	}
 
 	/* LINUX_CDROM_SEND_PACKET */
 	/* LINUX_CDROM_NEXT_WRITABLE */
@@ -2618,12 +2643,20 @@ linux_ioctl_drm(struct thread *td, struc
 	return sys_ioctl(td, (struct ioctl_args *)args);
 }
 
+#ifdef COMPAT_LINUX32
+#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
+#define PTRIN_CP(src,dst,fld) \
+	do { (dst).fld = PTRIN((src).fld); } while (0)
+#define PTROUT_CP(src,dst,fld) \
+	do { (dst).fld = PTROUT((src).fld); } while (0)
+
 static int
-linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
+linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
 {
+	struct sg_io_hdr io;
+	struct sg_io_hdr32 io32;
 	cap_rights_t rights;
 	struct file *fp;
-	u_long cmd;
 	int error;
 
 	error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
@@ -2631,12 +2664,98 @@ linux_ioctl_sg(struct thread *td, struct
 		printf("sg_linux_ioctl: fget returned %d\n", error);
 		return (error);
 	}
-	cmd = args->cmd;
 
-	error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td->td_ucred, td));
+	if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
+		goto out;
+
+	CP(io32, io, interface_id);
+	CP(io32, io, dxfer_direction);
+	CP(io32, io, cmd_len);
+	CP(io32, io, mx_sb_len);
+	CP(io32, io, iovec_count);
+	CP(io32, io, dxfer_len);
+	PTRIN_CP(io32, io, dxferp);
+	PTRIN_CP(io32, io, cmdp);
+	PTRIN_CP(io32, io, sbp);
+	CP(io32, io, timeout);
+	CP(io32, io, flags);
+	CP(io32, io, pack_id);
+	PTRIN_CP(io32, io, usr_ptr);
+	CP(io32, io, status);
+	CP(io32, io, masked_status);
+	CP(io32, io, msg_status);
+	CP(io32, io, sb_len_wr);
+	CP(io32, io, host_status);
+	CP(io32, io, driver_status);
+	CP(io32, io, resid);
+	CP(io32, io, duration);
+	CP(io32, io, info);
+
+	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
+		goto out;
+
+	CP(io, io32, interface_id);
+	CP(io, io32, dxfer_direction);
+	CP(io, io32, cmd_len);
+	CP(io, io32, mx_sb_len);
+	CP(io, io32, iovec_count);
+	CP(io, io32, dxfer_len);
+	PTROUT_CP(io, io32, dxferp);
+	PTROUT_CP(io, io32, cmdp);
+	PTROUT_CP(io, io32, sbp);
+	CP(io, io32, timeout);
+	CP(io, io32, flags);
+	CP(io, io32, pack_id);
+	PTROUT_CP(io, io32, usr_ptr);
+	CP(io, io32, status);
+	CP(io, io32, masked_status);
+	CP(io, io32, msg_status);
+	CP(io, io32, sb_len_wr);
+	CP(io, io32, host_status);
+	CP(io, io32, driver_status);
+	CP(io, io32, resid);
+	CP(io, io32, duration);
+	CP(io, io32, info);
+
+	error = copyout(&io32, (void *)args->arg, sizeof(io32));
+
+out:
 	fdrop(fp, td);
 	return (error);
 }
+#endif
+
+static int
+linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
+{
+
+	switch (args->cmd) {
+	case LINUX_SG_GET_VERSION_NUM:
+		args->cmd = SG_GET_VERSION_NUM;
+		break;
+	case LINUX_SG_SET_TIMEOUT:
+		args->cmd = SG_SET_TIMEOUT;
+		break;
+	case LINUX_SG_GET_TIMEOUT:
+		args->cmd = SG_GET_TIMEOUT;
+		break;
+	case LINUX_SG_IO:
+		args->cmd = SG_IO;
+#ifdef COMPAT_LINUX32
+		return (linux_ioctl_sg_io(td, args));
+#endif
+		break;
+	case LINUX_SG_GET_RESERVED_SIZE:
+		args->cmd = SG_GET_RESERVED_SIZE;
+		break;
+	case LINUX_SG_GET_SCSI_ID:
+		args->cmd = SG_GET_SCSI_ID;
+		break;
+	default:
+		return (ENODEV);
+	}
+	return (sys_ioctl(td, (struct ioctl_args *)args));
+}
 
 /*
  * Video4Linux (V4L) ioctl handler


More information about the svn-src-head mailing list