Annotation of sys/scsi/scsi_ioctl.c, Revision 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