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