scsiconf.c revision 1.9.3.1 1 /*
2 * Written by Julian Elischer (julian (at) tfs.com)
3 * for TRW Financial Systems for use under the MACH(2.5) operating system.
4 *
5 * TRW Financial Systems, in accordance with their agreement with Carnegie
6 * Mellon University, makes this software available to CMU to distribute
7 * or use in any manner that they see fit as long as this message is kept with
8 * the software. For this reason TFS also grants any other persons or
9 * organisations permission to use or modify this software.
10 *
11 * TFS supplies this software to be publicly redistributed
12 * on the understanding that TFS is not responsible for the correct
13 * functioning of this software in any circumstances.
14 *
15 * Ported to run under 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992
16 *
17 * $Id: scsiconf.c,v 1.9.3.1 1993/11/24 05:03:06 mycroft Exp $
18 */
19
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/malloc.h>
24 #include <sys/device.h>
25
26 #include "st.h"
27 #include "sd.h"
28 #include "ch.h"
29 #include "cd.h"
30 #include "uk.h"
31 #include "su.h"
32
33 #include <scsi/scsi_all.h>
34 #include <scsi/scsiconf.h>
35
36
37
38 #ifdef TFS
39 #include "bll.h"
40 #include "cals.h"
41 #include "kil.h"
42 #include "scan.h"
43 #else /* TFS */
44 #define NBLL 0
45 #define NCALS 0
46 #define NKIL 0
47 #define NSCAN 0
48 #endif /* TFS */
49
50 #if NSD > 0
51 extern sdattach();
52 #endif /* NSD */
53 #if NST > 0
54 extern stattach();
55 #endif /* NST */
56 #if NCH > 0
57 extern chattach();
58 #endif /* NCH */
59 #if NCD > 0
60 extern cdattach();
61 #endif /* NCD */
62 #if NBLL > 0
63 extern bllattach();
64 #endif /* NBLL */
65 #if NCALS > 0
66 extern calsattach();
67 #endif /* NCALS */
68 #if NKIL > 0
69 extern kil_attach();
70 #endif /* NKIL */
71 #if NUK > 0
72 extern ukattach();
73 #endif /* NUK */
74
75 /*
76 * The structure of pre-configured devices that might be turned
77 * off and therefore may not show up
78 */
79 struct predefined {
80 u_char scsibus;
81 u_char dev;
82 u_char lu;
83 errval(*attach_rtn) ();
84 char *devname;
85 char flags;
86 } pd[] =
87
88 {
89 #ifdef EXAMPLE_PREDEFINE
90 #if NSD > 0
91 {
92 0, 0, 0, sdattach, "sd", 0
93 }, /* define a disk at scsibus=0 dev=0 lu=0 */
94 #endif /* NSD */
95 #endif /* EXAMPLE_PREDEFINE */
96 {
97 0, 9, 9
98 } /*illegal dummy end entry */
99 };
100
101 /*
102 * The structure of known drivers for autoconfiguration
103 */
104 struct scsidevs {
105 u_int32 type;
106 boolean removable;
107 char *manufacturer;
108 char *model;
109 char *version;
110 errval(*attach_rtn) ();
111 char *devname;
112 char flags; /* 1 show my comparisons during boot(debug) */
113 };
114
115 #define SC_SHOWME 0x01
116 #define SC_ONE_LU 0x00
117 #define SC_MORE_LUS 0x02
118 #if NUK > 0
119
120 static struct scsidevs unknowndev = {
121 -1, 0, "standard", "any"
122 ,"any", ukattach, "uk", SC_MORE_LUS
123 };
124 #endif /*NUK*/
125 static struct scsidevs knowndevs[] =
126 {
127 #if NSD > 0
128 {
129 T_DIRECT, T_FIXED, "standard", "any"
130 ,"any", sdattach, "sd", SC_ONE_LU
131 },
132 {
133 T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S "
134 ,"B5A ", sdattach, "mx1", SC_ONE_LU
135 },
136 #endif /* NSD */
137 #if NST > 0
138 {
139 T_SEQUENTIAL, T_REMOV, "standard", "any"
140 ,"any", stattach, "st", SC_ONE_LU
141 },
142 #endif /* NST */
143 #if NCALS > 0
144 {
145 T_PROCESSOR, T_FIXED, "standard", "any"
146 ,"any", calsattach, "cals", SC_MORE_LUS
147 },
148 #endif /* NCALS */
149 #if NCH > 0
150 {
151 T_CHANGER, T_REMOV, "standard", "any"
152 ,"any", chattach, "ch", SC_ONE_LU
153 },
154 #endif /* NCH */
155 #if NCD > 0
156 #ifndef UKTEST /* make cdroms unrecognised to test the uk driver */
157 {
158 T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 "
159 ,"3.1a", cdattach, "cd", SC_ONE_LU
160 },
161 {
162 T_READONLY, T_REMOV, "PIONEER ", "CD-ROM DRM-600 "
163 ,"any", cdattach, "cd", SC_MORE_LUS
164 },
165 #endif
166 #endif /* NCD */
167 #if NBLL > 0
168 {
169 T_PROCESSOR, T_FIXED, "AEG ", "READER "
170 ,"V1.0", bllattach, "bll", SC_MORE_LUS
171 },
172 #endif /* NBLL */
173 #if NKIL > 0
174 {
175 T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 "
176 ,"any", kil_attach, "kil", SC_ONE_LU
177 },
178 #endif /* NKIL */
179
180 {
181 0
182 }
183 };
184
185 /*
186 * Declarations
187 */
188 struct predefined *scsi_get_predef();
189 struct scsidevs *scsi_probedev();
190 struct scsidevs *selectdev();
191 errval scsi_probe_bus __P((int bus, int targ, int lun));
192
193 struct scsi_device probe_switch =
194 {
195 NULL,
196 NULL,
197 NULL,
198 NULL,
199 "probe",
200 0,
201 };
202
203 int scsibusmatch __P((struct device *, struct cfdata *, void *));
204 void scsibusattach __P((struct device *, struct device *, void *));
205
206 struct cfdriver scsibuscd =
207 {
208 NULL,
209 "scsibus",
210 scsibusmatch,
211 scsibusattach,
212 DV_DULL,
213 sizeof(struct scsibus_data)
214 };
215
216 int
217 scsibusmatch(parent, cf, aux)
218 struct device *parent;
219 struct cfdata *cf;
220 void *aux;
221 {
222
223 return 1;
224 }
225
226 /*
227 * The routine called by the adapter boards to get all their
228 * devices configured in.
229 */
230 void
231 scsibusattach(parent, self, aux)
232 struct device *parent, *self;
233 void *aux;
234 {
235 struct scsibus_data *sb = (struct scsibus_data *)self;
236 struct scsi_link *sc_link_proto = aux;
237
238 sc_link_proto->scsibus = sb->sc_dev.dv_unit;
239 sb->adapter_link = sc_link_proto;
240 printf("\n");
241
242 #if defined(SCSI_DELAY) && SCSI_DELAY > 2
243 printf("%s: waiting for scsi devices to settle\n",
244 sb->sc_dev.dv_xname);
245 #else /* SCSI_DELAY > 2 */
246 #undef SCSI_DELAY
247 #define SCSI_DELAY 2
248 #endif /* SCSI_DELAY */
249 DELAY(1000000 * SCSI_DELAY);
250
251 scsi_probe_bus(sb->sc_dev.dv_unit, -1, -1);
252 }
253
254 /*
255 * Probe the requested scsi bus. It must be already set up.
256 * -1 requests all set up scsi busses.
257 * targ and lun optionally narrow the search if not -1
258 */
259 errval
260 scsi_probe_busses(bus, targ, lun)
261 int bus, targ, lun;
262 {
263 if (bus == -1) {
264 for (bus = 0; bus < scsibuscd.cd_ndevs; bus++)
265 if (scsibuscd.cd_devs[bus])
266 scsi_probe_bus(bus, targ, lun);
267 return 0;
268 } else {
269 return scsi_probe_bus(bus, targ, lun);
270 }
271 }
272
273 /*
274 * Probe the requested scsi bus. It must be already set up.
275 * targ and lun optionally narrow the search if not -1
276 */
277 errval
278 scsi_probe_bus(bus, targ, lun)
279 int bus, targ, lun;
280 {
281 struct scsibus_data *scsi;
282 int maxtarg, mintarg, maxlun, minlun;
283 struct scsi_link *sc_link_proto;
284 u_int8 scsi_addr ;
285 struct scsidevs *bestmatch = NULL;
286 struct predefined *predef = NULL;
287 struct scsi_link *sc_link = NULL;
288 boolean maybe_more;
289
290 if (bus < 0 || bus >= scsibuscd.cd_ndevs)
291 return ENXIO;
292 scsi = scsibuscd.cd_devs[bus];
293 if (!scsi)
294 return ENXIO;
295
296 sc_link_proto = scsi->adapter_link;
297 scsi_addr = sc_link_proto->adapter_targ;
298
299 if (targ == -1) {
300 maxtarg = 7;
301 mintarg = 0;
302 } else {
303 if (targ < 0 || targ > 7)
304 return EINVAL;
305 maxtarg = mintarg = targ;
306 }
307
308 if (lun == -1 ){
309 maxlun = 7;
310 minlun = 0;
311 } else {
312 if (lun < 0 || lun > 7)
313 return EINVAL;
314 maxlun = minlun = lun;
315 }
316
317
318 for (targ = mintarg; targ <= maxtarg; targ++) {
319 maybe_more = 0; /* by default only check 1 lun */
320 #if 0
321 if (targ == scsi_addr)
322 continue;
323 #endif
324 for (lun = minlun; lun <= maxlun; lun++) {
325 /*
326 * The spot appears to already have something
327 * linked in, skip past it. Must be doing a 'reprobe'
328 */
329 if (scsi->sc_link[targ][lun]) {
330 /* don't do this one, but check other luns */
331 maybe_more = 1;
332 continue;
333 }
334 /*
335 * If we presently don't have a link block
336 * then allocate one to use while probing
337 */
338 if (!sc_link) {
339 sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT);
340 *sc_link = *sc_link_proto; /* struct copy */
341 sc_link->opennings = 1;
342 sc_link->device = &probe_switch;
343 }
344 sc_link->target = targ;
345 sc_link->lun = lun;
346 predef = scsi_get_predef(sc_link, &maybe_more);
347 bestmatch = scsi_probedev(sc_link, &maybe_more);
348 if (bestmatch && predef) { /* both exist */
349 if (bestmatch->attach_rtn
350 != predef->attach_rtn) {
351 printf("Clash in found/expected devices\n");
352 #if NUK > 0
353 if (bestmatch == &unknowndev) {
354 printf("will link in PREDEFINED\n");
355 (*(predef->attach_rtn)) (sc_link);
356 } else
357 #endif /*NUK*/
358 {
359 printf("will link in FOUND\n");
360 (*(bestmatch->attach_rtn)) (sc_link);
361 }
362 } else {
363 (*(bestmatch->attach_rtn)) (sc_link);
364 }
365 }
366 if (bestmatch && !predef) /* just FOUND */
367 (*(bestmatch->attach_rtn)) (sc_link);
368 if (!bestmatch && predef) /* just predef */
369 (*(predef->attach_rtn)) (sc_link);
370 if (bestmatch || predef) { /* one exists */
371 scsi->sc_link[targ][lun] = sc_link;
372 sc_link = NULL; /* it's been used */
373 }
374 if (!(maybe_more)) { /* nothing suggests we'll find more */
375 break; /* nothing here, skip to next targ */
376 }
377 /* otherwise something says we should look further */
378 }
379 }
380 if (sc_link) {
381 free(sc_link, M_TEMP);
382 }
383 return 0;
384 }
385
386 /*
387 * given a target and lu, check if there is a predefined device for
388 * that address
389 */
390 struct predefined *
391 scsi_get_predef(sc_link, maybe_more)
392 struct scsi_link *sc_link;
393 boolean *maybe_more;
394 {
395 u_int8 unit = sc_link->scsibus;
396 u_int8 target = sc_link->target;
397 u_int8 lu = sc_link->lun;
398 struct scsi_adapter *scsi_adapter = sc_link->adapter;
399 u_int32 upto, numents;
400
401 numents = (sizeof(pd) / sizeof(struct predefined)) - 1;
402
403 for (upto = 0; upto < numents; upto++) {
404 if (pd[upto].scsibus != unit)
405 continue;
406 if (pd[upto].dev != target)
407 continue;
408 if (pd[upto].lu != lu)
409 continue;
410
411 printf("%s%d targ %d lun %d: <%s> - PRECONFIGURED -\n"
412 ,scsi_adapter->name
413 ,unit
414 ,target
415 ,lu
416 ,pd[upto].devname);
417 *maybe_more = pd[upto].flags & SC_MORE_LUS;
418 return &(pd[upto]);
419 }
420 return NULL;
421 }
422
423 /*
424 * given a target and lu, ask the device what
425 * it is, and find the correct driver table
426 * entry.
427 */
428 struct scsidevs *
429 scsi_probedev(sc_link, maybe_more)
430 boolean *maybe_more;
431 struct scsi_link *sc_link;
432 {
433 u_int8 target = sc_link->target;
434 u_int8 lun = sc_link->lun;
435 struct scsi_adapter *scsi_adapter = sc_link->adapter;
436 struct scsidevs *bestmatch = NULL;
437 char *dtype = NULL, *desc;
438 char *qtype;
439 static struct scsi_inquiry_data inqbuf;
440 u_int32 len, qualifier, type;
441 boolean remov;
442 char manu[32];
443 char model[32];
444 char version[32];
445
446 bzero(&inqbuf, sizeof(inqbuf));
447 /*
448 * Ask the device what it is
449 */
450 #ifdef SCSIDEBUG
451 if (target == DEBUGTARG && lu == DEBUGLUN)
452 sc_link->flags |= DEBUGLEVEL;
453 else
454 sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4);
455 #endif /* SCSIDEBUG */
456 /* catch unit attn */
457 scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
458 #ifdef DOUBTFULL
459 switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
460 case 0: /* said it WAS ready */
461 case EBUSY: /* replied 'NOT READY' but WAS present, continue */
462 case ENXIO:
463 break;
464 case EIO: /* device timed out */
465 case EINVAL: /* Lun not supported */
466 default:
467 return NULL;
468
469 }
470 #endif /*DOUBTFULL*/
471 #ifdef SCSI_2_DEF
472 /* some devices need to be told to go to SCSI2 */
473 /* However some just explode if you tell them this.. leave it out */
474 scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
475 #endif /*SCSI_2_DEF */
476
477 /* Now go ask the device all about itself */
478 if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0)
479 return NULL;
480
481 /*
482 * note what BASIC type of device it is
483 */
484 type = inqbuf.device & SID_TYPE;
485 qualifier = inqbuf.device & SID_QUAL;
486 remov = inqbuf.dev_qual2 & SID_REMOVABLE;
487
488 /*
489 * Any device qualifier that has the top bit set (qualifier&4 != 0)
490 * is vendor specific and won't match in this switch.
491 */
492 switch (qualifier) {
493 case SID_QUAL_LU_OK:
494 qtype = "";
495 break;
496
497 case SID_QUAL_LU_OFFLINE:
498 qtype = ", Unit not Connected!";
499 break;
500
501 case SID_QUAL_RSVD:
502 qtype = ", Reserved Peripheral Qualifier!";
503 *maybe_more = 1;
504 return NULL;
505 break;
506
507 case SID_QUAL_BAD_LU:
508 /*
509 * Check for a non-existent unit. If the device is returning
510 * this much, then we must set the flag that has
511 * the searchers keep looking on other luns.
512 */
513 qtype = ", The Target can't support this Unit!";
514 *maybe_more = 1;
515 return NULL;
516
517 default:
518 dtype = "vendor specific";
519 qtype = "";
520 *maybe_more = 1;
521 break;
522 }
523 if (dtype == 0) {
524 switch (type) {
525 case T_DIRECT:
526 dtype = "direct";
527 break;
528 case T_SEQUENTIAL:
529 dtype = "sequential";
530 break;
531 case T_PRINTER:
532 dtype = "printer";
533 break;
534 case T_PROCESSOR:
535 dtype = "processor";
536 break;
537 case T_READONLY:
538 dtype = "readonly";
539 break;
540 case T_WORM:
541 dtype = "worm";
542 break;
543 case T_SCANNER:
544 dtype = "scanner";
545 break;
546 case T_OPTICAL:
547 dtype = "optical";
548 break;
549 case T_CHANGER:
550 dtype = "changer";
551 break;
552 case T_COMM:
553 dtype = "communication";
554 break;
555 case T_NODEVICE:
556 *maybe_more = 1;
557 return NULL;
558 default:
559 dtype = NULL;
560 break;
561 }
562 }
563
564 /*
565 * Then if it's advanced enough, more detailed
566 * information
567 */
568 if ((inqbuf.version & SID_ANSII) > 0) {
569 if ((len = inqbuf.additional_length
570 + ((char *) inqbuf.unused
571 - (char *) &inqbuf))
572 > (sizeof(struct scsi_inquiry_data) - 1))
573 len = sizeof(struct scsi_inquiry_data) - 1;
574 desc = inqbuf.vendor;
575 desc[len - (desc - (char *) &inqbuf)] = 0;
576 strncpy(manu, inqbuf.vendor, 8);
577 manu[8] = 0;
578 strncpy(model, inqbuf.product, 16);
579 model[16] = 0;
580 strncpy(version, inqbuf.revision, 4);
581 version[4] = 0;
582 } else
583 /*
584 * If not advanced enough, use default values
585 */
586 {
587 desc = "early protocol device";
588 strncpy(manu, "unknown", 8);
589 strncpy(model, "unknown", 16);
590 strncpy(version, "????", 4);
591 }
592 printf("%s targ %d lun %d: <%s%s%s> SCSI%d ",
593 ((struct device *)sc_link->adapter_softc)->dv_xname,
594 target, lun, manu, model, version,
595 inqbuf.version & SID_ANSII);
596 if (dtype)
597 printf("%s", dtype);
598 else
599 printf("type %d", type);
600 printf(" %s\n", remov ? "removable" : "fixed");
601 if (qtype[0])
602 printf("%s targ %d lun %d: qualifier %d(%s)\n",
603 ((struct device *)sc_link->adapter_softc)->dv_xname,
604 target, lun, qualifier, qtype);
605
606 /*
607 * Try make as good a match as possible with
608 * available sub drivers
609 */
610 bestmatch = selectdev(qualifier, type, remov ? T_REMOV : T_FIXED,
611 manu, model, version);
612 if (bestmatch && bestmatch->flags & SC_MORE_LUS)
613 *maybe_more = 1;
614 return bestmatch;
615 }
616 /*
617 * Try make as good a match as possible with
618 * available sub drivers
619 */
620 struct scsidevs *
621 selectdev(qualifier, type, remov, manu, model, rev)
622 u_int32 qualifier, type;
623 boolean remov;
624 char *manu, *model, *rev;
625 {
626 u_int32 numents = (sizeof(knowndevs) / sizeof(struct scsidevs)) - 1;
627 u_int32 count = 0;
628 u_int32 bestmatches = 0;
629 struct scsidevs *bestmatch = (struct scsidevs *) 0;
630 struct scsidevs *thisentry = knowndevs;
631
632 type |= qualifier; /* why? */
633
634 thisentry--;
635 while (count++ < numents) {
636 thisentry++;
637 if (type != thisentry->type)
638 continue;
639 if (bestmatches < 1) {
640 bestmatches = 1;
641 bestmatch = thisentry;
642 }
643 if (remov != thisentry->removable)
644 continue;
645 if (bestmatches < 2) {
646 bestmatches = 2;
647 bestmatch = thisentry;
648 }
649 if (thisentry->flags & SC_SHOWME)
650 printf("\n%s-\n%s-", thisentry->manufacturer, manu);
651 if (strcmp(thisentry->manufacturer, manu))
652 continue;
653 if (bestmatches < 3) {
654 bestmatches = 3;
655 bestmatch = thisentry;
656 }
657 if (thisentry->flags & SC_SHOWME)
658 printf("\n%s-\n%s-", thisentry->model, model);
659 if (strcmp(thisentry->model, model))
660 continue;
661 if (bestmatches < 4) {
662 bestmatches = 4;
663 bestmatch = thisentry;
664 }
665 if (thisentry->flags & SC_SHOWME)
666 printf("\n%s-\n%s-", thisentry->version, rev);
667 if (strcmp(thisentry->version, rev))
668 continue;
669 if (bestmatches < 5) {
670 bestmatches = 5;
671 bestmatch = thisentry;
672 break;
673 }
674 }
675 if (!bestmatch) {
676 #if NUK > 0
677 bestmatch = &unknowndev;
678 #else
679 printf("No explicit device driver match.\n");
680 #endif
681 }
682 return bestmatch;
683 }
684