The Linux kernel supports two different versions of the SG_IO API, namely v3 and v4. This patch adds support for version 4 of this API. At least the sg3_utils package supports version 4 of this API. Version 4 of this API is used if /dev/bsg/H:C:I:L is used as device name.
This patch has been tested by inspecting the output of the following commands: modprobe scsi_debug dev_size_mb=16 delay=0 dev=$(lsscsi | sed -n 's,.*scsi_debug[^/]*/,/,p') ./strace -s256 sg_inq $dev echo 'Test XDWRITEREAD(10)' bsg=/dev/bsg/$(lsscsi | sed -n 's/^\[\([0-9:]*\)\].*scsi_debug.*/\1/p') dd if=/dev/zero bs=512 count=1 | ./strace -s 256 sg_raw -s 512 -r 1024 $bsg 53 00 00 00 00 01 00 00 01 00 Signed-off-by: Bart Van Assche <bart.vanass...@sandisk.com> --- configure.ac | 1 + scsi.c | 233 ++++++++++++++++++++++++++++++++++++++---------- xlat/bsg_protocol.in | 1 + xlat/bsg_subprotocol.in | 3 + 4 files changed, 189 insertions(+), 49 deletions(-) create mode 100644 xlat/bsg_protocol.in create mode 100644 xlat/bsg_subprotocol.in diff --git a/configure.ac b/configure.ac index 33af123..71296b0 100644 --- a/configure.ac +++ b/configure.ac @@ -222,6 +222,7 @@ AC_CHECK_HEADERS(m4_normalize([ elf.h inttypes.h ioctls.h + linux/bsg.h linux/falloc.h linux/filter.h linux/hiddev.h diff --git a/scsi.c b/scsi.c index bce149e..4a41125 100644 --- a/scsi.c +++ b/scsi.c @@ -35,6 +35,13 @@ #include "xlat/sg_io_dxfer_direction.h" +# ifdef HAVE_LINUX_BSG_H +# include <linux/bsg.h> +# include <sys/uio.h> +# include "xlat/bsg_protocol.h" +# include "xlat/bsg_subprotocol.h" +# endif + static void print_sg_io_buffer(struct tcb *tcp, unsigned long addr, const unsigned int len) { @@ -64,84 +71,212 @@ out: } static void -print_sg_io_req(struct tcb *tcp, struct sg_io_hdr *sg_io) +print_sg_io_v3_req(struct tcb *tcp, long arg) { - tprintf("{'%c', ", sg_io->interface_id); - printxval(sg_io_dxfer_direction, sg_io->dxfer_direction, + struct sg_io_hdr sg_io; + + if (umove(tcp, arg, &sg_io) < 0) { + tprintf(", %#lx", arg); + return; + } + + tprints(", "); + printxval(sg_io_dxfer_direction, sg_io.dxfer_direction, "SG_DXFER_???"); - tprintf(", cmd[%u]=", sg_io->cmd_len); - print_sg_io_buffer(tcp, (unsigned long)sg_io->cmdp, sg_io->cmd_len); - tprintf(", mx_sb_len=%d, ", sg_io->mx_sb_len); - tprintf("iovec_count=%d, ", sg_io->iovec_count); - tprintf("dxfer_len=%u, ", sg_io->dxfer_len); - tprintf("timeout=%u, ", sg_io->timeout); - tprintf("flags=%#x", sg_io->flags); - - if (sg_io->dxfer_direction == SG_DXFER_TO_DEV || - sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - tprintf(", data[%u]=", sg_io->dxfer_len); - if (sg_io->iovec_count) - tprint_iov_upto(tcp, sg_io->iovec_count, - (unsigned long)sg_io->dxferp, 1, - sg_io->dxfer_len); + tprintf(", cmd[%u]=", sg_io.cmd_len); + print_sg_io_buffer(tcp, (unsigned long)sg_io.cmdp, sg_io.cmd_len); + tprintf(", mx_sb_len=%d", sg_io.mx_sb_len); + tprintf(", iovec_count=%d", sg_io.iovec_count); + tprintf(", dxfer_len=%u", sg_io.dxfer_len); + tprintf(", timeout=%u", sg_io.timeout); + tprintf(", flags=%#x", sg_io.flags); + + if (sg_io.dxfer_direction == SG_DXFER_TO_DEV || + sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) { + tprintf(", data[%u]=", sg_io.dxfer_len); + if (sg_io.iovec_count) + tprint_iov_upto(tcp, sg_io.iovec_count, + (unsigned long)sg_io.dxferp, 1, + sg_io.dxfer_len); else - print_sg_io_buffer(tcp, (unsigned long)sg_io->dxferp, - sg_io->dxfer_len); + print_sg_io_buffer(tcp, (unsigned long)sg_io.dxferp, + sg_io.dxfer_len); } } static void -print_sg_io_res(struct tcb *tcp, struct sg_io_hdr *sg_io) +print_sg_io_v3_res(struct tcb *tcp, long arg) { + struct sg_io_hdr sg_io; uint32_t din_len; - if (sg_io->dxfer_direction == SG_DXFER_FROM_DEV || - sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - din_len = sg_io->dxfer_len; - if (sg_io->resid > 0) - din_len -= sg_io->resid; + if (umove(tcp, arg, &sg_io) < 0) { + tprintf(", %#lx", arg); + return; + } + + if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV || + sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) { + din_len = sg_io.dxfer_len; + if (sg_io.resid > 0) + din_len -= sg_io.resid; tprintf(", data[%u]=", din_len); - if (sg_io->iovec_count) - tprint_iov_upto(tcp, sg_io->iovec_count, - (unsigned long)sg_io->dxferp, 1, + if (sg_io.iovec_count) + tprint_iov_upto(tcp, sg_io.iovec_count, + (unsigned long)sg_io.dxferp, 1, din_len); else - print_sg_io_buffer(tcp, (unsigned long)sg_io->dxferp, + print_sg_io_buffer(tcp, (unsigned long)sg_io.dxferp, din_len); } - tprintf(", status=%02x, ", sg_io->status); - tprintf("masked_status=%02x, ", sg_io->masked_status); - tprintf("sb[%u]=", sg_io->sb_len_wr); - print_sg_io_buffer(tcp, (unsigned long)sg_io->sbp, sg_io->sb_len_wr); - tprintf(", host_status=%#x, ", sg_io->host_status); - tprintf("driver_status=%#x, ", sg_io->driver_status); - tprintf("resid=%d, ", sg_io->resid); - tprintf("duration=%d, ", sg_io->duration); - tprintf("info=%#x}", sg_io->info); + tprintf(", status=%02x", sg_io.status); + tprintf(", masked_status=%02x", sg_io.masked_status); + tprintf(", sb[%u]=", sg_io.sb_len_wr); + print_sg_io_buffer(tcp, (unsigned long)sg_io.sbp, sg_io.sb_len_wr); + tprintf(", host_status=%#x", sg_io.host_status); + tprintf(", driver_status=%#x", sg_io.driver_status); + tprintf(", resid=%d", sg_io.resid); + tprintf(", duration=%d", sg_io.duration); + tprintf(", info=%#x", sg_io.info); +} + +#ifdef HAVE_LINUX_BSG_H +static void +print_sg_io_v4_req(struct tcb *tcp, long arg) +{ + struct sg_io_v4 sg_io; + uint32_t dout_len; + + if (umove(tcp, arg, &sg_io) < 0) { + tprintf(", %#lx", arg); + return; + } + + tprints(", "); + printxval(bsg_protocol, sg_io.protocol, "BSG_PROTOCOL_???"); + tprints(", "); + printxval(bsg_subprotocol, sg_io.subprotocol, "BSG_SUB_PROTOCOL_???"); + tprintf(", request[%u]=", sg_io.request_len); + print_sg_io_buffer(tcp, sg_io.request, sg_io.request_len); + tprintf(", request_tag=%llu", sg_io.request_tag); + tprintf(", request_attr=%u", sg_io.request_attr); + tprintf(", request_priority=%u", sg_io.request_priority); + tprintf(", request_extra=%u", sg_io.request_extra); + tprintf(", max_response_len=%u", sg_io.max_response_len); + + tprintf(", dout_iovec_count=%u", sg_io.dout_iovec_count); + tprintf(", dout_xfer_len=%u", sg_io.dout_xfer_len); + tprintf(", din_iovec_count=%u", sg_io.din_iovec_count); + tprintf(", din_xfer_len=%u", sg_io.din_xfer_len); + tprintf(", timeout=%u", sg_io.timeout); + tprintf(", flags=%u", sg_io.flags); + tprintf(", usr_ptr=%llu", sg_io.usr_ptr); + tprintf(", spare_in=%u", sg_io.spare_in); + dout_len = sg_io.dout_xfer_len; + tprintf(", dout[%u]=", dout_len); + if (sg_io.dout_iovec_count) + tprint_iov_upto(tcp, sg_io.dout_iovec_count, sg_io.dout_xferp, + 1, dout_len); + else + print_sg_io_buffer(tcp, sg_io.dout_xferp, dout_len); +} + +static void +print_sg_io_v4_res(struct tcb *tcp, long arg) +{ + struct sg_io_v4 sg_io; + uint32_t din_len; + + if (umove(tcp, arg, &sg_io) < 0) { + tprintf(", %#lx", arg); + return; + } + + tprintf(", response[%u]=", sg_io.response_len); + print_sg_io_buffer(tcp, sg_io.response, sg_io.response_len); + din_len = sg_io.din_xfer_len; + if (sg_io.din_resid > 0) + din_len -= sg_io.din_resid; + tprintf(", din[%u]=", din_len); + if (sg_io.din_iovec_count) + tprint_iov_upto(tcp, sg_io.din_iovec_count, sg_io.din_xferp, + 1, din_len); + else + print_sg_io_buffer(tcp, sg_io.din_xferp, din_len); + tprintf(", driver_status=%u", sg_io.driver_status); + tprintf(", transport_status=%u", sg_io.transport_status); + tprintf(", device_status=%u", sg_io.device_status); + tprintf(", retry_delay=%u", sg_io.retry_delay); + tprintf(", info=%u", sg_io.info); + tprintf(", duration=%u", sg_io.duration); + tprintf(", response_len=%u", sg_io.response_len); + tprintf(", din_resid=%u", sg_io.din_resid); + tprintf(", dout_resid=%u", sg_io.dout_resid); + tprintf(", generated_tag=%llu", sg_io.generated_tag); + tprintf(", spare_out=%u", sg_io.spare_out); +} +#else +static void +print_sg_io_v4_req(struct tcb *tcp, long arg) +{ + tprintf(" (missing <linux/bsg.h>)"); +} + +static void +print_sg_io_v4_res(struct tcb *tcp, long arg) +{ +} +#endif + +static void +print_sg_io_req(struct tcb *tcp, uint32_t iid, long arg) +{ + tprintf("{'%c'", iid); + + switch (iid) { + case 'S': + print_sg_io_v3_req(tcp, arg); + break; + case 'Q': + print_sg_io_v4_req(tcp, arg); + break; + } + +} + +static void +print_sg_io_res(struct tcb *tcp, uint32_t iid, long arg) +{ + switch (iid) { + case 'S': + print_sg_io_v3_res(tcp, arg); + break; + case 'Q': + print_sg_io_v4_res(tcp, arg); + break; + } + + tprintf("}"); } int scsi_ioctl(struct tcb *tcp, const unsigned int code, long arg) { + uint32_t iid; + switch (code) { case SG_IO: if (entering(tcp)) { - struct sg_io_hdr sg_io; - - if (umove(tcp, arg, &sg_io) < 0) + if (umove(tcp, arg, &iid) < 0) tprintf(", %#lx", arg); else { tprints(", "); - print_sg_io_req(tcp, &sg_io); + print_sg_io_req(tcp, iid, arg); } } if (exiting(tcp)) { - struct sg_io_hdr sg_io; - - if (!syserror(tcp) && umove(tcp, arg, &sg_io) >= 0) - print_sg_io_res(tcp, &sg_io); - else - tprints("}"); + if (!syserror(tcp) && umove(tcp, arg, &iid) >= 0) + print_sg_io_res(tcp, iid, arg); } break; default: diff --git a/xlat/bsg_protocol.in b/xlat/bsg_protocol.in new file mode 100644 index 0000000..d47f15b --- /dev/null +++ b/xlat/bsg_protocol.in @@ -0,0 +1 @@ +BSG_PROTOCOL_SCSI diff --git a/xlat/bsg_subprotocol.in b/xlat/bsg_subprotocol.in new file mode 100644 index 0000000..5e63cd0 --- /dev/null +++ b/xlat/bsg_subprotocol.in @@ -0,0 +1,3 @@ +BSG_SUB_PROTOCOL_SCSI_CMD +BSG_SUB_PROTOCOL_SCSI_TMF +BSG_SUB_PROTOCOL_SCSI_TRANSPORT -- 2.1.4 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel