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