Add ioctl(SG_IOSUBMIT_V3) and ioctl(SG_IORECEIVE_V3). These ioctls are meant to be (almost) drop-in replacements for the write()/read() async version 3 interface. They only accept the version 3 interface. See the webpage at: http://sg.danny.cz/sg/sg_v40.html specifically the table in the section titled: "12 SG interface support changes". If sgv3 is a struct sg_io_hdr object, suitably configured, then res = write(sg_fd, &sgv3, sizeof(sgv3)); and res = ioctl(sg_fd, SG_IOSUBMIT_V3, &sgv3); are equivalent. Dito for read() and ioctl(SG_IORECEIVE_V3). Note this inconsistency: for async/non-blocking usage, only the v4 interface objects can use ioctl(SG_IOSUBMIT) and (SG_IORECEIVE) while only v3 interface objects can use ioctl(SG_IOSUBMIT_V3) and (SG_IORECEIVE_V3). However with the sync usage both v3 and v4 interface objects can use ioctl(SG_IO). The former action is preferred but existing practice for sync usage (i.e. the current sg driver supporting the v3 interface object with ioctl(SG_IO) while the bsg driver continues to support the v4 interface object with ioctl(SG_IO)) dictates the dual nature of ioctl(SG_IO). Signed-off-by: Douglas Gilbert <dgilbert@xxxxxxxxxxxx> --- drivers/scsi/sg.c | 81 ++++++++++++++++++++++++++++++++++++++++-- include/uapi/scsi/sg.h | 6 ++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7575dd66dbef..a261ad2c4567 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -12,9 +12,9 @@ * */ -static int sg_version_num = 30536; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.36" -static char *sg_version_date = "20140603"; +static int sg_version_num = 40001; /* 2 digits for each component */ +#define SG_VERSION_STR "4.0.01" +static char *sg_version_date = "20190520"; #include <linux/module.h> @@ -815,6 +815,24 @@ sg_ctl_iosubmit(struct file *filp, struct sg_fd *sfp, void __user *p) return -EPERM; } +static int +sg_ctl_iosubmit_v3(struct file *filp, struct sg_fd *sfp, void __user *p) +{ + int res; + u8 hdr_store[SZ_SG_IO_V4]; /* max(v3interface, v4interface) */ + struct sg_io_hdr *h3p = (struct sg_io_hdr *)hdr_store; + struct sg_device *sdp = sfp->parentdp; + + res = sg_allow_if_err_recovery(sdp, (filp->f_flags & O_NONBLOCK)); + if (unlikely(res)) + return res; + if (copy_from_user(h3p, p, SZ_SG_IO_HDR)) + return -EFAULT; + if (h3p->interface_id == 'S') + return sg_v3_submit(filp, sfp, h3p, false, NULL); + return -EPERM; +} + static void sg_execute_cmd(struct sg_fd *sfp, struct sg_request *srp) { @@ -1188,6 +1206,57 @@ sg_ctl_ioreceive(struct file *filp, struct sg_fd *sfp, void __user *p) return sg_v4_receive(sfp, srp, p, h4p); } +/* + * Called when ioctl(SG_IORECEIVE_V3) received. Expects a v3 interface. + * Checks if O_NONBLOCK file flag given, if not checks given flags field + * to see if SGV4_FLAG_IMMED is set. Either of these implies non blocking. + * When non-blocking and there is no request waiting, yields EAGAIN; + * otherwise it waits. + */ +static int +sg_ctl_ioreceive_v3(struct file *filp, struct sg_fd *sfp, void __user *p) +{ + bool non_block = !!(filp->f_flags & O_NONBLOCK); + int res; + int pack_id = SG_PACK_ID_WILDCARD; + u8 v3_holder[SZ_SG_IO_HDR]; + struct sg_io_hdr *h3p = (struct sg_io_hdr *)v3_holder; + struct sg_device *sdp = sfp->parentdp; + struct sg_request *srp; + + res = sg_allow_if_err_recovery(sdp, non_block); + if (unlikely(res)) + return res; + /* Get first three 32 bit integers: guard, proto+subproto */ + if (copy_from_user(h3p, p, SZ_SG_IO_HDR)) + return -EFAULT; + /* for v3: interface_id=='S' (in a 32 bit int) */ + if (h3p->interface_id != 'S') + return -EPERM; + if (h3p->flags & SGV4_FLAG_IMMED) + non_block = true; /* set by either this or O_NONBLOCK */ + SG_LOG(3, sdp, "%s: non_block(+IMMED)=%d\n", __func__, non_block); + + if (test_bit(SG_FFD_FORCE_PACKID, sfp->ffd_bm)) + pack_id = h3p->pack_id; + + srp = sg_find_srp_by_id(sfp, pack_id); + if (!srp) { /* nothing available so wait on packet or */ + if (unlikely(atomic_read(&sdp->detaching))) + return -ENODEV; + if (non_block) + return -EAGAIN; + res = wait_event_interruptible + (sfp->read_wait, + sg_get_ready_srp(sfp, &srp, pack_id)); + if (unlikely(atomic_read(&sdp->detaching))) + return -ENODEV; + if (unlikely(res)) + return res; /* signal --> -ERESTARTSYS */ + } /* now srp should be valid */ + return sg_v3_receive(sfp, srp, p); +} + static int sg_rd_v1v2(void __user *buf, int count, struct sg_fd *sfp, struct sg_request *srp) @@ -1842,9 +1911,15 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) case SG_IOSUBMIT: SG_LOG(3, sdp, "%s: SG_IOSUBMIT\n", __func__); return sg_ctl_iosubmit(filp, sfp, p); + case SG_IOSUBMIT_V3: + SG_LOG(3, sdp, "%s: SG_IOSUBMIT_V3\n", __func__); + return sg_ctl_iosubmit_v3(filp, sfp, p); case SG_IORECEIVE: SG_LOG(3, sdp, "%s: SG_IORECEIVE\n", __func__); return sg_ctl_ioreceive(filp, sfp, p); + case SG_IORECEIVE_V3: + SG_LOG(3, sdp, "%s: SG_IORECEIVE_V3\n", __func__); + return sg_ctl_ioreceive_v3(filp, sfp, p); case SG_IOABORT: SG_LOG(3, sdp, "%s: SG_IOABORT\n", __func__); if (read_only) diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h index cd58f918a784..8181e36442a8 100644 --- a/include/uapi/scsi/sg.h +++ b/include/uapi/scsi/sg.h @@ -359,6 +359,12 @@ struct sg_header { /* Provides identifying info about a prior submission (e.g. a tag) */ #define SG_IOABORT _IOW(SG_IOCTL_MAGIC_NUM, 0x43, struct sg_io_v4) +/* Submits a v3 interface object to driver */ +#define SG_IOSUBMIT_V3 _IOWR(SG_IOCTL_MAGIC_NUM, 0x45, struct sg_io_hdr) + +/* Gives some v3 identifying info to driver, receives associated response */ +#define SG_IORECEIVE_V3 _IOWR(SG_IOCTL_MAGIC_NUM, 0x46, struct sg_io_hdr) + /* command queuing is always on when the v3 or v4 interface is used */ #define SG_DEF_COMMAND_Q 0 -- 2.17.1