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

Annotation of sys/scsi/ch.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ch.c,v 1.32 2006/11/28 16:56:50 dlg Exp $     */
        !             2: /*     $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Partially based on an autochanger driver written by Stefan Grefen
        !             9:  * and on an autochanger driver written by the Systems Programming Group
        !            10:  * at the University of Utah Computer Science Department.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgements:
        !            22:  *     This product includes software developed by Jason R. Thorpe
        !            23:  *     for And Communications, http://www.and.com/
        !            24:  * 4. The name of the author may not be used to endorse or promote products
        !            25:  *    derived from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            28:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            29:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            30:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            31:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            32:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            33:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            34:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            35:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            36:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            37:  * SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/errno.h>
        !            43: #include <sys/ioctl.h>
        !            44: #include <sys/buf.h>
        !            45: #include <sys/proc.h>
        !            46: #include <sys/user.h>
        !            47: #include <sys/chio.h>
        !            48: #include <sys/device.h>
        !            49: #include <sys/malloc.h>
        !            50: #include <sys/conf.h>
        !            51: #include <sys/fcntl.h>
        !            52:
        !            53: #include <scsi/scsi_all.h>
        !            54: #include <scsi/scsi_changer.h>
        !            55: #include <scsi/scsiconf.h>
        !            56:
        !            57: #define CHRETRIES      2
        !            58: #define CHUNIT(x)      (minor((x)))
        !            59:
        !            60: struct ch_softc {
        !            61:        struct device   sc_dev;         /* generic device info */
        !            62:        struct scsi_link *sc_link;      /* link in the SCSI bus */
        !            63:
        !            64:        int             sc_picker;      /* current picker */
        !            65:
        !            66:        /*
        !            67:         * The following information is obtained from the
        !            68:         * element address assignment page.
        !            69:         */
        !            70:        int             sc_firsts[4];   /* firsts, indexed by CHET_* */
        !            71:        int             sc_counts[4];   /* counts, indexed by CHET_* */
        !            72:
        !            73:        /*
        !            74:         * The following mask defines the legal combinations
        !            75:         * of elements for the MOVE MEDIUM command.
        !            76:         */
        !            77:        u_int8_t        sc_movemask[4];
        !            78:
        !            79:        /*
        !            80:         * As above, but for EXCHANGE MEDIUM.
        !            81:         */
        !            82:        u_int8_t        sc_exchangemask[4];
        !            83:
        !            84:        int             flags;          /* misc. info */
        !            85:
        !            86:        /*
        !            87:         * Quirks; see below.
        !            88:         */
        !            89:        int             sc_settledelay; /* delay for settle */
        !            90:
        !            91: };
        !            92:
        !            93: /* sc_flags */
        !            94: #define CHF_ROTATE     0x01            /* picker can rotate */
        !            95:
        !            96: /* Autoconfiguration glue */
        !            97: int    chmatch(struct device *, void *, void *);
        !            98: void   chattach(struct device *, struct device *, void *);
        !            99:
        !           100: struct cfattach ch_ca = {
        !           101:        sizeof(struct ch_softc), chmatch, chattach
        !           102: };
        !           103:
        !           104: struct cfdriver ch_cd = {
        !           105:        NULL, "ch", DV_DULL
        !           106: };
        !           107:
        !           108: const struct scsi_inquiry_pattern ch_patterns[] = {
        !           109:        {T_CHANGER, T_REMOV,
        !           110:         "",            "",             ""},
        !           111: };
        !           112:
        !           113: int    ch_move(struct ch_softc *, struct changer_move *);
        !           114: int    ch_exchange(struct ch_softc *, struct changer_exchange *);
        !           115: int    ch_position(struct ch_softc *, struct changer_position *);
        !           116: int    ch_usergetelemstatus(struct ch_softc *,
        !           117:     struct changer_element_status_request *);
        !           118: int    ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t, int);
        !           119: int    ch_get_params(struct ch_softc *, int);
        !           120: int    ch_interpret_sense(struct scsi_xfer *xs);
        !           121: void   ch_get_quirks(struct ch_softc *, struct scsi_inquiry_data *);
        !           122:
        !           123: /* SCSI glue */
        !           124: struct scsi_device ch_switch = {
        !           125:        ch_interpret_sense,
        !           126:        NULL,
        !           127:        NULL,
        !           128:        NULL
        !           129: };
        !           130:
        !           131: /*
        !           132:  * SCSI changer quirks.
        !           133:  */
        !           134: struct chquirk {
        !           135:        struct  scsi_inquiry_pattern cq_match; /* device id pattern */
        !           136:        int     cq_settledelay; /* settle delay, in seconds */
        !           137: };
        !           138:
        !           139: struct chquirk chquirks[] = {
        !           140:        {{T_CHANGER, T_REMOV,
        !           141:          "SPECTRA",    "9000",         "0200"},
        !           142:         75},
        !           143: };
        !           144:
        !           145: int
        !           146: chmatch(parent, match, aux)
        !           147:        struct device *parent;
        !           148:        void *match, *aux;
        !           149: {
        !           150:        struct scsi_attach_args *sa = aux;
        !           151:        int priority;
        !           152:
        !           153:        (void)scsi_inqmatch(sa->sa_inqbuf,
        !           154:            ch_patterns, sizeof(ch_patterns)/sizeof(ch_patterns[0]),
        !           155:            sizeof(ch_patterns[0]), &priority);
        !           156:
        !           157:        return (priority);
        !           158: }
        !           159:
        !           160: void
        !           161: chattach(parent, self, aux)
        !           162:        struct device *parent, *self;
        !           163:        void *aux;
        !           164: {
        !           165:        struct ch_softc *sc = (struct ch_softc *)self;
        !           166:        struct scsi_attach_args *sa = aux;
        !           167:        struct scsi_link *link = sa->sa_sc_link;
        !           168:
        !           169:        /* Glue into the SCSI bus */
        !           170:        sc->sc_link = link;
        !           171:        link->device = &ch_switch;
        !           172:        link->device_softc = sc;
        !           173:        link->openings = 1;
        !           174:
        !           175:        printf("\n");
        !           176:
        !           177:        /*
        !           178:         * Store our our device's quirks.
        !           179:         */
        !           180:        ch_get_quirks(sc, sa->sa_inqbuf);
        !           181:
        !           182: }
        !           183:
        !           184: int
        !           185: chopen(dev, flags, fmt, p)
        !           186:        dev_t dev;
        !           187:        int flags, fmt;
        !           188:        struct proc *p;
        !           189: {
        !           190:        struct ch_softc *sc;
        !           191:        int oldcounts[4];
        !           192:        int i, unit, error = 0;
        !           193:
        !           194:        unit = CHUNIT(dev);
        !           195:        if ((unit >= ch_cd.cd_ndevs) ||
        !           196:            ((sc = ch_cd.cd_devs[unit]) == NULL))
        !           197:                return (ENXIO);
        !           198:
        !           199:        /*
        !           200:         * Only allow one open at a time.
        !           201:         */
        !           202:        if (sc->sc_link->flags & SDEV_OPEN)
        !           203:                return (EBUSY);
        !           204:
        !           205:        sc->sc_link->flags |= SDEV_OPEN;
        !           206:
        !           207:        /*
        !           208:         * Absorb any unit attention errors. We must notice
        !           209:         * "Not ready" errors as a changer will report "In the
        !           210:         * process of getting ready" any time it must rescan
        !           211:         * itself to determine the state of the changer.
        !           212:         */
        !           213:        error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES,
        !           214:            SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
        !           215:        if (error)
        !           216:                goto bad;
        !           217:
        !           218:        /*
        !           219:         * Get information about the device. Save old information
        !           220:         * so we can decide whether to be verbose about new parameters.
        !           221:         */
        !           222:        for (i = 0; i < 4; i++) {
        !           223:                oldcounts[i] = sc->sc_counts[i];
        !           224:        }
        !           225:        error = ch_get_params(sc, scsi_autoconf);
        !           226:        if (error)
        !           227:                goto bad;
        !           228:
        !           229:        for (i = 0; i < 4; i++) {
        !           230:                if (oldcounts[i] != sc->sc_counts[i]) {
        !           231:                        break;
        !           232:                }
        !           233:        }
        !           234:        if (i < 4) {
        !           235: #ifdef CHANGER_DEBUG
        !           236: #define PLURAL(c)      (c) == 1 ? "" : "s"
        !           237:                printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
        !           238:                    sc->sc_dev.dv_xname,
        !           239:                    sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
        !           240:                    sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
        !           241:                    sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
        !           242:                    sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
        !           243: #undef PLURAL
        !           244:                printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
        !           245:                    sc->sc_dev.dv_xname,
        !           246:                    sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
        !           247:                    sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
        !           248:                printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
        !           249:                    sc->sc_dev.dv_xname,
        !           250:                    sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
        !           251:                    sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
        !           252: #endif /* CHANGER_DEBUG */
        !           253:        }
        !           254:
        !           255:        /* Default the current picker. */
        !           256:        sc->sc_picker = sc->sc_firsts[CHET_MT];
        !           257:
        !           258:        return (0);
        !           259:
        !           260:  bad:
        !           261:        sc->sc_link->flags &= ~SDEV_OPEN;
        !           262:        return (error);
        !           263: }
        !           264:
        !           265: int
        !           266: chclose(dev, flags, fmt, p)
        !           267:        dev_t dev;
        !           268:        int flags, fmt;
        !           269:        struct proc *p;
        !           270: {
        !           271:        struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
        !           272:
        !           273:        sc->sc_link->flags &= ~SDEV_OPEN;
        !           274:        return (0);
        !           275: }
        !           276:
        !           277: int
        !           278: chioctl(dev, cmd, data, flags, p)
        !           279:        dev_t dev;
        !           280:        u_long cmd;
        !           281:        caddr_t data;
        !           282:        int flags;
        !           283:        struct proc *p;
        !           284: {
        !           285:        struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
        !           286:        int error = 0;
        !           287:
        !           288:        /*
        !           289:         * If this command can change the device's state, we must
        !           290:         * have the device open for writing.
        !           291:         */
        !           292:        switch (cmd) {
        !           293:        case CHIOGPICKER:
        !           294:        case CHIOGPARAMS:
        !           295:        case CHIOGSTATUS:
        !           296:                break;
        !           297:
        !           298:        default:
        !           299:                if ((flags & FWRITE) == 0)
        !           300:                        return (EBADF);
        !           301:        }
        !           302:
        !           303:        switch (cmd) {
        !           304:        case CHIOMOVE:
        !           305:                error = ch_move(sc, (struct changer_move *)data);
        !           306:                break;
        !           307:
        !           308:        case CHIOEXCHANGE:
        !           309:                error = ch_exchange(sc, (struct changer_exchange *)data);
        !           310:                break;
        !           311:
        !           312:        case CHIOPOSITION:
        !           313:                error = ch_position(sc, (struct changer_position *)data);
        !           314:                break;
        !           315:
        !           316:        case CHIOGPICKER:
        !           317:                *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
        !           318:                break;
        !           319:
        !           320:        case CHIOSPICKER:       {
        !           321:                int new_picker = *(int *)data;
        !           322:
        !           323:                if (new_picker > (sc->sc_counts[CHET_MT] - 1))
        !           324:                        return (EINVAL);
        !           325:                sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
        !           326:                break;          }
        !           327:
        !           328:        case CHIOGPARAMS:       {
        !           329:                struct changer_params *cp = (struct changer_params *)data;
        !           330:
        !           331:                cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
        !           332:                cp->cp_npickers = sc->sc_counts[CHET_MT];
        !           333:                cp->cp_nslots = sc->sc_counts[CHET_ST];
        !           334:                cp->cp_nportals = sc->sc_counts[CHET_IE];
        !           335:                cp->cp_ndrives = sc->sc_counts[CHET_DT];
        !           336:                break;          }
        !           337:
        !           338:        case CHIOGSTATUS:       {
        !           339:                struct changer_element_status_request *cesr =
        !           340:                    (struct changer_element_status_request *)data;
        !           341:
        !           342:                error = ch_usergetelemstatus(sc, cesr);
        !           343:                break;          }
        !           344:
        !           345:        /* Implement prevent/allow? */
        !           346:
        !           347:        default:
        !           348:                error = scsi_do_ioctl(sc->sc_link, dev, cmd, data,
        !           349:                    flags, p);
        !           350:                break;
        !           351:        }
        !           352:
        !           353:        return (error);
        !           354: }
        !           355:
        !           356: int
        !           357: ch_move(sc, cm)
        !           358:        struct ch_softc *sc;
        !           359:        struct changer_move *cm;
        !           360: {
        !           361:        struct scsi_move_medium cmd;
        !           362:        u_int16_t fromelem, toelem;
        !           363:
        !           364:        /*
        !           365:         * Check arguments.
        !           366:         */
        !           367:        if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
        !           368:                return (EINVAL);
        !           369:        if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
        !           370:            (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
        !           371:                return (ENODEV);
        !           372:
        !           373:        /*
        !           374:         * Check the request against the changer's capabilities.
        !           375:         */
        !           376:        if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
        !           377:                return (EINVAL);
        !           378:
        !           379:        /*
        !           380:         * Calculate the source and destination elements.
        !           381:         */
        !           382:        fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
        !           383:        toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
        !           384:
        !           385:        /*
        !           386:         * Build the SCSI command.
        !           387:         */
        !           388:        bzero(&cmd, sizeof(cmd));
        !           389:        cmd.opcode = MOVE_MEDIUM;
        !           390:        _lto2b(sc->sc_picker, cmd.tea);
        !           391:        _lto2b(fromelem, cmd.src);
        !           392:        _lto2b(toelem, cmd.dst);
        !           393:        if (cm->cm_flags & CM_INVERT)
        !           394:                cmd.flags |= MOVE_MEDIUM_INVERT;
        !           395:
        !           396:        /*
        !           397:         * Send command to changer.
        !           398:         */
        !           399:        return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
        !           400:            sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
        !           401: }
        !           402:
        !           403: int
        !           404: ch_exchange(sc, ce)
        !           405:        struct ch_softc *sc;
        !           406:        struct changer_exchange *ce;
        !           407: {
        !           408:        struct scsi_exchange_medium cmd;
        !           409:        u_int16_t src, dst1, dst2;
        !           410:
        !           411:        /*
        !           412:         * Check arguments.
        !           413:         */
        !           414:        if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
        !           415:            (ce->ce_sdsttype > CHET_DT))
        !           416:                return (EINVAL);
        !           417:        if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
        !           418:            (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
        !           419:            (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
        !           420:                return (ENODEV);
        !           421:
        !           422:        /*
        !           423:         * Check the request against the changer's capabilities.
        !           424:         */
        !           425:        if (((sc->sc_exchangemask[ce->ce_srctype] &
        !           426:            (1 << ce->ce_fdsttype)) == 0) ||
        !           427:            ((sc->sc_exchangemask[ce->ce_fdsttype] &
        !           428:            (1 << ce->ce_sdsttype)) == 0))
        !           429:                return (EINVAL);
        !           430:
        !           431:        /*
        !           432:         * Calculate the source and destination elements.
        !           433:         */
        !           434:        src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
        !           435:        dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
        !           436:        dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
        !           437:
        !           438:        /*
        !           439:         * Build the SCSI command.
        !           440:         */
        !           441:        bzero(&cmd, sizeof(cmd));
        !           442:        cmd.opcode = EXCHANGE_MEDIUM;
        !           443:        _lto2b(sc->sc_picker, cmd.tea);
        !           444:        _lto2b(src, cmd.src);
        !           445:        _lto2b(dst1, cmd.fdst);
        !           446:        _lto2b(dst2, cmd.sdst);
        !           447:        if (ce->ce_flags & CE_INVERT1)
        !           448:                cmd.flags |= EXCHANGE_MEDIUM_INV1;
        !           449:        if (ce->ce_flags & CE_INVERT2)
        !           450:                cmd.flags |= EXCHANGE_MEDIUM_INV2;
        !           451:
        !           452:        /*
        !           453:         * Send command to changer.
        !           454:         */
        !           455:        return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
        !           456:            sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
        !           457: }
        !           458:
        !           459: int
        !           460: ch_position(sc, cp)
        !           461:        struct ch_softc *sc;
        !           462:        struct changer_position *cp;
        !           463: {
        !           464:        struct scsi_position_to_element cmd;
        !           465:        u_int16_t dst;
        !           466:
        !           467:        /*
        !           468:         * Check arguments.
        !           469:         */
        !           470:        if (cp->cp_type > CHET_DT)
        !           471:                return (EINVAL);
        !           472:        if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
        !           473:                return (ENODEV);
        !           474:
        !           475:        /*
        !           476:         * Calculate the destination element.
        !           477:         */
        !           478:        dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
        !           479:
        !           480:        /*
        !           481:         * Build the SCSI command.
        !           482:         */
        !           483:        bzero(&cmd, sizeof(cmd));
        !           484:        cmd.opcode = POSITION_TO_ELEMENT;
        !           485:        _lto2b(sc->sc_picker, cmd.tea);
        !           486:        _lto2b(dst, cmd.dst);
        !           487:        if (cp->cp_flags & CP_INVERT)
        !           488:                cmd.flags |= POSITION_TO_ELEMENT_INVERT;
        !           489:
        !           490:        /*
        !           491:         * Send command to changer.
        !           492:         */
        !           493:        return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
        !           494:            sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
        !           495: }
        !           496:
        !           497: /*
        !           498:  * Copy a volume tag to a volume_tag struct, converting SCSI byte order
        !           499:  * to host native byte order in the volume serial number.  The volume
        !           500:  * label as returned by the changer is transferred to user mode as
        !           501:  * nul-terminated string.  Volume labels are truncated at the first
        !           502:  * space, as suggested by SCSI-2.
        !           503:  */
        !           504: static  void
        !           505: copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
        !           506: {
        !           507:        int i;
        !           508:
        !           509:        for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
        !           510:                char c = voltag->vif[i];
        !           511:                if (c && c != ' ')
        !           512:                        uvoltag->cv_volid[i] = c;
        !           513:                else
        !           514:                        break;
        !           515:        }
        !           516:        uvoltag->cv_volid[i] = '\0';
        !           517:        uvoltag->cv_serial = _2btol(voltag->vsn);
        !           518: }
        !           519:
        !           520: /*
        !           521:  * Copy an an element status descriptor to a user-mode
        !           522:  * changer_element_status structure.
        !           523:  */
        !           524: static void
        !           525: copy_element_status(int flags, struct read_element_status_descriptor *desc,
        !           526:     struct changer_element_status *ces)
        !           527: {
        !           528:        ces->ces_flags = desc->flags1;
        !           529:
        !           530:        if (flags & READ_ELEMENT_STATUS_PVOLTAG)
        !           531:                copy_voltag(&ces->ces_pvoltag, &desc->pvoltag);
        !           532:        if (flags & READ_ELEMENT_STATUS_AVOLTAG)
        !           533:                copy_voltag(&ces->ces_avoltag, &desc->avoltag);
        !           534: }
        !           535:
        !           536: /*
        !           537:  * Perform a READ ELEMENT STATUS on behalf of the user, and return to
        !           538:  * the user only the data the user is interested in (i.e. an array of
        !           539:  * changer_element_status structures)
        !           540:  */
        !           541: int
        !           542: ch_usergetelemstatus(sc, cesr)
        !           543:        struct ch_softc *sc;
        !           544:        struct changer_element_status_request *cesr;
        !           545: {
        !           546:        struct changer_element_status *user_data = NULL;
        !           547:        struct read_element_status_header *st_hdr;
        !           548:        struct read_element_status_page_header *pg_hdr;
        !           549:        struct read_element_status_descriptor *desc;
        !           550:        caddr_t data = NULL;
        !           551:        size_t size, desclen, udsize;
        !           552:        int chet = cesr->cesr_type;
        !           553:        int avail, i, error = 0;
        !           554:        int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
        !           555:
        !           556:        /*
        !           557:         * If there are no elements of the requested type in the changer,
        !           558:         * the request is invalid.
        !           559:         */
        !           560:        if (sc->sc_counts[chet] == 0)
        !           561:                return (EINVAL);
        !           562:
        !           563:        /*
        !           564:         * Request one descriptor for the given element type.  This
        !           565:         * is used to determine the size of the descriptor so that
        !           566:         * we can allocate enough storage for all of them.  We assume
        !           567:         * that the first one can fit into 1k.
        !           568:         */
        !           569:        data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
        !           570:        error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024,
        !           571:            want_voltags);
        !           572:        if (error)
        !           573:                goto done;
        !           574:
        !           575:        st_hdr = (struct read_element_status_header *)data;
        !           576:        pg_hdr = (struct read_element_status_page_header *)((u_long)st_hdr +
        !           577:            sizeof(struct read_element_status_header));
        !           578:        desclen = _2btol(pg_hdr->edl);
        !           579:
        !           580:        size = sizeof(struct read_element_status_header) +
        !           581:            sizeof(struct read_element_status_page_header) +
        !           582:            (desclen * sc->sc_counts[chet]);
        !           583:
        !           584:        /*
        !           585:         * Reallocate storage for descriptors and get them from the
        !           586:         * device.
        !           587:         */
        !           588:        free(data, M_DEVBUF);
        !           589:        data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
        !           590:        error = ch_getelemstatus(sc, sc->sc_firsts[chet],
        !           591:            sc->sc_counts[chet], data, size, want_voltags);
        !           592:        if (error)
        !           593:                goto done;
        !           594:
        !           595:        /*
        !           596:         * Fill in the user status array.
        !           597:         */
        !           598:        st_hdr = (struct read_element_status_header *)data;
        !           599:        pg_hdr = (struct read_element_status_page_header *)((u_long)data +
        !           600:            sizeof(struct read_element_status_header));
        !           601:
        !           602:        avail = _2btol(st_hdr->count);
        !           603:        if (avail != sc->sc_counts[chet]) {
        !           604:                error = EINVAL;
        !           605:                goto done;
        !           606:        }
        !           607:        udsize = avail * sizeof(struct changer_element_status);
        !           608:
        !           609:        user_data = malloc(udsize, M_DEVBUF, M_WAITOK);
        !           610:        bzero(user_data, udsize);
        !           611:
        !           612:        desc = (struct read_element_status_descriptor *)((u_long)data +
        !           613:            sizeof(struct read_element_status_header) +
        !           614:            sizeof(struct read_element_status_page_header));
        !           615:        for (i = 0; i < avail; ++i) {
        !           616:                struct changer_element_status *ces = &(user_data[i]);
        !           617:                copy_element_status(pg_hdr->flags, desc, ces);
        !           618:                (u_long)desc += desclen;
        !           619:        }
        !           620:
        !           621:        /* Copy array out to userspace. */
        !           622:        error = copyout(user_data, cesr->cesr_data, udsize);
        !           623:
        !           624:  done:
        !           625:        if (data != NULL)
        !           626:                free(data, M_DEVBUF);
        !           627:        if (user_data != NULL)
        !           628:                free(user_data, M_DEVBUF);
        !           629:        return (error);
        !           630: }
        !           631:
        !           632: int
        !           633: ch_getelemstatus(sc, first, count, data, datalen, voltag)
        !           634:        struct ch_softc *sc;
        !           635:        int first;
        !           636:        int count;
        !           637:        caddr_t data;
        !           638:        size_t datalen;
        !           639:        int voltag;
        !           640: {
        !           641:        struct scsi_read_element_status cmd;
        !           642:
        !           643:        /*
        !           644:         * Build SCSI command.
        !           645:         */
        !           646:        bzero(&cmd, sizeof(cmd));
        !           647:        cmd.opcode = READ_ELEMENT_STATUS;
        !           648:        _lto2b(first, cmd.sea);
        !           649:        _lto2b(count, cmd.count);
        !           650:        _lto3b(datalen, cmd.len);
        !           651:        if (voltag)
        !           652:                cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG;
        !           653:
        !           654:        /*
        !           655:         * Send command to changer.
        !           656:         */
        !           657:        return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
        !           658:            sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN));
        !           659: }
        !           660:
        !           661:
        !           662: /*
        !           663:  * Ask the device about itself and fill in the parameters in our
        !           664:  * softc.
        !           665:  */
        !           666: int
        !           667: ch_get_params(sc, flags)
        !           668:        struct ch_softc *sc;
        !           669:        int flags;
        !           670: {
        !           671:        union scsi_mode_sense_buf *data;
        !           672:        struct page_element_address_assignment *ea;
        !           673:        struct page_device_capabilities *cap;
        !           674:        int error, from;
        !           675:        u_int8_t *moves, *exchanges;
        !           676:
        !           677:        data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
        !           678:        if (data == NULL)
        !           679:                return (ENOMEM);
        !           680:
        !           681:        /*
        !           682:         * Grab info from the element address assignment page (0x1d).
        !           683:         */
        !           684:        error = scsi_do_mode_sense(sc->sc_link, 0x1d, data,
        !           685:            (void **)&ea, NULL, NULL, NULL, sizeof(*ea), flags, NULL);
        !           686:        if (error == 0 && ea == NULL)
        !           687:                error = EIO;
        !           688:        if (error != 0) {
        !           689: #ifdef CHANGER_DEBUG
        !           690:                printf("%s: could not sense element address page\n",
        !           691:                    sc->sc_dev.dv_xname);
        !           692: #endif
        !           693:                free(data, M_TEMP);
        !           694:                return (error);
        !           695:        }
        !           696:
        !           697:        sc->sc_firsts[CHET_MT] = _2btol(ea->mtea);
        !           698:        sc->sc_counts[CHET_MT] = _2btol(ea->nmte);
        !           699:        sc->sc_firsts[CHET_ST] = _2btol(ea->fsea);
        !           700:        sc->sc_counts[CHET_ST] = _2btol(ea->nse);
        !           701:        sc->sc_firsts[CHET_IE] = _2btol(ea->fieea);
        !           702:        sc->sc_counts[CHET_IE] = _2btol(ea->niee);
        !           703:        sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea);
        !           704:        sc->sc_counts[CHET_DT] = _2btol(ea->ndte);
        !           705:
        !           706:        /* XXX Ask for transport geometry page. */
        !           707:
        !           708:        /*
        !           709:         * Grab info from the capabilities page (0x1f).
        !           710:         */
        !           711:        error = scsi_do_mode_sense(sc->sc_link, 0x1f, data,
        !           712:            (void **)&cap, NULL, NULL, NULL, sizeof(*cap), flags, NULL);
        !           713:        if (cap == NULL)
        !           714:                error = EIO;
        !           715:        if (error != 0) {
        !           716: #ifdef CHANGER_DEBUG
        !           717:                printf("%s: could not sense capabilities page\n",
        !           718:                    sc->sc_dev.dv_xname);
        !           719: #endif
        !           720:                free(data, M_TEMP);
        !           721:                return (error);
        !           722:        }
        !           723:
        !           724:        bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
        !           725:        bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
        !           726:        moves = &cap->move_from_mt;
        !           727:        exchanges = &cap->exchange_with_mt;
        !           728:        for (from = CHET_MT; from <= CHET_DT; ++from) {
        !           729:                sc->sc_movemask[from] = moves[from];
        !           730:                sc->sc_exchangemask[from] = exchanges[from];
        !           731:        }
        !           732:
        !           733:        sc->sc_link->flags |= SDEV_MEDIA_LOADED;
        !           734:        free(data, M_TEMP);
        !           735:        return (0);
        !           736: }
        !           737:
        !           738: void
        !           739: ch_get_quirks(sc, inqbuf)
        !           740:        struct ch_softc *sc;
        !           741:        struct scsi_inquiry_data *inqbuf;
        !           742: {
        !           743:        const struct chquirk *match;
        !           744:        int priority;
        !           745:
        !           746:        sc->sc_settledelay = 0;
        !           747:
        !           748:        match = (const struct chquirk *)scsi_inqmatch(inqbuf,
        !           749:            (caddr_t)chquirks,
        !           750:            sizeof(chquirks) / sizeof(chquirks[0]),
        !           751:            sizeof(chquirks[0]), &priority);
        !           752:        if (priority != 0) {
        !           753:                sc->sc_settledelay = match->cq_settledelay;
        !           754:        }
        !           755: }
        !           756:
        !           757: /*
        !           758:  * Look at the returned sense and act on the error and detirmine
        !           759:  * The unix error number to pass back... (0 = report no error)
        !           760:  *                            (-1 = continue processing)
        !           761:  */
        !           762: int
        !           763: ch_interpret_sense(xs)
        !           764:        struct scsi_xfer *xs;
        !           765: {
        !           766:        struct scsi_sense_data *sense = &xs->sense;
        !           767:        struct scsi_link *sc_link = xs->sc_link;
        !           768:        u_int8_t serr = sense->error_code & SSD_ERRCODE;
        !           769:        u_int8_t skey = sense->flags & SSD_KEY;
        !           770:
        !           771:        if (((sc_link->flags & SDEV_OPEN) == 0) ||
        !           772:            (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
        !           773:                return (EJUSTRETURN); /* let the generic code handle it */
        !           774:
        !           775:        switch (skey) {
        !           776:
        !           777:        /*
        !           778:         * We do custom processing in ch for the unit becoming ready case.
        !           779:         * in this case we do not allow xs->retries to be decremented
        !           780:         * only on the "Unit Becoming Ready" case. This is because tape
        !           781:         * changers report "Unit Becoming Ready" when they rescan their
        !           782:         * state (i.e. when the door got opened) and can take a long time
        !           783:         * for large units. Rather than having a massive timeout for
        !           784:         * all operations (which would cause other problems) we allow
        !           785:         * changers to wait (but be interruptable with Ctrl-C) forever
        !           786:         * as long as they are reporting that they are becoming ready.
        !           787:         * all other cases are handled as per the default.
        !           788:         */
        !           789:        case SKEY_NOT_READY:
        !           790:                if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
        !           791:                        return (0);
        !           792:                switch (ASC_ASCQ(sense)) {
        !           793:                case SENSE_NOT_READY_BECOMING_READY:
        !           794:                        SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n",
        !           795:                            sense->add_sense_code_qual));
        !           796:                        /* don't count this as a retry */
        !           797:                        xs->retries++;
        !           798:                        return (scsi_delay(xs, 1));
        !           799:                default:
        !           800:                        return (EJUSTRETURN);
        !           801:        }
        !           802:        default:
        !           803:                return (EJUSTRETURN);
        !           804:        }
        !           805: }

CVSweb