Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 2007 Vladimir Nadvornik <nadvornik (at) suse.cz>
      3  * Copyright (c) 2007 Dmitry V. Levin <ldv (at) 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 
     29 #include "defs.h"
     30 
     31 #ifdef HAVE_SCSI_SG_H
     32 
     33 # include <sys/ioctl.h>
     34 # include <scsi/sg.h>
     35 
     36 # 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
     44 
     45 static void
     46 print_sg_io_buffer(struct tcb *tcp, unsigned long addr, const unsigned int len)
     47 {
     48 	unsigned char *buf = NULL;
     49 	unsigned int allocated, i;
     50 
     51 	tprints("[");
     52 	if (len == 0)
     53 		goto out;
     54 	allocated = (len > max_strlen) ? max_strlen : len;
     55 	if ((buf = malloc(allocated)) == NULL ||
     56 	    umoven(tcp, addr, allocated, buf) < 0) {
     57 		tprintf("%#lx", addr);
     58 		goto out;
     59 	}
     60 	tprintf("%02x", buf[0]);
     61 	for (i = 1; i < allocated; ++i)
     62 		tprintf(", %02x", buf[i]);
     63 	if (allocated != len)
     64 		tprints(", ...");
     65 out:
     66 	free(buf);
     67 	tprints("]");
     68 }
     69 
     70 static void
     71 print_sg_io_v3_req(struct tcb *tcp, long arg)
     72 {
     73 	struct sg_io_hdr sg_io;
     74 
     75 	if (umove(tcp, arg, &sg_io) < 0) {
     76 		tprintf(", %#lx", arg);
     77 		return;
     78 	}
     79 
     80 	tprints(", ");
     81 	printxval(sg_io_dxfer_direction, sg_io.dxfer_direction,
     82 		  "SG_DXFER_???");
     83 	tprintf(", cmd[%u]=", sg_io.cmd_len);
     84 	print_sg_io_buffer(tcp, (unsigned long) sg_io.cmdp, sg_io.cmd_len);
     85 	tprintf(", mx_sb_len=%d", sg_io.mx_sb_len);
     86 	tprintf(", iovec_count=%d", sg_io.iovec_count);
     87 	tprintf(", dxfer_len=%u", sg_io.dxfer_len);
     88 	tprintf(", timeout=%u", sg_io.timeout);
     89 	tprintf(", flags=%#x", sg_io.flags);
     90 
     91 	if (sg_io.dxfer_direction == SG_DXFER_TO_DEV ||
     92 	    sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
     93 		tprintf(", data[%u]=", sg_io.dxfer_len);
     94 		if (sg_io.iovec_count)
     95 			tprint_iov_upto(tcp, sg_io.iovec_count,
     96 					(unsigned long) sg_io.dxferp, 1,
     97 					sg_io.dxfer_len);
     98 		else
     99 			print_sg_io_buffer(tcp, (unsigned long) sg_io.dxferp,
    100 					   sg_io.dxfer_len);
    101 	}
    102 }
    103 
    104 static void
    105 print_sg_io_v3_res(struct tcb *tcp, long arg)
    106 {
    107 	struct sg_io_hdr sg_io;
    108 
    109 	if (umove(tcp, arg, &sg_io) < 0) {
    110 		tprintf(", %#lx", arg);
    111 		return;
    112 	}
    113 
    114 	if (sg_io.dxfer_direction == SG_DXFER_FROM_DEV ||
    115 	    sg_io.dxfer_direction == SG_DXFER_TO_FROM_DEV) {
    116 		uint32_t din_len = sg_io.dxfer_len;
    117 
    118 		if (sg_io.resid > 0)
    119 			din_len -= sg_io.resid;
    120 		tprintf(", data[%u]=", din_len);
    121 		if (sg_io.iovec_count)
    122 			tprint_iov_upto(tcp, sg_io.iovec_count,
    123 					(unsigned long) sg_io.dxferp, 1,
    124 					din_len);
    125 		else
    126 			print_sg_io_buffer(tcp, (unsigned long) sg_io.dxferp,
    127 					   din_len);
    128 	}
    129 	tprintf(", status=%02x", sg_io.status);
    130 	tprintf(", masked_status=%02x", sg_io.masked_status);
    131 	tprintf(", sb[%u]=", sg_io.sb_len_wr);
    132 	print_sg_io_buffer(tcp, (unsigned long) sg_io.sbp, sg_io.sb_len_wr);
    133 	tprintf(", host_status=%#x", sg_io.host_status);
    134 	tprintf(", driver_status=%#x", sg_io.driver_status);
    135 	tprintf(", resid=%d", sg_io.resid);
    136 	tprintf(", duration=%d", sg_io.duration);
    137 	tprintf(", info=%#x", sg_io.info);
    138 }
    139 
    140 #ifdef HAVE_LINUX_BSG_H
    141 
    142 static void
    143 print_sg_io_v4_req(struct tcb *tcp, long arg)
    144 {
    145 	struct sg_io_v4 sg_io;
    146 
    147 	if (umove(tcp, arg, &sg_io) < 0) {
    148 		tprintf(", %#lx", arg);
    149 		return;
    150 	}
    151 
    152 	tprints(", ");
    153 	printxval(bsg_protocol, sg_io.protocol, "BSG_PROTOCOL_???");
    154 	tprints(", ");
    155 	printxval(bsg_subprotocol, sg_io.subprotocol, "BSG_SUB_PROTOCOL_???");
    156 	tprintf(", request[%u]=", sg_io.request_len);
    157 	print_sg_io_buffer(tcp, sg_io.request, sg_io.request_len);
    158 	tprintf(", request_tag=%llu", (unsigned long long) sg_io.request_tag);
    159 	tprintf(", request_attr=%u", sg_io.request_attr);
    160 	tprintf(", request_priority=%u", sg_io.request_priority);
    161 	tprintf(", request_extra=%u", sg_io.request_extra);
    162 	tprintf(", max_response_len=%u", sg_io.max_response_len);
    163 
    164 	tprintf(", dout_iovec_count=%u", sg_io.dout_iovec_count);
    165 	tprintf(", dout_xfer_len=%u", sg_io.dout_xfer_len);
    166 	tprintf(", din_iovec_count=%u", sg_io.din_iovec_count);
    167 	tprintf(", din_xfer_len=%u", sg_io.din_xfer_len);
    168 	tprintf(", timeout=%u", sg_io.timeout);
    169 	tprintf(", flags=%u", sg_io.flags);
    170 	tprintf(", usr_ptr=%llu", (unsigned long long) sg_io.usr_ptr);
    171 	tprintf(", spare_in=%u", sg_io.spare_in);
    172 	tprintf(", dout[%u]=", sg_io.dout_xfer_len);
    173 	if (sg_io.dout_iovec_count)
    174 		tprint_iov_upto(tcp, sg_io.dout_iovec_count, sg_io.dout_xferp,
    175 				1, sg_io.dout_xfer_len);
    176 	else
    177 		print_sg_io_buffer(tcp, sg_io.dout_xferp, sg_io.dout_xfer_len);
    178 }
    179 
    180 static void
    181 print_sg_io_v4_res(struct tcb *tcp, long arg)
    182 {
    183 	struct sg_io_v4 sg_io;
    184 	uint32_t din_len;
    185 
    186 	if (umove(tcp, arg, &sg_io) < 0) {
    187 		tprintf(", %#lx", arg);
    188 		return;
    189 	}
    190 
    191 	tprintf(", response[%u]=", sg_io.response_len);
    192 	print_sg_io_buffer(tcp, sg_io.response, sg_io.response_len);
    193 	din_len = sg_io.din_xfer_len;
    194 	if (sg_io.din_resid > 0)
    195 		din_len -= sg_io.din_resid;
    196 	tprintf(", din[%u]=", din_len);
    197 	if (sg_io.din_iovec_count)
    198 		tprint_iov_upto(tcp, sg_io.din_iovec_count, sg_io.din_xferp,
    199 				1, din_len);
    200 	else
    201 		print_sg_io_buffer(tcp, sg_io.din_xferp, din_len);
    202 	tprintf(", driver_status=%u", sg_io.driver_status);
    203 	tprintf(", transport_status=%u", sg_io.transport_status);
    204 	tprintf(", device_status=%u", sg_io.device_status);
    205 	tprintf(", retry_delay=%u", sg_io.retry_delay);
    206 	tprintf(", info=%u", sg_io.info);
    207 	tprintf(", duration=%u", sg_io.duration);
    208 	tprintf(", response_len=%u", sg_io.response_len);
    209 	tprintf(", din_resid=%u", sg_io.din_resid);
    210 	tprintf(", dout_resid=%u", sg_io.dout_resid);
    211 	tprintf(", generated_tag=%llu", (unsigned long long) sg_io.generated_tag);
    212 	tprintf(", spare_out=%u", sg_io.spare_out);
    213 }
    214 
    215 #else /* !HAVE_LINUX_BSG_H */
    216 
    217 static void
    218 print_sg_io_v4_req(struct tcb *tcp, long arg)
    219 {
    220 	tprintf(", %#lx", arg);
    221 }
    222 
    223 static void
    224 print_sg_io_v4_res(struct tcb *tcp, long arg)
    225 {
    226 }
    227 
    228 #endif
    229 
    230 static void
    231 print_sg_io_req(struct tcb *tcp, uint32_t iid, long arg)
    232 {
    233 	tprintf("{'%c'", iid);
    234 
    235 	switch (iid) {
    236 	case 'S':
    237 		print_sg_io_v3_req(tcp, arg);
    238 		break;
    239 	case 'Q':
    240 		print_sg_io_v4_req(tcp, arg);
    241 		break;
    242 	default:
    243 		tprints(", ...");
    244 	}
    245 
    246 }
    247 
    248 static void
    249 print_sg_io_res(struct tcb *tcp, uint32_t iid, long arg)
    250 {
    251 	if (!syserror(tcp)) {
    252 		switch (iid) {
    253 		case 'S':
    254 			print_sg_io_v3_res(tcp, arg);
    255 			break;
    256 		case 'Q':
    257 			print_sg_io_v4_res(tcp, arg);
    258 			break;
    259 		}
    260 	}
    261 
    262 	tprintf("}");
    263 }
    264 
    265 int
    266 scsi_ioctl(struct tcb *tcp, const unsigned int code, long arg)
    267 {
    268 	uint32_t iid;
    269 
    270 	switch (code) {
    271 	case SG_IO:
    272 		if (entering(tcp)) {
    273 			tprints(", ");
    274 			if (umove(tcp, arg, &iid) < 0)
    275 				tprintf("%#lx", arg);
    276 			else
    277 				print_sg_io_req(tcp, iid, arg);
    278 		} else {
    279 			if (umove(tcp, arg, &iid) >= 0)
    280 				print_sg_io_res(tcp, iid, arg);
    281 		}
    282 		break;
    283 	default:
    284 		if (entering(tcp))
    285 			tprintf(", %#lx", arg);
    286 		break;
    287 	}
    288 	return 1;
    289 }
    290 
    291 #endif /* HAVE_SCSI_SG_H */
    292