From patchwork Fri Oct 26 17:53:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 10657701 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 71C2413A4 for ; Fri, 26 Oct 2018 17:54:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 558702CAFE for ; Fri, 26 Oct 2018 17:54:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 498C42CB03; Fri, 26 Oct 2018 17:54:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C353E2CAFE for ; Fri, 26 Oct 2018 17:54:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727323AbeJ0CcE (ORCPT ); Fri, 26 Oct 2018 22:32:04 -0400 Received: from smtp.infotech.no ([82.134.31.41]:57880 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726949AbeJ0CcE (ORCPT ); Fri, 26 Oct 2018 22:32:04 -0400 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id A915520419D; Fri, 26 Oct 2018 19:54:04 +0200 (CEST) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PTzxbX0tOXe5; Fri, 26 Oct 2018 19:53:55 +0200 (CEST) Received: from xtwo70.bingwo.ca (65.194.6.51.dyn.plus.net [51.6.194.65]) by smtp.infotech.no (Postfix) with ESMTPA id 2163E20417F; Fri, 26 Oct 2018 19:53:54 +0200 (CEST) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, tonyb@cybernetics.com, hare@suse.de, bart.vanassche@wdc.com Subject: [PATCH v3.5 8/8] sg: user controls for q_at_head, read_value Date: Fri, 26 Oct 2018 18:53:53 +0100 Message-Id: <20181026175353.24935-1-dgilbert@interlog.com> X-Mailer: git-send-email 2.17.1 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Also add a read_value integer the can be used by write a value from the SG_SEIRV_* group then the corresponding value will be returned. Signed-off-by: Douglas Gilbert --- The user can still override the new file scope setting on a a per command basis with the SG_FLAG_Q_AT_HEAD and SG_FLAG_Q_AT_TAIL in the sg v3 and v4 structures. An example of read_value usage is to write the value SG_SEIRV_FL_RQS to the read_value field. Then after the SG_SET_GET_EXTENDED ioctl is run, the number of (inactive) requests currently on this file descriptor's request free list is placed in the read_value field. Added in v3 is SG_SEIRV_DEV_FL_RQS which is an expansion of SG_SEIRV_FL_RQS. SG_SEIRV_DEV_FL_RQS counts free list entries on all sg file descriptors currently open on the device that the file descriptor (given to ioctl()) is associated with. Change since v3 [patches 1 to 7 of 8 are unchanged, this for 8/8]: - move sg_version_date definition from inside CONFIG_SCSI_PROC_FS conditional out to full file scope and near related definitions drivers/scsi/sg.c | 160 +++++++++++++++++++++++++++++++---------- include/scsi/sg.h | 32 ++------- include/uapi/scsi/sg.h | 49 ++++++------- 3 files changed, 150 insertions(+), 91 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 3e89bbd508de..5ba92f112481 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -18,6 +18,7 @@ static int sg_version_num = 30901; /* 2 digits for each component */ #define SG_VERSION_STR "3.9.01" +static char *sg_version_date = "20181024"; #include @@ -59,7 +60,6 @@ static int sg_version_num = 30901; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20181019"; static int sg_proc_init(void); #endif @@ -95,6 +95,10 @@ enum sg_rq_state { #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 @@ -187,6 +191,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 */ @@ -238,7 +243,7 @@ static struct sg_request *sg_add_request(struct sg_fd *sfp, int dxfr_len, static void sg_remove_request(struct sg_fd *sfp, struct sg_request *srp); static struct sg_device *sg_get_dev(int min_dev); static void sg_device_destroy(struct kref *kref); -static const char *sg_rq_state_str(u8 rq_state, bool long_str); +static const char *sg_rq_state_str(enum sg_rq_state rq_state, bool long_str); static struct sg_request *sg_mk_srp(struct sg_fd *sfp, bool first, rwlock_t *rwlp, unsigned long *iflagsp); @@ -855,7 +860,7 @@ sg_common_write(struct sg_fd *sfp, const struct sg_io_hdr *hi_p, if (h4p || !hi_p) return ERR_PTR(-EOPNOTSUPP); - srp = sg_add_request(sfp, hi_p->dxfer_len, false); + srp = sg_add_request(sfp, hi_p->dxfer_len, sync); if (IS_ERR(srp)) return srp; srp->header = *hi_p; /* structure assignment, could memcpy */ @@ -897,9 +902,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 = (hp->flags & SG_FLAG_Q_AT_HEAD); + else /* this sfd is defaulting to head */ + at_head = !(hp->flags & SG_FLAG_Q_AT_TAIL); srp->rq->timeout = timeout; kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */ @@ -1084,30 +1093,30 @@ sg_reserved_sz(struct sg_fd *sfp, struct sg_extended_info *seip) { bool free_n_srp = false; int result = 0; - int val, mx_sect_bytes; + int new_sz, mx_sect_bytes; unsigned long iflags; - struct sg_request *srp; /* prior reserve request */ + struct sg_request *o_srp; /* prior reserve request */ struct sg_request *n_srp; /* new sg_request, may be used */ - struct sg_request *flf_srp; /* free list first element */ + struct sg_request *t_srp; /* other fl entries */ struct sg_device *sdp = sfp->parentdp; mx_sect_bytes = max_sectors_bytes(sdp->device->request_queue); + o_srp = sfp->reserve_srp; if (!(seip->valid_wr_mask & SG_SEIM_RESERVED_SIZE)) { /* read only */ - srp = sfp->reserve_srp; - seip->reserved_sz = (u32)min_t(int, srp->data.dlen, + seip->reserved_sz = (u32)min_t(int, o_srp->data.dlen, mx_sect_bytes); SG_LOG(3, sdp, "%s: rd val=%u\n", __func__, seip->reserved_sz); return 0; } - val = min_t(int, (int)seip->reserved_sz, mx_sect_bytes); - SG_LOG(3, sdp, "%s: val=%u modify to %d\n", __func__, - seip->reserved_sz, val); + new_sz = min_t(int, (int)seip->reserved_sz, mx_sect_bytes); + SG_LOG(3, sdp, "%s: was %u, modify to %d\n", __func__, + o_srp->data.dlen, new_sz); /* Should sizes less than PAGE_SIZE be permitted? Round up? */ - n_srp = sg_mk_srp(sfp, true, NULL, NULL); + n_srp = sg_mk_srp(sfp, true /* can take time */, NULL, NULL); if (IS_ERR(n_srp)) return PTR_ERR(n_srp); - if (val > 0) { - result = sg_mk_sgat_dlen(n_srp, sfp, val); + if (new_sz > 0) { + result = sg_mk_sgat_dlen(n_srp, sfp, new_sz); if (result) { kfree(n_srp); return result; @@ -1115,35 +1124,39 @@ sg_reserved_sz(struct sg_fd *sfp, struct sg_extended_info *seip) } /* new sg_request object, sized correctly is now available */ write_lock_irqsave(&sfp->rq_list_lock, iflags); - srp = sfp->reserve_srp; - spin_lock(&srp->rq_entry_lck); - /* Should not matter if srp->rq_state != SG_RQ_INACTIVE */ + o_srp = sfp->reserve_srp; + spin_lock(&o_srp->rq_entry_lck); if (sfp->mmap_called) { result = -EBUSY; free_n_srp = true; goto unlock; } - flf_srp = list_first_entry_or_null(&sfp->rq_free_list, - struct sg_request, free_entry); - if (flf_srp && flf_srp != srp && val <= flf_srp->data.dlen) { - spin_lock(&flf_srp->rq_entry_lck); - if (flf_srp->rq_state == SG_RQ_INACTIVE) { - free_n_srp = true; - sfp->reserve_srp = flf_srp; + list_for_each_entry(t_srp, &sfp->rq_free_list, free_entry) { + if (t_srp != o_srp && new_sz <= t_srp->data.dlen) { + spin_lock(&t_srp->rq_entry_lck); + if (t_srp->rq_state == SG_RQ_INACTIVE) { + free_n_srp = true; + sfp->reserve_srp = t_srp; + } + spin_unlock(&t_srp->rq_entry_lck); } - spin_unlock(&flf_srp->rq_entry_lck); + if (free_n_srp) + break; } if (!free_n_srp) { - sfp->reserve_srp = n_srp; list_add(&n_srp->free_entry, &sfp->rq_free_list); + sfp->reserve_srp = n_srp; } if (seip->valid_rd_mask & SG_SEIM_RESERVED_SIZE) { - srp = sfp->reserve_srp; + struct sg_request *srp = sfp->reserve_srp; + seip->reserved_sz = (u32)min_t(int, srp->data.dlen, mx_sect_bytes); } unlock: - spin_unlock(&srp->rq_entry_lck); + if (new_sz > sfp->rem_sgat_thresh) + sfp->rem_sgat_thresh = new_sz; + spin_unlock(&o_srp->rq_entry_lck); write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (free_n_srp) { sg_remove_sgat(n_srp); @@ -1190,11 +1203,13 @@ static int sg_set_get_extended(struct sg_fd *sfp, void __user *p) { int result = 0; - u32 uv; + unsigned long iflags; + u32 uv, or_masks; struct sg_device *sdp = sfp->parentdp; + struct sg_fd *a_sfp; struct sg_extended_info *seip; + struct sg_request *srp; struct sg_extended_info sei; - u32 or_masks; seip = &sei; if (!access_ok(VERIFY_READ, p, SZ_SG_EXTENDED_INFO)) @@ -1208,8 +1223,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; @@ -1220,6 +1237,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; @@ -1230,8 +1248,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); @@ -1241,19 +1260,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", @@ -1261,7 +1293,50 @@ sg_set_get_extended(struct sg_fd *sfp, void __user *p) if (seip->valid_rd_mask & SG_SEIM_MINOR_INDEX) seip->minor_index = sdp->index; } - /* send object back to user space if any read mask set */ + if ((seip->valid_rd_mask & SG_SEIM_READ_VAL) && + (seip->valid_wr_mask & SG_SEIM_READ_VAL)) { + switch (seip->read_value) { + case SG_SEIRV_INT_MASK: + seip->read_value = SG_SEIM_ALL_BITS; + break; + case SG_SEIRV_BOOL_MASK: + seip->read_value = SG_CTL_FLAGM_ALL_BITS; + break; + case SG_SEIRV_VERS_NUM: + seip->read_value = sg_version_num; + break; + case SG_SEIRV_FL_RQS: + uv = 0; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + list_for_each_entry(srp, &sfp->rq_free_list, + free_entry) + ++uv; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); + seip->read_value = uv; + break; + case SG_SEIRV_DEV_FL_RQS: + uv = 0; + read_lock_irqsave(&sdp->sfd_lock, iflags); + list_for_each_entry(a_sfp, &sdp->sfds, + sfd_entry) { + read_lock(&a_sfp->rq_list_lock); + list_for_each_entry(srp, &a_sfp->rq_free_list, + free_entry) + ++uv; + read_unlock(&a_sfp->rq_list_lock); + } + read_unlock_irqrestore(&sdp->sfd_lock, iflags); + seip->read_value = uv; + break; + default: + SG_LOG(6, sdp, "%s: can't decode %d --> read_value\n", + __func__, seip->read_value); + seip->read_value = 0; + break; + } + } + + /* finally send object back to user space if any read mask set */ if (seip->valid_rd_mask || seip->ctl_flags_rd_mask) { if (access_ok(VERIFY_WRITE, p, SZ_SG_EXTENDED_INFO)) result = __copy_to_user(p, seip, SZ_SG_EXTENDED_INFO); @@ -1318,7 +1393,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) mutex_lock(&sfp->f_mutex); result = sg_set_get_extended(sfp, p); mutex_unlock(&sfp->f_mutex); - return 0; + return result; case SG_SET_TIMEOUT: SG_LOG(3, sdp, "%s: SG_SET_TIMEOUT\n", __func__); result = get_user(val, ip); @@ -2197,6 +2272,9 @@ init_sg(void) SG_MAX_DEVS, "sg"); if (rc) return rc; + pr_info("Registered %s[char major=0x%x], version: %s, date: %s\n", + "sg device ", SCSI_GENERIC_MAJOR, SG_VERSION_STR, + sg_version_date); sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic"); if ( IS_ERR(sg_sysfs_class) ) { rc = PTR_ERR(sg_sysfs_class); @@ -2592,7 +2670,12 @@ sg_get_rq_pack_id(struct sg_fd *sfp, int pack_id) return NULL; } -/* If rwlp and iflagsp non-NULL then release and re-take write lock */ +/* + * If 'first' is set then use GFP_KERNEL which may take time but has + * improved chance of success, otherwise use GFP_ATOMIC. Only in + * 'first' case, if both rwlp and iflagsp are non-NULL then release and + * re-take write rwlp. + */ static struct sg_request * sg_mk_srp(struct sg_fd *sfp, bool first, rwlock_t *rwlp, unsigned long *iflagsp) @@ -2851,6 +2934,7 @@ sg_add_sfp(struct sg_device *sdp) dlen : SG_TOT_FD_THRESHOLD; atomic_set(&sfp->sum_fd_dlens, 0); 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); @@ -3239,7 +3323,7 @@ sg_proc_seq_show_devstrs(struct seq_file *s, void *v) } static const char * -sg_rq_state_str(u8 rq_state, bool long_str) +sg_rq_state_str(enum sg_rq_state rq_state, bool long_str) { switch (rq_state) { case SG_RQ_INACTIVE: diff --git a/include/scsi/sg.h b/include/scsi/sg.h index 596f68746f66..46fc7cbffd78 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h @@ -4,41 +4,21 @@ #include -/* - * History: - * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - * process control of SCSI devices. - * Development Sponsored by Killy Corp. NY NY - * - * Original driver (sg.h): - * Copyright (C) 1992 Lawrence Foard - * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2018 Douglas Gilbert - * - * Version: 3.9.01 (20181016) - * This version is for 2.6, 3 and 4 series kernels. - * - * Documentation - * ============= - * A web site for the SG device driver can be found at: - * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file] - * The documentation for the sg version 3 driver can be found at: - * http://sg.danny.cz/sg/p/sg_v3_ho.html - * Also see: /Documentation/scsi/scsi-generic.txt - * - * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html - */ - #ifdef __KERNEL__ extern int sg_big_buff; /* for sysctl */ #endif +/* + * In version 3.9.01 of the sg driver, this file was spilt in two, with the + * bulk of the user space interface being placed in the file being included + * in the following line. + */ #include #ifdef __KERNEL__ #define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ) /* HZ == 'jiffies in 1 second' */ #endif -#undef SG_DEFAULT_TIMEOUT /* cause define in sg.c */ +#undef SG_DEFAULT_TIMEOUT /* because of conflicting define in sg.c */ #endif /* end of ifndef _SCSI_GENERIC_H guard */ diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h index 37588e1c4e3a..b64d155541ea 100644 --- a/include/uapi/scsi/sg.h +++ b/include/uapi/scsi/sg.h @@ -2,27 +2,6 @@ #ifndef _UAPI_SCSI_SG_H #define _UAPI_SCSI_SG_H -/* - * Want to block the original sg.h header from also being included. That - * causes lots of multiple definition errors. This will only work if this - * header is included _before_ the original sg.h header . - */ -#define _SCSI_GENERIC_H /* original kernel header guard */ -#define _SCSI_SG_H /* glibc header guard */ - -/* - * Other UAPI headers include linux/compiler.h to resolve "__" types but that - * doesn't always work, perhaps in the future. Fall back to linux/types.h . - */ -/* #include */ -#include -#include - -/* Still problems with __user so define to nothing */ -#define __user - -#include - /* * History: * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user @@ -48,6 +27,11 @@ * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html */ +#include +#include + +/* bsg.h contains the sg v4 use space interface structure. */ +#include /* * Same structure as used by readv() call. It defines one scatter-gather @@ -109,7 +93,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 @@ -186,12 +170,22 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_SEIM_TOT_FD_THRESH 0x4 /* tot_fd_thresh field valid */ #define SG_SEIM_CTL_FLAGS 0x8 /* ctl_flags_mask bits in ctl_flags */ #define SG_SEIM_MINOR_INDEX 0x10 /* sg device minor index number */ -#define SG_SEIM_ALL_BITS 0x1f /* should be OR of previous items */ +#define SG_SEIM_READ_VAL 0x20 /* write SG_SEIRV, read related */ +#define SG_SEIM_ALL_BITS 0x3f /* should be OR of previous items */ #define SG_CTL_FLAGM_TIME_IN_NS 0x1 /* time: nanosecs (def: millisecs) */ #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 */ +#define SG_CTL_FLAGM_ALL_BITS 0x1f /* should be OR of previous items */ + +/* Write one of the following values to sg_extended_info::read_value, get... */ +#define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */ +#define SG_SEIRV_BOOL_MASK 0x1 /* get SG_CTL_FLAGM_ALL_BITS */ +#define SG_SEIRV_VERS_NUM 0x2 /* get driver version number as int */ +#define SG_SEIRV_FL_RQS 0x3 /* number of requests in free list */ +#define SG_SEIRV_DEV_FL_RQS 0x4 /* sum of rqs on all fds on this dev */ /* * A pointer to the following structure is passed as the third argument to @@ -203,11 +197,11 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ * back to the user space. If the same bit is set in both the *_wr_mask and * corresponding *_rd_mask fields, then the write action takes place before * the read action and no other operation will split the two. This structure - * is padded to 64 bytes to allow for new values to be added in the future. + * is padded to 96 bytes to allow for new values to be added in the future. */ struct sg_extended_info { - __u32 valid_wr_mask; /* OR-ed SG_SEIM_* values */ - __u32 valid_rd_mask; /* OR-ed SG_SEIM_* values */ + __u32 valid_wr_mask; /* OR-ed SG_SEIM_* user->driver values */ + __u32 valid_rd_mask; /* OR-ed SG_SEIM_* driver->user values */ __u32 reserved_sz; /* data/sgl size of pre-allocated request */ __u32 rq_rem_sgat_thresh;/* request re-use: clear data/sgat if > */ __u32 tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */ @@ -215,7 +209,8 @@ struct sg_extended_info { __u32 ctl_flags_rd_mask; /* OR-ed SG_CTL_FLAGM_* values */ __u32 ctl_flags; /* bit values OR-ed, see SG_CTL_FLAGM_* */ __u32 minor_index; /* rd: kernel's sg device minor number */ - __u8 pad_to_64[28]; /* pad so struct is 64 bytes long */ + __u32 read_value; /* write known value, read back related */ + __u8 pad_to_96[56]; /* pad so struct is 96 bytes long */ }; /*