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