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

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

1.1     ! nbrk        1: /*     $OpenBSD: scsiconf.c,v 1.125 2007/05/08 18:50:39 deraadt Exp $  */
        !             2: /*     $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil 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:  * Originally written by Julian Elischer (julian@tfs.com)
        !            35:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
        !            36:  *
        !            37:  * TRW Financial Systems, in accordance with their agreement with Carnegie
        !            38:  * Mellon University, makes this software available to CMU to distribute
        !            39:  * or use in any manner that they see fit as long as this message is kept with
        !            40:  * the software. For this reason TFS also grants any other persons or
        !            41:  * organisations permission to use or modify this software.
        !            42:  *
        !            43:  * TFS supplies this software to be publicly redistributed
        !            44:  * on the understanding that TFS is not responsible for the correct
        !            45:  * functioning of this software in any circumstances.
        !            46:  *
        !            47:  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
        !            48:  */
        !            49:
        !            50: #include "bio.h"
        !            51:
        !            52: #include <sys/types.h>
        !            53: #include <sys/param.h>
        !            54: #include <sys/systm.h>
        !            55: #include <sys/malloc.h>
        !            56: #include <sys/device.h>
        !            57:
        !            58: #include <scsi/scsi_all.h>
        !            59: #include <scsi/scsiconf.h>
        !            60:
        !            61: #if NBIO > 0
        !            62: #include <sys/ioctl.h>
        !            63: #include <sys/scsiio.h>
        !            64: #include <dev/biovar.h>
        !            65: #endif
        !            66:
        !            67: /*
        !            68:  * Declarations
        !            69:  */
        !            70: int    scsi_probedev(struct scsibus_softc *, int, int);
        !            71:
        !            72: struct scsi_device probe_switch = {
        !            73:        NULL,
        !            74:        NULL,
        !            75:        NULL,
        !            76:        NULL,
        !            77: };
        !            78:
        !            79: int    scsibusmatch(struct device *, void *, void *);
        !            80: void   scsibusattach(struct device *, struct device *, void *);
        !            81: int    scsibusactivate(struct device *, enum devact);
        !            82: int    scsibusdetach(struct device *, int);
        !            83:
        !            84: int    scsibussubmatch(struct device *, void *, void *);
        !            85:
        !            86: #if NBIO > 0
        !            87: int    scsibus_bioctl(struct device *, u_long, caddr_t);
        !            88: #endif
        !            89:
        !            90: struct cfattach scsibus_ca = {
        !            91:        sizeof(struct scsibus_softc), scsibusmatch, scsibusattach,
        !            92:        scsibusdetach, scsibusactivate
        !            93: };
        !            94:
        !            95: struct cfdriver scsibus_cd = {
        !            96:        NULL, "scsibus", DV_DULL
        !            97: };
        !            98:
        !            99: #ifdef SCSIDEBUG
        !           100: int scsidebug_buses = SCSIDEBUG_BUSES;
        !           101: int scsidebug_targets = SCSIDEBUG_TARGETS;
        !           102: int scsidebug_luns = SCSIDEBUG_LUNS;
        !           103: int scsidebug_level = SCSIDEBUG_LEVEL;
        !           104: #endif
        !           105:
        !           106: int scsi_autoconf = SCSI_AUTOCONF;
        !           107:
        !           108: int scsibusprint(void *, const char *);
        !           109:
        !           110: const u_int8_t version_to_spc [] = {
        !           111:        0, /* 0x00: The device does not claim conformance to any standard. */
        !           112:        1, /* 0x01: (Obsolete) SCSI-1 in olden times. */
        !           113:        2, /* 0x02: (Obsolete) SCSI-2 in olden times. */
        !           114:        3, /* 0x03: The device complies to ANSI INCITS 301-1997 (SPC-3). */
        !           115:        2, /* 0x04: The device complies to ANSI INCITS 351-2001 (SPC-2). */
        !           116:        3, /* 0x05: The device complies to ANSI INCITS 408-2005 (SPC-3). */
        !           117:        4, /* 0x06: The device complies to SPC-4. */
        !           118:        0, /* 0x07: RESERVED. */
        !           119: };
        !           120:
        !           121: int
        !           122: scsiprint(void *aux, const char *pnp)
        !           123: {
        !           124:        /* only "scsibus"es can attach to "scsi"s; easy. */
        !           125:        if (pnp)
        !           126:                printf("scsibus at %s", pnp);
        !           127:
        !           128:        return (UNCONF);
        !           129: }
        !           130:
        !           131: int
        !           132: scsibusmatch(struct device *parent, void *match, void *aux)
        !           133: {
        !           134:        return (1);
        !           135: }
        !           136:
        !           137: /*
        !           138:  * The routine called by the adapter boards to get all their
        !           139:  * devices configured in.
        !           140:  */
        !           141: void
        !           142: scsibusattach(struct device *parent, struct device *self, void *aux)
        !           143: {
        !           144:        struct scsibus_softc            *sb = (struct scsibus_softc *)self;
        !           145:        struct scsibus_attach_args      *saa = aux;
        !           146:        struct scsi_link                *sc_link_proto = saa->saa_sc_link;
        !           147:        int                             nbytes, i;
        !           148:
        !           149:        if (!cold)
        !           150:                scsi_autoconf = 0;
        !           151:
        !           152:        sc_link_proto->scsibus = sb->sc_dev.dv_unit;
        !           153:        sb->adapter_link = sc_link_proto;
        !           154:        if (sb->adapter_link->adapter_buswidth == 0)
        !           155:                sb->adapter_link->adapter_buswidth = 8;
        !           156:        sb->sc_buswidth = sb->adapter_link->adapter_buswidth;
        !           157:        if (sb->adapter_link->luns == 0)
        !           158:                sb->adapter_link->luns = 8;
        !           159:
        !           160:        printf(": %d targets\n", sb->sc_buswidth);
        !           161:
        !           162:        /* Initialize shared data. */
        !           163:        scsi_init();
        !           164:
        !           165:        nbytes = sb->sc_buswidth * sizeof(struct scsi_link **);
        !           166:        sb->sc_link = malloc(nbytes, M_DEVBUF, M_NOWAIT);
        !           167:        if (sb->sc_link == NULL)
        !           168:                panic("scsibusattach: can't allocate target links");
        !           169:        nbytes = sb->adapter_link->luns * sizeof(struct scsi_link *);
        !           170:        for (i = 0; i < sb->sc_buswidth; i++) {
        !           171:                sb->sc_link[i] = malloc(nbytes, M_DEVBUF, M_NOWAIT);
        !           172:                if (sb->sc_link[i] == NULL)
        !           173:                        panic("scsibusattach: can't allocate lun links");
        !           174:                bzero(sb->sc_link[i], nbytes);
        !           175:        }
        !           176:
        !           177: #if NBIO > 0
        !           178:        if (bio_register(&sb->sc_dev, scsibus_bioctl) != 0)
        !           179:                printf("%s: unable to register bio\n", sb->sc_dev.dv_xname);
        !           180: #endif
        !           181:
        !           182:        scsi_probe_bus(sb);
        !           183: }
        !           184:
        !           185: int
        !           186: scsibusactivate(struct device *dev, enum devact act)
        !           187: {
        !           188:        return (config_activate_children(dev, act));
        !           189: }
        !           190:
        !           191: int
        !           192: scsibusdetach(struct device *dev, int type)
        !           193: {
        !           194:        struct scsibus_softc            *sb = (struct scsibus_softc *)dev;
        !           195:        int                             i, j, error;
        !           196:
        !           197: #if NBIO > 0
        !           198:        bio_unregister(&sb->sc_dev);
        !           199: #endif
        !           200:
        !           201:        if ((error = config_detach_children(dev, type)) != 0)
        !           202:                return (error);
        !           203:
        !           204:        for (i = 0; i < sb->sc_buswidth; i++) {
        !           205:                if (sb->sc_link[i] != NULL) {
        !           206:                        for (j = 0; j < sb->adapter_link->luns; j++) {
        !           207:                                if (sb->sc_link[i][j] != NULL)
        !           208:                                        free(sb->sc_link[i][j], M_DEVBUF);
        !           209:                        }
        !           210:                        free(sb->sc_link[i], M_DEVBUF);
        !           211:                }
        !           212:        }
        !           213:
        !           214:        free(sb->sc_link, M_DEVBUF);
        !           215:
        !           216:        /* Free shared data. */
        !           217:        scsi_deinit();
        !           218:
        !           219:        return (0);
        !           220: }
        !           221:
        !           222: int
        !           223: scsibussubmatch(struct device *parent, void *match, void *aux)
        !           224: {
        !           225:        struct cfdata                   *cf = match;
        !           226:        struct scsi_attach_args         *sa = aux;
        !           227:        struct scsi_link                *sc_link = sa->sa_sc_link;
        !           228:
        !           229:        if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sc_link->target)
        !           230:                return (0);
        !           231:        if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != sc_link->lun)
        !           232:                return (0);
        !           233:
        !           234:        return ((*cf->cf_attach->ca_match)(parent, match, aux));
        !           235: }
        !           236:
        !           237: #if NBIO > 0
        !           238: int
        !           239: scsibus_bioctl(struct device *dev, u_long cmd, caddr_t addr)
        !           240: {
        !           241:        struct scsibus_softc            *sc = (struct scsibus_softc *)dev;
        !           242:        struct sbioc_device             *sdev;
        !           243:
        !           244:        switch (cmd) {
        !           245:        case SBIOCPROBE:
        !           246:                sdev = (struct sbioc_device *)addr;
        !           247:
        !           248:                if (sdev->sd_target == -1 && sdev->sd_lun == -1)
        !           249:                        return (scsi_probe_bus(sc));
        !           250:
        !           251:                /* specific lun and wildcard target is bad */
        !           252:                if (sdev->sd_target == -1)
        !           253:                        return (EINVAL);
        !           254:
        !           255:                if (sdev->sd_lun == -1)
        !           256:                        return (scsi_probe_target(sc, sdev->sd_target));
        !           257:
        !           258:                return (scsi_probe_lun(sc, sdev->sd_target, sdev->sd_lun));
        !           259:
        !           260:        case SBIOCDETACH:
        !           261:                sdev = (struct sbioc_device *)addr;
        !           262:
        !           263:                if (sdev->sd_target == -1)
        !           264:                        return (EINVAL);
        !           265:
        !           266:                if (sdev->sd_lun == -1)
        !           267:                        return (scsi_detach_target(sc, sdev->sd_target, 0));
        !           268:
        !           269:                return (scsi_detach_lun(sc, sdev->sd_target, sdev->sd_lun, 0));
        !           270:
        !           271:        default:
        !           272:                return (ENOTTY);
        !           273:        }
        !           274: }
        !           275: #endif
        !           276:
        !           277: int
        !           278: scsi_probe_bus(struct scsibus_softc *sc)
        !           279: {
        !           280:        struct scsi_link *alink = sc->adapter_link;
        !           281:        int i;
        !           282:
        !           283:        for (i = 0; i < alink->adapter_buswidth; i++)
        !           284:                scsi_probe_target(sc, i);
        !           285:
        !           286:        return (0);
        !           287: }
        !           288:
        !           289: int
        !           290: scsi_probe_target(struct scsibus_softc *sc, int target)
        !           291: {
        !           292:        struct scsi_link *alink = sc->adapter_link;
        !           293:        struct scsi_link *link;
        !           294:        struct scsi_report_luns_data *report;
        !           295:        int i, nluns, lun;
        !           296:
        !           297:        if (scsi_probe_lun(sc, target, 0) == EINVAL)
        !           298:                return (EINVAL);
        !           299:
        !           300:        link = sc->sc_link[target][0];
        !           301:        if (link == NULL)
        !           302:                return (ENXIO);
        !           303:
        !           304:        if ((link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 &&
        !           305:            SCSISPC(link->inqdata.version) > 2) {
        !           306:                report = malloc(sizeof(*report), M_TEMP, M_WAITOK);
        !           307:                if (report == NULL)
        !           308:                        goto dumbscan;
        !           309:
        !           310:                if (scsi_report_luns(link, REPORT_NORMAL, report,
        !           311:                    sizeof(*report), scsi_autoconf | SCSI_SILENT |
        !           312:                    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY |
        !           313:                    SCSI_IGNORE_MEDIA_CHANGE, 10000) != 0) {
        !           314:                        free(report, M_TEMP);
        !           315:                        goto dumbscan;
        !           316:                }
        !           317:
        !           318:                /*
        !           319:                 * XXX In theory we should check if data is full, which
        !           320:                 * would indicate it needs to be enlarged and REPORT
        !           321:                 * LUNS tried again. Solaris tries up to 3 times with
        !           322:                 * larger sizes for data.
        !           323:                 */
        !           324:                nluns = _4btol(report->length) / RPL_LUNDATA_SIZE;
        !           325:                for (i = 0; i < nluns; i++) {
        !           326:                        if (report->luns[i].lundata[0] != 0)
        !           327:                                continue;
        !           328:                        lun = report->luns[i].lundata[RPL_LUNDATA_T0LUN];
        !           329:                        if (lun == 0)
        !           330:                                continue;
        !           331:
        !           332:                        /* Probe the provided LUN. Don't check LUN 0. */
        !           333:                        sc->sc_link[target][0] = NULL;
        !           334:                        scsi_probe_lun(sc, target, lun);
        !           335:                        sc->sc_link[target][0] = link;
        !           336:                }
        !           337:
        !           338:                free(report, M_TEMP);
        !           339:                return (0);
        !           340:        }
        !           341:
        !           342: dumbscan:
        !           343:        for (i = 1; i < alink->luns; i++) {
        !           344:                if (scsi_probe_lun(sc, target, i) == EINVAL)
        !           345:                        break;
        !           346:        }
        !           347:
        !           348:        return (0);
        !           349: }
        !           350:
        !           351: int
        !           352: scsi_probe_lun(struct scsibus_softc *sc, int target, int lun)
        !           353: {
        !           354:        struct scsi_link *alink = sc->adapter_link;
        !           355:
        !           356:        if (target < 0 || target >= alink->adapter_buswidth ||
        !           357:            target == alink->adapter_target ||
        !           358:            lun < 0 || lun >= alink->luns)
        !           359:                return (ENXIO);
        !           360:
        !           361:        return (scsi_probedev(sc, target, lun));
        !           362: }
        !           363:
        !           364: int
        !           365: scsi_detach_bus(struct scsibus_softc *sc, int flags)
        !           366: {
        !           367:        struct scsi_link *alink = sc->adapter_link;
        !           368:        int i;
        !           369:
        !           370:        for (i = 0; i < alink->adapter_buswidth; i++)
        !           371:                scsi_detach_target(sc, i, flags);
        !           372:
        !           373:        return (0);
        !           374: }
        !           375:
        !           376: int
        !           377: scsi_detach_target(struct scsibus_softc *sc, int target, int flags)
        !           378: {
        !           379:        struct scsi_link *alink = sc->adapter_link;
        !           380:        int i, err, rv = 0, detached = 0;
        !           381:
        !           382:        if (target < 0 || target >= alink->adapter_buswidth ||
        !           383:            target == alink->adapter_target)
        !           384:                return (ENXIO);
        !           385:
        !           386:        if (sc->sc_link[target] == NULL)
        !           387:                return (ENXIO);
        !           388:
        !           389:        for (i = 0; i < alink->luns; i++) { /* nicer backwards? */
        !           390:                if (sc->sc_link[target][i] == NULL)
        !           391:                        continue;
        !           392:
        !           393:                err = scsi_detach_lun(sc, target, i, flags);
        !           394:                if (err != 0)
        !           395:                        rv = err;
        !           396:                detached = 1;
        !           397:        }
        !           398:
        !           399:        return (detached ? rv : ENXIO);
        !           400: }
        !           401:
        !           402: int
        !           403: scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags)
        !           404: {
        !           405:        struct scsi_link *alink = sc->adapter_link;
        !           406:        struct scsi_link *link;
        !           407:        int rv;
        !           408:
        !           409:        if (target < 0 || target >= alink->adapter_buswidth ||
        !           410:            target == alink->adapter_target ||
        !           411:            lun < 0 || lun >= alink->luns)
        !           412:                return (ENXIO);
        !           413:
        !           414:        if (sc->sc_link[target] == NULL)
        !           415:                return (ENXIO);
        !           416:
        !           417:        link = sc->sc_link[target][lun];
        !           418:        if (link == NULL)
        !           419:                return (ENXIO);
        !           420:
        !           421:        if (((flags & DETACH_FORCE) == 0) && (link->flags & SDEV_OPEN))
        !           422:                return (EBUSY);
        !           423:
        !           424:        /* detaching a device from scsibus is a two step process... */
        !           425:
        !           426:        /* 1. detach the device */
        !           427:        rv = config_detach(link->device_softc, flags);
        !           428:        if (rv != 0)
        !           429:                return (rv);
        !           430:
        !           431:        /* 2. free up its state in the midlayer */
        !           432:        free(link, M_DEVBUF);
        !           433:        sc->sc_link[target][lun] = NULL;
        !           434:
        !           435:        return (0);
        !           436: }
        !           437:
        !           438: void
        !           439: scsi_strvis(u_char *dst, u_char *src, int len)
        !           440: {
        !           441:        u_char                          last;
        !           442:
        !           443:        /* Trim leading and trailing whitespace and NULs. */
        !           444:        while (len > 0 && (src[0] == ' ' || src[0] == '\t' || src[0] == '\n' ||
        !           445:            src[0] == '\0' || src[0] == 0xff))
        !           446:                ++src, --len;
        !           447:        while (len > 0 && (src[len-1] == ' ' || src[len-1] == '\t' ||
        !           448:            src[len-1] == '\n' || src[len-1] == '\0' || src[len-1] == 0xff))
        !           449:                --len;
        !           450:
        !           451:        last = 0xff;
        !           452:        while (len > 0) {
        !           453:                switch (*src) {
        !           454:                case ' ':
        !           455:                case '\t':
        !           456:                case '\n':
        !           457:                case '\0':
        !           458:                case 0xff:
        !           459:                        /* collapse whitespace and NULs to a single space */
        !           460:                        if (last != ' ')
        !           461:                                *dst++ = ' ';
        !           462:                        last = ' ';
        !           463:                        break;
        !           464:                case '\\':
        !           465:                        /* quote characters */
        !           466:                        *dst++ = '\\';
        !           467:                        *dst++ = '\\';
        !           468:                        last = '\\';
        !           469:                        break;
        !           470:                default:
        !           471:                        if (*src < 0x20 || *src >= 0x80) {
        !           472:                                /* non-printable characters */
        !           473:                                *dst++ = '\\';
        !           474:                                *dst++ = ((*src & 0300) >> 6) + '0';
        !           475:                                *dst++ = ((*src & 0070) >> 3) + '0';
        !           476:                                *dst++ = ((*src & 0007) >> 0) + '0';
        !           477:                        } else {
        !           478:                                /* normal characters */
        !           479:                                *dst++ = *src;
        !           480:                        }
        !           481:                        last = *src;
        !           482:                        break;
        !           483:                }
        !           484:                ++src, --len;
        !           485:        }
        !           486:
        !           487:        *dst++ = 0;
        !           488: }
        !           489:
        !           490: struct scsi_quirk_inquiry_pattern {
        !           491:        struct scsi_inquiry_pattern     pattern;
        !           492:        u_int16_t                       quirks;
        !           493: };
        !           494:
        !           495: const struct scsi_quirk_inquiry_pattern scsi_quirk_patterns[] = {
        !           496:        {{T_CDROM, T_REMOV,
        !           497:         "PLEXTOR", "CD-ROM PX-40TS", "1.01"},    SDEV_NOSYNC},
        !           498:
        !           499:        {{T_DIRECT, T_FIXED,
        !           500:         "MICROP  ", "1588-15MBSUN0669", ""},     SDEV_AUTOSAVE},
        !           501:        {{T_DIRECT, T_FIXED,
        !           502:         "DEC     ", "RZ55     (C) DEC", ""},     SDEV_AUTOSAVE},
        !           503:        {{T_DIRECT, T_FIXED,
        !           504:         "EMULEX  ", "MD21/S2     ESDI", "A00"},  SDEV_AUTOSAVE},
        !           505:        {{T_DIRECT, T_FIXED,
        !           506:         "IBMRAID ", "0662S",            ""},     SDEV_AUTOSAVE},
        !           507:        {{T_DIRECT, T_FIXED,
        !           508:         "IBM     ", "0663H",            ""},     SDEV_AUTOSAVE},
        !           509:        {{T_DIRECT, T_FIXED,
        !           510:         "IBM",   "0664",                ""},     SDEV_AUTOSAVE},
        !           511:        {{T_DIRECT, T_FIXED,
        !           512:         "IBM     ", "H3171-S2",         ""},     SDEV_AUTOSAVE},
        !           513:        {{T_DIRECT, T_FIXED,
        !           514:         "IBM     ", "KZ-C",             ""},     SDEV_AUTOSAVE},
        !           515:        /* Broken IBM disk */
        !           516:        {{T_DIRECT, T_FIXED,
        !           517:         ""        , "DFRSS2F",          ""},     SDEV_AUTOSAVE},
        !           518:        {{T_DIRECT, T_FIXED,
        !           519:         "QUANTUM ", "ELS85S          ", ""},     SDEV_AUTOSAVE},
        !           520:        {{T_DIRECT, T_REMOV,
        !           521:         "iomega", "jaz 1GB",            ""},     SDEV_NOTAGS},
        !           522:         {{T_DIRECT, T_FIXED,
        !           523:          "MICROP", "4421-07",           ""},     SDEV_NOTAGS},
        !           524:         {{T_DIRECT, T_FIXED,
        !           525:          "SEAGATE", "ST150176LW",        "0002"}, SDEV_NOTAGS},
        !           526:         {{T_DIRECT, T_FIXED,
        !           527:          "HP", "C3725S",                ""},     SDEV_NOTAGS},
        !           528:         {{T_DIRECT, T_FIXED,
        !           529:          "IBM", "DCAS",                         ""},     SDEV_NOTAGS},
        !           530:
        !           531:        {{T_SEQUENTIAL, T_REMOV,
        !           532:         "SONY    ", "SDT-5000        ", "3."},   SDEV_NOSYNC|SDEV_NOWIDE},
        !           533:        {{T_SEQUENTIAL, T_REMOV,
        !           534:         "WangDAT ", "Model 1300      ", "02.4"}, SDEV_NOSYNC|SDEV_NOWIDE},
        !           535:        {{T_SEQUENTIAL, T_REMOV,
        !           536:         "WangDAT ", "Model 2600      ", "01.7"}, SDEV_NOSYNC|SDEV_NOWIDE},
        !           537:        {{T_SEQUENTIAL, T_REMOV,
        !           538:         "WangDAT ", "Model 3200      ", "02.2"}, SDEV_NOSYNC|SDEV_NOWIDE},
        !           539:
        !           540:        /* ATAPI device quirks */
        !           541:         {{T_CDROM, T_REMOV,
        !           542:          "ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"}, ADEV_NOTUR},
        !           543:         {{T_CDROM, T_REMOV,
        !           544:          "CR-2801TE", "", "1.07"},              ADEV_NOSENSE},
        !           545:         {{T_CDROM, T_REMOV,
        !           546:          "CREATIVECD3630E", "", "AC101"},       ADEV_NOSENSE},
        !           547:         {{T_CDROM, T_REMOV,
        !           548:          "FX320S", "", "q01"},                  ADEV_NOSENSE},
        !           549:         {{T_CDROM, T_REMOV,
        !           550:          "GCD-R580B", "", "1.00"},              ADEV_LITTLETOC},
        !           551:         {{T_CDROM, T_REMOV,
        !           552:          "MATSHITA CR-574", "", "1.02"},        ADEV_NOCAPACITY},
        !           553:         {{T_CDROM, T_REMOV,
        !           554:          "MATSHITA CR-574", "", "1.06"},        ADEV_NOCAPACITY},
        !           555:         {{T_CDROM, T_REMOV,
        !           556:          "Memorex CRW-2642", "", "1.0g"},       ADEV_NOSENSE},
        !           557:         {{T_CDROM, T_REMOV,
        !           558:          "NEC                 CD-ROM DRIVE:273", "", "4.21"}, ADEV_NOTUR},
        !           559:         {{T_CDROM, T_REMOV,
        !           560:          "SANYO CRD-256P", "", "1.02"},         ADEV_NOCAPACITY},
        !           561:         {{T_CDROM, T_REMOV,
        !           562:          "SANYO CRD-254P", "", "1.02"},         ADEV_NOCAPACITY},
        !           563:         {{T_CDROM, T_REMOV,
        !           564:          "SANYO CRD-S54P", "", "1.08"},         ADEV_NOCAPACITY},
        !           565:         {{T_CDROM, T_REMOV,
        !           566:          "CD-ROM  CDR-S1", "", "1.70"},         ADEV_NOCAPACITY}, /* Sanyo */
        !           567:         {{T_CDROM, T_REMOV,
        !           568:          "CD-ROM  CDR-N16", "", "1.25"},        ADEV_NOCAPACITY}, /* Sanyo */
        !           569:         {{T_CDROM, T_REMOV,
        !           570:          "UJDCD8730", "", "1.14"},              ADEV_NODOORLOCK}, /* Acer */
        !           571: };
        !           572:
        !           573:
        !           574: /*
        !           575:  * Print out autoconfiguration information for a subdevice.
        !           576:  *
        !           577:  * This is a slight abuse of 'standard' autoconfiguration semantics,
        !           578:  * because 'print' functions don't normally print the colon and
        !           579:  * device information.  However, in this case that's better than
        !           580:  * either printing redundant information before the attach message,
        !           581:  * or having the device driver call a special function to print out
        !           582:  * the standard device information.
        !           583:  */
        !           584: int
        !           585: scsibusprint(void *aux, const char *pnp)
        !           586: {
        !           587:        struct scsi_attach_args         *sa = aux;
        !           588:        struct scsi_inquiry_data        *inqbuf;
        !           589:        u_int8_t                        type;
        !           590:        int                             removable;
        !           591:        char                            *dtype, *qtype;
        !           592:        char                            vendor[33], product[65], revision[17];
        !           593:        int                             target, lun;
        !           594:
        !           595:        if (pnp != NULL)
        !           596:                printf("%s", pnp);
        !           597:
        !           598:        inqbuf = sa->sa_inqbuf;
        !           599:
        !           600:        target = sa->sa_sc_link->target;
        !           601:        lun = sa->sa_sc_link->lun;
        !           602:
        !           603:        type = inqbuf->device & SID_TYPE;
        !           604:        removable = inqbuf->dev_qual2 & SID_REMOVABLE ? 1 : 0;
        !           605:
        !           606:        /*
        !           607:         * Figure out basic device type and qualifier.
        !           608:         */
        !           609:        dtype = 0;
        !           610:        switch (inqbuf->device & SID_QUAL) {
        !           611:        case SID_QUAL_LU_OK:
        !           612:                qtype = "";
        !           613:                break;
        !           614:
        !           615:        case SID_QUAL_LU_OFFLINE:
        !           616:                qtype = " offline";
        !           617:                break;
        !           618:
        !           619:        case SID_QUAL_RSVD:
        !           620:                panic("scsibusprint: qualifier == SID_QUAL_RSVD");
        !           621:
        !           622:        case SID_QUAL_BAD_LU:
        !           623:                panic("scsibusprint: qualifier == SID_QUAL_BAD_LU");
        !           624:
        !           625:        default:
        !           626:                qtype = "";
        !           627:                dtype = "vendor-unique";
        !           628:                break;
        !           629:        }
        !           630:        if (dtype == 0) {
        !           631:                switch (type) {
        !           632:                case T_DIRECT:
        !           633:                        dtype = "direct";
        !           634:                        break;
        !           635:                case T_SEQUENTIAL:
        !           636:                        dtype = "sequential";
        !           637:                        break;
        !           638:                case T_PRINTER:
        !           639:                        dtype = "printer";
        !           640:                        break;
        !           641:                case T_PROCESSOR:
        !           642:                        dtype = "processor";
        !           643:                        break;
        !           644:                case T_CDROM:
        !           645:                        dtype = "cdrom";
        !           646:                        break;
        !           647:                case T_WORM:
        !           648:                        dtype = "worm";
        !           649:                        break;
        !           650:                case T_SCANNER:
        !           651:                        dtype = "scanner";
        !           652:                        break;
        !           653:                case T_OPTICAL:
        !           654:                        dtype = "optical";
        !           655:                        break;
        !           656:                case T_CHANGER:
        !           657:                        dtype = "changer";
        !           658:                        break;
        !           659:                case T_COMM:
        !           660:                        dtype = "communication";
        !           661:                        break;
        !           662:                case T_ENCLOSURE:
        !           663:                        dtype = "enclosure services";
        !           664:                        break;
        !           665:                case T_RDIRECT:
        !           666:                        dtype = "simplified direct";
        !           667:                        break;
        !           668:                case T_NODEVICE:
        !           669:                        panic("scsibusprint: device type T_NODEVICE");
        !           670:                default:
        !           671:                        dtype = "unknown";
        !           672:                        break;
        !           673:                }
        !           674:        }
        !           675:
        !           676:        scsi_strvis(vendor, inqbuf->vendor, 8);
        !           677:        scsi_strvis(product, inqbuf->product, 16);
        !           678:        scsi_strvis(revision, inqbuf->revision, 4);
        !           679:
        !           680:        printf(" targ %d lun %d: <%s, %s, %s> SCSI%d %d/%s %s%s",
        !           681:            target, lun, vendor, product, revision,
        !           682:            SCSISPC(inqbuf->version), type, dtype,
        !           683:            removable ? "removable" : "fixed", qtype);
        !           684:
        !           685:        return (UNCONF);
        !           686: }
        !           687:
        !           688: /*
        !           689:  * Given a target and lun, ask the device what it is, and find the correct
        !           690:  * driver table entry.
        !           691:  *
        !           692:  * Return 0 if further LUNs are possible, EINVAL if not.
        !           693:  */
        !           694: int
        !           695: scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
        !           696: {
        !           697:        const struct scsi_quirk_inquiry_pattern *finger;
        !           698:        static struct scsi_inquiry_data inqbuf;
        !           699:        struct scsi_attach_args sa;
        !           700:        struct scsi_link *sc_link;
        !           701:        struct cfdata *cf;
        !           702:        int priority, rslt = 0;
        !           703:
        !           704:        /* Skip this slot if it is already attached and try the next LUN. */
        !           705:        if (scsi->sc_link[target][lun] != NULL)
        !           706:                return (0);
        !           707:
        !           708:        sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT);
        !           709:        if (sc_link == NULL)
        !           710:                return (EINVAL);
        !           711:
        !           712:        *sc_link = *scsi->adapter_link;
        !           713:        sc_link->target = target;
        !           714:        sc_link->lun = lun;
        !           715:        sc_link->device = &probe_switch;
        !           716:
        !           717:        SC_DEBUG(sc_link, SDEV_DB2, ("scsi_link created.\n"));
        !           718:
        !           719:        /*
        !           720:         * Tell drivers that are paying attention to avoid sync/wide/tags until
        !           721:         * INQUIRY data has been processed and the quirks information is
        !           722:         * complete. Some drivers set bits in quirks before we get here, so
        !           723:         * just add NOTAGS, NOWIDE and NOSYNC.
        !           724:         */
        !           725:        sc_link->quirks |= SDEV_NOSYNC | SDEV_NOWIDE | SDEV_NOTAGS;
        !           726:
        !           727:        /*
        !           728:         * Ask the device what it is
        !           729:         */
        !           730: #ifdef SCSIDEBUG
        !           731:        if (((1 << sc_link->scsibus) & scsidebug_buses) &&
        !           732:            ((1 << target) & scsidebug_targets) &&
        !           733:            ((1 << lun) & scsidebug_luns))
        !           734:                sc_link->flags |= scsidebug_level;
        !           735: #endif /* SCSIDEBUG */
        !           736:
        !           737: #if defined(mvme68k)
        !           738:        if (lun == 0) {
        !           739:                /* XXX some drivers depend on this */
        !           740:                scsi_test_unit_ready(sc_link, TEST_READY_RETRIES,
        !           741:                    scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST |
        !           742:                    SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
        !           743:        }
        !           744: #endif
        !           745:
        !           746:        /* Now go ask the device all about itself. */
        !           747:        rslt = scsi_inquire(sc_link, &inqbuf, scsi_autoconf | SCSI_SILENT);
        !           748:        if (rslt != 0) {
        !           749:                SC_DEBUG(sc_link, SDEV_DB2, ("Bad LUN. rslt = %i\n", rslt));
        !           750:                if (lun == 0)
        !           751:                        rslt = EINVAL;
        !           752:                goto bad;
        !           753:        }
        !           754:
        !           755:        switch (inqbuf.device & SID_QUAL) {
        !           756:        case SID_QUAL_RSVD:
        !           757:        case SID_QUAL_BAD_LU:
        !           758:        case SID_QUAL_LU_OFFLINE:
        !           759:                SC_DEBUG(sc_link, SDEV_DB1,
        !           760:                    ("Bad LUN. SID_QUAL = 0x%02x\n", inqbuf.device & SID_QUAL));
        !           761:                goto bad;
        !           762:
        !           763:        case SID_QUAL_LU_OK:
        !           764:                if ((inqbuf.device & SID_TYPE) == T_NODEVICE) {
        !           765:                        SC_DEBUG(sc_link, SDEV_DB1,
        !           766:                            ("Bad LUN. SID_TYPE = T_NODEVICE\n"));
        !           767:                        goto bad;
        !           768:                }
        !           769:                break;
        !           770:
        !           771:        default:
        !           772:                break;
        !           773:        }
        !           774:
        !           775:        if (lun == 0 || scsi->sc_link[target][0] == NULL)
        !           776:                ;
        !           777:        else if (sc_link->flags & SDEV_UMASS)
        !           778:                ;
        !           779:        else if (memcmp(&inqbuf, &scsi->sc_link[target][0]->inqdata,
        !           780:            sizeof inqbuf) == 0) {
        !           781:                /* The device doesn't distinguish between LUNs. */
        !           782:                SC_DEBUG(sc_link, SDEV_DB1, ("IDENTIFY not supported.\n"));
        !           783:                rslt = EINVAL;
        !           784:                goto bad;
        !           785:        }
        !           786:
        !           787:        finger = (const struct scsi_quirk_inquiry_pattern *)scsi_inqmatch(
        !           788:            &inqbuf, scsi_quirk_patterns,
        !           789:            sizeof(scsi_quirk_patterns)/sizeof(scsi_quirk_patterns[0]),
        !           790:            sizeof(scsi_quirk_patterns[0]), &priority);
        !           791:
        !           792:        /*
        !           793:         * Based upon the inquiry flags we got back, and if we're
        !           794:         * at SCSI-2 or better, remove some limiting quirks.
        !           795:         */
        !           796:        if (SCSISPC(inqbuf.version) >= 2) {
        !           797:                if ((inqbuf.flags & SID_CmdQue) != 0)
        !           798:                        sc_link->quirks &= ~SDEV_NOTAGS;
        !           799:                if ((inqbuf.flags & SID_Sync) != 0)
        !           800:                        sc_link->quirks &= ~SDEV_NOSYNC;
        !           801:                if ((inqbuf.flags & SID_WBus16) != 0)
        !           802:                        sc_link->quirks &= ~SDEV_NOWIDE;
        !           803:        }
        !           804:        /*
        !           805:         * Now apply any quirks from the table.
        !           806:         */
        !           807:        if (priority != 0)
        !           808:                sc_link->quirks |= finger->quirks;
        !           809:
        !           810:        /*
        !           811:         * Save INQUIRY.
        !           812:         */
        !           813:        memcpy(&sc_link->inqdata, &inqbuf, sizeof(sc_link->inqdata));
        !           814:
        !           815:        /*
        !           816:         * note what BASIC type of device it is
        !           817:         */
        !           818:        if ((inqbuf.dev_qual2 & SID_REMOVABLE) != 0)
        !           819:                sc_link->flags |= SDEV_REMOVABLE;
        !           820:
        !           821:        sa.sa_sc_link = sc_link;
        !           822:        sa.sa_inqbuf = &sc_link->inqdata;
        !           823:
        !           824:        if ((cf = config_search(scsibussubmatch, (struct device *)scsi,
        !           825:            &sa)) == 0) {
        !           826:                scsibusprint(&sa, scsi->sc_dev.dv_xname);
        !           827:                printf(" not configured\n");
        !           828:                goto bad;
        !           829:        }
        !           830:
        !           831:        /*
        !           832:         * Braindead USB devices, especially some x-in-1 media readers, try to
        !           833:         * 'help' by pretending any LUN is actually LUN 0 until they see a
        !           834:         * different LUN used in a command. So do an INQUIRY on LUN 1 at this
        !           835:         * point (since we are done with the data in inqbuf) to prevent such
        !           836:         * helpfulness before it causes confusion.
        !           837:         */
        !           838:        if (lun == 0 && (sc_link->flags & SDEV_UMASS) &&
        !           839:            scsi->sc_link[target][1] == NULL && sc_link->luns > 1) {
        !           840:                sc_link->lun = 1;
        !           841:                scsi_inquire(sc_link, &inqbuf, scsi_autoconf | SCSI_SILENT);
        !           842:                sc_link->lun = 0;
        !           843:        }
        !           844:
        !           845:        scsi->sc_link[target][lun] = sc_link;
        !           846:
        !           847:        /*
        !           848:         * Generate a TEST_UNIT_READY command. This gives drivers waiting for
        !           849:         * valid quirks data a chance to set wide/sync/tag options
        !           850:         * appropriately. It also clears any outstanding ACA conditions that
        !           851:         * INQUIRY may leave behind.
        !           852:         *
        !           853:         * Do this now so that any messages generated by config_attach() do not
        !           854:         * have negotiation messages inserted into their midst.
        !           855:         */
        !           856:        scsi_test_unit_ready(sc_link, TEST_READY_RETRIES,
        !           857:            scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST |
        !           858:            SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
        !           859:
        !           860:        config_attach((struct device *)scsi, cf, &sa, scsibusprint);
        !           861:
        !           862:        return (0);
        !           863:
        !           864: bad:
        !           865:        free(sc_link, M_DEVBUF);
        !           866:        return (rslt);
        !           867: }
        !           868:
        !           869: /*
        !           870:  * Return a priority based on how much of the inquiry data matches
        !           871:  * the patterns for the particular driver.
        !           872:  */
        !           873: const void *
        !           874: scsi_inqmatch(struct scsi_inquiry_data *inqbuf, const void *_base,
        !           875:     int nmatches, int matchsize, int *bestpriority)
        !           876: {
        !           877:        u_int8_t                        type;
        !           878:        int                             removable;
        !           879:        const void                      *bestmatch;
        !           880:        const unsigned char             *base = (const unsigned char *)_base;
        !           881:
        !           882:        /* Include the qualifier to catch vendor-unique types. */
        !           883:        type = inqbuf->device;
        !           884:        removable = inqbuf->dev_qual2 & SID_REMOVABLE ? T_REMOV : T_FIXED;
        !           885:
        !           886:        for (*bestpriority = 0, bestmatch = 0; nmatches--; base += matchsize) {
        !           887:                struct scsi_inquiry_pattern *match = (void *)base;
        !           888:                int priority, len;
        !           889:
        !           890:                if (type != match->type)
        !           891:                        continue;
        !           892:                if (removable != match->removable)
        !           893:                        continue;
        !           894:                priority = 2;
        !           895:                len = strlen(match->vendor);
        !           896:                if (bcmp(inqbuf->vendor, match->vendor, len))
        !           897:                        continue;
        !           898:                priority += len;
        !           899:                len = strlen(match->product);
        !           900:                if (bcmp(inqbuf->product, match->product, len))
        !           901:                        continue;
        !           902:                priority += len;
        !           903:                len = strlen(match->revision);
        !           904:                if (bcmp(inqbuf->revision, match->revision, len))
        !           905:                        continue;
        !           906:                priority += len;
        !           907:
        !           908: #if SCSIDEBUG
        !           909:                printf("scsi_inqmatch: %d/%d/%d <%s, %s, %s>\n",
        !           910:                    priority, match->type, match->removable,
        !           911:                    match->vendor, match->product, match->revision);
        !           912: #endif
        !           913:                if (priority > *bestpriority) {
        !           914:                        *bestpriority = priority;
        !           915:                        bestmatch = base;
        !           916:                }
        !           917:        }
        !           918:
        !           919:        return (bestmatch);
        !           920: }

CVSweb