/*
* Copyright (c) 2007 Vladimir Nadvornik <nadvornik@suse.cz>
- * Copyright (c) 2007 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2007-2017 Dmitry V. Levin <ldv@altlinux.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "defs.h"
#ifdef HAVE_SCSI_SG_H
-
-# include <linux/ioctl.h>
# include <scsi/sg.h>
+#endif
-# 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)
-{
- unsigned char *buf = NULL;
- unsigned int allocated, i;
-
- tprints("[");
- if (len == 0)
- goto out;
- allocated = (len > max_strlen) ? max_strlen : len;
- buf = malloc(allocated);
- if (!buf || umoven(tcp, addr, allocated, buf) < 0) {
- printaddr(addr);
- goto out;
- }
- tprintf("%02x", buf[0]);
- for (i = 1; i < allocated; ++i)
- tprintf(", %02x", buf[i]);
- if (allocated != len)
- tprints(", ...");
-out:
- free(buf);
- tprints("]");
-}
+#include "xlat/scsi_sg_commands.h"
+#include "xlat/sg_scsi_reset.h"
static int
-print_sg_io_v3_req(struct tcb *tcp, const long arg)
+decode_sg_io(struct tcb *const tcp, const uint32_t iid,
+ const kernel_ulong_t arg)
{
- struct sg_io_hdr sg_io;
-
- if (umove(tcp, arg, &sg_io) < 0) {
- tprints("???}");
- return RVAL_DECODED | 1;
+ switch (iid) {
+ case 'S':
+ return decode_sg_io_v3(tcp, arg);
+ case 'Q':
+ return decode_sg_io_v4(tcp, arg);
+ default:
+ tprintf("[%u]", iid);
+ return RVAL_DECODED | 1;
}
- 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);
- }
- return 1;
}
-static void
-print_sg_io_v3_res(struct tcb *tcp, const long arg)
-{
- struct sg_io_hdr sg_io;
-
- if (umove(tcp, arg, &sg_io) < 0) {
- tprints(", ???");
- 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,
- din_len);
- else
- 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);
-}
-
-#ifdef HAVE_LINUX_BSG_H
+#ifdef HAVE_SCSI_SG_H
static int
-print_sg_io_v4_req(struct tcb *tcp, const long arg)
+decode_sg_scsi_id(struct tcb *const tcp, const kernel_ulong_t arg)
{
- struct sg_io_v4 sg_io;
+ struct sg_scsi_id id;
- if (umove(tcp, arg, &sg_io) < 0) {
- tprints("???}");
- return RVAL_DECODED | 1;
- }
+ if (entering(tcp))
+ return 0;
- 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", (unsigned long long) 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", (unsigned long long) 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);
- return 1;
-}
-
-static void
-print_sg_io_v4_res(struct tcb *tcp, const long arg)
-{
- struct sg_io_v4 sg_io;
- uint32_t din_len;
-
- if (umove(tcp, arg, &sg_io) < 0) {
- tprints(", ???");
- return;
+ if (!umove_or_printaddr(tcp, arg, &id)) {
+ tprintf("{host_no=%d"
+ ", channel=%d"
+ ", scsi_id=%#x"
+ ", lun=%d"
+ ", scsi_type=%#x"
+ ", h_cmd_per_lun=%hd"
+ ", d_queue_depth=%hd}",
+ id.host_no,
+ id.channel,
+ id.scsi_id,
+ id.lun,
+ id.scsi_type,
+ id.h_cmd_per_lun,
+ id.d_queue_depth);
}
-
- 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", (unsigned long long) sg_io.generated_tag);
- tprintf(", spare_out=%u", sg_io.spare_out);
-}
-
-#else /* !HAVE_LINUX_BSG_H */
-
-static int
-print_sg_io_v4_req(struct tcb *tcp, const long arg)
-{
- tprints("...}");
return RVAL_DECODED | 1;
}
-static void
-print_sg_io_v4_res(struct tcb *tcp, const long arg)
+#endif /* HAVE_SCSI_SG_H */
+
+int
+scsi_ioctl(struct tcb *const tcp, const unsigned int code,
+ const kernel_ulong_t arg)
{
-}
+ switch (code) {
+ case SG_IO:
+ if (entering(tcp)) {
+ uint32_t iid;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, arg, &iid)) {
+ break;
+ } else {
+ return decode_sg_io(tcp, iid, arg);
+ }
+ } else {
+ uint32_t *piid = get_tcb_priv_data(tcp);
+ if (piid)
+ decode_sg_io(tcp, *piid, arg);
+ tprints("}");
+ break;
+ }
-#endif
+#ifdef HAVE_SCSI_SG_H
+ /* returns struct sg_scsi_id */
+ case SG_GET_SCSI_ID:
+ return decode_sg_scsi_id(tcp, arg);
+ /* returns struct sg_req_info */
+ case SG_GET_REQUEST_TABLE:
+ return decode_sg_req_info(tcp, arg);
+#endif /* HAVE_SCSI_SG_H */
-static int
-print_sg_io_req(struct tcb *tcp, uint32_t iid, const long arg)
-{
- tprintf("{'%c', ", iid);
+ /* takes a value by pointer */
+ case SG_SCSI_RESET: {
+ unsigned int val;
+ tprints(", ");
+ if (!umove_or_printaddr(tcp, arg, &val)) {
+ tprints("[");
+ if (val & SG_SCSI_RESET_NO_ESCALATE) {
+ printxval(sg_scsi_reset,
+ SG_SCSI_RESET_NO_ESCALATE, 0);
+ tprints("|");
+ }
+ printxval(sg_scsi_reset,
+ val & ~SG_SCSI_RESET_NO_ESCALATE,
+ "SG_SCSI_RESET_???");
+ tprints("]");
- switch (iid) {
- case 'S':
- return print_sg_io_v3_req(tcp, arg);
- case 'Q':
- return print_sg_io_v4_req(tcp, arg);
- default:
- tprints("...}");
- return RVAL_DECODED | 1;
+ }
+ break;
}
-}
+ /* takes a signed int by pointer */
+ case SG_NEXT_CMD_LEN:
+ case SG_SET_COMMAND_Q:
+ case SG_SET_DEBUG:
+ case SG_SET_FORCE_LOW_DMA:
+ case SG_SET_FORCE_PACK_ID:
+ case SG_SET_KEEP_ORPHAN:
+ case SG_SET_RESERVED_SIZE:
+ case SG_SET_TIMEOUT:
+ tprints(", ");
+ printnum_int(tcp, arg, "%d");
+ break;
-static void
-print_sg_io_res(struct tcb *tcp, uint32_t iid, const long arg)
-{
- switch (iid) {
- case 'S':
- print_sg_io_v3_res(tcp, arg);
+ /* returns a signed int by pointer */
+ case SG_EMULATED_HOST:
+ case SG_GET_ACCESS_COUNT:
+ case SG_GET_COMMAND_Q:
+ case SG_GET_KEEP_ORPHAN:
+ case SG_GET_LOW_DMA:
+ case SG_GET_NUM_WAITING:
+ case SG_GET_PACK_ID:
+ case SG_GET_RESERVED_SIZE:
+ case SG_GET_SG_TABLESIZE:
+ case SG_GET_TRANSFORM:
+ case SG_GET_VERSION_NUM:
+ if (entering(tcp))
+ return 0;
+ tprints(", ");
+ printnum_int(tcp, arg, "%d");
break;
- case 'Q':
- print_sg_io_v4_res(tcp, arg);
+
+ /* takes an integer by value */
+ case SG_SET_TRANSFORM:
+ tprintf(", %#x", (unsigned int) arg);
break;
- }
-}
-int
-scsi_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
-{
- uint32_t iid;
+ /* no arguments */
+ case SG_GET_TIMEOUT:
+ break;
- if (SG_IO != code)
+ default:
return RVAL_DECODED;
-
- if (entering(tcp)) {
- tprints(", ");
- if (!arg || umove(tcp, arg, &iid) < 0) {
- printaddr(arg);
- return RVAL_DECODED | 1;
- } else {
- return print_sg_io_req(tcp, iid, arg);
- }
- } else {
- if (!syserror(tcp)) {
- if (umove(tcp, arg, &iid) < 0)
- tprints(", ???");
- else
- print_sg_io_res(tcp, iid, arg);
- }
- tprintf("}");
- return RVAL_DECODED | 1;
}
-}
-#endif /* HAVE_SCSI_SG_H */
+ return RVAL_DECODED | 1;
+}