Annotation of sys/scsi/scsiconf.c, Revision 1.1.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