Add a SG_SET_GET_EXTENDED ioctl control for whether commands
will be queued_at_head or queued_at_tail by the block layer
(together with the scsi mid-level). It has file scope.

Signed-off-by: Douglas Gilbert <dgilb...@interlog.com>
---

The user can still override this setting on a per command
basis with the SG_FLAG_Q_AT_HEAD and SG_FLAG_Q_AT_TAIL
in the sg v3 and v4 structures.

 drivers/scsi/sg.c      | 35 +++++++++++++++++++++++++++++++----
 include/uapi/scsi/sg.h |  3 ++-
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 583846ebc5e0..258923aac50d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -93,6 +93,10 @@ static int sg_proc_init(void);
 #define SG_DEF_TIME_UNIT SG_TIME_UNIT_MS
 #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
 
+#define SG_FD_Q_AT_TAIL true
+#define SG_FD_Q_AT_HEAD false
+#define SG_DEFAULT_Q_AT SG_FD_Q_AT_HEAD        /* for backward compatibility */
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -185,6 +189,7 @@ struct sg_fd {              /* holds the state of a file 
descriptor */
        bool keep_orphan;/* false -> drop (def), true -> keep for read() */
        bool mmap_called;       /* false -> mmap() never called on this fd */
        bool time_in_ns;        /* report times in nanoseconds */
+       bool q_at_tail;         /* queue at tail if true, head when false */
        u8 next_cmd_len;        /* 0: automatic, >0: use on next write() */
        struct sg_request *reserve_srp; /* allocate on open(), starts on fl */
        struct fasync_struct *async_qp; /* used by asynchronous notification */
@@ -894,9 +899,13 @@ sg_common_write(struct sg_fd *sfp, const struct sg_io_hdr 
*hi_p,
                srp->start_ts = ktime_get_with_offset(TK_OFFS_BOOT);
        else
                hp->duration = jiffies_to_msecs(jiffies);
-       /* at tail if v3 or later interface and tail flag set */
-       at_head = !(hp->interface_id != '\0' &&
-                   (SG_FLAG_Q_AT_TAIL & hp->flags));
+
+       if (hp->interface_id == '\0')   /* v1 and v2 interface */
+               at_head = true;         /* backward compatibility */
+       else if (sfp->q_at_tail)  /* cmd flags can override sfd setting */
+               at_head = (SG_FLAG_Q_AT_HEAD & hp->flags);
+       else            /* this sfd is defaulting to head */
+               at_head = !(SG_FLAG_Q_AT_TAIL & hp->flags);
 
        srp->rq->timeout = timeout;
        kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
@@ -1186,8 +1195,10 @@ sg_set_get_extended(struct sg_fd *sfp, void __user *p)
        }
        SG_LOG(3, sdp, "%s: wr_mask=0x%x rd_mask=0x%x\n", __func__,
               seip->valid_wr_mask, seip->valid_rd_mask);
+       /* reserved_sz (u32), read-write */
        if (or_masks & SG_SEIM_RESERVED_SIZE)
                result = sg_reserved_sz(sfp, seip);
+       /* rq_rem_sgat_threshold (u32), read-write [impacts re-use only] */
        if (or_masks & SG_SEIM_RQ_REM_THRESH) {
                if (seip->valid_wr_mask & SG_SEIM_RQ_REM_THRESH) {
                        uv = seip->rq_rem_sgat_thresh;
@@ -1198,6 +1209,7 @@ sg_set_get_extended(struct sg_fd *sfp, void __user *p)
                if (seip->valid_rd_mask & SG_SEIM_RQ_REM_THRESH)
                        seip->rq_rem_sgat_thresh = sfp->rem_sgat_thresh;
        }
+       /* tot_fd_thresh (u32), read-write [sum of active cmd dlen_s] */
        if (or_masks & SG_SEIM_TOT_FD_THRESH) {
                if (seip->valid_wr_mask & SG_SEIM_TOT_FD_THRESH) {
                        uv = seip->tot_fd_thresh;
@@ -1208,8 +1220,9 @@ sg_set_get_extended(struct sg_fd *sfp, void __user *p)
                if (seip->valid_rd_mask & SG_SEIM_TOT_FD_THRESH)
                        seip->tot_fd_thresh = sfp->tot_fd_thresh;
        }
+       /* check all boolean flags if either wr or rd mask set in or_mask */
        if (or_masks & SG_SEIM_CTL_FLAGS) {
-               /* don't care whether wr or rd mask set in or_mask */
+               /* TIME_IN_NS boolean, read-write */
                if (seip->ctl_flags_wr_mask & SG_CTL_FLAGM_TIME_IN_NS)
                        sfp->time_in_ns =
                                !!(seip->ctl_flags & SG_CTL_FLAGM_TIME_IN_NS);
@@ -1219,19 +1232,32 @@ sg_set_get_extended(struct sg_fd *sfp, void __user *p)
                        else
                                seip->ctl_flags &= ~SG_CTL_FLAGM_TIME_IN_NS;
                }
+               /* ORPHANS boolean, read-only */
                if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_ORPHANS) {
                        if (sg_any_persistent_orphans(sfp))
                                seip->ctl_flags |= SG_CTL_FLAGM_ORPHANS;
                        else
                                seip->ctl_flags &= ~SG_CTL_FLAGM_ORPHANS;
                }
+               /* OTHER_OPENS boolean, read-only */
                if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_OTHER_OPENS) {
                        if (sdp->open_cnt > 1)
                                seip->ctl_flags |= SG_CTL_FLAGM_OTHER_OPENS;
                        else
                                seip->ctl_flags &= ~SG_CTL_FLAGM_OTHER_OPENS;
                }
+               /* Q_TAIL boolean, read-write */
+               if (seip->ctl_flags_wr_mask & SG_CTL_FLAGM_Q_TAIL)
+                       sfp->q_at_tail =
+                               !!(seip->ctl_flags & SG_CTL_FLAGM_Q_TAIL);
+               if (seip->ctl_flags_rd_mask & SG_CTL_FLAGM_Q_TAIL) {
+                       if (sfp->q_at_tail)
+                               seip->ctl_flags |= SG_CTL_FLAGM_Q_TAIL;
+                       else
+                               seip->ctl_flags &= ~SG_CTL_FLAGM_Q_TAIL;
+               }
        }
+       /* minor_index u32, read-only */
        if (or_masks & SG_SEIM_MINOR_INDEX) {
                if (seip->valid_wr_mask & SG_SEIM_MINOR_INDEX)
                        SG_LOG(2, sdp, "%s: writing to minor_index ignored\n",
@@ -2803,6 +2829,7 @@ sg_add_sfp(struct sg_device *sdp)
        sfp->rem_sgat_thresh = SG_RQ_DATA_THRESHOLD;
        sfp->tot_fd_thresh = SG_TOT_FD_THRESHOLD;
        sfp->time_in_ns = !!SG_DEF_TIME_UNIT;
+       sfp->q_at_tail = SG_DEFAULT_Q_AT;
        sfp->parentdp = sdp;
        if (atomic_read(&sdp->detaching)) {
                kfree(sfp);
diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h
index 027323bdfedc..659119d49f86 100644
--- a/include/uapi/scsi/sg.h
+++ b/include/uapi/scsi/sg.h
@@ -109,7 +109,7 @@ typedef struct sg_io_hdr {
 #define SG_FLAG_MMAP_IO 4      /* request memory mapped IO */
 /* no transfer of kernel buffers to/from user space; to debug indirect IO */
 #define SG_FLAG_NO_DXFER 0x10000
-/* defaults: for sg driver: Q_AT_HEAD; for block layer: Q_AT_TAIL */
+/* defaults: for sg driver (v3): Q_AT_HEAD; for block layer: Q_AT_TAIL */
 #define SG_FLAG_Q_AT_TAIL 0x10
 #define SG_FLAG_Q_AT_HEAD 0x20
 
@@ -192,6 +192,7 @@ typedef struct sg_req_info {        /* used by 
SG_GET_REQUEST_TABLE ioctl() */
 #define SG_CTL_FLAGM_TAG_FOR_PACK_ID   0x2
 #define SG_CTL_FLAGM_OTHER_OPENS       0x4 /* rd: other sg fd_s on this dev */
 #define SG_CTL_FLAGM_ORPHANS   0x8     /* rd: orphaned requests on this fd */
+#define SG_CTL_FLAGM_Q_TAIL    0x10    /* used for future cmds on this fd */
 
 /*
  * A pointer to the following structure is passed as the third argument to 
-- 
2.17.1

Reply via email to