1 /*
2 * Copyright (c) 2007 Vladimir Nadvornik <nadvornik@suse.cz>
3 * Copyright (c) 2007-2021 Dmitry V. Levin <ldv@strace.io>
4 * Copyright (c) 2015 Bart Van Assche <bart.vanassche@sandisk.com>
5 * Copyright (c) 2021-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10
11 #include "defs.h"
12
13 #ifdef HAVE_SCSI_SG_H
14
15 # include DEF_MPERS_TYPE(struct_sg_io_hdr)
16
17 # include <scsi/sg.h>
18
19 typedef struct sg_io_hdr struct_sg_io_hdr;
20
21 #endif /* HAVE_SCSI_SG_H */
22
23 #include MPERS_DEFS
24
25 #include "xlat/sg_io_info.h"
26
27 #ifdef HAVE_SCSI_SG_H
28 # include "xlat/sg_io_dxfer_direction.h"
29 # include "xlat/sg_io_flags.h"
30
31 static void
32 print_sg_io_buffer(struct tcb *const tcp, const kernel_ulong_t addr,
33 const unsigned int data_size, const unsigned int iovec_count)
34 {
35 if (iovec_count) {
36 tprint_iov_upto(tcp, iovec_count, addr, data_size,
37 iov_decode_str, NULL);
38 } else {
39 printstr_ex(tcp, addr, data_size, QUOTE_FORCE_HEX);
40 }
41 }
42
43 # define PRINT_FIELD_SG_IO_BUFFER(where_, field_, size_, count_, tcp_) \
44 do { \
45 tprints_field_name(#field_); \
46 print_sg_io_buffer((tcp_), (mpers_ptr_t)((where_).field_), \
47 (size_), (count_)); \
48 } while (0)
49
50 static int
51 decode_request(struct tcb *const tcp, const kernel_ulong_t arg)
52 {
53 struct_sg_io_hdr sg_io;
54 static const size_t skip_iid =
55 offsetof(struct_sg_io_hdr, dxfer_direction);
56
57 tprint_struct_begin();
58 tprints_field_name("interface_id");
59 tprints_string("'S'");
60 tprint_struct_next();
61 if (umoven_or_printaddr(tcp, arg + skip_iid, sizeof(sg_io) - skip_iid,
62 &sg_io.dxfer_direction)) {
63 tprint_struct_end();
64 return RVAL_IOCTL_DECODED;
65 }
66
67 PRINT_FIELD_XVAL(sg_io, dxfer_direction, sg_io_dxfer_direction,
68 "SG_DXFER_???");
69 tprint_struct_next();
70 PRINT_FIELD_U(sg_io, cmd_len);
71 tprint_struct_next();
72 PRINT_FIELD_SG_IO_BUFFER(sg_io, cmdp, sg_io.cmd_len, 0, tcp);
73 tprint_struct_next();
74 PRINT_FIELD_U(sg_io, mx_sb_len);
75 tprint_struct_next();
76 PRINT_FIELD_U(sg_io, iovec_count);
77 tprint_struct_next();
78 PRINT_FIELD_U(sg_io, dxfer_len);
79 tprint_struct_next();
80 PRINT_FIELD_U(sg_io, timeout);
81 tprint_struct_next();
82 PRINT_FIELD_FLAGS(sg_io, flags, sg_io_flags, "SG_FLAG_???");
83
84 if (sg_io.dxfer_direction == SG_DXFER_TO_DEV ||
85 sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
86 tprint_struct_next();
87 PRINT_FIELD_SG_IO_BUFFER(sg_io, dxferp, sg_io.dxfer_len, sg_io.iovec_count, tcp);
88 }
89
90 struct_sg_io_hdr *entering_sg_io = xobjdup(&sg_io);
91 entering_sg_io->interface_id = (unsigned char) 'S';
92 set_tcb_priv_data(tcp, entering_sg_io, free);
93
94 return 0;
95 }
96
97 static int
98 decode_response(struct tcb *const tcp, const kernel_ulong_t arg)
99 {
100 struct_sg_io_hdr *entering_sg_io = get_tcb_priv_data(tcp);
101 struct_sg_io_hdr sg_io;
102
103 if (umove(tcp, arg, &sg_io) < 0) {
104 /* print i/o fields fetched on entering syscall */
105 if (entering_sg_io->dxfer_direction == SG_DXFER_FROM_DEV) {
106 tprint_struct_next();
107 PRINT_FIELD_PTR(*entering_sg_io, dxferp);
108 }
109 tprint_struct_next();
110 PRINT_FIELD_PTR(*entering_sg_io, sbp);
111 return RVAL_IOCTL_DECODED;
112 }
113
114 if (sg_io.interface_id != entering_sg_io->interface_id) {
115 tprint_value_changed();
116 PRINT_FIELD_U(sg_io, interface_id);
117 return RVAL_IOCTL_DECODED;
118 }
119
120 if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV ||
121 sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
122 uint32_t din_len = sg_io.dxfer_len;
123 bool print_buffer = false;
124
125 if (sg_io.resid > 0 && (unsigned int) sg_io.resid <= din_len)
126 din_len -= sg_io.resid;
127
128 if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV) {
129 tprint_struct_next();
130 print_buffer = true;
131 } else if (din_len) {
132 tprint_value_changed();
133 print_buffer = true;
134 }
135
136 if (print_buffer) {
137 PRINT_FIELD_SG_IO_BUFFER(sg_io, dxferp, din_len,
138 sg_io.iovec_count, tcp);
139 }
140 }
141 tprint_struct_next();
142 PRINT_FIELD_X(sg_io, status);
143 tprint_struct_next();
144 PRINT_FIELD_X(sg_io, masked_status);
145 tprint_struct_next();
146 PRINT_FIELD_X(sg_io, msg_status);
147 tprint_struct_next();
148 PRINT_FIELD_U(sg_io, sb_len_wr);
149 tprint_struct_next();
150 PRINT_FIELD_SG_IO_BUFFER(sg_io, sbp, sg_io.sb_len_wr, 0, tcp);
151 tprint_struct_next();
152 PRINT_FIELD_X(sg_io, host_status);
153 tprint_struct_next();
154 PRINT_FIELD_X(sg_io, driver_status);
155 tprint_struct_next();
156 PRINT_FIELD_D(sg_io, resid);
157 tprint_struct_next();
158 PRINT_FIELD_U(sg_io, duration);
159 tprint_struct_next();
160 PRINT_FIELD_FLAGS(sg_io, info, sg_io_info, "SG_INFO_???");
161
162 return RVAL_IOCTL_DECODED;
163 }
164
165 #else /* !HAVE_SCSI_SG_H */
166
167 static int
168 decode_request(struct tcb *const tcp, const kernel_ulong_t arg)
169 {
170 tprint_struct_begin();
171 tprints_field_name("interface_id");
172 tprints_string("'S'");
173 tprint_struct_next();
174 tprint_more_data_follows();
175 tprint_struct_end();
176 return RVAL_IOCTL_DECODED;
177 }
178
179 static int
180 decode_response(struct tcb *const tcp, const kernel_ulong_t arg)
181 {
182 return 0;
183 }
184
185 #endif
186
187 MPERS_PRINTER_DECL(int, decode_sg_io_v3,
188 struct tcb *const tcp, const kernel_ulong_t arg)
189 {
190 return entering(tcp) ? decode_request(tcp, arg)
191 : decode_response(tcp, arg);
192 }