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.
Signed-off-by: Bart Van Assche <[email protected]> --- configure.ac | 1 + scsi.c | 248 ++++++++++++++++++++++++++++++++++++++++-------- xlat/bsg_protocol.in | 1 + xlat/bsg_subprotocol.in | 3 + 4 files changed, 211 insertions(+), 42 deletions(-) create mode 100644 xlat/bsg_protocol.in create mode 100644 xlat/bsg_subprotocol.in diff --git a/configure.ac b/configure.ac index a0b4859..112ea1d 100644 --- a/configure.ac +++ b/configure.ac @@ -225,6 +225,7 @@ AC_CHECK_HEADERS(m4_normalize([ elf.h inttypes.h ioctls.h + linux/bsg.h linux/falloc.h linux/perf_event.h linux/ptrace.h diff --git a/scsi.c b/scsi.c index daf7252..bd2bbb2 100644 --- a/scsi.c +++ b/scsi.c @@ -35,8 +35,15 @@ #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 char *addr, const unsigned int len) +print_sg_io_buffer(struct tcb *tcp, unsigned long addr, const unsigned int len) { unsigned char *buf = NULL; unsigned int allocated, i; @@ -45,8 +52,8 @@ print_sg_io_buffer(struct tcb *tcp, unsigned char *addr, const unsigned int len) return; allocated = (len > max_strlen) ? max_strlen : len; if ((buf = malloc(allocated)) == NULL || - umoven(tcp, (unsigned long) addr, allocated, (char *) buf) < 0) { - tprintf("%p", addr); + umoven(tcp, addr, allocated, (char *) buf) < 0) { + tprintf("%#lx", addr); free(buf); return; } @@ -58,70 +65,227 @@ print_sg_io_buffer(struct tcb *tcp, unsigned char *addr, const unsigned int len) tprints(", ..."); } +/* Print up to @len bytes of an iovec */ static void -print_sg_io_req(struct tcb *tcp, struct sg_io_hdr *sg_io) +print_sg_iovec(struct tcb *tcp, unsigned long iovec_addr, + const unsigned iovec_count, const unsigned len) { - tprintf("{'%c', ", sg_io->interface_id); - printxval(sg_io_dxfer_direction, sg_io->dxfer_direction, + struct iovec *iov; + unsigned allocated, i, r, s; + + if (len == 0) + return; + allocated = iovec_count * sizeof(*iov); + iov = malloc(allocated); + if (iov == NULL) + return; + if (umoven(tcp, iovec_addr, allocated, (void *)iov) < 0) { + tprintf("%#lx", iovec_addr); + goto free; + } + r = len; + if (r > max_strlen) + r = max_strlen; + for (i = 0; i < iovec_count; i++) { + s = iov[i].iov_len; + if (s > r) + s = r; + print_sg_io_buffer(tcp, (unsigned long)iov[i].iov_base, s); + r -= s; + } + if (len > max_strlen) + tprints(", ..."); + +free: + free(iov); +} + +static void +print_sg_io_v3_req(struct tcb *tcp, long arg) +{ + 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, 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); - printstr(tcp, (unsigned long) sg_io->dxferp, - 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); + printstr(tcp, (unsigned long) sg_io.dxferp, + sg_io.dxfer_len); tprints("]"); } } 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) { - if (sg_io->dxfer_direction == SG_DXFER_FROM_DEV || - sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - tprintf(", data[%u]=[", sg_io->dxfer_len); - printstr(tcp, (unsigned long) sg_io->dxferp, - sg_io->dxfer_len); + struct sg_io_hdr sg_io; + + 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) { + tprintf(", data[%u]=[", sg_io.dxfer_len); + printstr(tcp, (unsigned long) sg_io.dxferp, + sg_io.dxfer_len); tprints("]"); } - 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, 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); + tprints("]"); + 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) + print_sg_iovec(tcp, sg_io.dout_xferp, sg_io.dout_iovec_count, + dout_len); + else + print_sg_io_buffer(tcp, sg_io.dout_xferp, dout_len); + tprints("]"); +} + +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); + tprints("]"); + din_len = sg_io.din_xfer_len - sg_io.din_resid; + tprintf(", din[%u]=[", din_len); + if (sg_io.din_iovec_count) + print_sg_iovec(tcp, sg_io.din_xferp, sg_io.din_iovec_count, + din_len); + else + print_sg_io_buffer(tcp, sg_io.din_xferp, din_len); + tprints("]"); + 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); +} +#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); + if (!syserror(tcp) && umove(tcp, arg, &iid) >= 0) + print_sg_io_res(tcp, iid, arg); else tprints("}"); } 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.2 ------------------------------------------------------------------------------ New Year. New Location. New Benefits. New Data Center in Ashburn, VA. GigeNET is offering a free month of service with a new server in Ashburn. Choose from 2 high performing configs, both with 100TB of bandwidth. Higher redundancy.Lower latency.Increased capacity.Completely compliant. http://p.sf.net/sfu/gigenet _______________________________________________ Strace-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/strace-devel
