On 7/27/19 5:37 AM, Douglas Gilbert wrote: > Add support for the sg v4 interface based on struct sg_io_v4 found > in include/uapi/linux/bsg.h and only previously supported by the > bsg driver. Add ioctl(SG_IOSUBMIT) and ioctl(SG_IORECEIVE) for > async (non-blocking) usage of the sg v4 interface. Do not accept > the v3 interface with these ioctls. Do not accept the v4 > interface with this driver's existing write() and read() > system calls. > > For sync (blocking) usage expand the existing ioctl(SG_IO) > to additionally accept the sg v4 interface object. > > Signed-off-by: Douglas Gilbert <dgilbert@xxxxxxxxxxxx> > --- > drivers/scsi/sg.c | 489 ++++++++++++++++++++++++++++++++--------- > include/uapi/scsi/sg.h | 37 +++- > 2 files changed, 420 insertions(+), 106 deletions(-) > > diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c > index 4d6635af7da7..dd779931ada4 100644 > --- a/drivers/scsi/sg.c > +++ b/drivers/scsi/sg.c > @@ -7,8 +7,9 @@ > * > * Original driver (sg.c): > * Copyright (C) 1992 Lawrence Foard > - * Version 2 and 3 extensions to driver: > + * Version 2, 3 and 4 extensions to driver: > * Copyright (C) 1998 - 2019 Douglas Gilbert > + * > */ > > static int sg_version_num = 30901; /* [x]xyyzz where [x] empty when x=0 */ > @@ -40,10 +41,12 @@ static char *sg_version_date = "20190606"; > #include <linux/atomic.h> > #include <linux/ratelimit.h> > #include <linux/uio.h> > -#include <linux/cred.h> /* for sg_check_file_access() */ > +#include <linux/cred.h> /* for sg_check_file_access() */ > +#include <linux/bsg.h> > #include <linux/proc_fs.h> > > -#include "scsi.h" > +#include <scsi/scsi.h> > +#include <scsi/scsi_eh.h> > #include <scsi/scsi_dbg.h> > #include <scsi/scsi_host.h> > #include <scsi/scsi_driver.h> > @@ -99,6 +102,7 @@ enum sg_rq_state { > #define SG_ADD_RQ_MAX_RETRIES 40 /* to stop infinite _trylock(s) */ > > /* Bit positions (flags) for sg_request::frq_bm bitmask follow */ > +#define SG_FRQ_IS_V4I 0 /* true (set) when is v4 interface */ > #define SG_FRQ_IS_ORPHAN 1 /* owner of request gone */ > #define SG_FRQ_SYNC_INVOC 2 /* synchronous (blocking) invocation */ > #define SG_FRQ_DIO_IN_USE 3 /* false->indirect_IO,mmap; 1->dio */ > @@ -159,6 +163,15 @@ struct sg_slice_hdr3 { > void __user *usr_ptr; > }; > > +struct sg_slice_hdr4 { /* parts of sg_io_v4 object needed in async usage */ > + void __user *sbp; /* derived from sg_io_v4::response */ > + u64 usr_ptr; /* hold sg_io_v4::usr_ptr as given (u64) */ > + int out_resid; > + s16 dir; /* data xfer direction; SG_DXFER_* */ > + u16 cmd_len; /* truncated of sg_io_v4::request_len */ > + u16 max_sb_len; /* truncated of sg_io_v4::max_response_len */ > +}; > + > struct sg_scatter_hold { /* holding area for scsi scatter gather info */ > struct page **pages; /* num_sgat element array of struct page* */ > int buflen; /* capacity in bytes (dlen<=buflen) */ > @@ -175,7 +188,10 @@ struct sg_request { /* active SCSI command or inactive on free list (fl) */ > struct list_head fl_entry; /* member of rq_fl */ > spinlock_t req_lck; > struct sg_scatter_hold sgat_h; /* hold buffer, perhaps scatter list */ > - struct sg_slice_hdr3 s_hdr3; /* subset of sg_io_hdr */ > + union { > + struct sg_slice_hdr3 s_hdr3; /* subset of sg_io_hdr */ > + struct sg_slice_hdr4 s_hdr4; /* reduced size struct sg_io_v4 */ > + }; > u32 duration; /* cmd duration in milliseconds */ > u32 rq_flags; /* hold user supplied flags */ > u32 rq_info; /* info supplied by v3 and v4 interfaces */ > @@ -235,7 +251,10 @@ struct sg_device { /* holds the state of each scsi generic device */ > struct sg_comm_wr_t { /* arguments to sg_common_write() */ > int timeout; > unsigned long frq_bm[1]; /* see SG_FRQ_* defines above */ > - struct sg_io_hdr *h3p; > + union { /* selector is frq_bm.SG_FRQ_IS_V4I */ > + struct sg_io_hdr *h3p; > + struct sg_io_v4 *h4p; > + }; > u8 *cmnd; > }; > > @@ -244,12 +263,12 @@ static void sg_rq_end_io(struct request *rq, blk_status_t status); > /* Declarations of other static functions used before they are defined */ > static int sg_proc_init(void); > static int sg_start_req(struct sg_request *srp, u8 *cmd, int cmd_len, > - int dxfer_dir); > + struct sg_io_v4 *h4p, int dxfer_dir); > static void sg_finish_scsi_blk_rq(struct sg_request *srp); > static int sg_mk_sgat(struct sg_request *srp, struct sg_fd *sfp, int minlen); > -static int sg_submit(struct file *filp, struct sg_fd *sfp, > - struct sg_io_hdr *hp, bool sync, > - struct sg_request **o_srp); > +static int sg_v3_submit(struct file *filp, struct sg_fd *sfp, > + struct sg_io_hdr *hp, bool sync, > + struct sg_request **o_srp); > static struct sg_request *sg_common_write(struct sg_fd *sfp, > struct sg_comm_wr_t *cwp); > static int sg_rd_append(struct sg_request *srp, void __user *outp, > @@ -257,11 +276,11 @@ static int sg_rd_append(struct sg_request *srp, void __user *outp, > static void sg_remove_sgat(struct sg_request *srp); > static struct sg_fd *sg_add_sfp(struct sg_device *sdp); > static void sg_remove_sfp(struct kref *); > -static struct sg_request *sg_find_srp_by_id(struct sg_fd *sfp, int pack_id); > +static struct sg_request *sg_find_srp_by_id(struct sg_fd *sfp, int id); > static struct sg_request *sg_add_request(struct sg_fd *sfp, int dxfr_len, > struct sg_comm_wr_t *cwrp); > static void sg_deact_request(struct sg_fd *sfp, struct sg_request *srp); > -static struct sg_device *sg_get_dev(int dev); > +static struct sg_device *sg_get_dev(int min_dev); > static void sg_device_destroy(struct kref *kref); > static struct sg_request *sg_mk_srp_sgat(struct sg_fd *sfp, bool first, > int db_len); > @@ -274,8 +293,11 @@ static void sg_rep_rq_state_fail(struct sg_fd *sfp, > > #define SZ_SG_HEADER ((int)sizeof(struct sg_header)) /* v1 and v2 header */ > #define SZ_SG_IO_HDR ((int)sizeof(struct sg_io_hdr)) /* v3 header */ > +#define SZ_SG_IO_V4 ((int)sizeof(struct sg_io_v4)) /* v4 header (in bsg.h) */ > #define SZ_SG_REQ_INFO ((int)sizeof(struct sg_req_info)) > > +/* There is a assert that SZ_SG_IO_V4 >= SZ_SG_IO_HDR in first function */ > + > #define SG_IS_DETACHING(sdp) test_bit(SG_FDEV_DETACHING, (sdp)->fdev_bm) > #define SG_HAVE_EXCLUDE(sdp) test_bit(SG_FDEV_EXCLUDE, (sdp)->fdev_bm) > #define SG_RS_ACTIVE(srp) (atomic_read(&(srp)->rq_st) != SG_RS_INACTIVE) > @@ -295,6 +317,7 @@ static void sg_rep_rq_state_fail(struct sg_fd *sfp, > > #if IS_ENABLED(CONFIG_SCSI_LOGGING) && IS_ENABLED(SG_DEBUG) > #define SG_LOG_BUFF_SZ 48 > +#define SG_LOG_ACTIVE 1 > > #define SG_LOG(depth, sfp, fmt, a...) \ > do { \ > @@ -332,6 +355,10 @@ static void sg_rep_rq_state_fail(struct sg_fd *sfp, > static int > sg_check_file_access(struct file *filp, const char *caller) > { > + /* can't put following in declarations where it belongs */ > + compiletime_assert(SZ_SG_IO_V4 >= SZ_SG_IO_HDR, > + "struct sg_io_v4 should be larger than sg_io_hdr"); > + > if (filp->f_cred != current_real_cred()) { > pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", > caller, task_tgid_vnr(current), current->comm); > @@ -347,10 +374,11 @@ sg_check_file_access(struct file *filp, const char *caller) > > static int > sg_wait_open_event(struct sg_device *sdp, bool o_excl) > + __must_hold(&sdp->open_rel_lock) This actually has nothing to do with the sg4 interface support. Please move out locking annotations into a separate patch. Cheers, Hannes -- Dr. Hannes Reinecke Teamlead Storage & Networking hare@xxxxxxx +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 21284 (AG Nürnberg)