1f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown#include "defs.h"
2f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
3f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown#ifdef LINUX
4f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown#include <sys/ioctl.h>
5f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown#include <scsi/sg.h>
6f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
7f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownstatic const struct xlat sg_io_dxfer_direction[] = {
8f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	{SG_DXFER_NONE,        "SG_DXFER_NONE"},
9f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	{SG_DXFER_TO_DEV,      "SG_DXFER_TO_DEV"},
10f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	{SG_DXFER_FROM_DEV,    "SG_DXFER_FROM_DEV"},
11f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	{SG_DXFER_TO_FROM_DEV, "SG_DXFER_TO_FROM_DEV"},
12f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	{0, NULL}
13f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown};
14f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
15f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownstatic void
16f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownprint_sg_io_buffer(struct tcb *tcp, unsigned char *addr, int len)
17f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown{
18f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	unsigned char *buf = NULL;
19f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	int     allocated, i;
20f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
21f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	if (len == 0)
22f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		return;
23f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	allocated = (len > max_strlen) ? max_strlen : len;
24f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	if (len < 0 ||
25f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	    (buf = malloc(allocated)) == NULL ||
26f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	    umoven(tcp, (unsigned long) addr, allocated, (char *) buf) < 0) {
27f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf("%p", addr);
28f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		free(buf);
29f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		return;
30f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	}
31f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("%02x", buf[0]);
32f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	for (i = 1; i < allocated; ++i)
33f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf(", %02x", buf[i]);
34f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	free(buf);
35f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	if (allocated != len)
36f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf(", ...");
37f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown}
38f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
39f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownstatic void
40f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownprint_sg_io_req(struct tcb *tcp, struct sg_io_hdr *sg_io)
41f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown{
42f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("{'%c', ", sg_io->interface_id);
43f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	printxval(sg_io_dxfer_direction, sg_io->dxfer_direction,
44f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		  "SG_DXFER_???");
45f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf(", cmd[%u]=[", sg_io->cmd_len);
46f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	print_sg_io_buffer(tcp, sg_io->cmdp, sg_io->cmd_len);
47f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("], mx_sb_len=%d, ", sg_io->mx_sb_len);
48f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("iovec_count=%d, ", sg_io->iovec_count);
49f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("dxfer_len=%u, ", sg_io->dxfer_len);
50f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("timeout=%u, ", sg_io->timeout);
51f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("flags=%#x", sg_io->flags);
52f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
53f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	if (sg_io->dxfer_direction == SG_DXFER_TO_DEV ||
54f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	    sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
55f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf(", data[%u]=[", sg_io->dxfer_len);
56f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		printstr(tcp, (unsigned long) sg_io->dxferp,
57f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			 sg_io->dxfer_len);
58f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf("]");
59f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	}
60f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown}
61f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
62f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownstatic void
63f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownprint_sg_io_res(struct tcb *tcp, struct sg_io_hdr *sg_io)
64f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown{
65f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	if (sg_io->dxfer_direction == SG_DXFER_FROM_DEV ||
66f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	    sg_io->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
67f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf(", data[%u]=[", sg_io->dxfer_len);
68f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		printstr(tcp, (unsigned long) sg_io->dxferp,
69f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			 sg_io->dxfer_len);
70f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		tprintf("]");
71f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	}
72f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf(", status=%02x, ", sg_io->status);
73f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("masked_status=%02x, ", sg_io->masked_status);
74f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("sb[%u]=[", sg_io->sb_len_wr);
75f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	print_sg_io_buffer(tcp, sg_io->sbp, sg_io->sb_len_wr);
76f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("], host_status=%#x, ", sg_io->host_status);
77f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("driver_status=%#x, ", sg_io->driver_status);
78f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("resid=%d, ", sg_io->resid);
79f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("duration=%d, ", sg_io->duration);
80f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	tprintf("info=%#x}", sg_io->info);
81f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown}
82f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
83f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownint
84f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brownscsi_ioctl(struct tcb *tcp, long code, long arg)
85f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown{
86f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	switch (code) {
87f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	case SG_IO:
88f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		if (entering(tcp)) {
89f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			struct sg_io_hdr sg_io;
90f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
91f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			if (umove(tcp, arg, &sg_io) < 0)
92f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown				tprintf(", %#lx", arg);
93f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			else {
94f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown				tprintf(", ");
95f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown				print_sg_io_req(tcp, &sg_io);
96f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			}
97f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		}
98f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		if (exiting(tcp)) {
99f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			struct sg_io_hdr sg_io;
100f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown
101f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			if (!syserror(tcp) && umove(tcp, arg, &sg_io) >= 0)
102f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown				print_sg_io_res(tcp, &sg_io);
103f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			else
104f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown				tprintf("}");
105f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		}
106f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		break;
107f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	default:
108f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		if (entering(tcp))
109f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown			tprintf(", %#lx", arg);
110f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown		break;
111f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	}
112f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown	return 1;
113f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown}
114f76f96e20f766e6bb91593885b1e800f8bc14a52Jeff Brown#endif /* LINUX */
115