1 /* $NetBSD: linux_sg.c,v 1.12 2007/12/20 23:02:56 dsl Exp $ */
4 * Copyright (c) 2004 Soren S. Jorvang. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: linux_sg.c,v 1.12 2007/12/20 23:02:56 dsl Exp $");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/ioctl.h>
35 #include <sys/filedesc.h>
36 #include <sys/mount.h>
38 #include <sys/device.h>
40 #include <sys/scsiio.h>
41 #include <dev/scsipi/scsipi_all.h>
42 #include <dev/scsipi/scsiconf.h>
44 #include <sys/syscallargs.h>
46 #include <compat/linux/common/linux_types.h>
47 #include <compat/linux/common/linux_ioctl.h>
48 #include <compat/linux/common/linux_signal.h>
49 #include <compat/linux/common/linux_sg.h>
50 #include <compat/linux/common/linux_ipc.h>
51 #include <compat/linux/common/linux_sem.h>
53 #include <compat/linux/linux_syscallargs.h>
55 int linux_sg_version
= 30125;
58 #define DPRINTF(a) printf a
64 static void dump_sg_io(struct linux_sg_io_hdr
*);
65 static void dump_scsireq(struct scsireq
*);
68 static int bsd_to_linux_host_status(int);
69 static int bsd_to_linux_driver_status(int);
72 linux_ioctl_sg(struct lwp
*l
, const struct linux_sys_ioctl_args
*uap
,
76 u_long com
= SCARG(uap
, com
);
78 int (*ioctlf
)(file_t
*, u_long
, void *);
79 struct linux_sg_io_hdr lreq
;
82 if ((fp
= fd_getfile(SCARG(uap
, fd
))) == NULL
)
85 ioctlf
= fp
->f_ops
->fo_ioctl
;
88 DPRINTF(("Command = %lx\n", com
));
90 case LINUX_SG_GET_VERSION_NUM
: {
91 error
= copyout(&version
, SCARG(uap
, data
),
92 sizeof(linux_sg_version
));
96 error
= copyin(SCARG(uap
, data
), &lreq
, sizeof(lreq
));
98 DPRINTF(("failed to copy in request data %d\n", error
));
102 #ifdef LINUX_SG_DEBUG
105 (void)memset(&req
, 0, sizeof(req
));
106 switch (lreq
.dxfer_direction
) {
107 case SG_DXFER_TO_DEV
:
108 req
.flags
= SCCMD_WRITE
;
110 case SG_DXFER_FROM_DEV
:
111 req
.flags
= SCCMD_READ
;
114 DPRINTF(("unknown direction %d\n",
115 lreq
.dxfer_direction
));
119 if (lreq
.iovec_count
!= 0) {
122 DPRINTF(("scatter/gather not supported\n"));
126 if (lreq
.cmd_len
> sizeof(req
.cmd
)) {
127 DPRINTF(("invalid command length %d\n", lreq
.cmd_len
));
132 error
= copyin(lreq
.cmdp
, req
.cmd
, lreq
.cmd_len
);
134 DPRINTF(("failed to copy in cmd data %d\n", error
));
138 req
.timeout
= lreq
.timeout
;
139 req
.cmdlen
= lreq
.cmd_len
;
140 req
.datalen
= lreq
.dxfer_len
;
141 req
.databuf
= lreq
.dxferp
;
143 error
= ioctlf(fp
, SCIOCCOMMAND
, &req
);
145 DPRINTF(("SCIOCCOMMAND failed %d\n", error
));
148 #ifdef LINUX_SG_DEBUG
151 if (req
.senselen_used
) {
152 if (req
.senselen
> lreq
.mx_sb_len
)
153 req
.senselen
= lreq
.mx_sb_len
;
154 lreq
.sb_len_wr
= req
.senselen
;
155 error
= copyout(req
.sense
, lreq
.sbp
, req
.senselen
);
157 DPRINTF(("sense copyout failed %d\n", error
));
164 lreq
.status
= req
.status
;
165 lreq
.masked_status
= 0; /* XXX */
166 lreq
.host_status
= bsd_to_linux_host_status(req
.retsts
);
167 lreq
.sb_len_wr
= req
.datalen_used
;
168 lreq
.driver_status
= bsd_to_linux_driver_status(req
.error
);
169 lreq
.resid
= req
.datalen
- req
.datalen_used
;
170 lreq
.duration
= req
.timeout
; /* XXX */
171 lreq
.info
= 0; /* XXX */
172 error
= copyout(&lreq
, SCARG(uap
, data
), sizeof(lreq
));
174 DPRINTF(("failed to copy out req data %d\n", error
));
177 case LINUX_SG_EMULATED_HOST
:
178 case LINUX_SG_SET_TRANSFORM
:
179 case LINUX_SG_GET_TRANSFORM
:
180 case LINUX_SG_GET_NUM_WAITING
:
181 case LINUX_SG_SCSI_RESET
:
182 case LINUX_SG_GET_REQUEST_TABLE
:
183 case LINUX_SG_SET_KEEP_ORPHAN
:
184 case LINUX_SG_GET_KEEP_ORPHAN
:
185 case LINUX_SG_GET_ACCESS_COUNT
:
186 case LINUX_SG_SET_FORCE_LOW_DMA
:
187 case LINUX_SG_GET_LOW_DMA
:
188 case LINUX_SG_GET_SG_TABLESIZE
:
189 case LINUX_SG_GET_SCSI_ID
:
190 case LINUX_SG_SET_FORCE_PACK_ID
:
191 case LINUX_SG_GET_PACK_ID
:
192 case LINUX_SG_SET_RESERVED_SIZE
:
193 case LINUX_SG_GET_RESERVED_SIZE
:
197 /* version 2 interfaces */
198 case LINUX_SG_SET_TIMEOUT
:
200 case LINUX_SG_GET_TIMEOUT
:
201 /* ioctl returns value..., grr. */
204 case LINUX_SG_GET_COMMAND_Q
:
205 case LINUX_SG_SET_COMMAND_Q
:
206 case LINUX_SG_SET_DEBUG
:
207 case LINUX_SG_NEXT_CMD_LEN
:
213 fd_putfile(SCARG(uap
, fd
));
215 DPRINTF(("Return=%d\n", error
));
220 bsd_to_linux_driver_status(int bs
)
228 return LINUX_DRIVER_SENSE
;
229 case XS_RESOURCE_SHORTAGE
:
230 return LINUX_DRIVER_SOFT
;
231 case XS_DRIVER_STUFFUP
:
232 return LINUX_DRIVER_ERROR
;
235 return LINUX_DRIVER_TIMEOUT
;
237 return LINUX_DRIVER_BUSY
;
239 return LINUX_SUGGEST_ABORT
;
241 return LINUX_SUGGEST_RETRY
;
246 bsd_to_linux_host_status(int bs
)
253 return LINUX_DID_TIME_OUT
;
255 return LINUX_DID_BUS_BUSY
;
258 return LINUX_DID_ERROR
;
264 #ifdef LINUX_SG_DEBUG
266 dump_sg_io(struct linux_sg_io_hdr
*lr
)
268 printf("linuxreq [interface_id=%x, dxfer_direction=%d, cmd_len=%d, "
269 "mx_sb_len=%d, iovec_count=%d, dxfer_len=%d, dxferp=%p, "
270 "cmdp=%p, sbp=%p, timeout=%u, flags=%d, pack_id=%d, "
271 "usr_ptr=%p, status=%u, masked_status=%u, sb_len_wr=%u, "
272 "host_status=%u, driver_status=%u, resid=%d, duration=%u, "
274 lr
->interface_id
, lr
->dxfer_direction
, lr
->cmd_len
,
275 lr
->mx_sb_len
, lr
->iovec_count
, lr
->dxfer_len
, lr
->dxferp
,
276 lr
->cmdp
, lr
->sbp
, lr
->timeout
, lr
->flags
, lr
->pack_id
,
277 lr
->usr_ptr
, lr
->status
, lr
->masked_status
, lr
->sb_len_wr
,
278 lr
->host_status
, lr
->driver_status
, lr
->resid
, lr
->duration
,
283 dump_scsireq(struct scsireq
*br
)
286 printf("bsdreq [flags=%lx, timeout=%lu, cmd=[ ",
287 br
->flags
, br
->timeout
);
288 for (i
= 0; i
< sizeof(br
->cmd
) / sizeof(br
->cmd
[0]); i
++)
289 printf("%.2u ", br
->cmd
[i
]);
290 printf("], cmdlen=%u, databuf=%p, datalen=%lu, datalen_used=%lu, "
292 br
->cmdlen
, br
->databuf
, br
->datalen
, br
->datalen_used
);
293 for (i
= 0; i
< sizeof(br
->sense
) / sizeof(br
->sense
[0]); i
++)
294 printf("%.2u ", br
->sense
[i
]);
295 printf("], senselen=%u, senselen_used=%u, status=%u, retsts=%u, "
297 br
->senselen
, br
->senselen_used
, br
->status
, br
->retsts
, br
->error
);