Annotation of sys/scsi/scsi_ioctl.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: scsi_ioctl.c,v 1.28 2007/01/16 00:43:19 krw Exp $ */
2: /* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1994 Charles Hannum. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Charles Hannum.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31: */
32:
33: /*
34: * Contributed by HD Associates (hd@world.std.com).
35: * Copyright (c) 1992, 1993 HD Associates
36: *
37: * Berkeley style copyright.
38: */
39:
40: #include <sys/types.h>
41: #include <sys/errno.h>
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/file.h>
45: #include <sys/malloc.h>
46: #include <sys/buf.h>
47: #include <sys/proc.h>
48: #include <sys/device.h>
49: #include <sys/fcntl.h>
50:
51: #include <scsi/scsi_all.h>
52: #include <scsi/scsiconf.h>
53: #include <sys/scsiio.h>
54:
55: struct scsi_ioctl {
56: LIST_ENTRY(scsi_ioctl) si_list;
57: struct buf si_bp;
58: struct uio si_uio;
59: struct iovec si_iov;
60: scsireq_t si_screq;
61: struct scsi_link *si_sc_link;
62: };
63:
64: LIST_HEAD(, scsi_ioctl) si_head;
65:
66: struct scsi_ioctl *si_get(void);
67: void si_free(struct scsi_ioctl *);
68: struct scsi_ioctl *si_find(struct buf *);
69: void scsistrategy(struct buf *);
70:
71: const unsigned char scsi_readsafe_cmd[256] = {
72: [0x00] = 1, /* TEST UNIT READY */
73: [0x03] = 1, /* REQUEST SENSE */
74: [0x08] = 1, /* READ(6) */
75: [0x12] = 1, /* INQUIRY */
76: [0x1a] = 1, /* MODE SENSE */
77: [0x1b] = 1, /* START STOP */
78: [0x23] = 1, /* READ FORMAT CAPACITIES */
79: [0x25] = 1, /* READ CDVD CAPACITY */
80: [0x28] = 1, /* READ(10) */
81: [0x2b] = 1, /* SEEK */
82: [0x2f] = 1, /* VERIFY(10) */
83: [0x3c] = 1, /* READ BUFFER */
84: [0x3e] = 1, /* READ LONG */
85: [0x42] = 1, /* READ SUBCHANNEL */
86: [0x43] = 1, /* READ TOC PMA ATIP */
87: [0x44] = 1, /* READ HEADER */
88: [0x45] = 1, /* PLAY AUDIO(10) */
89: [0x46] = 1, /* GET CONFIGURATION */
90: [0x47] = 1, /* PLAY AUDIO MSF */
91: [0x48] = 1, /* PLAY AUDIO TI */
92: [0x4a] = 1, /* GET EVENT STATUS NOTIFICATION */
93: [0x4b] = 1, /* PAUSE RESUME */
94: [0x4e] = 1, /* STOP PLAY SCAN */
95: [0x51] = 1, /* READ DISC INFO */
96: [0x52] = 1, /* READ TRACK RZONE INFO */
97: [0x5a] = 1, /* MODE SENSE(10) */
98: [0x88] = 1, /* READ(16) */
99: [0x8f] = 1, /* VERIFY(16) */
100: [0xa4] = 1, /* REPORT KEY */
101: [0xa5] = 1, /* PLAY AUDIO(12) */
102: [0xa8] = 1, /* READ(12) */
103: [0xac] = 1, /* GET PERFORMANCE */
104: [0xad] = 1, /* READ DVD STRUCTURE */
105: [0xb9] = 1, /* READ CD MSF */
106: [0xba] = 1, /* SCAN */
107: [0xbc] = 1, /* PLAY CD */
108: [0xbd] = 1, /* MECHANISM STATUS */
109: [0xbe] = 1 /* READ CD */
110: };
111:
112: struct scsi_ioctl *
113: si_get(void)
114: {
115: struct scsi_ioctl *si;
116: int s;
117:
118: si = malloc(sizeof(struct scsi_ioctl), M_TEMP, M_WAITOK);
119: bzero(si, sizeof(struct scsi_ioctl));
120: s = splbio();
121: LIST_INSERT_HEAD(&si_head, si, si_list);
122: splx(s);
123: return (si);
124: }
125:
126: void
127: si_free(struct scsi_ioctl *si)
128: {
129: int s;
130:
131: s = splbio();
132: LIST_REMOVE(si, si_list);
133: splx(s);
134: free(si, M_TEMP);
135: }
136:
137: struct scsi_ioctl *
138: si_find(struct buf *bp)
139: {
140: struct scsi_ioctl *si;
141: int s;
142:
143: s = splbio();
144: LIST_FOREACH(si, &si_head, si_list) {
145: if (bp == &si->si_bp)
146: break;
147: }
148: splx(s);
149:
150: return (si);
151: }
152:
153: /*
154: * We let the user interpret his own sense in the generic scsi world.
155: * This routine is called at interrupt time if the SCSI_USER bit was set
156: * in the flags passed to scsi_scsi_cmd(). No other completion processing
157: * takes place, even if we are running over another device driver.
158: * The lower level routines that call us here, will free the xs and restart
159: * the device's queue if such exists.
160: */
161: void
162: scsi_user_done(struct scsi_xfer *xs)
163: {
164: struct buf *bp;
165: struct scsi_ioctl *si;
166: scsireq_t *screq;
167: struct scsi_link *sc_link;
168:
169: splassert(IPL_BIO);
170:
171: bp = xs->bp;
172: if (bp == NULL) { /* ALL user requests must have a buf */
173: sc_print_addr(xs->sc_link);
174: printf("User command with no buf\n");
175: return;
176: }
177:
178: si = si_find(bp);
179: if (si == NULL) {
180: sc_print_addr(xs->sc_link);
181: printf("User command with no ioctl\n");
182: return;
183: }
184:
185: screq = &si->si_screq;
186: sc_link = si->si_sc_link;
187: SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n"));
188:
189: screq->retsts = 0;
190: screq->status = xs->status;
191: switch (xs->error) {
192: case XS_NOERROR:
193: SC_DEBUG(sc_link, SDEV_DB3, ("no error\n"));
194: /* probably rubbish */
195: screq->datalen_used = xs->datalen - xs->resid;
196: screq->retsts = SCCMD_OK;
197: break;
198: case XS_SENSE:
199: SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n"));
200: screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
201: bcopy(&xs->sense, screq->sense, screq->senselen);
202: screq->retsts = SCCMD_SENSE;
203: break;
204: case XS_SHORTSENSE:
205: SC_DEBUG(sc_link, SDEV_DB3, ("have short sense\n"));
206: screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
207: bcopy(&xs->sense, screq->sense, screq->senselen);
208: screq->retsts = SCCMD_UNKNOWN;
209: break;
210: case XS_DRIVER_STUFFUP:
211: sc_print_addr(sc_link);
212: printf("host adapter code inconsistency\n");
213: screq->retsts = SCCMD_UNKNOWN;
214: break;
215: case XS_TIMEOUT:
216: SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n"));
217: screq->retsts = SCCMD_TIMEOUT;
218: break;
219: case XS_BUSY:
220: SC_DEBUG(sc_link, SDEV_DB3, ("busy\n"));
221: screq->retsts = SCCMD_BUSY;
222: break;
223: default:
224: sc_print_addr(sc_link);
225: printf("unknown error category (0x%x) from host adapter code\n",
226: xs->error);
227: screq->retsts = SCCMD_UNKNOWN;
228: break;
229: }
230:
231: biodone(bp); /* we're waiting on it in scsi_strategy() */
232: }
233:
234:
235: /* Pseudo strategy function
236: * Called by scsi_do_ioctl() via physio/physstrat if there is to
237: * be data transferred, and directly if there is no data transfer.
238: *
239: * Should I reorganize this so it returns to physio instead
240: * of sleeping in scsiio_scsi_cmd? Is there any advantage, other
241: * than avoiding the probable duplicate wakeup in iodone? [PD]
242: *
243: * No, seems ok to me... [JRE]
244: * (I don't see any duplicate wakeups)
245: *
246: * Can't be used with block devices or raw_read/raw_write directly
247: * from the cdevsw/bdevsw tables because they couldn't have added
248: * the screq structure. [JRE]
249: */
250: void
251: scsistrategy(struct buf *bp)
252: {
253: struct scsi_ioctl *si;
254: scsireq_t *screq;
255: struct scsi_link *sc_link;
256: int error;
257: int flags = 0;
258: int s;
259:
260: si = si_find(bp);
261: if (si == NULL) {
262: printf("user_strat: No ioctl\n");
263: error = EINVAL;
264: goto bad;
265: }
266:
267: screq = &si->si_screq;
268: sc_link = si->si_sc_link;
269: SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n"));
270:
271: /*
272: * We're in trouble if physio tried to break up the transfer.
273: */
274: if (bp->b_bcount != screq->datalen) {
275: sc_print_addr(sc_link);
276: printf("physio split the request.. cannot proceed\n");
277: error = EIO;
278: goto bad;
279: }
280:
281: if (screq->timeout == 0) {
282: error = EINVAL;
283: goto bad;
284: }
285:
286: if (screq->cmdlen > sizeof(struct scsi_generic)) {
287: sc_print_addr(sc_link);
288: printf("cmdlen too big\n");
289: error = EFAULT;
290: goto bad;
291: }
292:
293: if (screq->flags & SCCMD_READ)
294: flags |= SCSI_DATA_IN;
295: if (screq->flags & SCCMD_WRITE)
296: flags |= SCSI_DATA_OUT;
297: if (screq->flags & SCCMD_TARGET)
298: flags |= SCSI_TARGET;
299: if (screq->flags & SCCMD_ESCAPE)
300: flags |= SCSI_ESCAPE;
301:
302: error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd,
303: screq->cmdlen, (u_char *)bp->b_data, screq->datalen,
304: 0, /* user must do the retries *//* ignored */
305: screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP);
306:
307: /* because there is a bp, scsi_scsi_cmd will return immediately */
308: if (error)
309: goto bad;
310:
311: SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n"));
312: s = splbio();
313: while ((bp->b_flags & B_DONE) == 0)
314: tsleep(bp, PRIBIO, "scistr", 0);
315: splx(s);
316: SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n"));
317:
318: return;
319:
320: bad:
321: bp->b_flags |= B_ERROR;
322: bp->b_error = error;
323: s = splbio();
324: biodone(bp);
325: splx(s);
326: }
327:
328: /*
329: * Something (e.g. another driver) has called us
330: * with an sc_link for a target/lun/adapter, and a scsi
331: * specific ioctl to perform, better try.
332: * If user-level type command, we must still be running
333: * in the context of the calling process
334: */
335: int
336: scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
337: int flag, struct proc *p)
338: {
339: int error;
340:
341: SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
342:
343: switch(cmd) {
344: case SCIOCIDENTIFY: {
345: struct scsi_addr *sca = (struct scsi_addr *)addr;
346:
347: if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0)
348: /* A 'real' SCSI target. */
349: sca->type = TYPE_SCSI;
350: else
351: /* An 'emulated' SCSI target. */
352: sca->type = TYPE_ATAPI;
353: sca->scbus = sc_link->scsibus;
354: sca->target = sc_link->target;
355: sca->lun = sc_link->lun;
356: return (0);
357: }
358: case SCIOCCOMMAND:
359: if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]])
360: break;
361: /* FALLTHROUGH */
362: case SCIOCDEBUG:
363: case SCIOCRESET:
364: if ((flag & FWRITE) == 0)
365: return (EPERM);
366: break;
367: default:
368: if (sc_link->adapter->ioctl)
369: return ((sc_link->adapter->ioctl)(sc_link, cmd, addr,
370: flag, p));
371: else
372: return (ENOTTY);
373: }
374:
375: switch(cmd) {
376: case SCIOCCOMMAND: {
377: scsireq_t *screq = (scsireq_t *)addr;
378: struct scsi_ioctl *si;
379:
380: si = si_get();
381: si->si_screq = *screq;
382: si->si_sc_link = sc_link;
383: if (screq->datalen) {
384: si->si_iov.iov_base = screq->databuf;
385: si->si_iov.iov_len = screq->datalen;
386: si->si_uio.uio_iov = &si->si_iov;
387: si->si_uio.uio_iovcnt = 1;
388: si->si_uio.uio_resid = screq->datalen;
389: si->si_uio.uio_offset = 0;
390: si->si_uio.uio_segflg = UIO_USERSPACE;
391: si->si_uio.uio_rw =
392: (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE;
393: si->si_uio.uio_procp = p;
394: error = physio(scsistrategy, &si->si_bp, dev,
395: (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
396: sc_link->adapter->scsi_minphys, &si->si_uio);
397: } else {
398: /* if no data, no need to translate it.. */
399: si->si_bp.b_flags = 0;
400: si->si_bp.b_data = 0;
401: si->si_bp.b_bcount = 0;
402: si->si_bp.b_dev = dev;
403: si->si_bp.b_proc = p;
404: scsistrategy(&si->si_bp);
405: error = si->si_bp.b_error;
406: }
407: *screq = si->si_screq;
408: si_free(si);
409: return (error);
410: }
411: case SCIOCDEBUG: {
412: int level = *((int *)addr);
413:
414: SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
415: sc_link->flags &= ~SDEV_DBX; /* clear debug bits */
416: if (level & 1)
417: sc_link->flags |= SDEV_DB1;
418: if (level & 2)
419: sc_link->flags |= SDEV_DB2;
420: if (level & 4)
421: sc_link->flags |= SDEV_DB3;
422: if (level & 8)
423: sc_link->flags |= SDEV_DB4;
424: return (0);
425: }
426: case SCIOCRESET: {
427: scsi_scsi_cmd(sc_link, 0, 0, 0, 0, GENRETRY, 2000, NULL,
428: SCSI_RESET);
429: return (0);
430: }
431: default:
432: #ifdef DIAGNOSTIC
433: panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
434: #endif
435: return (0);
436: }
437: }
CVSweb