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