Commit | Line | Data |
---|---|---|
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 |
51 | extern sdattach(); |
52 | #endif /* NSD */ | |
15637ed4 | 53 | #if NST > 0 |
519fb2b7 RG |
54 | extern stattach(); |
55 | #endif /* NST */ | |
15637ed4 | 56 | #if NCH > 0 |
519fb2b7 RG |
57 | extern chattach(); |
58 | #endif /* NCH */ | |
15637ed4 | 59 | #if NCD > 0 |
519fb2b7 RG |
60 | extern cdattach(); |
61 | #endif /* NCD */ | |
15637ed4 | 62 | #if NBLL > 0 |
519fb2b7 RG |
63 | extern bllattach(); |
64 | #endif /* NBLL */ | |
15637ed4 | 65 | #if NCALS > 0 |
519fb2b7 RG |
66 | extern calsattach(); |
67 | #endif /* NCALS */ | |
15637ed4 | 68 | #if NKIL > 0 |
519fb2b7 RG |
69 | extern kil_attach(); |
70 | #endif /* NKIL */ | |
71 | #if NUK > 0 | |
72 | extern 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 | */ | |
83 | struct 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 | */ | |
89 | struct 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 | */ | |
114 | struct 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 | ||
130 | static struct scsidevs unknowndev = { | |
131 | -1, 0, "standard", "any" | |
132 | ,"any", ukattach, "uk", SC_MORE_LUS | |
133 | }; | |
134 | #endif /*NUK*/ | |
135 | static 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 | */ | |
198 | struct predefined *scsi_get_predef(); | |
199 | struct scsidevs *scsi_probedev(); | |
200 | struct scsidevs *selectdev(); | |
201 | errval scsi_probe_bus __P((int bus, int targ, int lun)); | |
202 | ||
203 | struct 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 | */ | |
218 | int32 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 | */ | |
224 | void | |
225 | scsi_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 | */ | |
257 | errval | |
258 | scsi_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 | */ | |
274 | errval | |
275 | scsi_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 | */ | |
383 | struct predefined * | |
384 | scsi_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 | */ | |
421 | struct scsidevs * | |
422 | scsi_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 | */ | |
631 | struct scsidevs * | |
632 | selectdev(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 | } |