1 /* $NetBSD: scsipi_ioctl.c,v 1.65 2008/04/28 20:23:58 martin Exp $ */
4 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Contributed by HD Associates (hd@world.std.com).
34 * Copyright (c) 1992, 1993 HD Associates
36 * Berkeley style copyright.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: scsipi_ioctl.c,v 1.65 2008/04/28 20:23:58 martin Exp $");
42 #include "opt_compat_freebsd.h"
43 #include "opt_compat_netbsd.h"
45 #include <sys/param.h>
46 #include <sys/errno.h>
47 #include <sys/systm.h>
48 #include <sys/malloc.h>
51 #include <sys/device.h>
52 #include <sys/fcntl.h>
54 #include <dev/scsipi/scsipi_all.h>
55 #include <dev/scsipi/scsipiconf.h>
56 #include <dev/scsipi/scsipi_base.h>
57 #include <dev/scsipi/scsiconf.h>
58 #include <sys/scsiio.h>
64 LIST_ENTRY(scsi_ioctl
) si_list
;
69 struct scsipi_periph
*si_periph
;
72 static LIST_HEAD(, scsi_ioctl
) si_head
;
74 static struct scsi_ioctl
*
77 struct scsi_ioctl
*si
;
80 si
= malloc(sizeof(struct scsi_ioctl
), M_TEMP
, M_WAITOK
|M_ZERO
);
83 LIST_INSERT_HEAD(&si_head
, si
, si_list
);
89 si_free(struct scsi_ioctl
*si
)
94 LIST_REMOVE(si
, si_list
);
96 buf_destroy(&si
->si_bp
);
100 static struct scsi_ioctl
*
101 si_find(struct buf
*bp
)
103 struct scsi_ioctl
*si
;
107 for (si
= si_head
.lh_first
; si
!= 0; si
= si
->si_list
.le_next
)
108 if (bp
== &si
->si_bp
)
115 * We let the user interpret his own sense in the generic scsi world.
116 * This routine is called at interrupt time if the XS_CTL_USERCMD bit was set
117 * in the flags passed to scsi_scsipi_cmd(). No other completion processing
118 * takes place, even if we are running over another device driver.
119 * The lower level routines that call us here, will free the xs and restart
120 * the device's queue if such exists.
123 scsipi_user_done(struct scsipi_xfer
*xs
)
126 struct scsi_ioctl
*si
;
128 struct scsipi_periph
*periph
= xs
->xs_periph
;
134 scsipi_printaddr(periph
);
135 printf("user command with no buf\n");
136 panic("scsipi_user_done");
142 scsipi_printaddr(periph
);
143 printf("user command with no ioctl\n");
144 panic("scsipi_user_done");
148 screq
= &si
->si_screq
;
150 SC_DEBUG(xs
->xs_periph
, SCSIPI_DB2
, ("user-done\n"));
153 screq
->status
= xs
->status
;
156 SC_DEBUG(periph
, SCSIPI_DB3
, ("no error\n"));
157 screq
->datalen_used
=
158 xs
->datalen
- xs
->resid
; /* probably rubbish */
159 screq
->retsts
= SCCMD_OK
;
162 SC_DEBUG(periph
, SCSIPI_DB3
, ("have sense\n"));
163 screq
->senselen_used
= min(sizeof(xs
->sense
.scsi_sense
),
165 memcpy(screq
->sense
, &xs
->sense
.scsi_sense
, screq
->senselen
);
166 screq
->retsts
= SCCMD_SENSE
;
169 SC_DEBUG(periph
, SCSIPI_DB3
, ("have short sense\n"));
170 screq
->senselen_used
= min(sizeof(xs
->sense
.atapi_sense
),
172 memcpy(screq
->sense
, &xs
->sense
.scsi_sense
, screq
->senselen
);
173 screq
->retsts
= SCCMD_UNKNOWN
; /* XXX need a shortsense here */
175 case XS_DRIVER_STUFFUP
:
176 scsipi_printaddr(periph
);
177 printf("passthrough: adapter inconsistency\n");
178 screq
->retsts
= SCCMD_UNKNOWN
;
181 SC_DEBUG(periph
, SCSIPI_DB3
, ("seltimeout\n"));
182 screq
->retsts
= SCCMD_TIMEOUT
;
185 SC_DEBUG(periph
, SCSIPI_DB3
, ("timeout\n"));
186 screq
->retsts
= SCCMD_TIMEOUT
;
189 SC_DEBUG(periph
, SCSIPI_DB3
, ("busy\n"));
190 screq
->retsts
= SCCMD_BUSY
;
193 scsipi_printaddr(periph
);
194 printf("unknown error category %d from adapter\n",
196 screq
->retsts
= SCCMD_UNKNOWN
;
200 if (xs
->xs_control
& XS_CTL_ASYNC
) {
208 /* Pseudo strategy function
209 * Called by scsipi_do_ioctl() via physio/physstrat if there is to
210 * be data transfered, and directly if there is no data transfer.
212 * Should I reorganize this so it returns to physio instead
213 * of sleeping in scsiio_scsipi_cmd? Is there any advantage, other
214 * than avoiding the probable duplicate wakeup in iodone? [PD]
216 * No, seems ok to me... [JRE]
217 * (I don't see any duplicate wakeups)
219 * Can't be used with block devices or raw_read/raw_write directly
220 * from the cdevsw/bdevsw tables because they couldn't have added
221 * the screq structure. [JRE]
224 scsistrategy(struct buf
*bp
)
226 struct scsi_ioctl
*si
;
228 struct scsipi_periph
*periph
;
234 printf("scsistrategy: "
235 "No matching ioctl request found in queue\n");
239 screq
= &si
->si_screq
;
240 periph
= si
->si_periph
;
241 SC_DEBUG(periph
, SCSIPI_DB2
, ("user_strategy\n"));
244 * We're in trouble if physio tried to break up the transfer.
246 if (bp
->b_bcount
!= screq
->datalen
) {
247 scsipi_printaddr(periph
);
248 printf("physio split the request.. cannot proceed\n");
253 if (screq
->timeout
== 0) {
258 if (screq
->cmdlen
> sizeof(struct scsipi_generic
)) {
259 scsipi_printaddr(periph
);
260 printf("cmdlen too big\n");
265 if ((screq
->flags
& SCCMD_READ
) && screq
->datalen
> 0)
266 flags
|= XS_CTL_DATA_IN
;
267 if ((screq
->flags
& SCCMD_WRITE
) && screq
->datalen
> 0)
268 flags
|= XS_CTL_DATA_OUT
;
269 if (screq
->flags
& SCCMD_TARGET
)
270 flags
|= XS_CTL_TARGET
;
271 if (screq
->flags
& SCCMD_ESCAPE
)
272 flags
|= XS_CTL_ESCAPE
;
274 error
= scsipi_command(periph
, (void *)screq
->cmd
, screq
->cmdlen
,
275 (void *)bp
->b_data
, screq
->datalen
,
276 0, /* user must do the retries *//* ignored */
277 screq
->timeout
, bp
, flags
| XS_CTL_USERCMD
);
281 bp
->b_resid
= bp
->b_bcount
;
288 * Something (e.g. another driver) has called us
289 * with a periph and a scsi-specific ioctl to perform,
290 * better try. If user-level type command, we must
291 * still be running in the context of the calling process
294 scsipi_do_ioctl(struct scsipi_periph
*periph
, dev_t dev
, u_long cmd
,
295 void *addr
, int flag
, struct lwp
*l
)
299 SC_DEBUG(periph
, SCSIPI_DB2
, ("scsipi_do_ioctl(0x%lx)\n", cmd
));
304 /* Check for the safe-ness of this request. */
310 if ((((scsireq_t
*)addr
)->flags
& SCCMD_READ
) == 0 &&
311 (flag
& FWRITE
) == 0)
315 if ((flag
& FWRITE
) == 0)
321 scsireq_t
*screq
= (scsireq_t
*)addr
;
322 struct scsi_ioctl
*si
;
326 si
->si_screq
= *screq
;
327 si
->si_periph
= periph
;
328 len
= screq
->datalen
;
330 si
->si_iov
.iov_base
= screq
->databuf
;
331 si
->si_iov
.iov_len
= len
;
332 si
->si_uio
.uio_iov
= &si
->si_iov
;
333 si
->si_uio
.uio_iovcnt
= 1;
334 si
->si_uio
.uio_resid
= len
;
335 si
->si_uio
.uio_offset
= 0;
337 (screq
->flags
& SCCMD_READ
) ? UIO_READ
: UIO_WRITE
;
338 if ((flag
& FKIOCTL
) == 0) {
339 si
->si_uio
.uio_vmspace
= l
->l_proc
->p_vmspace
;
341 UIO_SETUP_SYSSPACE(&si
->si_uio
);
343 error
= physio(scsistrategy
, &si
->si_bp
, dev
,
344 (screq
->flags
& SCCMD_READ
) ? B_READ
: B_WRITE
,
345 periph
->periph_channel
->chan_adapter
->adapt_minphys
,
348 /* if no data, no need to translate it.. */
349 si
->si_bp
.b_flags
= 0;
350 si
->si_bp
.b_data
= 0;
351 si
->si_bp
.b_bcount
= 0;
352 si
->si_bp
.b_dev
= dev
;
353 si
->si_bp
.b_proc
= l
->l_proc
;
354 scsistrategy(&si
->si_bp
);
355 error
= si
->si_bp
.b_error
;
357 *screq
= si
->si_screq
;
362 int level
= *((int *)addr
);
364 SC_DEBUG(periph
, SCSIPI_DB3
, ("debug set to %d\n", level
));
365 periph
->periph_dbflags
= 0;
367 periph
->periph_dbflags
|= SCSIPI_DB1
;
369 periph
->periph_dbflags
|= SCSIPI_DB2
;
371 periph
->periph_dbflags
|= SCSIPI_DB3
;
373 periph
->periph_dbflags
|= SCSIPI_DB4
;
379 case SCIOCIDENTIFY
: {
380 struct scsi_addr
*sca
= (struct scsi_addr
*)addr
;
382 switch (scsipi_periph_bustype(periph
)) {
383 case SCSIPI_BUSTYPE_SCSI
:
384 sca
->type
= TYPE_SCSI
;
385 sca
->addr
.scsi
.scbus
=
386 device_unit(device_parent(periph
->periph_dev
));
387 sca
->addr
.scsi
.target
= periph
->periph_target
;
388 sca
->addr
.scsi
.lun
= periph
->periph_lun
;
390 case SCSIPI_BUSTYPE_ATAPI
:
391 sca
->type
= TYPE_ATAPI
;
392 sca
->addr
.atapi
.atbus
=
393 device_unit(device_parent(periph
->periph_dev
));
394 sca
->addr
.atapi
.drive
= periph
->periph_target
;
399 #if defined(COMPAT_12) || defined(COMPAT_FREEBSD)
400 /* SCIOCIDENTIFY before ATAPI staff merge */
401 case OSCIOCIDENTIFY
: {
402 struct oscsi_addr
*sca
= (struct oscsi_addr
*)addr
;
404 switch (scsipi_periph_bustype(periph
)) {
405 case SCSIPI_BUSTYPE_SCSI
:
407 device_unit(device_parent(periph
->periph_dev
));
408 sca
->target
= periph
->periph_target
;
409 sca
->lun
= periph
->periph_lun
;
420 panic("scsipi_do_ioctl: impossible");