xref: /netbsd-src/sys/dev/scsipi/scsipi_ioctl.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: scsipi_ioctl.c,v 1.28 1997/10/18 19:51:04 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@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 = scsipi_command(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