1 /* $NetBSD: scsiconf.c,v 1.17 1994/11/03 22:09:00 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Charles Hannum. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Charles Hannum. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Originally written by Julian Elischer (julian@tfs.com) 34 * for TRW Financial Systems for use under the MACH(2.5) operating system. 35 * 36 * TRW Financial Systems, in accordance with their agreement with Carnegie 37 * Mellon University, makes this software available to CMU to distribute 38 * or use in any manner that they see fit as long as this message is kept with 39 * the software. For this reason TFS also grants any other persons or 40 * organisations permission to use or modify this software. 41 * 42 * TFS supplies this software to be publicly redistributed 43 * on the understanding that TFS is not responsible for the correct 44 * functioning of this software in any circumstances. 45 * 46 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 47 */ 48 49 #include <sys/types.h> 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/malloc.h> 53 #include <sys/device.h> 54 55 #include <scsi/scsi_all.h> 56 #include <scsi/scsiconf.h> 57 58 #include "st.h" 59 #include "sd.h" 60 #include "ch.h" 61 #include "cd.h" 62 #include "uk.h" 63 #include "su.h" 64 65 #ifdef TFS 66 #include "bll.h" 67 #include "cals.h" 68 #include "kil.h" 69 #include "scan.h" 70 #else /* TFS */ 71 #define NBLL 0 72 #define NCALS 0 73 #define NKIL 0 74 #define NSCAN 0 75 #endif /* TFS */ 76 77 /* 78 * The structure of known drivers for autoconfiguration 79 */ 80 struct scsidevs { 81 char *devname; 82 u_int32 type; 83 boolean removable; 84 int flags; /* 1 show my comparisons during boot(debug) */ 85 #define SC_SHOWME 0x01 86 #define SC_ONE_LU 0x00 87 #define SC_MORE_LUS 0x02 88 char *manufacturer; 89 char *model; 90 char *version; 91 }; 92 93 #if NUK > 0 94 static struct scsidevs unknowndev = { 95 "uk", -1, 0, SC_MORE_LUS, 96 "standard", "any", "any" 97 }; 98 #endif /*NUK*/ 99 100 static struct scsidevs knowndevs[] = { 101 #if NSD > 0 102 { "sd", T_DIRECT, T_FIXED, SC_ONE_LU, 103 "standard", "any", "any" }, 104 { "sd", T_DIRECT, T_FIXED, SC_ONE_LU, 105 "MAXTOR ", "XT-4170S ", "B5A " }, 106 #endif /* NSD */ 107 #if NST > 0 108 { "st", T_SEQUENTIAL, T_REMOV, SC_ONE_LU, 109 "standard", "any", "any" }, 110 #endif /* NST */ 111 #if NCALS > 0 112 { "cals", T_PROCESSOR, T_FIXED, SC_MORE_LUS, 113 "standard", "any", "any" }, 114 #endif /* NCALS */ 115 #if NCH > 0 116 { "ch", T_CHANGER, T_REMOV, SC_ONE_LU, 117 "standard", "any", "any" }, 118 #endif /* NCH */ 119 #if NCD > 0 120 #ifndef UKTEST /* make cdroms unrecognised to test the uk driver */ 121 { "cd", T_READONLY, T_REMOV, SC_ONE_LU, 122 "SONY ", "CD-ROM CDU-8012 ", "3.1a" }, 123 { "cd", T_READONLY, T_REMOV, SC_MORE_LUS, 124 "PIONEER ", "CD-ROM DRM-600 ", "any" }, 125 #endif 126 #endif /* NCD */ 127 #if NBLL > 0 128 { "bll", T_PROCESSOR, T_FIXED, SC_MORE_LUS, 129 "AEG ", "READER ", "V1.0" }, 130 #endif /* NBLL */ 131 #if NKIL > 0 132 { "kil", T_SCANNER, T_FIXED, SC_ONE_LU, 133 "KODAK ", "IL Scanner 900 ", "any" }, 134 #endif /* NKIL */ 135 { 0 } 136 }; 137 138 /* 139 * Declarations 140 */ 141 struct scsidevs *scsi_probedev(); 142 struct scsidevs *selectdev(); 143 int scsi_probe_bus __P((int bus, int targ, int lun)); 144 145 struct scsi_device probe_switch = { 146 NULL, 147 NULL, 148 NULL, 149 NULL, 150 "probe", 151 0, 152 }; 153 154 int scsibusmatch __P((struct device *, void *, void *)); 155 void scsibusattach __P((struct device *, struct device *, void *)); 156 157 struct cfdriver scsibuscd = { 158 NULL, "scsibus", scsibusmatch, scsibusattach, DV_DULL, 159 sizeof(struct scsibus_data) 160 }; 161 162 int 163 scsibusmatch(parent, match, aux) 164 struct device *parent; 165 void *match, *aux; 166 { 167 168 return 1; 169 } 170 171 /* 172 * The routine called by the adapter boards to get all their 173 * devices configured in. 174 */ 175 void 176 scsibusattach(parent, self, aux) 177 struct device *parent, *self; 178 void *aux; 179 { 180 struct scsibus_data *sb = (struct scsibus_data *)self; 181 struct scsi_link *sc_link_proto = aux; 182 183 sc_link_proto->scsibus = sb->sc_dev.dv_unit; 184 sb->adapter_link = sc_link_proto; 185 printf("\n"); 186 187 #if defined(SCSI_DELAY) && SCSI_DELAY > 2 188 printf("%s: waiting for scsi devices to settle\n", 189 sb->sc_dev.dv_xname); 190 #else /* SCSI_DELAY > 2 */ 191 #undef SCSI_DELAY 192 #define SCSI_DELAY 2 193 #endif /* SCSI_DELAY */ 194 delay(1000000 * SCSI_DELAY); 195 196 scsi_probe_bus(sb->sc_dev.dv_unit, -1, -1); 197 } 198 199 /* 200 * Probe the requested scsi bus. It must be already set up. 201 * -1 requests all set up scsi busses. 202 * targ and lun optionally narrow the search if not -1 203 */ 204 int 205 scsi_probe_busses(bus, targ, lun) 206 int bus, targ, lun; 207 { 208 209 if (bus == -1) { 210 for (bus = 0; bus < scsibuscd.cd_ndevs; bus++) 211 if (scsibuscd.cd_devs[bus]) 212 scsi_probe_bus(bus, targ, lun); 213 return 0; 214 } else { 215 return scsi_probe_bus(bus, targ, lun); 216 } 217 } 218 219 /* 220 * Probe the requested scsi bus. It must be already set up. 221 * targ and lun optionally narrow the search if not -1 222 */ 223 int 224 scsi_probe_bus(bus, targ, lun) 225 int bus, targ, lun; 226 { 227 struct scsibus_data *scsi; 228 int maxtarg, mintarg, maxlun, minlun; 229 struct scsi_link *sc_link_proto; 230 u_int8 scsi_addr ; 231 struct scsidevs *bestmatch = NULL; 232 struct scsi_link *sc_link = NULL; 233 boolean maybe_more; 234 235 if (bus < 0 || bus >= scsibuscd.cd_ndevs) 236 return ENXIO; 237 scsi = scsibuscd.cd_devs[bus]; 238 if (!scsi) 239 return ENXIO; 240 241 sc_link_proto = scsi->adapter_link; 242 scsi_addr = sc_link_proto->adapter_targ; 243 244 if (targ == -1) { 245 maxtarg = 7; 246 mintarg = 0; 247 } else { 248 if (targ < 0 || targ > 7) 249 return EINVAL; 250 maxtarg = mintarg = targ; 251 } 252 253 if (lun == -1) { 254 maxlun = 7; 255 minlun = 0; 256 } else { 257 if (lun < 0 || lun > 7) 258 return EINVAL; 259 maxlun = minlun = lun; 260 } 261 262 for (targ = mintarg; targ <= maxtarg; targ++) { 263 maybe_more = 0; /* by default only check 1 lun */ 264 #if 0 /* XXXX */ 265 if (targ == scsi_addr) 266 continue; 267 #endif 268 for (lun = minlun; lun <= maxlun; lun++) { 269 /* 270 * The spot appears to already have something 271 * linked in, skip past it. Must be doing a 'reprobe' 272 */ 273 if (scsi->sc_link[targ][lun]) { 274 /* don't do this one, but check other luns */ 275 maybe_more = 1; 276 continue; 277 } 278 /* 279 * If we presently don't have a link block 280 * then allocate one to use while probing 281 */ 282 if (!sc_link) { 283 sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT); 284 *sc_link = *sc_link_proto; /* struct copy */ 285 sc_link->opennings = 1; 286 sc_link->device = &probe_switch; 287 } 288 sc_link->target = targ; 289 sc_link->lun = lun; 290 bestmatch = scsi_probedev(sc_link, &maybe_more); 291 /* 292 * We already know what the device is. We use a 293 * special matching routine which insists that the 294 * cfdata is of the right type rather than putting 295 * more intelligence in individual match routines for 296 * each high-level driver. We must have 297 * scsi_targmatch() do all of the comparisons, or we 298 * could get stuck in an infinite loop trying the same 299 * device repeatedly. We use the `fordriver' field of 300 * the scsi_link for now, rather than inventing a new 301 * structure just for the config_search(). 302 */ 303 if (bestmatch) { 304 sc_link->fordriver = bestmatch->devname; 305 if (config_found((struct device *)scsi, 306 sc_link, NULL)) { 307 scsi->sc_link[targ][lun] = sc_link; 308 sc_link = NULL; /* it's been used */ 309 } else 310 printf("No matching config entry.\n"); 311 } 312 if (!maybe_more)/* nothing suggests we'll find more */ 313 break; /* nothing here, skip to next targ */ 314 /* otherwise something says we should look further */ 315 } 316 } 317 if (sc_link) 318 free(sc_link, M_TEMP); 319 return 0; 320 } 321 322 int 323 scsi_targmatch(parent, match, aux) 324 struct device *parent; 325 void *match, *aux; 326 { 327 struct cfdata *cf = match; 328 struct scsi_link *sc_link = aux; 329 char *devname = sc_link->fordriver; 330 331 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sc_link->target) 332 return 0; 333 if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != sc_link->lun) 334 return 0; 335 if (strcmp(cf->cf_driver->cd_name, devname)) 336 return 0; 337 338 return 1; 339 } 340 341 /* 342 * given a target and lu, ask the device what 343 * it is, and find the correct driver table 344 * entry. 345 */ 346 struct scsidevs * 347 scsi_probedev(sc_link, maybe_more) 348 boolean *maybe_more; 349 struct scsi_link *sc_link; 350 { 351 u_int8 target = sc_link->target; 352 u_int8 lun = sc_link->lun; 353 struct scsi_adapter *scsi_adapter = sc_link->adapter; 354 struct scsidevs *bestmatch = NULL; 355 char *dtype = NULL, *desc; 356 char *qtype; 357 static struct scsi_inquiry_data inqbuf; 358 u_int32 len, qualifier, type; 359 boolean remov; 360 char manu[32]; 361 char model[32]; 362 char version[32]; 363 364 bzero(&inqbuf, sizeof(inqbuf)); 365 /* 366 * Ask the device what it is 367 */ 368 #ifdef SCSIDEBUG 369 if (target == DEBUGTARG && lun == DEBUGLUN) 370 sc_link->flags |= DEBUGLEVEL; 371 else 372 sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4); 373 #endif /* SCSIDEBUG */ 374 /* catch unit attn */ 375 scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); 376 #ifdef DOUBTFULL 377 switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { 378 case 0: /* said it WAS ready */ 379 case EBUSY: /* replied 'NOT READY' but WAS present, continue */ 380 case ENXIO: 381 break; 382 case EIO: /* device timed out */ 383 case EINVAL: /* Lun not supported */ 384 default: 385 return NULL; 386 387 } 388 #endif /*DOUBTFULL*/ 389 #ifdef SCSI_2_DEF 390 /* some devices need to be told to go to SCSI2 */ 391 /* However some just explode if you tell them this.. leave it out */ 392 scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); 393 #endif /*SCSI_2_DEF */ 394 395 /* Now go ask the device all about itself */ 396 if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) 397 return NULL; 398 399 /* 400 * note what BASIC type of device it is 401 */ 402 type = inqbuf.device & SID_TYPE; 403 qualifier = inqbuf.device & SID_QUAL; 404 remov = inqbuf.dev_qual2 & SID_REMOVABLE; 405 406 /* 407 * Any device qualifier that has the top bit set (qualifier&4 != 0) 408 * is vendor specific and won't match in this switch. 409 */ 410 switch (qualifier) { 411 case SID_QUAL_LU_OK: 412 qtype = ""; 413 break; 414 415 case SID_QUAL_LU_OFFLINE: 416 qtype = ", Unit not Connected!"; 417 break; 418 419 case SID_QUAL_RSVD: 420 qtype = ", Reserved Peripheral Qualifier!"; 421 *maybe_more = 1; 422 return NULL; 423 break; 424 425 case SID_QUAL_BAD_LU: 426 /* 427 * Check for a non-existent unit. If the device is returning 428 * this much, then we must set the flag that has 429 * the searchers keep looking on other luns. 430 */ 431 qtype = ", The Target can't support this Unit!"; 432 *maybe_more = 1; 433 return NULL; 434 435 default: 436 dtype = "vendor specific"; 437 qtype = ""; 438 *maybe_more = 1; 439 break; 440 } 441 if (dtype == 0) { 442 switch (type) { 443 case T_DIRECT: 444 dtype = "direct"; 445 break; 446 case T_SEQUENTIAL: 447 dtype = "sequential"; 448 break; 449 case T_PRINTER: 450 dtype = "printer"; 451 break; 452 case T_PROCESSOR: 453 dtype = "processor"; 454 break; 455 case T_READONLY: 456 dtype = "readonly"; 457 break; 458 case T_WORM: 459 dtype = "worm"; 460 break; 461 case T_SCANNER: 462 dtype = "scanner"; 463 break; 464 case T_OPTICAL: 465 dtype = "optical"; 466 break; 467 case T_CHANGER: 468 dtype = "changer"; 469 break; 470 case T_COMM: 471 dtype = "communication"; 472 break; 473 case T_NODEVICE: 474 *maybe_more = 1; 475 return NULL; 476 default: 477 dtype = NULL; 478 break; 479 } 480 } 481 482 /* 483 * Then if it's advanced enough, more detailed 484 * information 485 */ 486 if ((inqbuf.version & SID_ANSII) > 0) { 487 if ((len = inqbuf.additional_length 488 + ((char *) inqbuf.unused 489 - (char *) &inqbuf)) 490 > (sizeof(struct scsi_inquiry_data) - 1)) 491 len = sizeof(struct scsi_inquiry_data) - 1; 492 desc = inqbuf.vendor; 493 desc[len - (desc - (char *) &inqbuf)] = 0; 494 strncpy(manu, inqbuf.vendor, 8); 495 manu[8] = 0; 496 strncpy(model, inqbuf.product, 16); 497 model[16] = 0; 498 strncpy(version, inqbuf.revision, 4); 499 version[4] = 0; 500 } else 501 /* 502 * If not advanced enough, use default values 503 */ 504 { 505 desc = "early protocol device"; 506 strncpy(manu, "unknown", 8); 507 strncpy(model, "unknown", 16); 508 strncpy(version, "????", 4); 509 } 510 printf("%s targ %d lun %d: <%s%s%s> SCSI%d ", 511 ((struct device *)sc_link->adapter_softc)->dv_xname, 512 target, lun, manu, model, version, 513 inqbuf.version & SID_ANSII); 514 if (dtype) 515 printf("%s", dtype); 516 else 517 printf("type %d", type); 518 printf(" %s\n", remov ? "removable" : "fixed"); 519 if (qtype[0]) 520 printf("%s targ %d lun %d: qualifier %d(%s)\n", 521 ((struct device *)sc_link->adapter_softc)->dv_xname, 522 target, lun, qualifier, qtype); 523 524 /* 525 * Try make as good a match as possible with 526 * available sub drivers 527 */ 528 bestmatch = selectdev(qualifier, type, remov ? T_REMOV : T_FIXED, 529 manu, model, version); 530 if (bestmatch && bestmatch->flags & SC_MORE_LUS) 531 *maybe_more = 1; 532 return bestmatch; 533 } 534 535 /* 536 * Try make as good a match as possible with 537 * available sub drivers 538 */ 539 struct scsidevs * 540 selectdev(qualifier, type, remov, manu, model, rev) 541 u_int32 qualifier, type; 542 boolean remov; 543 char *manu, *model, *rev; 544 { 545 u_int32 numents = (sizeof(knowndevs) / sizeof(struct scsidevs)) - 1; 546 u_int32 count = 0; 547 u_int32 bestmatches = 0; 548 struct scsidevs *bestmatch = (struct scsidevs *) 0; 549 struct scsidevs *thisentry = knowndevs; 550 551 type |= qualifier; /* why? */ 552 553 thisentry--; 554 while (count++ < numents) { 555 thisentry++; 556 if (type != thisentry->type) 557 continue; 558 if (bestmatches < 1) { 559 bestmatches = 1; 560 bestmatch = thisentry; 561 } 562 if (remov != thisentry->removable) 563 continue; 564 if (bestmatches < 2) { 565 bestmatches = 2; 566 bestmatch = thisentry; 567 } 568 if (thisentry->flags & SC_SHOWME) 569 printf("\n%s-\n%s-", thisentry->manufacturer, manu); 570 if (strcmp(thisentry->manufacturer, manu)) 571 continue; 572 if (bestmatches < 3) { 573 bestmatches = 3; 574 bestmatch = thisentry; 575 } 576 if (thisentry->flags & SC_SHOWME) 577 printf("\n%s-\n%s-", thisentry->model, model); 578 if (strcmp(thisentry->model, model)) 579 continue; 580 if (bestmatches < 4) { 581 bestmatches = 4; 582 bestmatch = thisentry; 583 } 584 if (thisentry->flags & SC_SHOWME) 585 printf("\n%s-\n%s-", thisentry->version, rev); 586 if (strcmp(thisentry->version, rev)) 587 continue; 588 if (bestmatches < 5) { 589 bestmatches = 5; 590 bestmatch = thisentry; 591 break; 592 } 593 } 594 #if NUK > 0 595 if (!bestmatch) 596 bestmatch = &unknowndev; 597 #endif 598 if (!bestmatch) 599 printf("No matching driver.\n"); 600 return bestmatch; 601 } 602