Commit | Line | Data |
---|---|---|
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 | |
55 | extern sdattach(); | |
56 | #endif NSD | |
57 | #if NST > 0 | |
58 | extern stattach(); | |
59 | #endif NST | |
60 | #if NCH > 0 | |
61 | extern chattach(); | |
62 | #endif NCH | |
63 | #if NCD > 0 | |
64 | extern cdattach(); | |
65 | #endif NCD | |
66 | #if NBLL > 0 | |
67 | extern bllattach(); | |
68 | #endif NBLL | |
69 | #if NCALS > 0 | |
70 | extern calsattach(); | |
71 | #endif NCALS | |
72 | #if NKIL > 0 | |
73 | extern 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 | \***************************************************************/ | |
80 | struct 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 | } | |
89 | pd[] = | |
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 | \***************************************************************/ | |
103 | static 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 | |
117 | knowndevs[] = { | |
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 | \***************************************************************/ | |
154 | struct predefined *scsi_get_predef(); | |
155 | struct scsidevs *scsi_probedev(); | |
156 | struct scsidevs *selectdev(); | |
157 | ||
158 | /* controls debug level within the scsi subsystem */ | |
159 | /* see scsiconf.h for values */ | |
160 | int scsi_debug = 0x0; | |
161 | int 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 | \***************************************************************/ | |
167 | scsi_attachdevs( unit, scsi_addr, scsi_switch) | |
168 | int unit,scsi_addr; | |
169 | struct 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 | \***********************************************/ | |
257 | struct predefined *scsi_get_predef(unit,target,lu,maybe_more) | |
258 | int 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 | \***********************************************/ | |
288 | struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more) | |
289 | ||
290 | struct scsi_switch *scsi_switch; | |
291 | int unit,target,lu; | |
292 | int *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 | \***********************************************/ | |
479 | struct scsidevs | |
480 | *selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev) | |
481 | int unit,target,lu; | |
482 | struct scsi_switch *dvr_switch; | |
483 | int qualifier,type,remov; | |
484 | char *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 | ||
559 | static 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 | \***********************************************/ | |
565 | scsi_ready(unit,target,lu,scsi_switch, flags) | |
566 | struct 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; | |
590 | retry: 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 | \***********************************************/ | |
652 | scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags) | |
653 | struct scsi_switch *scsi_switch; | |
654 | u_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; | |
678 | retry: 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 | ||
738 | lto3b(val, bytes) | |
739 | u_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) | |
750 | u_char *bytes; | |
751 | { | |
752 | int rc; | |
753 | rc = (*bytes++ << 16); | |
754 | rc += (*bytes++ << 8); | |
755 | rc += *bytes; | |
756 | return(rc); | |
757 | } | |
758 |