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