1 /* 2 * Written by Julian Elischer (julian@tfs.com) 3 * Hacked by Theo de Raadt <deraadt@fsa.ca> 4 * for TRW Financial Systems for use under the MACH(2.5) operating system. 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 17 #include "sys/types.h" 18 #include "sys/param.h" 19 #include "sys/systm.h" 20 #include "sys/errno.h" 21 #include "sys/ioctl.h" 22 #include "sys/buf.h" 23 #include "sys/proc.h" 24 #include "sys/user.h" 25 #include "sys/dkbad.h" 26 #include "sys/disklabel.h" 27 #include "scsi/scsi_all.h" 28 #include "scsi/scsiconf.h" 29 30 #include "st.h" 31 #include "sd.h" 32 #include "ch.h" 33 #include "cd.h" 34 #define NBLL 0 35 #define NCALS 0 36 #define NKIL 0 37 38 #if NSD > 0 39 extern int sdattach(); 40 #endif NSD 41 #if NST > 0 42 extern int stattach(); 43 #endif NST 44 #if NCH > 0 45 extern int chattach(); 46 #endif NCH 47 #if NCD > 0 48 extern int cdattach(); 49 #endif NCD 50 #if NBLL > 0 51 extern int bllattach(); 52 #endif NBLL 53 #if NCALS > 0 54 extern int calsattach(); 55 #endif NCALS 56 #if NKIL > 0 57 extern int kil_attach(); 58 #endif NKIL 59 60 struct scsidevs knowndevs[] = { 61 #if NSD > 0 62 { 63 SC_TSD, T_DIRECT, T_FIXED, "standard", "any" ,"any", 64 sdattach, "sd" ,SC_ONE_LU 65 }, { 66 SC_TSD, T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S ", "B5A ", 67 sdattach, "mx1", SC_ONE_LU 68 }, 69 #endif NSD 70 #if NST > 0 71 { 72 SC_TST, T_SEQUENTIAL, T_REMOV, "standard", "any", "any", 73 stattach, "st" ,SC_ONE_LU 74 }, 75 #endif NST 76 #if NCD > 0 77 { 78 SC_TCD, T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 ", "3.1a", 79 cdattach, "cd", SC_ONE_LU 80 }, 81 #endif NCD 82 #if NCALS > 0 83 { 84 -1, T_PROCESSOR, T_FIXED, "standard" , "any" ,"any", 85 calsattach, "cals", SC_MORE_LUS 86 }, 87 #endif NCALS 88 #if NCH > 0 89 { 90 -1, T_CHANGER, T_REMOV, "standard", "any", "any", 91 chattach, "ch", SC_ONE_LU 92 }, 93 #endif NCH 94 #if NBLL > 0 95 { 96 -1, T_PROCESSOR, T_FIXED, "AEG ", "READER ", "V1.0", 97 bllattach, "bll", SC_MORE_LUS 98 }, 99 #endif NBLL 100 #if NKIL > 0 101 { 102 -1, T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 ", "any", 103 kil_attach, "kil", SC_ONE_LU 104 }, 105 #endif NKIL 106 }; 107 108 /* controls debug level within the scsi subsystem: see scsiconf.h */ 109 int scsi_debug = 0; 110 111 struct scsidevs * 112 scsi_probe(int masunit, struct scsi_switch *sw, int physid, int type, int want) 113 { 114 static struct scsi_inquiry_data inqbuf; 115 struct scsidevs *ret = (struct scsidevs *)0; 116 int targ = physid >> 3; 117 int lun = physid & 7; 118 char *qtype=NULL, *dtype=NULL, *desc; 119 char manu[9], model[17], revision[5]; 120 int len; 121 122 bzero(&inqbuf, sizeof inqbuf); 123 124 /*printf("probe: %s%d targ %d lun %d\n", 125 sw->name, masunit, targ, lun);*/ 126 127 if( scsi_ready(masunit, targ, lun, sw, 128 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) 129 return (struct scsidevs *)-1; 130 131 if( scsi_inquire(masunit, targ, lun, sw, (u_char *)&inqbuf, 132 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) 133 return (struct scsidevs *)-1; 134 135 if( inqbuf.device_qualifier==3 && inqbuf.device_type==T_NODEVICE) 136 return (struct scsidevs *)-1; 137 138 switch(inqbuf.device_qualifier) { 139 case 0: 140 qtype = ""; 141 break; 142 case 1: 143 qtype = "Unit not Connected!"; 144 break; 145 case 2: 146 qtype =", Reserved Peripheral Qualifier!"; 147 break; 148 case 3: 149 qtype = ", The Target can't support this Unit!"; 150 break; 151 default: 152 dtype = "vendor specific"; 153 qtype = ""; 154 break; 155 } 156 157 if (dtype == NULL) { 158 switch(inqbuf.device_type) { 159 case T_DIRECT: 160 dtype = "direct"; 161 break; 162 case T_SEQUENTIAL: 163 dtype = "seq"; 164 break; 165 case T_PRINTER: 166 dtype = "pr"; 167 break; 168 case T_PROCESSOR: 169 dtype = "cpu"; 170 break; 171 case T_READONLY: 172 dtype = "ro"; 173 break; 174 case T_WORM: 175 dtype = "worm"; 176 break; 177 case T_SCANNER: 178 dtype = "scan"; 179 break; 180 case T_OPTICAL: 181 dtype = "optic"; 182 break; 183 case T_CHANGER: 184 dtype = "changer"; 185 break; 186 case T_COMM: 187 dtype = "comm"; 188 break; 189 default: 190 dtype = "???"; 191 break; 192 } 193 } 194 195 if(inqbuf.ansii_version > 0) { 196 len = inqbuf.additional_length + 197 ((char *)inqbuf.unused - (char *)&inqbuf); 198 if( len > sizeof(struct scsi_inquiry_data) - 1) 199 len = sizeof(struct scsi_inquiry_data) - 1; 200 desc = inqbuf.vendor; 201 desc[len-(desc-(char *)&inqbuf)] = 0; 202 strncpy(manu, inqbuf.vendor, sizeof inqbuf.vendor); 203 manu[sizeof inqbuf.vendor] = '\0'; 204 strncpy(model, inqbuf.product, sizeof inqbuf.product); 205 model[sizeof inqbuf.product] = '\0'; 206 strncpy(revision, inqbuf.revision, sizeof inqbuf.revision); 207 revision[sizeof inqbuf.revision] = '\0'; 208 } else { 209 desc = "early protocol device"; 210 strcpy(manu, "????"); 211 strcpy(model, ""); 212 strcpy(revision, ""); 213 } 214 215 if(want) 216 goto print; 217 218 ret = selectdev(masunit, targ, lun, sw, inqbuf.device_qualifier, 219 inqbuf.device_type, inqbuf.removable, manu, model, revision, type); 220 if(sw->printed[targ] & (1<<lun)) 221 return ret; 222 223 print: 224 printf("%s%d targ %d lun %d: type %d(%s) %s <%s%s%s> SCSI%d\n", 225 sw->name, masunit, targ, lun, 226 inqbuf.device_type, dtype, 227 inqbuf.removable ? "removable" : "fixed", 228 manu, model, revision, inqbuf.ansii_version); 229 if(qtype[0]) 230 printf("%s%d targ %d lun %d: qualifier %d(%s)\n", 231 sw->name, masunit, targ, lun, 232 inqbuf.device_qualifier, qtype); 233 return ret; 234 } 235 236 void 237 scsi_warn(int masunit, int mytarg, struct scsi_switch *sw) 238 { 239 struct scsidevs *match = (struct scsidevs *)0; 240 int physid; 241 int targ, lun; 242 243 for(targ=0; targ<8; targ++) { 244 if(targ==mytarg) 245 continue; 246 for(lun=0; lun<8; lun++) { 247 /* check if device already used, or empty */ 248 if( sw->empty[targ] & (1<<lun) ) 249 continue; 250 if( sw->used[targ] & (1<<lun) ) 251 continue; 252 253 physid = targ*8 + lun; 254 match = scsi_probe(masunit, sw, physid, 0, 0); 255 256 if(match == (struct scsidevs *)-1) { 257 if(lun==0) 258 sw->empty[targ] = 0xff; 259 else 260 sw->empty[targ] = 0xff; 261 continue; 262 } 263 if(match) { 264 targ = physid >> 3; 265 lun = physid & 7; 266 if(match->flags & SC_MORE_LUS) 267 sw->empty[targ] |= (1<<lun); 268 else 269 sw->empty[targ] = 0xff; 270 } 271 } 272 } 273 } 274 275 /* 276 * not quite perfect. If we have two "drive ?" entries, this will 277 * probe through all the devices twice. It should have realized that 278 * any device that is not found the first time won't exist later on. 279 */ 280 int 281 scsi_attach(int masunit, int mytarg, struct scsi_switch *sw, 282 int *physid, int *unit, int type) 283 { 284 struct scsidevs *match = (struct scsidevs *)0; 285 int targ, lun; 286 int ret=0; 287 288 /*printf("%s%d probing at targ %d lun %d..\n", 289 sw->name, masunit, *physid >> 3, *physid & 7);*/ 290 291 if( *physid!=-1 ) { 292 targ = *physid >> 3; 293 lun = *physid & 7; 294 295 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) ) 296 return -1; 297 298 match = scsi_probe(masunit, sw, *physid, type, 0); 299 if(match == (struct scsidevs *)-1) { 300 match = (struct scsidevs *)0; 301 if(lun==0) 302 sw->empty[targ] = 0xff; 303 else 304 sw->empty[targ] |= (1<<lun); 305 return -1; 306 } 307 308 sw->printed[targ] |= (1<<lun); 309 if(!match) 310 return -1; 311 312 ret = (*(match->attach_rtn))(masunit, sw, *physid, *unit); 313 goto success; 314 } 315 316 for(targ=0; targ<8; targ++) { 317 if(targ==mytarg) 318 continue; 319 for(lun=0; lun<8; lun++) { 320 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) ) 321 continue; 322 323 *physid = targ*8 + lun; 324 match = scsi_probe(masunit, sw, *physid, type, 0); 325 if( match==(struct scsidevs *)-1) { 326 if(lun==0) 327 sw->empty[targ] = 0xff; 328 else 329 sw->empty[targ] |= (1<<lun); 330 match = (struct scsidevs *)0; 331 continue; 332 } 333 if(!match) { 334 sw->printed[targ] |= (1<<lun); 335 break; 336 } 337 ret = (*(match->attach_rtn))(masunit, sw, *physid, *unit); 338 if(ret==0) 339 goto success; 340 return -1; 341 } 342 } 343 *physid = -1; /* failed... */ 344 return -1; 345 346 success: 347 targ = *physid >> 3; 348 lun = *physid & 7; 349 if(match->flags & SC_MORE_LUS) { 350 sw->used[targ] |= (1<<lun); 351 sw->printed[targ] |= (1<<lun); 352 } else { 353 sw->used[targ] = 0xff; 354 sw->printed[targ] = 0xff; 355 } 356 return 0; 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