@@ -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);
@@ -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
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 <dgilbert@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(-)