scsipi_ioctl.c revision 1.37.8.1 1 /* $NetBSD: scsipi_ioctl.c,v 1.37.8.1 1999/12/21 23:19:55 wrstuden Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Contributed by HD Associates (hd (at) world.std.com).
41 * Copyright (c) 1992, 1993 HD Associates
42 *
43 * Berkeley style copyright.
44 */
45
46 #include "opt_compat_freebsd.h"
47 #include "opt_compat_netbsd.h"
48
49 #include <sys/types.h>
50 #include <sys/errno.h>
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/malloc.h>
54 #include <sys/buf.h>
55 #include <sys/proc.h>
56 #include <sys/device.h>
57 #include <sys/fcntl.h>
58
59 #include <dev/scsipi/scsipi_all.h>
60 #include <dev/scsipi/scsipiconf.h>
61 #include <dev/scsipi/scsiconf.h>
62 #include <sys/scsiio.h>
63
64 #include "scsibus.h"
65 #include "atapibus.h"
66
67 struct scsi_ioctl {
68 LIST_ENTRY(scsi_ioctl) si_list;
69 struct buf si_bp;
70 struct uio si_uio;
71 struct iovec si_iov;
72 scsireq_t si_screq;
73 struct scsipi_link *si_sc_link;
74 };
75
76 LIST_HEAD(, scsi_ioctl) si_head;
77
78 struct scsi_ioctl *si_find __P((struct buf *));
79 void si_free __P((struct scsi_ioctl *));
80 struct scsi_ioctl *si_get __P((void));
81 void scsistrategy __P((struct buf *));
82
83 struct scsi_ioctl *
84 si_get()
85 {
86 struct scsi_ioctl *si;
87 int s;
88
89 si = malloc(sizeof(struct scsi_ioctl), M_TEMP, M_WAITOK);
90 bzero(si, sizeof(struct scsi_ioctl));
91 s = splbio();
92 LIST_INSERT_HEAD(&si_head, si, si_list);
93 splx(s);
94 return (si);
95 }
96
97 void
98 si_free(si)
99 struct scsi_ioctl *si;
100 {
101 int s;
102
103 s = splbio();
104 LIST_REMOVE(si, si_list);
105 splx(s);
106 free(si, M_TEMP);
107 }
108
109 struct scsi_ioctl *
110 si_find(bp)
111 struct buf *bp;
112 {
113 struct scsi_ioctl *si;
114 int s;
115
116 s = splbio();
117 for (si = si_head.lh_first; si != 0; si = si->si_list.le_next)
118 if (bp == &si->si_bp)
119 break;
120 splx(s);
121 return (si);
122 }
123
124 /*
125 * We let the user interpret his own sense in the generic scsi world.
126 * This routine is called at interrupt time if the XS_CTL_USERCMD bit was set
127 * in the flags passed to scsi_scsipi_cmd(). No other completion processing
128 * takes place, even if we are running over another device driver.
129 * The lower level routines that call us here, will free the xs and restart
130 * the device's queue if such exists.
131 */
132 void
133 scsipi_user_done(xs)
134 struct scsipi_xfer *xs;
135 {
136 struct buf *bp;
137 struct scsi_ioctl *si;
138 scsireq_t *screq;
139 struct scsipi_link *sc_link;
140
141 bp = xs->bp;
142 if (bp == NULL) { /* ALL user requests must have a buf */
143 xs->sc_link->sc_print_addr(xs->sc_link);
144 printf("User command with no buf\n");
145 return;
146 }
147 si = si_find(bp);
148 if (si == NULL) {
149 xs->sc_link->sc_print_addr(xs->sc_link);
150 printf("User command with no ioctl\n");
151 return;
152 }
153 screq = &si->si_screq;
154 sc_link = si->si_sc_link;
155 SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n"));
156
157 screq->retsts = 0;
158 screq->status = xs->status;
159 switch (xs->error) {
160 case XS_NOERROR:
161 SC_DEBUG(sc_link, SDEV_DB3, ("no error\n"));
162 screq->datalen_used =
163 xs->datalen - xs->resid; /* probably rubbish */
164 screq->retsts = SCCMD_OK;
165 break;
166 case XS_SENSE:
167 SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n"));
168 screq->senselen_used = min(sizeof(xs->sense.scsi_sense),
169 SENSEBUFLEN);
170 bcopy(&xs->sense.scsi_sense, screq->sense, screq->senselen);
171 screq->retsts = SCCMD_SENSE;
172 break;
173 case XS_SHORTSENSE:
174 SC_DEBUG(sc_link, SDEV_DB3, ("have short sense\n"));
175 screq->senselen_used = min(sizeof(xs->sense.atapi_sense),
176 SENSEBUFLEN);
177 bcopy(&xs->sense.scsi_sense, screq->sense, screq->senselen);
178 screq->retsts = SCCMD_UNKNOWN; /* XXX need a shortsense here */
179 break;
180 case XS_DRIVER_STUFFUP:
181 sc_link->sc_print_addr(sc_link);
182 printf("host adapter code inconsistency\n");
183 screq->retsts = SCCMD_UNKNOWN;
184 break;
185 case XS_SELTIMEOUT:
186 SC_DEBUG(sc_link, SDEV_DB3, ("seltimeout\n"));
187 screq->retsts = SCCMD_TIMEOUT;
188 break;
189 case XS_TIMEOUT:
190 SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n"));
191 screq->retsts = SCCMD_TIMEOUT;
192 break;
193 case XS_BUSY:
194 SC_DEBUG(sc_link, SDEV_DB3, ("busy\n"));
195 screq->retsts = SCCMD_BUSY;
196 break;
197 default:
198 sc_link->sc_print_addr(sc_link);
199 printf("unknown error category %d from host adapter code\n",
200 xs->error);
201 screq->retsts = SCCMD_UNKNOWN;
202 break;
203 }
204 biodone(bp); /* we're waiting on it in scsi_strategy() */
205 }
206
207
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.
211 *
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]
215 *
216 * No, seems ok to me... [JRE]
217 * (I don't see any duplicate wakeups)
218 *
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]
222 */
223 void
224 scsistrategy(bp)
225 struct buf *bp;
226 {
227 struct scsi_ioctl *si;
228 scsireq_t *screq;
229 struct scsipi_link *sc_link;
230 int error;
231 int flags = 0;
232 int s;
233
234 si = si_find(bp);
235 if (si == NULL) {
236 printf("user_strat: No ioctl\n");
237 error = EINVAL;
238 goto bad;
239 }
240 screq = &si->si_screq;
241 sc_link = si->si_sc_link;
242 SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n"));
243
244 /*
245 * We're in trouble if physio tried to break up the transfer.
246 */
247 if (bp->b_bcount != screq->datalen) {
248 sc_link->sc_print_addr(sc_link);
249 printf("physio split the request.. cannot proceed\n");
250 error = EIO;
251 goto bad;
252 }
253
254 if (screq->timeout == 0) {
255 error = EINVAL;
256 goto bad;
257 }
258
259 if (screq->cmdlen > sizeof(struct scsipi_generic)) {
260 sc_link->sc_print_addr(sc_link);
261 printf("cmdlen too big\n");
262 error = EFAULT;
263 goto bad;
264 }
265
266 if (screq->flags & SCCMD_READ)
267 flags |= XS_CTL_DATA_IN;
268 if (screq->flags & SCCMD_WRITE)
269 flags |= XS_CTL_DATA_OUT;
270 if (screq->flags & SCCMD_TARGET)
271 flags |= XS_CTL_TARGET;
272 if (screq->flags & SCCMD_ESCAPE)
273 flags |= XS_CTL_ESCAPE;
274
275 error = scsipi_command(sc_link,
276 (struct scsipi_generic *)screq->cmd, screq->cmdlen,
277 (u_char *)bp->b_data, screq->datalen,
278 0, /* user must do the retries *//* ignored */
279 screq->timeout, bp, flags | XS_CTL_USERCMD | XS_CTL_ASYNC);
280
281 /* because there is a bp, scsi_scsipi_cmd will return immediatly */
282 if (error)
283 goto bad;
284
285 SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n"));
286 s = splbio();
287 while ((bp->b_flags & B_DONE) == 0)
288 tsleep(bp, PRIBIO, "scistr", 0);
289 splx(s);
290 SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n"));
291
292 return;
293
294 bad:
295 bp->b_flags |= B_ERROR;
296 bp->b_error = error;
297 biodone(bp);
298 }
299
300 /*
301 * Something (e.g. another driver) has called us
302 * with an sc_link for a target/lun/adapter, and a scsi
303 * specific ioctl to perform, better try.
304 * If user-level type command, we must still be running
305 * in the context of the calling process
306 */
307 int
308 scsipi_do_ioctl(sc_link, dev, cmd, addr, flag, p)
309 struct scsipi_link *sc_link;
310 dev_t dev;
311 u_long cmd;
312 caddr_t addr;
313 int flag;
314 struct proc *p;
315 {
316 int error;
317
318 SC_DEBUG(sc_link, SDEV_DB2, ("scsipi_do_ioctl(0x%lx)\n", cmd));
319
320 /* Check for the safe-ness of this request. */
321 switch (cmd) {
322 case OSCIOCIDENTIFY:
323 case SCIOCIDENTIFY:
324 break;
325 case SCIOCCOMMAND:
326 if ((((scsireq_t *)addr)->flags & SCCMD_READ) == 0 &&
327 (flag & FWRITE) == 0)
328 return (EBADF);
329 break;
330 default:
331 if ((flag & FWRITE) == 0)
332 return (EBADF);
333 }
334
335 switch (cmd) {
336 case SCIOCCOMMAND: {
337 scsireq_t *screq = (scsireq_t *)addr;
338 struct scsi_ioctl *si;
339 int len;
340
341 si = si_get();
342 si->si_screq = *screq;
343 si->si_sc_link = sc_link;
344 len = screq->datalen;
345 if (len) {
346 si->si_iov.iov_base = screq->databuf;
347 si->si_iov.iov_len = len;
348 si->si_uio.uio_iov = &si->si_iov;
349 si->si_uio.uio_iovcnt = 1;
350 si->si_uio.uio_resid = len;
351 si->si_uio.uio_offset = 0;
352 si->si_uio.uio_segflg = UIO_USERSPACE;
353 si->si_uio.uio_rw =
354 (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE;
355 si->si_uio.uio_procp = p;
356 error = physio(scsistrategy, &si->si_bp, dev,
357 (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
358 sc_link->adapter->scsipi_minphys, &si->si_uio,
359 DEF_BSHIFT);
360 } else {
361 /* if no data, no need to translate it.. */
362 si->si_bp.b_flags = 0;
363 si->si_bp.b_data = 0;
364 si->si_bp.b_bcount = 0;
365 si->si_bp.b_dev = dev;
366 si->si_bp.b_proc = p;
367 si->si_bp.b_bshift = DEF_BSHIFT;
368 si->si_bp.b_bsize = DEF_BSIZE;
369 scsistrategy(&si->si_bp);
370 error = si->si_bp.b_error;
371 }
372 *screq = si->si_screq;
373 si_free(si);
374 return (error);
375 }
376 case SCIOCDEBUG: {
377 int level = *((int *)addr);
378
379 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
380 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */
381 if (level & 1)
382 sc_link->flags |= SDEV_DB1;
383 if (level & 2)
384 sc_link->flags |= SDEV_DB2;
385 if (level & 4)
386 sc_link->flags |= SDEV_DB3;
387 if (level & 8)
388 sc_link->flags |= SDEV_DB4;
389 return (0);
390 }
391 case SCIOCRECONFIG:
392 case SCIOCDECONFIG:
393 return (EINVAL);
394 case SCIOCIDENTIFY: {
395 struct scsi_addr *sca = (struct scsi_addr *)addr;
396
397 switch (sc_link->type) {
398 case BUS_SCSI:
399 sca->type = TYPE_SCSI;
400 sca->addr.scsi.scbus = sc_link->scsipi_scsi.scsibus;
401 sca->addr.scsi.target = sc_link->scsipi_scsi.target;
402 sca->addr.scsi.lun = sc_link->scsipi_scsi.lun;
403 return (0);
404 case BUS_ATAPI:
405 sca->type = TYPE_ATAPI;
406 sca->addr.atapi.atbus = sc_link->scsipi_atapi.atapibus;
407 sca->addr.atapi.drive = sc_link->scsipi_atapi.drive;
408 return (0);
409 }
410 return (ENXIO);
411 }
412 #if defined(COMPAT_12) || defined(COMPAT_FREEBSD)
413 /* SCIOCIDENTIFY before ATAPI staff merge */
414 case OSCIOCIDENTIFY: {
415 struct oscsi_addr *sca = (struct oscsi_addr *)addr;
416
417 switch (sc_link->type) {
418 case BUS_SCSI:
419 sca->scbus = sc_link->scsipi_scsi.scsibus;
420 sca->target = sc_link->scsipi_scsi.target;
421 sca->lun = sc_link->scsipi_scsi.lun;
422 return (0);
423 }
424 return (ENODEV);
425 }
426 #endif
427 default:
428 return (ENOTTY);
429 }
430
431 #ifdef DIAGNOSTIC
432 panic("scsipi_do_ioctl: impossible");
433 #endif
434 }
435