Add the source code for /usr/src/usr.bin from the Net/2 tape
[unix-history] / usr / src / sys.386bsd / scsi / scsiconf.c
CommitLineData
65d7dd25
JE
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 *
15 *
16 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
17 * -------------------- ----- ----------------------
18 * CURRENT PATCH LEVEL: 1 00098
19 * -------------------- ----- ----------------------
20 *
21 * 16 Feb 93 Julian Elischer ADDED for SCSI system
22 */
23
24/*
25 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
26 */
27
28/*
29$Log:
30*
31*/
32#include <sys/types.h>
33#include "st.h"
34#include "sd.h"
35#include "ch.h"
36#include "cd.h"
37
38#ifdef MACH
39#include <i386/machparam.h>
40#endif MACH
41#include <scsi/scsi_all.h>
42#include <scsi/scsiconf.h>
43
44#if !defined(OSF) && !defined(__386BSD__)
45#include "bll.h"
46#include "cals.h"
47#include "kil.h"
48#else
49#define NBLL 0
50#define NCALS 0
51#define NKIL 0
52#endif /* !defined(OSF) && !defined(__386BSD__) */
53
54#if NSD > 0
55extern sdattach();
56#endif NSD
57#if NST > 0
58extern stattach();
59#endif NST
60#if NCH > 0
61extern chattach();
62#endif NCH
63#if NCD > 0
64extern cdattach();
65#endif NCD
66#if NBLL > 0
67extern bllattach();
68#endif NBLL
69#if NCALS > 0
70extern calsattach();
71#endif NCALS
72#if NKIL > 0
73extern kil_attach();
74#endif NKIL
75
76/***************************************************************\
77* The structure of pre-configured devices that might be turned *
78* off and therefore may not show up *
79\***************************************************************/
80struct predefined
81{
82 u_char scsibus;
83 u_char dev;
84 u_char lu;
85 int (*attach_rtn)();
86 char *devname;
87 char flags;
88}
89pd[] =
90{
91#ifdef EXAMPLE_PREDEFINE
92#if NSD > 0
93 {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */
94#endif NSD
95#endif EXAMPLE_PREDEFINE
96 {0,9,9} /*illegal dummy end entry */
97};
98
99
100/***************************************************************\
101* The structure of known drivers for autoconfiguration *
102\***************************************************************/
103static struct scsidevs
104{
105 int type;
106 int removable;
107 char *manufacturer;
108 char *model;
109 char *version;
110 int (*attach_rtn)();
111 char *devname;
112 char flags; /* 1 show my comparisons during boot(debug) */
113}
114#define SC_SHOWME 0x01
115#define SC_ONE_LU 0x00
116#define SC_MORE_LUS 0x02
117knowndevs[] = {
118#if NSD > 0
119 { T_DIRECT,T_FIXED,"standard","any"
120 ,"any",sdattach,"sd",SC_ONE_LU },
121 { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S "
122 ,"B5A ",sdattach,"mx1",SC_ONE_LU },
123#endif NSD
124#if NST > 0
125 { T_SEQUENTIAL,T_REMOV,"standard","any"
126 ,"any",stattach,"st",SC_ONE_LU },
127#endif NST
128#if NCALS > 0
129 { T_PROCESSOR,T_FIXED,"standard","any"
130 ,"any",calsattach,"cals",SC_MORE_LUS },
131#endif NCALS
132#if NCH > 0
133 { T_CHANGER,T_REMOV,"standard","any"
134 ,"any",chattach,"ch",SC_ONE_LU },
135#endif NCH
136#if NCD > 0
137 { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 "
138 ,"3.1a",cdattach,"cd",SC_ONE_LU },
139#endif NCD
140#if NBLL > 0
141 { T_PROCESSOR,T_FIXED,"AEG ","READER "
142 ,"V1.0",bllattach,"bll",SC_MORE_LUS },
143#endif NBLL
144#if NKIL > 0
145 { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 "
146 ,"any",kil_attach,"kil",SC_ONE_LU },
147#endif NKIL
148
149{0}
150};
151/***************************************************************\
152* Declarations *
153\***************************************************************/
154struct predefined *scsi_get_predef();
155struct scsidevs *scsi_probedev();
156struct scsidevs *selectdev();
157
158/* controls debug level within the scsi subsystem */
159/* see scsiconf.h for values */
160int scsi_debug = 0x0;
161int scsibus = 0x0; /* This is the Nth scsibus */
162
163/***************************************************************\
164* The routine called by the adapter boards to get all their *
165* devices configured in. *
166\***************************************************************/
167scsi_attachdevs( unit, scsi_addr, scsi_switch)
168int unit,scsi_addr;
169struct scsi_switch *scsi_switch;
170{
171 int targ,lun;
172 struct scsidevs *bestmatch = (struct scsidevs *)0;
173 struct predefined *predef;
174 int maybe_more;
175
176#ifdef SCSI_DELAY
177#if SCSI_DELAY > 2
178 printf("waiting for scsi devices to settle\n");
179#else SCSI_DELAY > 2
180#define SCSI_DELAY 15
181#endif SCSI_DELAY > 2
182#else
183#define SCSI_DELAY 2
184#endif SCSI_DELAY
185 spinwait(1000 * SCSI_DELAY);
186 targ = 0;
187 while(targ < 8)
188 {
189 maybe_more = 0; /* by default only check 1 lun */
190 if (targ == scsi_addr)
191 {
192 targ++;
193 continue;
194 }
195 lun = 0;
196 while(lun < 8)
197 {
198 predef = scsi_get_predef(scsibus
199 ,targ
200 ,lun
201 ,&maybe_more);
202 bestmatch = scsi_probedev(unit
203 ,targ
204 ,lun
205 ,scsi_switch
206 ,&maybe_more);
207 if((bestmatch) && (predef)) /* both exist */
208 {
209 if(bestmatch->attach_rtn
210 != predef->attach_rtn)
211 {
212 printf("Clash in found/expected devices\n");
213 printf("will link in FOUND\n");
214 }
215 (*(bestmatch->attach_rtn))(unit,
216 targ,
217 lun,
218 scsi_switch);
219 }
220 if((bestmatch) && (!predef)) /* just FOUND */
221 {
222 (*(bestmatch->attach_rtn))(unit,
223 targ,
224 lun,
225 scsi_switch);
226 }
227 if((!bestmatch) && (predef)) /* just predef */
228 {
229 (*(predef->attach_rtn))(unit,
230 targ,
231 lun,
232 scsi_switch);
233 }
234 if(!(maybe_more)) /* nothing suggests we'll find more */
235 {
236 break; /* nothing here, skip to next targ */
237 }
238 /* otherwise something says we should look further*/
239 lun++;
240 }
241 targ++;
242 }
243#if NGENSCSI > 0
244 /***************************************************************\
245 * If available hook up the generic scsi driver, letting it *
246 * know which target is US. (i.e. illegal or at least special) *
247 \***************************************************************/
248 genscsi_attach(unit,scsi_addr,0,scsi_switch);
249#endif
250 scsibus++; /* next time we are on the NEXT scsi bus */
251}
252
253/***********************************************\
254* given a target and lu, check if there is a *
255* predefined device for that address *
256\***********************************************/
257struct predefined *scsi_get_predef(unit,target,lu,maybe_more)
258int unit,target,lu,*maybe_more;
259{
260 int upto,numents;
261
262 numents = (sizeof(pd)/sizeof(struct predefined)) - 1;
263
264 for(upto = 0;upto < numents;upto++)
265 {
266 if(pd[upto].scsibus != unit)
267 continue;
268 if(pd[upto].dev != target)
269 continue;
270 if(pd[upto].lu != lu)
271 continue;
272
273 printf(" dev%d,lu%d: %s - PRECONFIGURED -\n"
274 ,target
275 ,lu
276 ,pd[upto].devname);
277 *maybe_more = pd[upto].flags & SC_MORE_LUS;
278 return(&(pd[upto]));
279 }
280 return((struct predefined *)0);
281}
282
283/***********************************************\
284* given a target and lu, ask the device what *
285* it is, and find the correct driver table *
286* entry. *
287\***********************************************/
288struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more)
289
290struct scsi_switch *scsi_switch;
291int unit,target,lu;
292int *maybe_more;
293{
294 struct scsidevs *bestmatch = (struct scsidevs *)0;
295 char *dtype=(char *)0,*desc;
296 char *qtype;
297 static struct scsi_inquiry_data inqbuf;
298 int len,qualifier,type,remov;
299 char manu[32];
300 char model[32];
301 char version[32];
302
303
304 bzero(&inqbuf,sizeof(inqbuf));
305 /***********************************************\
306 * Ask the device what it is *
307 \***********************************************/
308#ifdef DEBUG
309 if((target == 0) && (lu == 0))
310 scsi_debug = 0xfff;
311 else
312 scsi_debug = 0;
313#endif DEBUG
314 if(scsi_ready( unit,
315 target,
316 lu,
317 scsi_switch,
318 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
319 {
320 return(struct scsidevs *)0;
321 }
322 if(scsi_inquire(unit,
323 target,
324 lu,
325 scsi_switch,
326 &inqbuf,
327 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
328 {
329 return(struct scsidevs *)0;
330 }
331
332 /***********************************************\
333 * note what BASIC type of device it is *
334 \***********************************************/
335 if(scsi_debug & SHOWINQUIRY)
336 {
337 desc=(char *)&inqbuf;
338 printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
339 desc[0], desc[1], desc[2], desc[3],
340 desc[4], desc[5], desc[6], desc[7],
341 desc[8], desc[9], desc[10], desc[11],
342 desc[12]);
343 }
344
345 type = inqbuf.device_type;
346 qualifier = inqbuf.device_qualifier;
347 remov = inqbuf.removable;
348
349 /* Check for a non-existent unit. If the device is returning
350 * this much, then we must set the flag that has
351 * the searcher keep looking on other luns.
352 */
353 if (qualifier == 3 && type == T_NODEVICE)
354 {
355 *maybe_more = 1;
356 return (struct scsidevs *)0;
357 }
358
359 /* Any device qualifier that has
360 * the top bit set (qualifier&4 != 0) is vendor specific and
361 * won't match in this switch.
362 */
363
364 switch(qualifier)
365 {
366 case 0:
367 qtype="";
368 break;
369 case 1:
370 qtype=", Unit not Connected!";
371 break;
372 case 2:
373 qtype=", Reserved Peripheral Qualifier!";
374 break;
375 case 3:
376 qtype=", The Target can't support this Unit!";
377 break;
378
379 default:
380 dtype="vendor specific";
381 qtype="";
382 *maybe_more = 1;
383 break;
384 }
385
386 if (dtype == 0)
387 switch(type)
388 {
389 case T_DIRECT:
390 dtype="direct";
391 break;
392 case T_SEQUENTIAL:
393 dtype="sequential";
394 break;
395 case T_PRINTER:
396 dtype="printer";
397 break;
398 case T_PROCESSOR:
399 dtype="processor";
400 break;
401 case T_READONLY:
402 dtype="readonly";
403 break;
404 case T_WORM:
405 dtype="worm";
406 break;
407 case T_SCANNER:
408 dtype="scanner";
409 break;
410 case T_OPTICAL:
411 dtype="optical";
412 break;
413 case T_CHANGER:
414 dtype="changer";
415 break;
416 case T_COMM:
417 dtype="communication";
418 break;
419 default:
420 dtype="unknown";
421 break;
422 }
423
424 /***********************************************\
425 * Then if it's advanced enough, more detailed *
426 * information *
427 \***********************************************/
428 if(inqbuf.ansii_version > 0)
429 {
430 if ((len = inqbuf.additional_length
431 + ( (char *)inqbuf.unused
432 - (char *)&inqbuf))
433 > (sizeof(struct scsi_inquiry_data) - 1))
434 len = sizeof(struct scsi_inquiry_data) - 1;
435 desc=inqbuf.vendor;
436 desc[len-(desc - (char *)&inqbuf)] = 0;
437 strncpy(manu,inqbuf.vendor,8);manu[8]=0;
438 strncpy(model,inqbuf.product,16);model[16]=0;
439 strncpy(version,inqbuf.revision,4);version[4]=0;
440 }
441 else
442 /***********************************************\
443 * If not advanced enough, use default values *
444 \***********************************************/
445 {
446 desc="early protocol device";
447 strncpy(manu,"unknown",8);
448 strncpy(model,"unknown",16);
449 strncpy(version,"????",4);
450 }
451 printf(" dev%d,lu%d: type %d:%d(%s%s),%s '%s%s%s' scsi%d\n"
452 ,target
453 ,lu
454 ,qualifier,type
455 ,dtype,qtype
456 ,remov?"removable":"fixed"
457 ,manu
458 ,model
459 ,version
460 ,inqbuf.ansii_version
461 );
462 /***********************************************\
463 * Try make as good a match as possible with *
464 * available sub drivers *
465 \***********************************************/
466 bestmatch = (selectdev(unit,target,lu,&scsi_switch,
467 qualifier,type,remov,manu,model,version));
468 if((bestmatch) && (bestmatch->flags & SC_MORE_LUS))
469 {
470 *maybe_more = 1;
471 }
472 return(bestmatch);
473}
474
475/***********************************************\
476* Try make as good a match as possible with *
477* available sub drivers *
478\***********************************************/
479struct scsidevs
480*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev)
481int unit,target,lu;
482struct scsi_switch *dvr_switch;
483int qualifier,type,remov;
484char *manu,*model,*rev;
485{
486 int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1;
487 int count = 0;
488 int bestmatches = 0;
489 struct scsidevs *bestmatch = (struct scsidevs *)0;
490 struct scsidevs *thisentry = knowndevs;
491
492 type |= (qualifier << 5);
493
494 thisentry--;
495 while( count++ < numents)
496 {
497 thisentry++;
498 if(type != thisentry->type)
499 {
500 continue;
501 }
502 if(bestmatches < 1)
503 {
504 bestmatches = 1;
505 bestmatch = thisentry;
506 }
507 if(remov != thisentry->removable)
508 {
509 continue;
510 }
511 if(bestmatches < 2)
512 {
513 bestmatches = 2;
514 bestmatch = thisentry;
515 }
516 if(thisentry->flags & SC_SHOWME)
517 printf("\n%s-\n%s-",thisentry->manufacturer, manu);
518 if(strcmp(thisentry->manufacturer, manu))
519 {
520 continue;
521 }
522 if(bestmatches < 3)
523 {
524 bestmatches = 3;
525 bestmatch = thisentry;
526 }
527 if(thisentry->flags & SC_SHOWME)
528 printf("\n%s-\n%s-",thisentry->model, model);
529 if(strcmp(thisentry->model, model))
530 {
531 continue;
532 }
533 if(bestmatches < 4)
534 {
535 bestmatches = 4;
536 bestmatch = thisentry;
537 }
538 if(thisentry->flags & SC_SHOWME)
539 printf("\n%s-\n%s-",thisentry->version, rev);
540 if(strcmp(thisentry->version, rev))
541 {
542 continue;
543 }
544 if(bestmatches < 5)
545 {
546 bestmatches = 5;
547 bestmatch = thisentry;
548 break;
549 }
550 }
551
552 if (bestmatch == (struct scsidevs *)0)
553 printf(" No explicit device driver match for \"%s %s\".\n",
554 manu, model);
555
556 return(bestmatch);
557}
558
559static int recurse = 0;
560/***********************************************\
561* Do a scsi operation asking a device if it is *
562* ready. Use the scsi_cmd routine in the switch *
563* table. *
564\***********************************************/
565scsi_ready(unit,target,lu,scsi_switch, flags)
566struct scsi_switch *scsi_switch;
567{
568 struct scsi_test_unit_ready scsi_cmd;
569 struct scsi_xfer scsi_xfer;
570 volatile int rval;
571 int key;
572
573 bzero(&scsi_cmd, sizeof(scsi_cmd));
574 bzero(&scsi_xfer, sizeof(scsi_xfer));
575 scsi_cmd.op_code = TEST_UNIT_READY;
576
577 scsi_xfer.flags=flags | INUSE;
578 scsi_xfer.adapter=unit;
579 scsi_xfer.targ=target;
580 scsi_xfer.lu=lu;
581 scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
582 scsi_xfer.retries=8;
583 scsi_xfer.timeout=10000;
584 scsi_xfer.cmdlen=sizeof(scsi_cmd);
585 scsi_xfer.data=0;
586 scsi_xfer.datalen=0;
587 scsi_xfer.resid=0;
588 scsi_xfer.when_done=0;
589 scsi_xfer.done_arg=0;
590retry: scsi_xfer.error=0;
591 /*******************************************************\
592 * do not use interrupts *
593 \*******************************************************/
594 rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer);
595 if (rval != COMPLETE)
596 {
597 if(scsi_debug)
598 {
599 printf("scsi error, rval = 0x%x\n",rval);
600 printf("code from driver: 0x%x\n",scsi_xfer.error);
601 }
602 switch(scsi_xfer.error)
603 {
604 case XS_SENSE:
605 /*******************************************************\
606 * Any sense value is illegal except UNIT ATTENTION *
607 * In which case we need to check again to get the *
608 * correct response. *
609 *( especially exabytes) *
610 \*******************************************************/
611 if(scsi_xfer.sense.error_class == 7 )
612 {
613 key = scsi_xfer.sense.ext.extended.sense_key ;
614 switch(key)
615 {
616 case 2: /* not ready BUT PRESENT! */
617 return(COMPLETE);
618 case 6:
619 spinwait(1000);
620 if(scsi_xfer.retries--)
621 {
622 scsi_xfer.flags &= ~ITSDONE;
623 goto retry;
624 }
625 return(COMPLETE);
626 default:
627 if(scsi_debug)
628 printf("%d:%d,key=%x.",
629 target,lu,key);
630 }
631 }
632 return(HAD_ERROR);
633 case XS_BUSY:
634 spinwait(1000);
635 if(scsi_xfer.retries--)
636 {
637 scsi_xfer.flags &= ~ITSDONE;
638 goto retry;
639 }
640 return(COMPLETE); /* it's busy so it's there */
641 case XS_TIMEOUT:
642 default:
643 return(HAD_ERROR);
644 }
645 }
646 return(COMPLETE);
647}
648/***********************************************\
649* Do a scsi operation asking a device what it is*
650* Use the scsi_cmd routine in the switch table. *
651\***********************************************/
652scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags)
653struct scsi_switch *scsi_switch;
654u_char *inqbuf;
655{
656 struct scsi_inquiry scsi_cmd;
657 struct scsi_xfer scsi_xfer;
658 volatile int rval;
659
660 bzero(&scsi_cmd, sizeof(scsi_cmd));
661 bzero(&scsi_xfer, sizeof(scsi_xfer));
662 scsi_cmd.op_code = INQUIRY;
663 scsi_cmd.length = sizeof(struct scsi_inquiry_data);
664
665 scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE;
666 scsi_xfer.adapter=unit;
667 scsi_xfer.targ=target;
668 scsi_xfer.lu=lu;
669 scsi_xfer.retries=8;
670 scsi_xfer.timeout=10000;
671 scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
672 scsi_xfer.cmdlen= sizeof(struct scsi_inquiry);
673 scsi_xfer.data=inqbuf;
674 scsi_xfer.datalen=sizeof(struct scsi_inquiry_data);
675 scsi_xfer.resid=sizeof(struct scsi_inquiry_data);
676 scsi_xfer.when_done=0;
677 scsi_xfer.done_arg=0;
678retry: scsi_xfer.error=0;
679 /*******************************************************\
680 * do not use interrupts *
681 \*******************************************************/
682 if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE)
683 {
684 if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error);
685 switch(scsi_xfer.error)
686 {
687 case XS_NOERROR:
688 break;
689 case XS_SENSE:
690 /*******************************************************\
691 * Any sense value is illegal except UNIT ATTENTION *
692 * In which case we need to check again to get the *
693 * correct response. *
694 *( especially exabytes) *
695 \*******************************************************/
696 if((scsi_xfer.sense.error_class == 7 )
697 && (scsi_xfer.sense.ext.extended.sense_key == 6))
698 { /* it's changed so it's there */
699 spinwait(1000);
700 {
701 if(scsi_xfer.retries--)
702 {
703 scsi_xfer.flags &= ~ITSDONE;
704 goto retry;
705 }
706 }
707 return( COMPLETE);
708 }
709 return(HAD_ERROR);
710 case XS_BUSY:
711 spinwait(1000);
712 if(scsi_xfer.retries--)
713 {
714 scsi_xfer.flags &= ~ITSDONE;
715 goto retry;
716 }
717 case XS_TIMEOUT:
718 default:
719 return(HAD_ERROR);
720 }
721 }
722 return(COMPLETE);
723}
724
725
726
727
728/***********************************************\
729* Utility routines often used in SCSI stuff *
730\***********************************************/
731
732/***********************************************\
733* convert a physical address to 3 bytes, *
734* MSB at the lowest address, *
735* LSB at the highest. *
736\***********************************************/
737
738lto3b(val, bytes)
739u_char *bytes;
740{
741 *bytes++ = (val&0xff0000)>>16;
742 *bytes++ = (val&0xff00)>>8;
743 *bytes = val&0xff;
744}
745
746/***********************************************\
747* The reverse of lto3b *
748\***********************************************/
749_3btol(bytes)
750u_char *bytes;
751{
752 int rc;
753 rc = (*bytes++ << 16);
754 rc += (*bytes++ << 8);
755 rc += *bytes;
756 return(rc);
757}
758