aboutsummaryrefslogtreecommitdiff
path: root/testing/sg_tst_ioctl.c
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-12-17 21:16:36 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-12-17 21:16:36 +0000
commit18c9852db91032afe4bedd85857d558402b360e2 (patch)
treee1f3ef6efab1d17665cb19e85d43439888291a6e /testing/sg_tst_ioctl.c
parentd906e8cb000e95d9260d1833d3692c1c763e489a (diff)
downloadsg3_utils-18c9852db91032afe4bedd85857d558402b360e2.tar.gz
testing: improve sgs_dd, sg_tst_async and sg_tst_ioctl sg v4 test utilities
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@799 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing/sg_tst_ioctl.c')
-rw-r--r--testing/sg_tst_ioctl.c519
1 files changed, 368 insertions, 151 deletions
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index d7dc227b..d0d7d153 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -21,6 +21,8 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/socket.h> /* For passing fd_s via Unix sockets */
+
/* Kernel uapi header contain __user decorations on user space pointers
* to indicate they are unsafe in the kernel space. However glibc takes
* all those __user decorations out from headers in /usr/include/linux .
@@ -45,7 +47,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 0.98 20181207";
+static const char * version_str = "Version: 1.01 20181216";
#define INQ_REPLY_LEN 96
#define INQ_CMD_LEN 6
@@ -67,14 +69,29 @@ static const char * version_str = "Version: 0.98 20181207";
#define DEF_RESERVE_BUFF_SZ (256 * 1024)
+static bool is_parent = false;
+static bool do_fork = false;
+static bool ioctl_only = false;
+static bool q_at_tail = false;
+static bool write_only = false;
+
+static int childs_pid = 0;
+static int q_len = DEF_Q_LEN;
+static int sleep_secs = 0;
+static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
+static int verbose = 0;
+
+static const char * relative_cp = NULL;
+
static void
usage(void)
{
- printf("Usage: 'sg_tst_ioctl [-h] [-l=Q_LEN] [-o] [-r=SZ] [-s=SEC] "
+ printf("Usage: 'sg_tst_ioctl [-f] [-h] [-l=Q_LEN] [-o] [-r=SZ] [-s=SEC] "
"[-t]\n"
- " [-v] [-V] [-w] <sg_device>'\n"
+ " [-v] [-V] [-w] <sg_device> [<sg_device2>]'\n"
" where:\n"
+ " -f fork and test share between processes\n"
" -h help: print usage message then exit\n"
" -l=Q_LEN queue length, between 1 and 511 (def: 16)\n"
" -o ioctls only, then exit\n"
@@ -87,125 +104,114 @@ usage(void)
" -w write (submit) only then exit\n");
}
-
-int
-main(int argc, char * argv[])
+/* This function taken from Keith Parkard's blog dated 2101205 */
+static ssize_t
+sock_fd_write(int sock, const void *buf, ssize_t buflen, int fd)
{
- bool done;
- bool q_at_tail = false;
- bool ioctl_only = false;
- bool write_only = false;
- int sg_fd, k, ok, ver_num, pack_id, num_waiting, access_count;
- int sg_fd2 = -1;
- uint8_t inq_cdb[INQ_CMD_LEN] =
- {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
- uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
- {0x1d, 0, 0, 0, 0, 0};
- uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
- sg_io_hdr_t io_hdr[MAX_Q_LEN];
- sg_io_hdr_t rio_hdr;
- char * file_name = 0;
- char ebuff[EBUFF_SZ];
- uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
- int q_len = DEF_Q_LEN;
- int sleep_secs = 0;
- int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
- int verbose = 0;
- uint32_t cflags;
- struct sg_extended_info sei;
- struct sg_extended_info * seip;
- const char * second_fname = "/dev/sg2";
- struct sg_scsi_id ssi;
+ ssize_t size;
+ struct msghdr msg;
+ struct iovec iov;
+ union {
+ struct cmsghdr cmsghdr;
+ char control[CMSG_SPACE(sizeof (int))];
+ } cmsgu;
+ struct cmsghdr *cmsg;
+
+ iov.iov_base = (void *)buf; /* OS shouldn't write back in this */
+ iov.iov_len = buflen;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (fd != -1) {
+ msg.msg_control = cmsgu.control;
+ msg.msg_controllen = sizeof(cmsgu.control);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof (int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ printf ("passing fd %d\n", fd);
+ *((int *) CMSG_DATA(cmsg)) = fd;
+ } else {
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ printf ("not passing fd\n");
+ }
- for (k = 1; k < argc; ++k) {
- if (0 == memcmp("-t", argv[k], 2))
- q_at_tail = true;
- else if (0 == memcmp("-h", argv[k], 2)) {
- file_name = 0;
- break;
- } else if (0 == memcmp("-l=", argv[k], 3)) {
- q_len = atoi(argv[k] + 3);
- if ((q_len > 511) || (q_len < 1)) {
- printf("Expect -l= to take a number (q length) between 1 "
- "and 511\n");
- file_name = 0;
- break;
- }
- } else if (0 == memcmp("-o", argv[k], 2))
- ioctl_only = true;
- else if (0 == memcmp("-r=", argv[k], 3)) {
- reserve_buff_sz = atoi(argv[k] + 3);
- if (reserve_buff_sz < 0) {
- printf("Expect -r= to take a number 0 or higher\n");
- file_name = 0;
- break;
+ size = sendmsg(sock, &msg, 0);
+
+ if (size < 0)
+ perror ("sendmsg");
+ return size;
+}
+
+/* This function taken from Keith Parkard's blog dated 2101205 */
+static ssize_t
+sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
+{
+ ssize_t size;
+
+ if (fd) {
+ struct msghdr msg;
+ struct iovec iov;
+ union {
+ struct cmsghdr cmsghdr;
+ char control[CMSG_SPACE(sizeof (int))];
+ } cmsgu;
+ struct cmsghdr *cmsg;
+
+ iov.iov_base = buf;
+ iov.iov_len = bufsize;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgu.control;
+ msg.msg_controllen = sizeof(cmsgu.control);
+ size = recvmsg (sock, &msg, 0);
+ if (size < 0) {
+ perror ("recvmsg");
+ exit(1);
+ }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ if (cmsg->cmsg_level != SOL_SOCKET) {
+ fprintf (stderr, "invalid cmsg_level %d\n",
+ cmsg->cmsg_level);
+ exit(1);
}
- } else if (0 == memcmp("-s=", argv[k], 3)) {
- sleep_secs = atoi(argv[k] + 3);
- if (sleep_secs < 0) {
- printf("Expect -s= to take a number 0 or higher\n");
- file_name = 0;
- break;
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ fprintf (stderr, "invalid cmsg_type %d\n",
+ cmsg->cmsg_type);
+ exit(1);
}
- } else if (0 == memcmp("-vvvv", argv[k], 5))
- verbose += 4;
- else if (0 == memcmp("-vvv", argv[k], 4))
- verbose += 3;
- else if (0 == memcmp("-vv", argv[k], 3))
- verbose += 2;
- else if (0 == memcmp("-v", argv[k], 2))
- verbose += 1;
- else if (0 == memcmp("-V", argv[k], 2)) {
- printf("%s\n", version_str);
- file_name = 0;
- break;
- } else if (0 == memcmp("-w", argv[k], 2))
- write_only = true;
- else if (*argv[k] == '-') {
- printf("Unrecognized switch: %s\n", argv[k]);
- file_name = 0;
- break;
- }
- else if (0 == file_name)
- file_name = argv[k];
- else {
- printf("too many arguments\n");
- file_name = 0;
- break;
- }
- }
- if (0 == file_name) {
- usage();
- return 1;
- }
-
- /* An access mode of O_RDWR is required for write()/read() interface */
- if ((sg_fd = open(file_name, O_RDWR)) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sg_queue_tst: error opening file: %s", file_name);
- perror(ebuff);
- return 1;
- }
- if (verbose)
- fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
- file_name, sg_fd);
- if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) {
- pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
- strerror(errno));
- goto out;
+ *fd = *((int *) CMSG_DATA(cmsg));
+ printf ("received fd %d\n", *fd);
+ } else
+ *fd = -1;
+ } else {
+ size = read (sock, buf, bufsize);
+ if (size < 0) {
+ perror("read");
+ exit(1);
+ }
}
- printf("Linux sg driver version: %d\n", ver_num);
+ return size;
+}
- if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "%s: error opening file: %s", __func__, second_fname);
- perror(ebuff);
- return 1;
- }
- if (verbose)
- fprintf(stderr, "opened second file: %s successfully, fd=%d\n",
- second_fname, sg_fd2);
+static int
+tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
+ int sock, const char * cp)
+{
+ uint32_t cflags;
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
seip = &sei;
memset(seip, 0, sizeof(*seip));
@@ -224,6 +230,8 @@ main(int argc, char * argv[])
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_OTHER_OPENS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_ORPHANS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_Q_TAIL;
+ seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_SHARE;
+ seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_MASTER;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_UNSHARE;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_MASTER_FINI;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_MASTER_ERR;
@@ -233,48 +241,54 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
#if 1
- printf("SG_SET_GET_EXTENDED ioctl ok\n");
+ printf("%sSG_SET_GET_EXTENDED ioctl ok\n", cp);
if (SG_SEIM_RESERVED_SIZE & seip->valid_rd_mask)
- printf(" reserved size: %u\n", seip->reserved_sz);
+ printf(" %sreserved size: %u\n", cp, seip->reserved_sz);
if (SG_SEIM_MINOR_INDEX & seip->valid_rd_mask)
- printf(" minor index: %u\n", seip->minor_index);
+ printf(" %sminor index: %u\n", cp, seip->minor_index);
if (SG_SEIM_RQ_REM_THRESH & seip->valid_rd_mask)
- printf(" rq_rem_sgat_thresh: %u\n", seip->rq_rem_sgat_thresh);
+ printf(" %srq_rem_sgat_thresh: %u\n", cp, seip->rq_rem_sgat_thresh);
if (SG_SEIM_TOT_FD_THRESH & seip->valid_rd_mask)
- printf(" tot_fd_thresh: %u\n", seip->tot_fd_thresh);
+ printf(" %stot_fd_thresh: %u\n", cp, seip->tot_fd_thresh);
if ((SG_SEIM_CTL_FLAGS & seip->valid_rd_mask) ||
(SG_SEIM_CTL_FLAGS & seip->valid_wr_mask)) {
cflags = seip->ctl_flags;
if (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags_rd_mask)
- printf(" TIME_IN_NS: %s\n",
+ printf(" %sTIME_IN_NS: %s\n", cp,
(SG_CTL_FLAGM_TIME_IN_NS & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_OTHER_OPENS & seip->ctl_flags_rd_mask)
- printf(" OTHER_OPENS: %s\n",
+ printf(" %sOTHER_OPENS: %s\n", cp,
(SG_CTL_FLAGM_OTHER_OPENS & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_ORPHANS & seip->ctl_flags_rd_mask)
- printf(" ORPHANS: %s\n",
+ printf(" %sORPHANS: %s\n", cp,
(SG_CTL_FLAGM_ORPHANS & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_Q_TAIL & seip->ctl_flags_rd_mask)
- printf(" Q_TAIL: %s\n",
+ printf(" %sQ_TAIL: %s\n", cp,
(SG_CTL_FLAGM_Q_TAIL & cflags) ? "true" : "false");
+ if (SG_CTL_FLAGM_IS_SHARE & seip->ctl_flags_rd_mask)
+ printf(" %sIS_SHARE: %s\n", cp,
+ (SG_CTL_FLAGM_IS_SHARE & cflags) ? "true" : "false");
+ if (SG_CTL_FLAGM_IS_MASTER & seip->ctl_flags_rd_mask)
+ printf(" %sIS_MASTER: %s\n", cp,
+ (SG_CTL_FLAGM_IS_MASTER & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_UNSHARE & seip->ctl_flags_rd_mask)
- printf(" UNSHARE: %s\n",
+ printf(" %sUNSHARE: %s\n", cp,
(SG_CTL_FLAGM_UNSHARE & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_MASTER_FINI & seip->ctl_flags_rd_mask)
- printf(" MASTER_FINI: %s\n",
+ printf(" %sMASTER_FINI: %s\n", cp,
(SG_CTL_FLAGM_MASTER_FINI & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_MASTER_ERR & seip->ctl_flags_rd_mask)
- printf(" MASTER_ERR: %s\n",
+ printf(" %sMASTER_ERR: %s\n", cp,
(SG_CTL_FLAGM_MASTER_ERR & cflags) ? "true" : "false");
if (SG_CTL_FLAGM_CHECK_FOR_MORE & seip->ctl_flags_rd_mask)
- printf(" CHECK_FOR_MORE: %s\n",
+ printf(" %sCHECK_FOR_MORE: %s\n", cp,
(SG_CTL_FLAGM_CHECK_FOR_MORE & cflags) ? "true" : "false");
}
if (SG_SEIM_MINOR_INDEX & seip->valid_rd_mask)
- printf(" minor_index: %u\n", seip->minor_index);
+ printf(" %sminor_index: %u\n", cp, seip->minor_index);
printf("\n");
#endif
@@ -285,10 +299,20 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
+ }
+ printf(" %sread_value[SG_SEIRV_INT_MASK]= %u\n", cp, seip->read_value);
+
+ memset(seip, 0, sizeof(*seip));
+ seip->valid_wr_mask |= SG_SEIM_READ_VAL;
+ seip->valid_rd_mask |= SG_SEIM_READ_VAL;
+ seip->read_value = SG_SEIRV_BOOL_MASK;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
+ strerror(errno));
+ return 1;
}
- printf("SG_SET_GET_EXTENDED ioctl ok\n");
- printf(" read_value[SG_SEIRV_INT_MASK]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_BOOL_MASK]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
@@ -297,9 +321,9 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
- printf(" read_value[SG_SEIRV_VERS_NUM]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_VERS_NUM]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
@@ -308,9 +332,9 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
- printf(" read_value[SG_SEIRV_FL_RQS]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_FL_RQS]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
@@ -319,9 +343,9 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
- printf(" read_value[SG_SEIRV_DEV_FL_RQS]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_DEV_FL_RQS]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
@@ -330,9 +354,9 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
- printf(" read_value[SG_SEIRV_TRC_SZ]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_TRC_SZ]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
@@ -341,9 +365,9 @@ main(int argc, char * argv[])
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
strerror(errno));
- goto out;
+ return 1;
}
- printf(" read_value[SG_SEIRV_TRC_MAX_SZ]= %u\n", seip->read_value);
+ printf(" %sread_value[SG_SEIRV_TRC_MAX_SZ]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_SHARE_FD;
@@ -353,10 +377,15 @@ main(int argc, char * argv[])
#else
seip->share_fd = sg_fd;
#endif
- if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0)
- pr2serr("ioctl(SG_SET_GET_EXTENDED) shared_fd=%d, failed errno=%d "
- "%s\n", sg_fd2, errno, strerror(errno));
- printf(" read back shared_fd= %u\n", seip->share_fd);
+ if (do_fork && is_parent)
+ goto bypass_share;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("%sioctl(SG_SET_GET_EXTENDED) shared_fd=%d, failed errno=%d "
+ "%s\n", cp, sg_fd2, errno, strerror(errno));
+ }
+ printf(" %sshare successful, read back shared_fd= %d\n", cp,
+ (int)seip->share_fd);
+bypass_share:
// printf("SG_IOSUBMIT value=0x%lx\n", SG_IOSUBMIT);
// printf("SG_IORECEIVE value=0x%lx\n", SG_IORECEIVE);
@@ -364,17 +393,203 @@ main(int argc, char * argv[])
pr2serr("ioctl(SG_GET_TRANSFORM) fail expected, errno=%d %s\n",
errno, strerror(errno));
else
- printf("SG_GET_TRANSFORM okay (does nothing)\n");
+ printf("%sSG_GET_TRANSFORM okay (does nothing)\n", cp);
if (ioctl(sg_fd, SG_SET_TRANSFORM, NULL) < 0)
pr2serr("ioctl(SG_SET_TRANSFORM) fail expected, errno=%d %s\n",
errno, strerror(errno));
else
- printf("SG_SET_TRANSFORM okay (does nothing)\n");
+ printf("%sSG_SET_TRANSFORM okay (does nothing)\n", cp);
printf("\n");
+ /* test sending a sg file descriptor between 2 processes using UNIX
+ * sockets */
+ if (do_fork && is_parent && fnp && (sock >= 0)) { /* master/READ side */
+ int res;
+ int fd_ma = open(fnp, O_RDWR);
+
+ if (fd_ma < 0) {
+ pr2serr("%s: opening %s failed: %s\n", __func__, fnp,
+ strerror(errno));
+ return 1;
+ }
+ res = sock_fd_write(sock, "boo", 4, fd_ma);
+ if (res < 0)
+ pr2serr("%s: sock_fd_write() failed\n", __func__);
+ else
+ printf("%s: sock_fd_write() returned: %d\n", __func__, res);
+ } else if (do_fork && !is_parent && fn2p && (sock >= 0)) {
+ int res, fd_ma;
+ /* int fd_sl = open(fn2p, O_RDWR); not needed */
+ uint8_t b[32];
+
+ fd_ma = -1;
+ res = sock_fd_read(sock, b, sizeof(b), &fd_ma);
+ if (res < 0)
+ pr2serr("%s: sock_fd_read() failed\n", __func__);
+ else
+ printf("%s: sock_fd_read() returned: %d, fd_ma=%d\n", __func__,
+ res, fd_ma);
+ /* yes it works! */
+ }
+ return 0;
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ bool done;
+ int sg_fd, k, ok, ver_num, pack_id, num_waiting, access_count;
+ int sg_fd2 = -1;
+ int sock = -1;
+ uint8_t inq_cdb[INQ_CMD_LEN] =
+ {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
+ uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
+ {0x1d, 0, 0, 0, 0, 0};
+ uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
+ sg_io_hdr_t io_hdr[MAX_Q_LEN];
+ sg_io_hdr_t rio_hdr;
+ char * file_name = 0;
+ char ebuff[EBUFF_SZ];
+ uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
+ const char * second_fname = NULL;
+ const char * cp;
+ struct sg_scsi_id ssi;
+
+ for (k = 1; k < argc; ++k) {
+ if (0 == memcmp("-f", argv[k], 2))
+ do_fork = true;
+ else if (0 == memcmp("-h", argv[k], 2)) {
+ file_name = 0;
+ break;
+ } else if (0 == memcmp("-l=", argv[k], 3)) {
+ q_len = atoi(argv[k] + 3);
+ if ((q_len > 511) || (q_len < 1)) {
+ printf("Expect -l= to take a number (q length) between 1 "
+ "and 511\n");
+ file_name = 0;
+ break;
+ }
+ } else if (0 == memcmp("-o", argv[k], 2))
+ ioctl_only = true;
+ else if (0 == memcmp("-r=", argv[k], 3)) {
+ reserve_buff_sz = atoi(argv[k] + 3);
+ if (reserve_buff_sz < 0) {
+ printf("Expect -r= to take a number 0 or higher\n");
+ file_name = 0;
+ break;
+ }
+ } else if (0 == memcmp("-s=", argv[k], 3)) {
+ sleep_secs = atoi(argv[k] + 3);
+ if (sleep_secs < 0) {
+ printf("Expect -s= to take a number 0 or higher\n");
+ file_name = 0;
+ break;
+ }
+ } else if (0 == memcmp("-t", argv[k], 2))
+ q_at_tail = true;
+ else if (0 == memcmp("-vvvv", argv[k], 5))
+ verbose += 4;
+ else if (0 == memcmp("-vvv", argv[k], 4))
+ verbose += 3;
+ else if (0 == memcmp("-vv", argv[k], 3))
+ verbose += 2;
+ else if (0 == memcmp("-v", argv[k], 2))
+ verbose += 1;
+ else if (0 == memcmp("-V", argv[k], 2)) {
+ printf("%s\n", version_str);
+ file_name = 0;
+ break;
+ } else if (0 == memcmp("-w", argv[k], 2))
+ write_only = true;
+ else if (*argv[k] == '-') {
+ printf("Unrecognized switch: %s\n", argv[k]);
+ file_name = 0;
+ break;
+ }
+ else if (0 == file_name)
+ file_name = argv[k];
+ else if (NULL == second_fname)
+ second_fname = argv[k];
+ else {
+ printf("too many arguments\n");
+ file_name = 0;
+ break;
+ }
+ }
+ if (0 == file_name) {
+ printf("No filename (sg device) given\n\n");
+ usage();
+ return 1;
+ }
+
+ /* An access mode of O_RDWR is required for write()/read() interface */
+ if ((sg_fd = open(file_name, O_RDWR)) < 0) {
+ snprintf(ebuff, EBUFF_SZ,
+ "error opening file: %s", file_name);
+ perror(ebuff);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
+ file_name, sg_fd);
+
+ if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) {
+ pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
+ strerror(errno));
+ goto out;
+ }
+ printf("Linux sg driver version: %d\n", ver_num);
+
+ if (second_fname) {
+ if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
+ snprintf(ebuff, EBUFF_SZ,
+ "%s: error opening file: %s", __func__, second_fname);
+ perror(ebuff);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "opened second file: %s successfully, fd=%d\n",
+ second_fname, sg_fd2);
+ }
+
+ if (do_fork) {
+ int pid;
+ int sv[2];
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
+ perror("socketpair");
+ exit(1);
+ }
+ printf("socketpair: sv[0]=%d, sv[1]=%d sg_fd=%d\n", sv[0], sv[1],
+ sg_fd);
+ pid = fork();
+ if (pid < 0) {
+ perror("fork() failed");
+ goto out;
+ } else if (0 == pid) {
+ relative_cp = "child ";
+ is_parent = false;
+ close(sv[0]);
+ sock = sv[1];
+ } else {
+ relative_cp = "parent ";
+ is_parent = true;
+ childs_pid = pid;
+ close(sv[1]);
+ sock = sv[0];
+ }
+ }
+
+ cp = do_fork ? relative_cp : "";
+ if (tst_ioctl(file_name, sg_fd, second_fname, sg_fd2, sock, cp))
+ goto out;
if (ioctl_only)
goto out;
+ if (do_fork && !is_parent)
+ return 0;
+
printf("start write() calls\n");
for (k = 0; k < q_len; ++k) {
/* Prepare INQUIRY command */
@@ -405,7 +620,7 @@ main(int argc, char * argv[])
/* io_hdr[k].usr_ptr = NULL; */
if (write(sg_fd, &io_hdr[k], sizeof(sg_io_hdr_t)) < 0) {
- perror("sg_queue_tst: sg write error");
+ pr2serr("%ssg write errno=%d [%s]\n", cp, errno, strerror(errno));
close(sg_fd);
return 1;
}
@@ -440,6 +655,8 @@ main(int argc, char * argv[])
if (write_only)
goto out;
+ if (do_fork)
+ printf("\n\nFollowing starting with get_pack_id are all CHILD\n");
if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
errno, strerror(errno));
@@ -475,7 +692,7 @@ main(int argc, char * argv[])
memset(&rio_hdr, 0, sizeof(sg_io_hdr_t));
rio_hdr.interface_id = 'S';
if (read(sg_fd, &rio_hdr, sizeof(sg_io_hdr_t)) < 0) {
- perror("sg_queue_tst: sg read error");
+ perror("sg read error");
close(sg_fd);
return 1;
}