[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

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