scsipi_ioctl.c revision 1.35 1 /* $NetBSD: scsipi_ioctl.c,v 1.35 1998/11/17 14:38:43 bouyer 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 SCSI_USER 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_TIMEOUT:
186 SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n"));
187 screq->retsts = SCCMD_TIMEOUT;
188 break;
189 case XS_BUSY:
190 SC_DEBUG(sc_link, SDEV_DB3, ("busy\n"));
191 screq->retsts = SCCMD_BUSY;
192 break;
193 default:
194 sc_link->sc_print_addr(sc_link);
195 printf("unknown error category from host adapter code\n");
196 screq->retsts = SCCMD_UNKNOWN;
197 break;
198 }
199 biodone(bp); /* we're waiting on it in scsi_strategy() */
200 }
201
202
203 /* Pseudo strategy function
204 * Called by scsipi_do_ioctl() via physio/physstrat if there is to
205 * be data transfered, and directly if there is no data transfer.
206 *
207 * Should I reorganize this so it returns to physio instead
208 * of sleeping in scsiio_scsipi_cmd? Is there any advantage, other
209 * than avoiding the probable duplicate wakeup in iodone? [PD]
210 *
211 * No, seems ok to me... [JRE]
212 * (I don't see any duplicate wakeups)
213 *
214 * Can't be used with block devices or raw_read/raw_write directly
215 * from the cdevsw/bdevsw tables because they couldn't have added
216 * the screq structure. [JRE]
217 */
218 void
219 scsistrategy(bp)
220 struct buf *bp;
221 {
222 struct scsi_ioctl *si;
223 scsireq_t *screq;
224 struct scsipi_link *sc_link;
225 int error;
226 int flags = 0;
227 int s;
228
229 si = si_find(bp);
230 if (si == NULL) {
231 printf("user_strat: No ioctl\n");
232 error = EINVAL;
233 goto bad;
234 }
235 screq = &si->si_screq;
236 sc_link = si->si_sc_link;
237 SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n"));
238
239 /*
240 * We're in trouble if physio tried to break up the transfer.
241 */
242 if (bp->b_bcount != screq->datalen) {
243 sc_link->sc_print_addr(sc_link);
244 printf("physio split the request.. cannot proceed\n");
245 error = EIO;
246 goto bad;
247 }
248
249 if (screq->timeout == 0) {
250 error = EINVAL;
251 goto bad;
252 }
253
254 if (screq->cmdlen > sizeof(struct scsipi_generic)) {
255 sc_link->sc_print_addr(sc_link);
256 printf("cmdlen too big\n");
257 error = EFAULT;
258 goto bad;
259 }
260
261 if (screq->flags & SCCMD_READ)
262 flags |= SCSI_DATA_IN;
263 if (screq->flags & SCCMD_WRITE)
264 flags |= SCSI_DATA_OUT;
265 if (screq->flags & SCCMD_TARGET)
266 flags |= SCSI_TARGET;
267 if (screq->flags & SCCMD_ESCAPE)
268 flags |= SCSI_ESCAPE;
269
270 error = scsipi_command(sc_link,
271 (struct scsipi_generic *)screq->cmd, screq->cmdlen,
272 (u_char *)bp->b_data, screq->datalen,
273 0, /* user must do the retries *//* ignored */
274 screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP);
275
276 /* because there is a bp, scsi_scsipi_cmd will return immediatly */
277 if (error)
278 goto bad;
279
280 SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n"));
281 s = splbio();
282 while ((bp->b_flags & B_DONE) == 0)
283 tsleep(bp, PRIBIO, "scistr", 0);
284 splx(s);
285 SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n"));
286
287 return;
288
289 bad:
290 bp->b_flags |= B_ERROR;
291 bp->b_error = error;
292 biodone(bp);
293 }
294
295 /*
296 * Something (e.g. another driver) has called us
297 * with an sc_link for a target/lun/adapter, and a scsi
298 * specific ioctl to perform, better try.
299 * If user-level type command, we must still be running
300 * in the context of the calling process
301 */
302 int
303 scsipi_do_ioctl(sc_link, dev, cmd, addr, flag, p)
304 struct scsipi_link *sc_link;
305 dev_t dev;
306 u_long cmd;
307 caddr_t addr;
308 int flag;
309 struct proc *p;
310 {
311 int error;
312
313 SC_DEBUG(sc_link, SDEV_DB2, ("scsipi_do_ioctl(0x%lx)\n", cmd));
314
315 /* Check for the safe-ness of this request. */
316 switch (cmd) {
317 case OSCIOCIDENTIFY:
318 case SCIOCIDENTIFY:
319 break;
320 case SCIOCCOMMAND:
321 if ((((scsireq_t *)addr)->flags & SCCMD_READ) == 0 &&
322 (flag & FWRITE) == 0)
323 return (EBADF);
324 break;
325 default:
326 if ((flag & FWRITE) == 0)
327 return (EBADF);
328 }
329
330 switch (cmd) {
331 case SCIOCCOMMAND: {
332 scsireq_t *screq = (scsireq_t *)addr;
333 struct scsi_ioctl *si;
334 int len;
335
336 si = si_get();
337 si->si_screq = *screq;
338 si->si_sc_link = sc_link;
339 len = screq->datalen;
340 if (len) {
341 si->si_iov.iov_base = screq->databuf;
342 si->si_iov.iov_len = len;
343 si->si_uio.uio_iov = &si->si_iov;
344 si->si_uio.uio_iovcnt = 1;
345 si->si_uio.uio_resid = len;
346 si->si_uio.uio_offset = 0;
347 si->si_uio.uio_segflg = UIO_USERSPACE;
348 si->si_uio.uio_rw =
349 (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE;
350 si->si_uio.uio_procp = p;
351 error = physio(scsistrategy, &si->si_bp, dev,
352 (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
353 sc_link->adapter->scsipi_minphys, &si->si_uio);
354 } else {
355 /* if no data, no need to translate it.. */
356 si->si_bp.b_flags = 0;
357 si->si_bp.b_data = 0;
358 si->si_bp.b_bcount = 0;
359 si->si_bp.b_dev = dev;
360 si->si_bp.b_proc = p;
361 scsistrategy(&si->si_bp);
362 error = si->si_bp.b_error;
363 }
364 *screq = si->si_screq;
365 si_free(si);
366 return (error);
367 }
368 case SCIOCDEBUG: {
369 int level = *((int *)addr);
370
371 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
372 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */
373 if (level & 1)
374 sc_link->flags |= SDEV_DB1;
375 if (level & 2)
376 sc_link->flags |= SDEV_DB2;
377 if (level & 4)
378 sc_link->flags |= SDEV_DB3;
379 if (level & 8)
380 sc_link->flags |= SDEV_DB4;
381 return (0);
382 }
383 case SCIOCRECONFIG:
384 case SCIOCDECONFIG:
385 return (EINVAL);
386 case SCIOCIDENTIFY: {
387 struct scsi_addr *sca = (struct scsi_addr *)addr;
388
389 switch (sc_link->type) {
390 case BUS_SCSI:
391 sca->type = TYPE_SCSI;
392 sca->addr.scsi.scbus = sc_link->scsipi_scsi.scsibus;
393 sca->addr.scsi.target = sc_link->scsipi_scsi.target;
394 sca->addr.scsi.lun = sc_link->scsipi_scsi.lun;
395 return (0);
396 case BUS_ATAPI:
397 sca->type = TYPE_ATAPI;
398 sca->addr.atapi.atbus = sc_link->scsipi_atapi.atapibus;
399 sca->addr.atapi.drive = sc_link->scsipi_atapi.drive;
400 return (0);
401 }
402 return (ENXIO);
403 }
404 #if defined(COMPAT_12) || defined(COMPAT_FREEBSD)
405 /* SCIOCIDENTIFY before ATAPI staff merge */
406 case OSCIOCIDENTIFY: {
407 struct oscsi_addr *sca = (struct oscsi_addr *)addr;
408
409 switch (sc_link->type) {
410 case BUS_SCSI:
411 sca->scbus = sc_link->scsipi_scsi.scsibus;
412 sca->target = sc_link->scsipi_scsi.target;
413 sca->lun = sc_link->scsipi_scsi.lun;
414 return (0);
415 }
416 return (ENODEV);
417 }
418 #endif
419 default:
420 return (ENOTTY);
421 }
422
423 #ifdef DIAGNOSTIC
424 panic("scsipi_do_ioctl: impossible");
425 #endif
426 }
427