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