1 /* 2 * Written by Julian Elischer (julian@tfs.com) 3 * for TRW Financial Systems for use under the MACH(2.5) operating system. 4 * Hacked by Theo de Raadt <deraadt@fsa.ca> 5 * 6 * TRW Financial Systems, in accordance with their agreement with Carnegie 7 * Mellon University, makes this software available to CMU to distribute 8 * or use in any manner that they see fit as long as this message is kept with 9 * the software. For this reason TFS also grants any other persons or 10 * organisations permission to use or modify this software. 11 * 12 * TFS supplies this software to be publicly redistributed 13 * on the understanding that TFS is not responsible for the correct 14 * functioning of this software in any circumstances. 15 * 16 * $Id: scsiconf.c,v 1.9 1993/05/27 10:14:02 deraadt Exp $ 17 */ 18 19 #include "sys/types.h" 20 #include "sys/param.h" 21 #include "sys/systm.h" 22 #include "sys/errno.h" 23 #include "sys/ioctl.h" 24 #include "sys/buf.h" 25 #include "sys/proc.h" 26 #include "sys/user.h" 27 #include "sys/dkbad.h" 28 #include "sys/disklabel.h" 29 #include "scsi/scsi_all.h" 30 #include "scsi/scsiconf.h" 31 32 #include "st.h" 33 #include "sd.h" 34 #include "ch.h" 35 #include "cd.h" 36 #define NBLL 0 37 #define NCALS 0 38 #define NKIL 0 39 40 #if NSD > 0 41 extern int sdattach(); 42 #endif NSD 43 #if NST > 0 44 extern int stattach(); 45 #endif NST 46 #if NCH > 0 47 extern int chattach(); 48 #endif NCH 49 #if NCD > 0 50 extern int cdattach(); 51 #endif NCD 52 #if NBLL > 0 53 extern int bllattach(); 54 #endif NBLL 55 #if NCALS > 0 56 extern int calsattach(); 57 #endif NCALS 58 #if NKIL > 0 59 extern int kil_attach(); 60 #endif NKIL 61 62 struct scsidevs knowndevs[] = { 63 #if NSD > 0 64 { 65 SC_TSD, T_DIRECT, T_FIXED, "standard", "any" ,"any", 66 sdattach, "sd" ,SC_ONE_LU 67 }, { 68 SC_TSD, T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S ", "B5A ", 69 sdattach, "mx1", SC_ONE_LU 70 }, 71 #endif NSD 72 #if NST > 0 73 { 74 SC_TST, T_SEQUENTIAL, T_REMOV, "standard", "any", "any", 75 stattach, "st" ,SC_ONE_LU 76 }, 77 #endif NST 78 #if NCD > 0 79 { 80 SC_TCD, T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 ", "3.1a", 81 cdattach, "cd", SC_ONE_LU 82 }, { 83 SC_TCD, T_READONLY, T_REMOV, "PIONEER ", "CD-ROM DRM-600 ", "any", 84 cdattach, "cd", SC_MORE_LUS 85 }, 86 #endif NCD 87 #if NCALS > 0 88 { 89 -1, T_PROCESSOR, T_FIXED, "standard" , "any" ,"any", 90 calsattach, "cals", SC_MORE_LUS 91 } 92 #endif NCALS 93 #if NCH > 0 94 { 95 -1, T_CHANGER, T_REMOV, "standard", "any", "any", 96 chattach, "ch", SC_ONE_LU 97 }, 98 #endif NCH 99 #if NBLL > 0 100 { 101 -1, T_PROCESSOR, T_FIXED, "AEG ", "READER ", "V1.0", 102 bllattach, "bll", SC_MORE_LUS 103 }, 104 #endif NBLL 105 #if NKIL > 0 106 { 107 -1, T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 ", "any", 108 kil_attach, "kil", SC_ONE_LU 109 }, 110 #endif NKIL 111 }; 112 113 /* controls debug level within the scsi subsystem: see scsiconf.h */ 114 int scsi_debug = 0; 115 116 struct scsidevs * 117 scsi_probe(int masunit, struct scsi_switch *sw, int physid, int type, int want) 118 { 119 static struct scsi_inquiry_data inqbuf; 120 struct scsidevs *ret = (struct scsidevs *)0; 121 int targ = physid >> 3; 122 int lun = physid & 7; 123 char *qtype=NULL, *dtype=NULL, *desc; 124 char manu[9], model[17], revision[5]; 125 int len; 126 127 bzero(&inqbuf, sizeof inqbuf); 128 129 /*printf("probe: %s%d targ %d lun %d\n", 130 sw->name, masunit, targ, lun);*/ 131 132 if( scsi_ready(masunit, targ, lun, sw, 133 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) 134 return (struct scsidevs *)-1; 135 136 if( scsi_inquire(masunit, targ, lun, sw, (u_char *)&inqbuf, 137 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) 138 return (struct scsidevs *)0; 139 140 if( inqbuf.device_qualifier==3 && inqbuf.device_type==T_NODEVICE) 141 return (struct scsidevs *)0; 142 143 switch(inqbuf.device_qualifier) { 144 case 0: 145 qtype = ""; 146 break; 147 case 1: 148 qtype = "Unit not Connected!"; 149 break; 150 case 2: 151 qtype =", Reserved Peripheral Qualifier!"; 152 break; 153 case 3: 154 qtype = ", The Target can't support this Unit!"; 155 break; 156 default: 157 dtype = "vendor specific"; 158 qtype = ""; 159 break; 160 } 161 162 if (dtype == NULL) { 163 switch(inqbuf.device_type) { 164 case T_DIRECT: 165 dtype = "direct"; 166 break; 167 case T_SEQUENTIAL: 168 dtype = "seq"; 169 break; 170 case T_PRINTER: 171 dtype = "pr"; 172 break; 173 case T_PROCESSOR: 174 dtype = "cpu"; 175 break; 176 case T_READONLY: 177 dtype = "ro"; 178 break; 179 case T_WORM: 180 dtype = "worm"; 181 break; 182 case T_SCANNER: 183 dtype = "scan"; 184 break; 185 case T_OPTICAL: 186 dtype = "optic"; 187 break; 188 case T_CHANGER: 189 dtype = "changer"; 190 break; 191 case T_COMM: 192 dtype = "comm"; 193 break; 194 default: 195 dtype = "???"; 196 break; 197 } 198 } 199 200 if(inqbuf.ansii_version > 0) { 201 len = inqbuf.additional_length + 202 ((char *)inqbuf.unused - (char *)&inqbuf); 203 if( len > sizeof(struct scsi_inquiry_data) - 1) 204 len = sizeof(struct scsi_inquiry_data) - 1; 205 desc = inqbuf.vendor; 206 desc[len-(desc-(char *)&inqbuf)] = 0; 207 strncpy(manu, inqbuf.vendor, sizeof inqbuf.vendor); 208 manu[sizeof inqbuf.vendor] = '\0'; 209 strncpy(model, inqbuf.product, sizeof inqbuf.product); 210 model[sizeof inqbuf.product] = '\0'; 211 strncpy(revision, inqbuf.revision, sizeof inqbuf.revision); 212 revision[sizeof inqbuf.revision] = '\0'; 213 } else { 214 desc = "early protocol device"; 215 strcpy(manu, "????"); 216 strcpy(model, ""); 217 strcpy(revision, ""); 218 } 219 220 if(want) 221 goto print; 222 223 ret = selectdev(masunit, targ, lun, sw, inqbuf.device_qualifier, 224 inqbuf.device_type, inqbuf.removable, manu, model, revision, type); 225 if(sw->printed[targ] & (1<<lun)) 226 return ret; 227 228 print: 229 printf("%s%d targ %d lun %d: type %d(%s) %s <%s%s%s> SCSI%d\n", 230 sw->name, masunit, targ, lun, 231 inqbuf.device_type, dtype, 232 inqbuf.removable ? "removable" : "fixed", 233 manu, model, revision, inqbuf.ansii_version); 234 if(qtype[0]) 235 printf("%s%d targ %d lun %d: qualifier %d(%s)\n", 236 sw->name, masunit, targ, lun, 237 inqbuf.device_qualifier, qtype); 238 sw->printed[targ] |= (1<<lun); 239 return ret; 240 } 241 242 void 243 scsi_warn(int masunit, int mytarg, struct scsi_switch *sw) 244 { 245 struct scsidevs *match = (struct scsidevs *)0; 246 int physid; 247 int targ, lun; 248 249 for(targ=0; targ<8; targ++) { 250 if(targ==mytarg) 251 continue; 252 for(lun=0; lun<8; lun++) { 253 /* check if device already used, or empty */ 254 if( sw->empty[targ] & (1<<lun) ) 255 continue; 256 if( sw->used[targ] & (1<<lun) ) 257 continue; 258 259 physid = targ*8 + lun; 260 match = scsi_probe(masunit, sw, physid, 0, 0); 261 262 if(match == (struct scsidevs *)-1) { 263 if(lun==0) 264 sw->empty[targ] = 0xff; 265 else 266 sw->empty[targ] = 0xff; 267 continue; 268 } 269 if(match) { 270 targ = physid >> 3; 271 lun = physid & 7; 272 if(match->flags & SC_MORE_LUS) 273 sw->empty[targ] |= (1<<lun); 274 else 275 sw->empty[targ] = 0xff; 276 } 277 } 278 } 279 } 280 281 /* 282 * not quite perfect. If we have two "drive ?" entries, this will 283 * probe through all the devices twice. It should have realized that 284 * any device that is not found the first time won't exist later on. 285 */ 286 int 287 scsi_attach(int masunit, int mytarg, struct scsi_switch *sw, 288 int *physid, int *unit, int type) 289 { 290 struct scsidevs *match = (struct scsidevs *)0; 291 int targ, lun; 292 int ret=0; 293 294 /*printf("%s%d probing at targ %d lun %d..\n", 295 sw->name, masunit, *physid >> 3, *physid & 7);*/ 296 297 if( *physid!=-1 ) { 298 targ = *physid >> 3; 299 lun = *physid & 7; 300 301 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) ) 302 return 0; 303 304 match = scsi_probe(masunit, sw, *physid, type, 0); 305 if(match == (struct scsidevs *)-1) { 306 match = (struct scsidevs *)0; 307 if(lun==0) 308 sw->empty[targ] = 0xff; 309 else 310 sw->empty[targ] |= (1<<lun); 311 return 0; 312 } 313 314 if(!match) 315 return 0; 316 317 ret = (*(match->attach_rtn))(masunit, sw, *physid, unit); 318 goto success; 319 } 320 321 for(targ=0; targ<8; targ++) { 322 if(targ==mytarg) 323 continue; 324 for(lun=0; lun<8; lun++) { 325 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) ) 326 continue; 327 328 *physid = targ*8 + lun; 329 match = scsi_probe(masunit, sw, *physid, type, 0); 330 if( match==(struct scsidevs *)-1) { 331 if(lun==0) 332 sw->empty[targ] = 0xff; 333 else 334 sw->empty[targ] |= (1<<lun); 335 match = (struct scsidevs *)0; 336 continue; 337 } 338 if(!match) 339 break; 340 ret = (*(match->attach_rtn))(masunit, sw, *physid, unit); 341 if(ret) 342 goto success; 343 return 0; 344 } 345 } 346 *physid = -1; /* failed... */ 347 return 0; 348 349 success: 350 targ = *physid >> 3; 351 lun = *physid & 7; 352 if(match->flags & SC_MORE_LUS) 353 sw->used[targ] |= (1<<lun); 354 else 355 sw->used[targ] = 0xff; 356 return ret; 357 } 358 359 /* 360 * Try make as good a match as possible with 361 * available sub drivers 362 */ 363 struct scsidevs * 364 selectdev(int unit, int target, int lu, struct scsi_switch *sw, int qual, 365 int dtype, int remov, char *manu, char *model, char *rev, int type) 366 { 367 struct scsidevs *sdbest = (struct scsidevs *)0; 368 struct scsidevs *sdent = knowndevs; 369 int numents = sizeof(knowndevs)/sizeof(struct scsidevs); 370 int count = 0, sdbestes = 0; 371 372 dtype |= (qual << 5); 373 374 sdent--; 375 while( count++ < numents) { 376 sdent++; 377 if(dtype != sdent->dtype) 378 continue; 379 if(type != sdent->type) 380 continue; 381 if(sdbestes < 1) { 382 sdbestes = 1; 383 sdbest = sdent; 384 } 385 if(remov != sdent->removable) 386 continue; 387 if(sdbestes < 2) { 388 sdbestes = 2; 389 sdbest = sdent; 390 } 391 if(sdent->flags & SC_SHOWME) 392 printf("\n%s-\n%s-", sdent->manufacturer, manu); 393 if(strcmp(sdent->manufacturer, manu)) 394 continue; 395 if(sdbestes < 3) { 396 sdbestes = 3; 397 sdbest = sdent; 398 } 399 if(sdent->flags & SC_SHOWME) 400 printf("\n%s-\n%s-",sdent->model, model); 401 if(strcmp(sdent->model, model)) 402 continue; 403 if(sdbestes < 4) { 404 sdbestes = 4; 405 sdbest = sdent; 406 } 407 if(sdent->flags & SC_SHOWME) 408 printf("\n%s-\n%s-",sdent->version, rev); 409 if(strcmp(sdent->version, rev)) 410 continue; 411 if(sdbestes < 5) { 412 sdbestes = 5; 413 sdbest = sdent; 414 break; 415 } 416 } 417 return sdbest; 418 } 419 420 /* 421 * Do a scsi operation asking a device if it is 422 * ready. Use the scsi_cmd routine in the switch 423 * table. 424 */ 425 int 426 scsi_ready(int unit, int target, int lu, 427 struct scsi_switch *sw, int flags) 428 { 429 struct scsi_test_unit_ready scsi_cmd; 430 struct scsi_xfer scsi_xfer; 431 volatile int rval; 432 int key; 433 434 bzero(&scsi_cmd, sizeof(scsi_cmd)); 435 bzero(&scsi_xfer, sizeof(scsi_xfer)); 436 scsi_cmd.op_code = TEST_UNIT_READY; 437 438 scsi_xfer.flags = flags | INUSE; 439 scsi_xfer.adapter = unit; 440 scsi_xfer.targ = target; 441 scsi_xfer.lu = lu; 442 scsi_xfer.cmd = (struct scsi_generic *)&scsi_cmd; 443 scsi_xfer.retries = 8; 444 scsi_xfer.timeout = 10000; 445 scsi_xfer.cmdlen = sizeof(scsi_cmd); 446 scsi_xfer.data = 0; 447 scsi_xfer.datalen = 0; 448 scsi_xfer.resid = 0; 449 scsi_xfer.when_done = 0; 450 scsi_xfer.done_arg = 0; 451 retry: scsi_xfer.error = 0; 452 453 /* don't use interrupts! */ 454 455 rval = (*(sw->scsi_cmd))(&scsi_xfer); 456 if (rval != COMPLETE) { 457 if(scsi_debug) { 458 printf("scsi error, rval = 0x%x\n", rval); 459 printf("code from driver: 0x%x\n", scsi_xfer.error); 460 } 461 switch(scsi_xfer.error) { 462 case XS_SENSE: 463 /* 464 * Any sense value is illegal except UNIT ATTENTION 465 * In which case we need to check again to get the 466 * correct response. (especially exabytes) 467 */ 468 if(scsi_xfer.sense.error_class == 7 ) { 469 key = scsi_xfer.sense.ext.extended.sense_key ; 470 switch(key) { 471 case 2: /* not ready BUT PRESENT! */ 472 return(COMPLETE); 473 case 6: 474 spinwait(1000); 475 if(scsi_xfer.retries--) { 476 scsi_xfer.flags &= ~ITSDONE; 477 goto retry; 478 } 479 return(COMPLETE); 480 default: 481 if(scsi_debug) 482 printf("%d:%d,key=%x.", target, 483 lu, key); 484 } 485 } 486 return(HAD_ERROR); 487 case XS_BUSY: 488 spinwait(1000); 489 if(scsi_xfer.retries--) { 490 scsi_xfer.flags &= ~ITSDONE; 491 goto retry; 492 } 493 return COMPLETE; /* it's busy so it's there */ 494 case XS_TIMEOUT: 495 default: 496 return HAD_ERROR; 497 } 498 } 499 return COMPLETE; 500 } 501 502 /* 503 * Do a scsi operation asking a device what it is 504 * Use the scsi_cmd routine in the switch table. 505 */ 506 int 507 scsi_inquire(int unit, int target, int lu, struct scsi_switch *sw, 508 u_char *inqbuf, int flags) 509 { 510 struct scsi_inquiry scsi_cmd; 511 struct scsi_xfer scsi_xfer; 512 513 bzero(&scsi_cmd, sizeof(scsi_cmd)); 514 bzero(&scsi_xfer, sizeof(scsi_xfer)); 515 scsi_cmd.op_code = INQUIRY; 516 scsi_cmd.length = sizeof(struct scsi_inquiry_data); 517 518 scsi_xfer.flags = flags | SCSI_DATA_IN | INUSE; 519 scsi_xfer.adapter = unit; 520 scsi_xfer.targ = target; 521 scsi_xfer.lu = lu; 522 scsi_xfer.retries = 8; 523 scsi_xfer.timeout = 10000; 524 scsi_xfer.cmd = (struct scsi_generic *)&scsi_cmd; 525 scsi_xfer.cmdlen = sizeof(struct scsi_inquiry); 526 scsi_xfer.data = inqbuf; 527 scsi_xfer.datalen = sizeof(struct scsi_inquiry_data); 528 scsi_xfer.resid = sizeof(struct scsi_inquiry_data); 529 scsi_xfer.when_done = 0; 530 scsi_xfer.done_arg = 0; 531 532 retry: 533 scsi_xfer.error=0; 534 /* don't use interrupts! */ 535 536 if ((*(sw->scsi_cmd))(&scsi_xfer) != COMPLETE) { 537 if(scsi_debug) 538 printf("inquiry had error(0x%x) ",scsi_xfer.error); 539 switch(scsi_xfer.error) { 540 case XS_NOERROR: 541 break; 542 case XS_SENSE: 543 /* 544 * Any sense value is illegal except UNIT ATTENTION 545 * In which case we need to check again to get the 546 * correct response. (especially exabytes) 547 */ 548 if( scsi_xfer.sense.error_class==7 && 549 scsi_xfer.sense.ext.extended.sense_key==6) { 550 /* it's changed so it's there */ 551 spinwait(1000); 552 if(scsi_xfer.retries--) { 553 scsi_xfer.flags &= ~ITSDONE; 554 goto retry; 555 } 556 return COMPLETE; 557 } 558 return HAD_ERROR; 559 case XS_BUSY: 560 spinwait(1000); 561 if(scsi_xfer.retries--) { 562 scsi_xfer.flags &= ~ITSDONE; 563 goto retry; 564 } 565 case XS_TIMEOUT: 566 default: 567 return(HAD_ERROR); 568 } 569 } 570 return COMPLETE; 571 } 572 573 /* 574 * convert a physical address to 3 bytes, 575 * MSB at the lowest address, 576 * LSB at the highest. 577 */ 578 void 579 lto3b(u_long val, u_char *bytes) 580 { 581 *bytes++ = (val&0xff0000)>>16; 582 *bytes++ = (val&0xff00)>>8; 583 *bytes = val&0xff; 584 } 585 586 /* 587 * The reverse of lto3b 588 */ 589 u_long 590 _3btol(u_char *bytes) 591 { 592 u_long rc; 593 594 rc = (*bytes++ << 16); 595 rc += (*bytes++ << 8); 596 rc += *bytes; 597 return rc; 598 } 599 600