xref: /openbsd-src/sys/scsi/scsiconf.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: scsiconf.c,v 1.58 2001/06/24 21:29:04 mickey 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 <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/malloc.h>
54 #include <sys/device.h>
55 
56 #include <scsi/scsi_all.h>
57 #include <scsi/scsiconf.h>
58 
59 #if 0
60 #if NCALS > 0
61 	{ T_PROCESSOR, T_FIXED, 1,
62 	  0, 0, 0 },
63 #endif	/* NCALS */
64 #if NBLL > 0
65 	{ T_PROCESSOR, T_FIXED, 1,
66 	  "AEG     ", "READER          ", "V1.0" },
67 #endif	/* NBLL */
68 #if NKIL > 0
69 	{ T_SCANNER, T_FIXED, 0,
70 	  "KODAK   ", "IL Scanner 900  ", 0 },
71 #endif	/* NKIL */
72 #endif
73 
74 /*
75  * Declarations
76  */
77 void scsi_probedev __P((struct scsibus_softc *, int, int));
78 int scsi_probe_bus __P((int bus, int target, int lun));
79 
80 struct scsi_device probe_switch = {
81 	NULL,
82 	NULL,
83 	NULL,
84 	NULL,
85 };
86 
87 int scsibusmatch __P((struct device *, void *, void *));
88 void scsibusattach __P((struct device *, struct device *, void *));
89 int  scsibusactivate __P((struct device *, enum devact));
90 int  scsibusdetach __P((struct device *, int));
91 void scsibuszeroref __P((struct device *));
92 
93 int scsibussubmatch __P((struct device *, void *, void *));
94 
95 
96 
97 struct cfattach scsibus_ca = {
98 	sizeof(struct scsibus_softc), scsibusmatch, scsibusattach,
99 	scsibusdetach, scsibusactivate, scsibuszeroref
100 };
101 
102 struct cfdriver scsibus_cd = {
103 	NULL, "scsibus", DV_DULL
104 };
105 
106 int scsidebug_targets = SCSIDEBUG_TARGETS;
107 int scsidebug_luns = SCSIDEBUG_LUNS;
108 int scsidebug_level = SCSIDEBUG_LEVEL;
109 
110 int scsi_autoconf = SCSI_AUTOCONF;
111 
112 int scsibusprint __P((void *, const char *));
113 
114 int
115 scsiprint(aux, pnp)
116 	void *aux;
117 	const char *pnp;
118 {
119 #ifndef __OpenBSD__
120 	struct scsi_link *l = aux;
121 #endif
122 
123 	/* only "scsibus"es can attach to "scsi"s; easy. */
124 	if (pnp)
125 		printf("scsibus at %s", pnp);
126 
127 #ifndef __OpenBSD__
128 	/* don't print channel if the controller says there can be only one. */
129 	if (l->channel != SCSI_CHANNEL_ONLY_ONE)
130 		printf(" channel %d", l->channel);
131 #endif
132 	return (UNCONF);
133 }
134 
135 int
136 scsibusmatch(parent, match, aux)
137 	struct device *parent;
138 	void *match, *aux;
139 {
140 
141 	return 1;
142 }
143 
144 /*
145  * The routine called by the adapter boards to get all their
146  * devices configured in.
147  */
148 void
149 scsibusattach(parent, self, aux)
150 	struct device *parent, *self;
151 	void *aux;
152 {
153 	struct scsibus_softc *sb = (struct scsibus_softc *)self;
154 	struct scsi_link *sc_link_proto = aux;
155 	int nbytes, i;
156 
157 	if (!cold)
158 		scsi_autoconf = 0;
159 
160 	sc_link_proto->scsibus = sb->sc_dev.dv_unit;
161 	sb->adapter_link = sc_link_proto;
162 	if (sb->adapter_link->adapter_buswidth == 0)
163 		sb->adapter_link->adapter_buswidth = 8;
164 	sb->sc_buswidth = sb->adapter_link->adapter_buswidth;
165 	if (sb->adapter_link->luns == 0)
166 		sb->adapter_link->luns = 8;
167 
168 	printf(": %d targets\n", sb->sc_buswidth);
169 
170 	nbytes = sb->sc_buswidth * sizeof(struct scsi_link **);
171 	sb->sc_link = (struct scsi_link ***)malloc(nbytes, M_DEVBUF, M_NOWAIT);
172 	if (sb->sc_link == NULL)
173 		panic("scsibusattach: can't allocate target links");
174 	nbytes = 8 * sizeof(struct scsi_link *);
175 	for (i = 0; i < sb->sc_buswidth; i++) {
176 		sb->sc_link[i] = (struct scsi_link **)malloc(nbytes,
177 		    M_DEVBUF, M_NOWAIT);
178 		if (sb->sc_link[i] == NULL)
179 			panic("scsibusattach: can't allocate lun links");
180 		bzero(sb->sc_link[i], nbytes);
181 	}
182 
183 #if defined(SCSI_DELAY) && SCSI_DELAY > 2
184 	printf("%s: waiting for scsi devices to settle\n",
185 		sb->sc_dev.dv_xname);
186 #else	/* SCSI_DELAY > 2 */
187 #undef	SCSI_DELAY
188 #define SCSI_DELAY 2
189 #endif	/* SCSI_DELAY */
190 	delay(1000000 * SCSI_DELAY);
191 
192 	scsi_probe_bus(sb->sc_dev.dv_unit, -1, -1);
193 }
194 
195 
196 int
197 scsibusactivate(dev, act)
198 	struct device *dev;
199 	enum devact act;
200 {
201 	return (config_activate_children(dev, act));
202 }
203 
204 int
205 scsibusdetach (dev, type)
206 	struct device *dev;
207 	int type;
208 {
209 	return (config_detach_children(dev, type));
210 }
211 
212 void
213 scsibuszeroref(dev)
214 	struct device *dev;
215 {
216 	struct scsibus_softc *sb = (struct scsibus_softc *)dev;
217 	int i;
218 
219 	for (i = 0; i < sb->sc_buswidth; i++) {
220 		if (sb->sc_link[i] != NULL)
221 			free(sb->sc_link[i], M_DEVBUF);
222 	}
223 
224 	free(sb->sc_link, M_DEVBUF);
225 }
226 
227 
228 
229 int
230 scsibussubmatch(parent, match, aux)
231 	struct device *parent;
232 	void *match, *aux;
233 {
234 	struct cfdata *cf = match;
235 	struct scsibus_attach_args *sa = aux;
236 	struct scsi_link *sc_link = sa->sa_sc_link;
237 
238 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sc_link->target)
239 		return 0;
240 	if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != sc_link->lun)
241 		return 0;
242 	return ((*cf->cf_attach->ca_match)(parent, match, aux));
243 }
244 
245 /*
246  * Probe the requested scsi bus. It must be already set up.
247  * -1 requests all set up scsi busses.
248  * target and lun optionally narrow the search if not -1
249  */
250 int
251 scsi_probe_busses(bus, target, lun)
252 	int bus, target, lun;
253 {
254 
255 	if (bus == -1) {
256 		for (bus = 0; bus < scsibus_cd.cd_ndevs; bus++)
257 			if (scsibus_cd.cd_devs[bus])
258 				scsi_probe_bus(bus, target, lun);
259 		return 0;
260 	} else {
261 		return scsi_probe_bus(bus, target, lun);
262 	}
263 }
264 
265 /*
266  * Probe the requested scsi bus. It must be already set up.
267  * target and lun optionally narrow the search if not -1
268  */
269 int
270 scsi_probe_bus(bus, target, lun)
271 	int bus, target, lun;
272 {
273 	struct scsibus_softc *scsi;
274 	int maxtarget, mintarget, maxlun, minlun;
275 	u_int16_t scsi_addr;
276 
277 	if (bus < 0 || bus >= scsibus_cd.cd_ndevs)
278 		return ENXIO;
279 	scsi = scsibus_cd.cd_devs[bus];
280 	if (!scsi)
281 		return ENXIO;
282 
283 	scsi_addr = scsi->adapter_link->adapter_target;
284 
285 	if (target == -1) {
286 		maxtarget = scsi->adapter_link->adapter_buswidth - 1;
287 		mintarget = 0;
288 	} else {
289 		if (target < 0 ||
290 		    target >= scsi->adapter_link->adapter_buswidth)
291 			return EINVAL;
292 		maxtarget = mintarget = target;
293 	}
294 
295 	if (lun == -1) {
296 		maxlun = scsi->adapter_link->luns - 1;
297 		minlun = 0;
298 	} else {
299 		if (lun < 0 || lun > 7)
300 			return EINVAL;
301 		maxlun = minlun = lun;
302 	}
303 
304 	for (target = mintarget; target <= maxtarget; target++) {
305 		if (target == scsi_addr)
306 			continue;
307 		for (lun = minlun; lun <= maxlun; lun++) {
308 			/*
309 			 * See if there's a device present, and configure it.
310 			 */
311 			scsi_probedev(scsi, target, lun);
312 			if ((scsi->moreluns & (1 << target)) == 0)
313 				break;
314 			/* otherwise something says we should look further */
315 		}
316 	}
317 	return 0;
318 }
319 
320 void
321 scsi_strvis(dst, src, len)
322 	u_char *dst, *src;
323 	int len;
324 {
325 
326 	/* Trim leading and trailing blanks and NULs. */
327 	while (len > 0 && (src[0] == ' ' || src[0] == '\0' || src[0] == 0xff))
328 		++src, --len;
329 	while (len > 0 && (src[len-1] == ' ' || src[len-1] == '\0' ||
330 	    src[len-1] == 0xff))
331 		--len;
332 
333 	while (len > 0) {
334 		if (*src < 0x20 || *src >= 0x80) {
335 			/* non-printable characters */
336 			*dst++ = '\\';
337 			*dst++ = ((*src & 0300) >> 6) + '0';
338 			*dst++ = ((*src & 0070) >> 3) + '0';
339 			*dst++ = ((*src & 0007) >> 0) + '0';
340 		} else if (*src == '\\') {
341 			/* quote characters */
342 			*dst++ = '\\';
343 			*dst++ = '\\';
344 		} else {
345 			/* normal characters */
346 			*dst++ = *src;
347 		}
348 		++src, --len;
349 	}
350 
351 	*dst++ = 0;
352 }
353 
354 struct scsi_quirk_inquiry_pattern {
355 	struct scsi_inquiry_pattern pattern;
356 	u_int16_t quirks;
357 };
358 
359 struct scsi_quirk_inquiry_pattern scsi_quirk_patterns[] = {
360 	{{T_CDROM, T_REMOV,
361 	 "CHINON  ", "CD-ROM CDS-431  ", ""},     SDEV_NOLUNS},
362 	{{T_CDROM, T_REMOV,
363 	 "Chinon  ", "CD-ROM CDS-525  ", ""},     SDEV_NOLUNS},
364 	{{T_CDROM, T_REMOV,
365 	 "CHINON  ", "CD-ROM CDS-535  ", ""},     SDEV_NOLUNS},
366 	{{T_CDROM, T_REMOV,
367 	 "DEC     ", "RRD42   (C) DEC ", ""},     SDEV_NOLUNS},
368 	{{T_CDROM, T_REMOV,
369 	 "DENON   ", "DRD-25X         ", "V"},    SDEV_NOLUNS},
370 	{{T_CDROM, T_REMOV,
371 	 "HP      ", "C4324/C4325     ", ""},     SDEV_NOLUNS},
372 	{{T_CDROM, T_REMOV,
373 	 "IMS     ", "CDD521/10       ", "2.06"}, SDEV_NOLUNS},
374 	{{T_CDROM, T_REMOV,
375 	 "MATSHITA", "CD-ROM CR-5XX   ", "1.0b"}, SDEV_NOLUNS},
376 	{{T_CDROM, T_REMOV,
377 	 "MEDAVIS ", "RENO CD-ROMX2A  ", ""},	  SDEV_NOLUNS},
378 	{{T_CDROM, T_REMOV,
379 	 "MEDIAVIS", "CDR-H93MV       ", "1.3"}, SDEV_NOLUNS},
380 	{{T_CDROM, T_REMOV,
381 	 "NEC     ", "CD-ROM DRIVE:55 ", ""},     SDEV_NOLUNS},
382 	{{T_CDROM, T_REMOV,
383 	 "NEC     ", "CD-ROM DRIVE:83 ", ""},     SDEV_NOLUNS},
384 	{{T_CDROM, T_REMOV,
385 	 "NEC     ", "CD-ROM DRIVE:84 ", ""},     SDEV_NOLUNS},
386 	{{T_CDROM, T_REMOV,
387 	 "NEC     ", "CD-ROM DRIVE:210", "1.0"},  SDEV_NOLUNS},
388 	{{T_CDROM, T_REMOV,
389 	 "NEC     ", "CD-ROM DRIVE:501", ""},     SDEV_NOLUNS},
390 	{{T_CDROM, T_REMOV,
391 	 "NEC     ", "CD-ROM DRIVE:841", ""},     SDEV_NOLUNS},
392 	{{T_CDROM, T_REMOV,
393 	 "PIONEER ", "CD-ROM DR-124X  ", "1.01"}, SDEV_NOLUNS},
394 	{{T_CDROM, T_REMOV,
395 	 "SONY    ", "CD-ROM CDU-541  ", ""},     SDEV_NOLUNS},
396 	{{T_CDROM, T_REMOV,
397 	 "SONY    ", "CD-ROM CDU-55S  ", ""},     SDEV_NOLUNS},
398 	{{T_CDROM, T_REMOV,
399 	 "SONY    ", "CD-ROM CDU-561  ", ""},     SDEV_NOLUNS},
400 	{{T_CDROM, T_REMOV,
401 	 "SONY    ", "CD-ROM CDU-8003A", ""},     SDEV_NOLUNS},
402 	{{T_CDROM, T_REMOV,
403 	 "SONY    ", "CD-ROM CDU-8012 ", ""},     SDEV_NOLUNS},
404 	{{T_CDROM, T_REMOV,
405 	 "TEAC    ", "CD-ROM          ", "1.06"}, SDEV_NOLUNS},
406 	{{T_CDROM, T_REMOV,
407 	 "TEAC    ", "CD-ROM CD-56S   ", "1.0B"}, SDEV_NOLUNS},
408 	{{T_CDROM, T_REMOV,
409 	 "TEXEL   ", "CD-ROM          ", "1.06"}, SDEV_NOLUNS},
410 	{{T_CDROM, T_REMOV,
411 	 "TEXEL   ", "CD-ROM DM-XX24 K", "1.10"}, SDEV_NOLUNS},
412 	{{T_CDROM, T_REMOV,
413 	 "TOSHIBA ", "XM-4101TASUNSLCD", "1755"}, SDEV_NOLUNS},
414 	{{T_CDROM, T_REMOV,
415 	 "ShinaKen", "CD-ROM DM-3x1S", "1.04"},   SDEV_NOLUNS},
416 	{{T_CDROM, T_REMOV,
417 	 "JVC     ", "R2626           ", "1.55"}, SDEV_NOLUNS},
418 	{{T_CDROM, T_REMOV,
419 	 "CyberDrv", "", ""}, SDEV_NOLUNS},
420 	{{T_CDROM, T_REMOV,
421 	 "PLEXTOR", "CD-ROM PX-40TS", "1.01"}, SDEV_NOSYNC},
422 
423  	{{T_OPTICAL, T_REMOV,
424  	 "EPSON   ", "OMD-5010        ", "3.08"}, SDEV_NOLUNS},
425 	{{T_OPTICAL, T_REMOV,
426 	 "FUJITSU", "M2513A",            "0800"}, SDEV_NOMODESENSE},
427 	{{T_OPTICAL, T_REMOV,
428 	 "DELTIS  ", "MOS321          ", "3.30"}, SDEV_NOMODESENSE},
429 
430 	{{T_OPTICAL, T_REMOV,
431 	 "EPSON   ", "OMD-5010        ", "3.08"}, SDEV_NOLUNS},
432 	{{T_OPTICAL, T_REMOV,
433 	 "FUJITSU", "M2513A",            "0800"}, SDEV_NOMODESENSE},
434 	{{T_OPTICAL, T_REMOV,
435 	 "DELTIS  ", "MOS321          ", "3.30"}, SDEV_NOMODESENSE},
436 
437 	{{T_DIRECT, T_FIXED,
438 	 "MICROP  ", "1588-15MBSUN0669", ""},     SDEV_AUTOSAVE},
439 	{{T_DIRECT, T_FIXED,
440 	 "DEC     ", "RZ55     (C) DEC", ""},     SDEV_AUTOSAVE},
441 	{{T_DIRECT, T_FIXED,
442 	 "EMULEX  ", "MD21/S2     ESDI", "A00"},  SDEV_FORCELUNS|SDEV_AUTOSAVE},
443 	/* Gives non-media hardware failure in response to start-unit command */
444 	{{T_DIRECT, T_FIXED,
445 	 "HITACHI", "DK515C",            "CP15"}, SDEV_NOSTARTUNIT},
446 	{{T_DIRECT, T_FIXED,
447 	 "HITACHI", "DK515C",            "CP16"}, SDEV_NOSTARTUNIT},
448 	{{T_DIRECT, T_FIXED,
449 	 "IBMRAID ", "0662S",            ""},     SDEV_AUTOSAVE},
450 	{{T_DIRECT, T_FIXED,
451 	 "IBM     ", "0663H",            ""},     SDEV_AUTOSAVE},
452 	{{T_DIRECT, T_FIXED,
453 	 "IBM",	  "0664",		 ""},	  SDEV_AUTOSAVE},
454 	{{T_DIRECT, T_FIXED,
455 	 "IBM     ", "H3171-S2",         ""},	  SDEV_NOLUNS|SDEV_AUTOSAVE},
456 	{{T_DIRECT, T_FIXED,
457 	 "IBM     ", "KZ-C",		 ""},	  SDEV_AUTOSAVE},
458 	/* Broken IBM disk */
459 	{{T_DIRECT, T_FIXED,
460 	 ""	   , "DFRSS2F",		 ""},	  SDEV_AUTOSAVE},
461 	{{T_DIRECT, T_FIXED,
462 	 "MAXTOR  ", "XT-3280         ", ""},     SDEV_NOLUNS},
463 	{{T_DIRECT, T_FIXED,
464 	 "MAXTOR  ", "XT-4380S        ", ""},     SDEV_NOLUNS},
465 	{{T_DIRECT, T_FIXED,
466 	 "MAXTOR  ", "MXT-1240S       ", ""},     SDEV_NOLUNS},
467 	{{T_DIRECT, T_FIXED,
468 	 "MAXTOR  ", "XT-4170S        ", ""},     SDEV_NOLUNS},
469 	{{T_DIRECT, T_FIXED,
470 	 "MAXTOR  ", "XT-8760S",	 ""},     SDEV_NOLUNS},
471 	{{T_DIRECT, T_FIXED,
472 	 "MAXTOR  ", "LXT-213S        ", ""},     SDEV_NOLUNS},
473 	{{T_DIRECT, T_FIXED,
474 	 "MAXTOR  ", "LXT-213S SUN0207", ""},     SDEV_NOLUNS},
475 	{{T_DIRECT, T_FIXED,
476 	 "MAXTOR  ", "LXT-200S        ", ""},     SDEV_NOLUNS},
477 	{{T_DIRECT, T_FIXED,
478 	 "MST     ", "SnapLink        ", ""},     SDEV_NOLUNS},
479 	{{T_DIRECT, T_FIXED,
480 	 "NEC     ", "D3847           ", "0307"}, SDEV_NOLUNS},
481 	{{T_DIRECT, T_FIXED,
482 	 "QUANTUM ", "ELS85S          ", ""},	  SDEV_AUTOSAVE},
483 	{{T_DIRECT, T_FIXED,
484 	 "QUANTUM ", "LPS525S         ", ""},     SDEV_NOLUNS},
485 	{{T_DIRECT, T_FIXED,
486 	 "QUANTUM ", "P105S 910-10-94x", ""},     SDEV_NOLUNS},
487 	{{T_DIRECT, T_FIXED,
488 	 "QUANTUM ", "PD1225S         ", ""},     SDEV_NOLUNS},
489 	{{T_DIRECT, T_FIXED,
490 	 "QUANTUM ", "PD210S   SUN0207", ""},     SDEV_NOLUNS},
491 	{{T_DIRECT, T_FIXED,
492 	 "RODIME  ", "RO3000S         ", ""},     SDEV_NOLUNS},
493 	{{T_DIRECT, T_FIXED,
494 	 "SEAGATE ", "ST125N          ", ""},     SDEV_NOLUNS},
495 	{{T_DIRECT, T_FIXED,
496 	 "SEAGATE ", "ST157N          ", ""},     SDEV_NOLUNS},
497 	{{T_DIRECT, T_FIXED,
498 	 "SEAGATE ", "ST296           ", ""},     SDEV_NOLUNS},
499 	{{T_DIRECT, T_FIXED,
500 	 "SEAGATE ", "ST296N          ", ""},     SDEV_NOLUNS},
501 	{{T_DIRECT, T_FIXED,
502 	 "SEAGATE ", "ST19171FC",	 ""},	  SDEV_NOMODESENSE},
503 	{{T_DIRECT, T_FIXED,
504 	 "SEAGATE ", "ST34501FC       ", ""},     SDEV_NOMODESENSE},
505         {{T_DIRECT, T_FIXED,
506 	 "TOSHIBA ", "MK538FB         ", "6027"}, SDEV_NOLUNS},
507 	{{T_DIRECT, T_REMOV,
508 	 "iomega", "jaz 1GB",		 ""},	  SDEV_NOMODESENSE|SDEV_NOTAGS},
509 	{{T_DIRECT, T_REMOV,
510 	 "IOMEGA", "ZIP 100",		 ""},	  SDEV_NOMODESENSE},
511 	{{T_DIRECT, T_REMOV,
512 	 "IOMEGA", "ZIP 250",		 ""},	  SDEV_NOMODESENSE},
513 	{{T_DIRECT, T_FIXED,
514 	 "IBM", "0661467",               "G"},    SDEV_NOMODESENSE},
515 	/* Letting the motor run kills floppy drives and disks quit fast. */
516 	{{T_DIRECT, T_REMOV,
517 	 "TEAC", "FC-1",                 ""},     SDEV_NOSTARTUNIT},
518 	{{T_DIRECT, T_FIXED,
519 	 "NEC ", "SD120S-200      ",	 "0001"}, SDEV_NOLUNS},
520 
521 	/* XXX: QIC-36 tape behind Emulex adapter.  Very broken. */
522 	{{T_SEQUENTIAL, T_REMOV,
523 	 "        ", "                ", "    "}, SDEV_NOLUNS},
524 	{{T_SEQUENTIAL, T_REMOV,
525 	 "CALIPER ", "CP150           ", ""},     SDEV_NOLUNS},
526 	{{T_SEQUENTIAL, T_REMOV,
527 	 "DEC     ", "TZ30            ", ""},     SDEV_NOLUNS},
528 	{{T_SEQUENTIAL, T_REMOV,
529 	 "DEC     ", "TK50            ", ""},     SDEV_NOLUNS},
530 	{{T_SEQUENTIAL, T_REMOV,
531 	 "EXABYTE ", "EXB-8200        ", ""},     SDEV_NOLUNS},
532 	{{T_SEQUENTIAL, T_REMOV,
533 	 "SONY    ", "SDT-2000        ", "2.09"}, SDEV_NOLUNS},
534 	{{T_SEQUENTIAL, T_REMOV,
535 	 "SONY    ", "SDT-5000        ", "3."},   SDEV_NOSYNC|SDEV_NOWIDE},
536 	{{T_SEQUENTIAL, T_REMOV,
537 	 "SONY    ", "SDT-5200        ", "3."},   SDEV_NOLUNS},
538 	{{T_SEQUENTIAL, T_REMOV,
539 	 "TANDBERG", " TDC 3600       ", ""},     SDEV_NOLUNS},
540 	/* Following entry reported as a Tandberg 3600; ref. PR1933 */
541 	{{T_SEQUENTIAL, T_REMOV,
542 	 "ARCHIVE ", "VIPER 150  21247", ""},     SDEV_NOLUNS},
543 	/* Following entry for a Cipher ST150S */
544 	{{T_SEQUENTIAL, T_REMOV,
545 	 "ARCHIVE ", "VIPER 1500 21247", "2.2G"}, SDEV_NOLUNS},
546 	{{T_SEQUENTIAL, T_REMOV,
547 	 "ARCHIVE ", "Python 28454-XXX", ""},     SDEV_NOLUNS},
548 	{{T_SEQUENTIAL, T_REMOV,
549 	 "WANGTEK ", "5099ES SCSI",      ""},     SDEV_NOLUNS},
550 	{{T_SEQUENTIAL, T_REMOV,
551 	 "WANGTEK ", "5150ES SCSI",      ""},     SDEV_NOLUNS},
552 	{{T_SEQUENTIAL, T_REMOV,
553 	 "WangDAT ", "Model 1300      ", "02.4"}, SDEV_NOSYNC|SDEV_NOWIDE},
554 	{{T_SEQUENTIAL, T_REMOV,
555 	 "WangDAT ", "Model 2600      ", "01.7"}, SDEV_NOSYNC|SDEV_NOWIDE},
556 	{{T_SEQUENTIAL, T_REMOV,
557 	 "WangDAT ", "Model 3200      ", "02.2"}, SDEV_NOSYNC|SDEV_NOWIDE},
558 
559 	{{T_SCANNER, T_FIXED,
560 	 "RICOH   ", "IS60            ", "1R08"}, SDEV_NOLUNS},
561 	{{T_SCANNER, T_FIXED,
562 	 "UMAX    ", "Astra 1200S     ", "V2.9"}, SDEV_NOLUNS},
563 	{{T_SCANNER, T_FIXED,
564 	 "ULTIMA  ", "AT3     1.60    ", ""},     SDEV_NOLUNS},
565 	{{T_SCANNER, T_FIXED,
566 	 "UMAX    ", "SuperVista S-12 ", "V1.9"}, SDEV_NOLUNS},
567 
568 	{{T_ENCLOSURE, T_FIXED,
569 	 "SUN     ", "SENA", ""},                 SDEV_NOLUNS},
570 
571 	/* ATAPI device quirks */
572         {{T_CDROM, T_REMOV,
573          "ALPS ELECTRIC CO.,LTD. DC544C", "", "SW03D"}, ADEV_NOTUR},
574         {{T_CDROM, T_REMOV,
575          "BCD-16X", "", ""},                    SDEV_NOSTARTUNIT},
576         {{T_CDROM, T_REMOV,
577          "BCD-24X", "", ""},                    SDEV_NOSTARTUNIT},
578         {{T_CDROM, T_REMOV,
579          "CR-2801TE", "", "1.07"},              ADEV_NOSENSE},
580         {{T_CDROM, T_REMOV,
581          "CREATIVECD3630E", "", "AC101"},       ADEV_NOSENSE},
582         {{T_CDROM, T_REMOV,
583          "FX320S", "", "q01"},                  ADEV_NOSENSE},
584         {{T_CDROM, T_REMOV,
585          "GCD-R580B", "", "1.00"},              ADEV_LITTLETOC},
586         {{T_CDROM, T_REMOV,
587          "MATSHITA CR-574", "", "1.02"},        ADEV_NOCAPACITY},
588         {{T_CDROM, T_REMOV,
589          "MATSHITA CR-574", "", "1.06"},        ADEV_NOCAPACITY},
590         {{T_CDROM, T_REMOV,
591          "Memorex CRW-2642", "", "1.0g"},       ADEV_NOSENSE},
592         {{T_CDROM, T_REMOV,
593          "NEC                 CD-ROM DRIVE:273", "", "4.21"}, ADEV_NOTUR},
594         {{T_CDROM, T_REMOV,
595          "SANYO CRD-256P", "", "1.02"},         ADEV_NOCAPACITY},
596         {{T_CDROM, T_REMOV,
597          "SANYO CRD-254P", "", "1.02"},         ADEV_NOCAPACITY},
598         {{T_CDROM, T_REMOV,
599          "SANYO CRD-S54P", "", "1.08"},         ADEV_NOCAPACITY},
600         {{T_CDROM, T_REMOV,
601          "CD-ROM  CDR-S1", "", "1.70"},         ADEV_NOCAPACITY}, /* Sanyo */
602         {{T_CDROM, T_REMOV,
603          "CD-ROM  CDR-N16", "", "1.25"},        ADEV_NOCAPACITY}, /* Sanyo */
604         {{T_CDROM, T_REMOV,
605          "UJDCD8730", "", "1.14"},              ADEV_NODOORLOCK}, /* Acer */
606 };
607 
608 
609 /*
610  * Print out autoconfiguration information for a subdevice.
611  *
612  * This is a slight abuse of 'standard' autoconfiguration semantics,
613  * because 'print' functions don't normally print the colon and
614  * device information.  However, in this case that's better than
615  * either printing redundant information before the attach message,
616  * or having the device driver call a special function to print out
617  * the standard device information.
618  */
619 int
620 scsibusprint(aux, pnp)
621 	void	*aux;
622 	const char *pnp;
623 {
624 	struct scsibus_attach_args *sa = aux;
625 	struct scsi_inquiry_data *inqbuf;
626 	u_int8_t type;
627 	boolean removable;
628 	char *dtype, *qtype;
629 	char vendor[33], product[65], revision[17];
630 	int target, lun;
631 
632 	if (pnp != NULL)
633 		printf("%s", pnp);
634 
635 	inqbuf = sa->sa_inqbuf;
636 
637 	target = sa->sa_sc_link->target;
638 	lun = sa->sa_sc_link->lun;
639 
640 	type = inqbuf->device & SID_TYPE;
641 	removable = inqbuf->dev_qual2 & SID_REMOVABLE ? 1 : 0;
642 
643 	/*
644 	 * Figure out basic device type and qualifier.
645 	 */
646 	dtype = 0;
647 	switch (inqbuf->device & SID_QUAL) {
648 	case SID_QUAL_LU_OK:
649 		qtype = "";
650 		break;
651 
652 	case SID_QUAL_LU_OFFLINE:
653 		qtype = " offline";
654 		break;
655 
656 	case SID_QUAL_RSVD:
657 	case SID_QUAL_BAD_LU:
658 		panic("scsibusprint: impossible qualifier");
659 
660 	default:
661 		qtype = "";
662 		dtype = "vendor-unique";
663 		break;
664 	}
665 	if (dtype == 0) {
666 		switch (type) {
667 		case T_DIRECT:
668 			dtype = "direct";
669 			break;
670 		case T_SEQUENTIAL:
671 			dtype = "sequential";
672 			break;
673 		case T_PRINTER:
674 			dtype = "printer";
675 			break;
676 		case T_PROCESSOR:
677 			dtype = "processor";
678 			break;
679 		case T_CDROM:
680 			dtype = "cdrom";
681 			break;
682 		case T_WORM:
683 			dtype = "worm";
684 			break;
685 		case T_SCANNER:
686 			dtype = "scanner";
687 			break;
688 		case T_OPTICAL:
689 			dtype = "optical";
690 			break;
691 		case T_CHANGER:
692 			dtype = "changer";
693 			break;
694 		case T_COMM:
695 			dtype = "communication";
696 			break;
697 		case T_ENCLOSURE:
698 			dtype = "enclosure services";
699 			break;
700 		case T_NODEVICE:
701 			panic("scsibusprint: impossible device type");
702 		default:
703 			dtype = "unknown";
704 			break;
705 		}
706 	}
707 
708 	scsi_strvis(vendor, inqbuf->vendor, 8);
709 	scsi_strvis(product, inqbuf->product, 16);
710 	scsi_strvis(revision, inqbuf->revision, 4);
711 
712 	printf(" targ %d lun %d: <%s, %s, %s> SCSI%d %d/%s %s%s",
713 	    target, lun, vendor, product, revision,
714 	    inqbuf->version & SID_ANSII, type, dtype,
715 	    removable ? "removable" : "fixed", qtype);
716 
717 	return (UNCONF);
718 }
719 
720 /*
721  * given a target and lu, ask the device what
722  * it is, and find the correct driver table
723  * entry.
724  */
725 void
726 scsi_probedev(scsi, target, lun)
727 	struct scsibus_softc *scsi;
728 	int target, lun;
729 {
730 	struct scsi_link *sc_link;
731 	static struct scsi_inquiry_data inqbuf;
732 	struct scsi_quirk_inquiry_pattern *finger;
733 	int checkdtype, priority;
734 	struct scsibus_attach_args sa;
735 	struct cfdata *cf;
736 
737 	/* Skip this slot if it is already attached. */
738 	if (scsi->sc_link[target][lun])
739 		return;
740 
741 	sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT);
742 	if (sc_link == NULL)
743 		return;
744 	*sc_link = *scsi->adapter_link;
745 	sc_link->target = target;
746 	sc_link->lun = lun;
747 	sc_link->device = &probe_switch;
748 	sc_link->inquiry_flags = 0;
749 
750 	/*
751 	 * Ask the device what it is
752 	 */
753 #ifdef SCSIDEBUG
754 	if (((1 << target) & scsidebug_targets) &&
755 	    ((1 << lun) & scsidebug_luns))
756 		sc_link->flags |= scsidebug_level;
757 #endif /* SCSIDEBUG */
758 
759 	(void) scsi_test_unit_ready(sc_link,
760 	    scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
761 
762 #ifdef SCSI_2_DEF
763 	/* some devices need to be told to go to SCSI2 */
764 	/* However some just explode if you tell them this.. leave it out */
765 	scsi_change_def(sc_link, scsi_autoconf | SCSI_SILENT);
766 #endif /* SCSI_2_DEF */
767 
768 	/* Now go ask the device all about itself. */
769 	bzero(&inqbuf, sizeof(inqbuf));
770 	if (scsi_inquire(sc_link, &inqbuf, scsi_autoconf) != 0)
771 		goto bad;
772 
773 	{
774 		int len = inqbuf.additional_length;
775 		while (len < 3)
776 			inqbuf.unused[len++] = '\0';
777 		while (len < 3 + 28)
778 			inqbuf.unused[len++] = ' ';
779 		if (inqbuf.additional_length == 0) {
780 			if (inqbuf.dev_qual2 == 0xb0) {
781 				strncpy(inqbuf.unused+3, "DEC", 3);
782 				strncpy(inqbuf.unused+11, "TZ30", 4);
783 			} else if (inqbuf.dev_qual2 == 0xd0) {
784 				strncpy(inqbuf.unused+3, "DEC", 3);
785 				strncpy(inqbuf.unused+11, "TK50", 4);
786 			}
787 		}
788 	}
789 
790 	finger = (struct scsi_quirk_inquiry_pattern *)scsi_inqmatch(&inqbuf,
791 	    (caddr_t)scsi_quirk_patterns,
792 	    sizeof(scsi_quirk_patterns)/sizeof(scsi_quirk_patterns[0]),
793 	    sizeof(scsi_quirk_patterns[0]), &priority);
794 
795 	/*
796 	 * Based upon the inquiry flags we got back, and if we're
797 	 * at SCSI-2 or better, set some limiting quirks.
798 	 */
799 	if ((inqbuf.version & SID_ANSII) >= 2) {
800 		if ((inqbuf.flags & SID_CmdQue) == 0)
801 			sc_link->quirks |= SDEV_NOTAGS;
802 		if ((inqbuf.flags & SID_Sync) == 0)
803 			sc_link->quirks |= SDEV_NOSYNC;
804 		if ((inqbuf.flags & SID_WBus16) == 0)
805 			sc_link->quirks |= SDEV_NOWIDE;
806 	}
807 	/*
808 	 * Now apply any quirks from the table.
809 	 */
810 	if (priority != 0)
811 		sc_link->quirks |= finger->quirks;
812 	if ((inqbuf.version & SID_ANSII) == 0 &&
813 	    (sc_link->quirks & SDEV_FORCELUNS) == 0)
814 		sc_link->quirks |= SDEV_NOLUNS;
815 	sc_link->scsi_version = inqbuf.version;
816 
817 	if ((sc_link->quirks & SDEV_NOLUNS) == 0)
818 		scsi->moreluns |= (1 << target);
819 
820 	/*
821 	 * Save INQUIRY "flags" (SID_Linked, etc.) for low-level drivers.
822 	 */
823 	sc_link->inquiry_flags = inqbuf.flags;
824 
825 	/*
826 	 * note what BASIC type of device it is
827 	 */
828 	if ((inqbuf.dev_qual2 & SID_REMOVABLE) != 0)
829 		sc_link->flags |= SDEV_REMOVABLE;
830 
831 	/*
832 	 * Any device qualifier that has the top bit set (qualifier&4 != 0)
833 	 * is vendor specific and won't match in this switch.
834 	 * All we do here is throw out bad/negative responses.
835 	 */
836 	checkdtype = 0;
837 	switch (inqbuf.device & SID_QUAL) {
838 	case SID_QUAL_LU_OK:
839 	case SID_QUAL_LU_OFFLINE:
840 		checkdtype = 1;
841 		break;
842 
843 	case SID_QUAL_RSVD:
844 	case SID_QUAL_BAD_LU:
845 		goto bad;
846 
847 	default:
848 		break;
849 	}
850 	if (checkdtype) {
851 		switch (inqbuf.device & SID_TYPE) {
852 		case T_DIRECT:
853 		case T_SEQUENTIAL:
854 		case T_PRINTER:
855 		case T_PROCESSOR:
856 		case T_CDROM:
857 		case T_WORM:
858 		case T_SCANNER:
859 		case T_OPTICAL:
860 		case T_CHANGER:
861 		case T_COMM:
862 		default:
863 			break;
864 		case T_NODEVICE:
865 			goto bad;
866 		}
867 	}
868 
869 	sa.sa_sc_link = sc_link;
870 	sa.sa_inqbuf = &inqbuf;
871 
872 	if ((cf = config_search(scsibussubmatch, (struct device *)scsi, &sa)) != 0) {
873 		scsi->sc_link[target][lun] = sc_link;
874 		config_attach((struct device *)scsi, cf, &sa, scsibusprint);
875 	} else {
876 		scsibusprint(&sa, scsi->sc_dev.dv_xname);
877 		printf(" not configured\n");
878 		goto bad;
879 	}
880 
881 	return;
882 
883 bad:
884 	free(sc_link, M_DEVBUF);
885 	return;
886 }
887 
888 /*
889  * Return a priority based on how much of the inquiry data matches
890  * the patterns for the particular driver.
891  */
892 caddr_t
893 scsi_inqmatch(inqbuf, base, nmatches, matchsize, bestpriority)
894 	struct scsi_inquiry_data *inqbuf;
895 	caddr_t base;
896 	int nmatches, matchsize;
897 	int *bestpriority;
898 {
899 	u_int8_t type;
900 	boolean removable;
901 	caddr_t bestmatch;
902 
903 	/* Include the qualifier to catch vendor-unique types. */
904 	type = inqbuf->device;
905 	removable = inqbuf->dev_qual2 & SID_REMOVABLE ? T_REMOV : T_FIXED;
906 
907 	for (*bestpriority = 0, bestmatch = 0; nmatches--; base += matchsize) {
908 		struct scsi_inquiry_pattern *match = (void *)base;
909 		int priority, len;
910 
911 		if (type != match->type)
912 			continue;
913 		if (removable != match->removable)
914 			continue;
915 		priority = 2;
916 		len = strlen(match->vendor);
917 		if (bcmp(inqbuf->vendor, match->vendor, len))
918 			continue;
919 		priority += len;
920 		len = strlen(match->product);
921 		if (bcmp(inqbuf->product, match->product, len))
922 			continue;
923 		priority += len;
924 		len = strlen(match->revision);
925 		if (bcmp(inqbuf->revision, match->revision, len))
926 			continue;
927 		priority += len;
928 
929 #if SCSIDEBUG
930 		printf("scsi_inqmatch: %d/%d/%d <%s, %s, %s>\n",
931 		    priority, match->type, match->removable,
932 		    match->vendor, match->product, match->revision);
933 #endif
934 		if (priority > *bestpriority) {
935 			*bestpriority = priority;
936 			bestmatch = base;
937 		}
938 	}
939 
940 	return (bestmatch);
941 }
942