blob: 83ff8fe0e9da04c9a55b70431ee88e45fb013ac3 [file] [log] [blame]
Dmitry V. Levin27aeaa22012-03-16 10:43:32 +00001/*
2 * Copyright (c) 2007 Vladimir Nadvornik <nadvornik@suse.cz>
3 * Copyright (c) 2007 Dmitry V. Levin <ldv@altlinux.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
Dmitry V. Levinb011af52007-06-30 11:37:09 +000029#include "defs.h"
Dmitry V. Levinfdb896e2014-02-25 23:04:55 +000030
31#ifdef HAVE_SCSI_SG_H
32
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +030033# include <linux/ioctl.h>
Dmitry V. Levinfdb896e2014-02-25 23:04:55 +000034# include <scsi/sg.h>
Dmitry V. Levinb011af52007-06-30 11:37:09 +000035
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010036# include "xlat/sg_io_dxfer_direction.h"
37
38# ifdef HAVE_LINUX_BSG_H
39# include <linux/bsg.h>
40# include <sys/uio.h>
41# include "xlat/bsg_protocol.h"
42# include "xlat/bsg_subprotocol.h"
43# endif
Dmitry V. Levinb011af52007-06-30 11:37:09 +000044
Dmitry V. Levin48b06a62016-05-07 23:10:50 +000045static bool
46print_uchar(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
Dmitry V. Levinb011af52007-06-30 11:37:09 +000047{
Dmitry V. Levin48b06a62016-05-07 23:10:50 +000048 tprintf("%02x", (unsigned int) (* (unsigned char *) elem_buf));
Dmitry V. Levinb011af52007-06-30 11:37:09 +000049
Dmitry V. Levin48b06a62016-05-07 23:10:50 +000050 return true;
51}
52
53static void
54print_sg_io_buffer(struct tcb *tcp, const unsigned long addr, const unsigned int len)
55{
56 unsigned char buf;
57
58 print_array(tcp, addr, len, &buf, sizeof(buf),
59 umoven_or_printaddr, print_uchar, 0);
Dmitry V. Levinb011af52007-06-30 11:37:09 +000060}
61
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +030062static int
63print_sg_io_v3_req(struct tcb *tcp, const long arg)
Dmitry V. Levinb011af52007-06-30 11:37:09 +000064{
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010065 struct sg_io_hdr sg_io;
Dmitry V. Levinb011af52007-06-30 11:37:09 +000066
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010067 if (umove(tcp, arg, &sg_io) < 0) {
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +030068 tprints("???}");
69 return RVAL_DECODED | 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010070 }
71
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010072 printxval(sg_io_dxfer_direction, sg_io.dxfer_direction,
73 "SG_DXFER_???");
74 tprintf(", cmd[%u]=", sg_io.cmd_len);
75 print_sg_io_buffer(tcp, (unsigned long) sg_io.cmdp, sg_io.cmd_len);
76 tprintf(", mx_sb_len=%d", sg_io.mx_sb_len);
77 tprintf(", iovec_count=%d", sg_io.iovec_count);
78 tprintf(", dxfer_len=%u", sg_io.dxfer_len);
79 tprintf(", timeout=%u", sg_io.timeout);
80 tprintf(", flags=%#x", sg_io.flags);
81
82 if (sg_io.dxfer_direction == SG_DXFER_TO_DEV ||
83 sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
84 tprintf(", data[%u]=", sg_io.dxfer_len);
85 if (sg_io.iovec_count)
86 tprint_iov_upto(tcp, sg_io.iovec_count,
87 (unsigned long) sg_io.dxferp, 1,
88 sg_io.dxfer_len);
Bart Van Assche791145e2015-02-06 13:36:26 +010089 else
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010090 print_sg_io_buffer(tcp, (unsigned long) sg_io.dxferp,
91 sg_io.dxfer_len);
Dmitry V. Levinb011af52007-06-30 11:37:09 +000092 }
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +030093 return 1;
Dmitry V. Levinb011af52007-06-30 11:37:09 +000094}
95
96static void
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +030097print_sg_io_v3_res(struct tcb *tcp, const long arg)
Dmitry V. Levinb011af52007-06-30 11:37:09 +000098{
Bart Van Assche67d0a8e2015-02-06 13:37:03 +010099 struct sg_io_hdr sg_io;
Bart Van Assche0014bb12015-02-06 13:36:26 +0100100
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100101 if (umove(tcp, arg, &sg_io) < 0) {
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300102 tprints(", ???");
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100103 return;
104 }
105
106 if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV ||
107 sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
108 uint32_t din_len = sg_io.dxfer_len;
109
110 if (sg_io.resid > 0)
111 din_len -= sg_io.resid;
Bart Van Assche791145e2015-02-06 13:36:26 +0100112 tprintf(", data[%u]=", din_len);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100113 if (sg_io.iovec_count)
114 tprint_iov_upto(tcp, sg_io.iovec_count,
115 (unsigned long) sg_io.dxferp, 1,
Bart Van Assche791145e2015-02-06 13:36:26 +0100116 din_len);
117 else
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100118 print_sg_io_buffer(tcp, (unsigned long) sg_io.dxferp,
Bart Van Assche791145e2015-02-06 13:36:26 +0100119 din_len);
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000120 }
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100121 tprintf(", status=%02x", sg_io.status);
122 tprintf(", masked_status=%02x", sg_io.masked_status);
123 tprintf(", sb[%u]=", sg_io.sb_len_wr);
124 print_sg_io_buffer(tcp, (unsigned long) sg_io.sbp, sg_io.sb_len_wr);
125 tprintf(", host_status=%#x", sg_io.host_status);
126 tprintf(", driver_status=%#x", sg_io.driver_status);
127 tprintf(", resid=%d", sg_io.resid);
128 tprintf(", duration=%d", sg_io.duration);
129 tprintf(", info=%#x", sg_io.info);
130}
131
132#ifdef HAVE_LINUX_BSG_H
133
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300134static int
135print_sg_io_v4_req(struct tcb *tcp, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100136{
137 struct sg_io_v4 sg_io;
138
139 if (umove(tcp, arg, &sg_io) < 0) {
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300140 tprints("???}");
141 return RVAL_DECODED | 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100142 }
143
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100144 printxval(bsg_protocol, sg_io.protocol, "BSG_PROTOCOL_???");
145 tprints(", ");
146 printxval(bsg_subprotocol, sg_io.subprotocol, "BSG_SUB_PROTOCOL_???");
147 tprintf(", request[%u]=", sg_io.request_len);
148 print_sg_io_buffer(tcp, sg_io.request, sg_io.request_len);
Dmitry V. Levin51507202016-05-26 10:07:36 +0000149 tprintf(", request_tag=%" PRI__u64, sg_io.request_tag);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100150 tprintf(", request_attr=%u", sg_io.request_attr);
151 tprintf(", request_priority=%u", sg_io.request_priority);
152 tprintf(", request_extra=%u", sg_io.request_extra);
153 tprintf(", max_response_len=%u", sg_io.max_response_len);
154
155 tprintf(", dout_iovec_count=%u", sg_io.dout_iovec_count);
156 tprintf(", dout_xfer_len=%u", sg_io.dout_xfer_len);
157 tprintf(", din_iovec_count=%u", sg_io.din_iovec_count);
158 tprintf(", din_xfer_len=%u", sg_io.din_xfer_len);
159 tprintf(", timeout=%u", sg_io.timeout);
160 tprintf(", flags=%u", sg_io.flags);
Dmitry V. Levin51507202016-05-26 10:07:36 +0000161 tprintf(", usr_ptr=%" PRI__u64, sg_io.usr_ptr);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100162 tprintf(", spare_in=%u", sg_io.spare_in);
163 tprintf(", dout[%u]=", sg_io.dout_xfer_len);
164 if (sg_io.dout_iovec_count)
165 tprint_iov_upto(tcp, sg_io.dout_iovec_count, sg_io.dout_xferp,
166 1, sg_io.dout_xfer_len);
167 else
168 print_sg_io_buffer(tcp, sg_io.dout_xferp, sg_io.dout_xfer_len);
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300169 return 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100170}
171
172static void
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300173print_sg_io_v4_res(struct tcb *tcp, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100174{
175 struct sg_io_v4 sg_io;
176 uint32_t din_len;
177
178 if (umove(tcp, arg, &sg_io) < 0) {
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300179 tprints(", ???");
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100180 return;
181 }
182
183 tprintf(", response[%u]=", sg_io.response_len);
184 print_sg_io_buffer(tcp, sg_io.response, sg_io.response_len);
185 din_len = sg_io.din_xfer_len;
186 if (sg_io.din_resid > 0)
187 din_len -= sg_io.din_resid;
188 tprintf(", din[%u]=", din_len);
189 if (sg_io.din_iovec_count)
190 tprint_iov_upto(tcp, sg_io.din_iovec_count, sg_io.din_xferp,
191 1, din_len);
192 else
193 print_sg_io_buffer(tcp, sg_io.din_xferp, din_len);
194 tprintf(", driver_status=%u", sg_io.driver_status);
195 tprintf(", transport_status=%u", sg_io.transport_status);
196 tprintf(", device_status=%u", sg_io.device_status);
197 tprintf(", retry_delay=%u", sg_io.retry_delay);
198 tprintf(", info=%u", sg_io.info);
199 tprintf(", duration=%u", sg_io.duration);
200 tprintf(", response_len=%u", sg_io.response_len);
201 tprintf(", din_resid=%u", sg_io.din_resid);
202 tprintf(", dout_resid=%u", sg_io.dout_resid);
Dmitry V. Levin51507202016-05-26 10:07:36 +0000203 tprintf(", generated_tag=%" PRI__u64, sg_io.generated_tag);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100204 tprintf(", spare_out=%u", sg_io.spare_out);
205}
206
207#else /* !HAVE_LINUX_BSG_H */
208
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300209static int
210print_sg_io_v4_req(struct tcb *tcp, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100211{
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300212 tprints("...}");
213 return RVAL_DECODED | 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100214}
215
216static void
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300217print_sg_io_v4_res(struct tcb *tcp, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100218{
219}
220
221#endif
222
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300223static int
224print_sg_io_req(struct tcb *tcp, uint32_t iid, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100225{
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300226 tprintf("{'%c', ", iid);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100227
228 switch (iid) {
229 case 'S':
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300230 return print_sg_io_v3_req(tcp, arg);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100231 case 'Q':
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300232 return print_sg_io_v4_req(tcp, arg);
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100233 default:
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300234 tprints("...}");
235 return RVAL_DECODED | 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100236 }
237
238}
239
240static void
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300241print_sg_io_res(struct tcb *tcp, uint32_t iid, const long arg)
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100242{
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300243 switch (iid) {
244 case 'S':
245 print_sg_io_v3_res(tcp, arg);
246 break;
247 case 'Q':
248 print_sg_io_v4_res(tcp, arg);
249 break;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100250 }
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000251}
252
253int
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300254scsi_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000255{
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100256 uint32_t iid;
257
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300258 if (SG_IO != code)
259 return RVAL_DECODED;
260
261 if (entering(tcp)) {
262 tprints(", ");
263 if (!arg || umove(tcp, arg, &iid) < 0) {
264 printaddr(arg);
265 return RVAL_DECODED | 1;
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100266 } else {
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300267 return print_sg_io_req(tcp, iid, arg);
268 }
269 } else {
270 if (!syserror(tcp)) {
271 if (umove(tcp, arg, &iid) < 0)
272 tprints(", ???");
273 else
Bart Van Assche67d0a8e2015-02-06 13:37:03 +0100274 print_sg_io_res(tcp, iid, arg);
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000275 }
Dmitry V. Levin3d0e1f32015-07-07 21:38:07 +0300276 tprintf("}");
277 return RVAL_DECODED | 1;
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000278 }
Dmitry V. Levinb011af52007-06-30 11:37:09 +0000279}
Dmitry V. Levinfdb896e2014-02-25 23:04:55 +0000280
281#endif /* HAVE_SCSI_SG_H */