From 67d0a8ecfa288928c2096123a9ddfb0e5392edbf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 6 Feb 2015 13:37:03 +0100 Subject: [PATCH] scsi: add bsg support 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 '/ scsi_debug /s,^[^/]*,,p') ./strace -eioctl -s256 sg_inq $dev echo 'Test XDWRITEREAD(10)' bsg=/dev/bsg/$(lsscsi | sed -n '/ scsi_debug /s,^\[\([^]]\+\)\].*,\1,p') dd if=/dev/zero bs=512 count=1 | ./strace -eioctl -s256 sg_raw -s 512 -r 1024 $bsg 53 00 00 00 00 01 00 00 01 00 * configure.ac (AC_CHECK_HEADERS): Add linux/bsg.h. * xlat/bsg_protocol.in: New file. * xlat/bsg_subprotocol.in: Likewise. * scsi.c: Include them and . (print_sg_io_v3_req, print_sg_io_v3_res, print_sg_io_v4_req, print_sg_io_v4_res): New functions. (print_sg_io_req, print_sg_io_res): Use them. (scsi_ioctl): Update callers. Signed-off-by: Bart Van Assche Signed-off-by: Dmitry V. Levin --- configure.ac | 1 + scsi.c | 250 +++++++++++++++++++++++++++++++--------- xlat/bsg_protocol.in | 1 + xlat/bsg_subprotocol.in | 3 + 4 files changed, 200 insertions(+), 55 deletions(-) create mode 100644 xlat/bsg_protocol.in create mode 100644 xlat/bsg_subprotocol.in diff --git a/configure.ac b/configure.ac index 2be3892f..b3e62bf0 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 da7851ec..81737ab7 100644 --- a/scsi.c +++ b/scsi.c @@ -33,7 +33,14 @@ # include # include -#include "xlat/sg_io_dxfer_direction.h" +# include "xlat/sg_io_dxfer_direction.h" + +# ifdef HAVE_LINUX_BSG_H +# include +# include +# 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) @@ -61,83 +68,216 @@ 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, - "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); + struct sg_io_hdr sg_io; - 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); + 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); 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) { - if (sg_io->dxfer_direction == SG_DXFER_FROM_DEV || - sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - uint32_t din_len = sg_io->dxfer_len; + struct sg_io_hdr sg_io; - 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) { + uint32_t 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; + + 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); + tprintf(", dout[%u]=", sg_io.dout_xfer_len); + if (sg_io.dout_iovec_count) + tprint_iov_upto(tcp, sg_io.dout_iovec_count, sg_io.dout_xferp, + 1, sg_io.dout_xfer_len); + else + print_sg_io_buffer(tcp, sg_io.dout_xferp, sg_io.dout_xfer_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 /* !HAVE_LINUX_BSG_H */ + +static void +print_sg_io_v4_req(struct tcb *tcp, long arg) +{ + tprintf(", %#lx", arg); +} + +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; + default: + tprints(", ..."); + } + +} + +static void +print_sg_io_res(struct tcb *tcp, uint32_t iid, long arg) +{ + if (!syserror(tcp)) { + 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) - tprintf(", %#lx", arg); - else { - tprints(", "); - print_sg_io_req(tcp, &sg_io); - } - } - 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); + tprints(", "); + if (umove(tcp, arg, &iid) < 0) + tprintf("%#lx", arg); else - tprints("}"); + print_sg_io_req(tcp, iid, arg); + } else { + if (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 00000000..d47f15b7 --- /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 00000000..5e63cd03 --- /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