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