[BACK]Return to scsi_ioctl.c CVS log [TXT][DIR] Up to [local] / sys / scsi

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