scsiconf.c revision 1.5 1 /*
2 * Written by Julian Elischer (julian (at) tfs.com)
3 * for TRW Financial Systems for use under the MACH(2.5) operating system.
4 * Hacked by Theo de Raadt <deraadt (at) fsa.ca>
5 *
6 * TRW Financial Systems, in accordance with their agreement with Carnegie
7 * Mellon University, makes this software available to CMU to distribute
8 * or use in any manner that they see fit as long as this message is kept with
9 * the software. For this reason TFS also grants any other persons or
10 * organisations permission to use or modify this software.
11 *
12 * TFS supplies this software to be publicly redistributed
13 * on the understanding that TFS is not responsible for the correct
14 * functioning of this software in any circumstances.
15 */
16
17 #include "sys/types.h"
18 #include "sys/param.h"
19 #include "sys/systm.h"
20 #include "sys/errno.h"
21 #include "sys/ioctl.h"
22 #include "sys/buf.h"
23 #include "sys/proc.h"
24 #include "sys/user.h"
25 #include "sys/dkbad.h"
26 #include "sys/disklabel.h"
27 #include "scsi/scsi_all.h"
28 #include "scsi/scsiconf.h"
29
30 #include "st.h"
31 #include "sd.h"
32 #include "ch.h"
33 #include "cd.h"
34 #define NBLL 0
35 #define NCALS 0
36 #define NKIL 0
37
38 #if NSD > 0
39 extern int sdattach();
40 #endif NSD
41 #if NST > 0
42 extern int stattach();
43 #endif NST
44 #if NCH > 0
45 extern int chattach();
46 #endif NCH
47 #if NCD > 0
48 extern int cdattach();
49 #endif NCD
50 #if NBLL > 0
51 extern int bllattach();
52 #endif NBLL
53 #if NCALS > 0
54 extern int calsattach();
55 #endif NCALS
56 #if NKIL > 0
57 extern int kil_attach();
58 #endif NKIL
59
60 struct scsidevs knowndevs[] = {
61 #if NSD > 0
62 {
63 SC_TSD, T_DIRECT, T_FIXED, "standard", "any" ,"any",
64 sdattach, "sd" ,SC_ONE_LU
65 }, {
66 SC_TSD, T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S ", "B5A ",
67 sdattach, "mx1", SC_ONE_LU
68 },
69 #endif NSD
70 #if NST > 0
71 {
72 SC_TST, T_SEQUENTIAL, T_REMOV, "standard", "any", "any",
73 stattach, "st" ,SC_ONE_LU
74 },
75 #endif NST
76 #if NCD > 0
77 {
78 SC_TCD, T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 ", "3.1a",
79 cdattach, "cd", SC_ONE_LU
80 },
81 #endif NCD
82 #if NCALS > 0
83 {
84 -1, T_PROCESSOR, T_FIXED, "standard" , "any" ,"any",
85 calsattach, "cals", SC_MORE_LUS
86 },
87 #endif NCALS
88 #if NCH > 0
89 {
90 -1, T_CHANGER, T_REMOV, "standard", "any", "any",
91 chattach, "ch", SC_ONE_LU
92 },
93 #endif NCH
94 #if NBLL > 0
95 {
96 -1, T_PROCESSOR, T_FIXED, "AEG ", "READER ", "V1.0",
97 bllattach, "bll", SC_MORE_LUS
98 },
99 #endif NBLL
100 #if NKIL > 0
101 {
102 -1, T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 ", "any",
103 kil_attach, "kil", SC_ONE_LU
104 },
105 #endif NKIL
106 };
107
108 /* controls debug level within the scsi subsystem: see scsiconf.h */
109 int scsi_debug = 0;
110
111 struct scsidevs *
112 scsi_probe(int masunit, struct scsi_switch *sw, int physid, int type, int want)
113 {
114 static struct scsi_inquiry_data inqbuf;
115 struct scsidevs *ret = (struct scsidevs *)0;
116 int targ = physid >> 3;
117 int lun = physid & 7;
118 char *qtype=NULL, *dtype=NULL, *desc;
119 char manu[9], model[17], revision[5];
120 int len;
121
122 bzero(&inqbuf, sizeof inqbuf);
123
124 /*printf("probe: %s%d targ %d lun %d\n",
125 sw->name, masunit, targ, lun);*/
126
127 if( scsi_ready(masunit, targ, lun, sw,
128 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
129 return (struct scsidevs *)0;
130
131 if( scsi_inquire(masunit, targ, lun, sw, (u_char *)&inqbuf,
132 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
133 return (struct scsidevs *)0;
134
135 if( inqbuf.device_qualifier==3 && inqbuf.device_type==T_NODEVICE)
136 return (struct scsidevs *)0;
137
138 switch(inqbuf.device_qualifier) {
139 case 0:
140 qtype = "";
141 break;
142 case 1:
143 qtype = "Unit not Connected!";
144 break;
145 case 2:
146 qtype =", Reserved Peripheral Qualifier!";
147 break;
148 case 3:
149 qtype = ", The Target can't support this Unit!";
150 break;
151 default:
152 dtype = "vendor specific";
153 qtype = "";
154 break;
155 }
156
157 if (dtype == NULL) {
158 switch(inqbuf.device_type) {
159 case T_DIRECT:
160 dtype = "direct";
161 break;
162 case T_SEQUENTIAL:
163 dtype = "seq";
164 break;
165 case T_PRINTER:
166 dtype = "pr";
167 break;
168 case T_PROCESSOR:
169 dtype = "cpu";
170 break;
171 case T_READONLY:
172 dtype = "ro";
173 break;
174 case T_WORM:
175 dtype = "worm";
176 break;
177 case T_SCANNER:
178 dtype = "scan";
179 break;
180 case T_OPTICAL:
181 dtype = "optic";
182 break;
183 case T_CHANGER:
184 dtype = "changer";
185 break;
186 case T_COMM:
187 dtype = "comm";
188 break;
189 default:
190 dtype = "???";
191 break;
192 }
193 }
194
195 if(inqbuf.ansii_version > 0) {
196 len = inqbuf.additional_length +
197 ((char *)inqbuf.unused - (char *)&inqbuf);
198 if( len > sizeof(struct scsi_inquiry_data) - 1)
199 len = sizeof(struct scsi_inquiry_data) - 1;
200 desc = inqbuf.vendor;
201 desc[len-(desc-(char *)&inqbuf)] = 0;
202 strncpy(manu, inqbuf.vendor, sizeof inqbuf.vendor);
203 manu[sizeof inqbuf.vendor] = '\0';
204 strncpy(model, inqbuf.product, sizeof inqbuf.product);
205 model[sizeof inqbuf.product] = '\0';
206 strncpy(revision, inqbuf.revision, sizeof inqbuf.revision);
207 revision[sizeof inqbuf.revision] = '\0';
208 } else {
209 desc = "early protocol device";
210 strcpy(manu, "????");
211 strcpy(model, "");
212 strcpy(revision, "");
213 }
214
215 if(want)
216 goto print;
217
218 ret = selectdev(masunit, targ, lun, sw, inqbuf.device_qualifier,
219 inqbuf.device_type, inqbuf.removable, manu, model, revision, type);
220 if(sw->printed[targ] & (1<<lun))
221 return ret;
222
223 print:
224 printf("%s%d targ %d lun %d: type %d(%s) %s <%s%s%s> SCSI%d\n",
225 sw->name, masunit, targ, lun,
226 inqbuf.device_type, dtype,
227 inqbuf.removable ? "removable" : "fixed",
228 manu, model, revision, inqbuf.ansii_version);
229 if(qtype[0])
230 printf("%s%d targ %d lun %d: qualifier %d(%s)\n",
231 sw->name, masunit, targ, lun,
232 inqbuf.device_qualifier, qtype);
233 return ret;
234 }
235
236 void
237 scsi_warn(int masunit, int mytarg, struct scsi_switch *sw)
238 {
239 struct scsidevs *match = (struct scsidevs *)0;
240 int physid;
241 int targ, lun;
242
243 for(targ=0; targ<8; targ++) {
244 if(targ==mytarg)
245 continue;
246 for(lun=0; lun<8; lun++) {
247 /* check if device already used, or empty */
248 if( sw->empty[targ] & (1<<lun) )
249 continue;
250 if( sw->used[targ] & (1<<lun) )
251 continue;
252
253 physid = targ*8 + lun;
254 match = scsi_probe(masunit, sw, physid, 0, 0);
255
256 if(match == (struct scsidevs *)-1) {
257 if(lun==0)
258 sw->empty[targ] = 0xff;
259 else
260 sw->empty[targ] = 0xff;
261 continue;
262 }
263 if(match) {
264 targ = physid >> 3;
265 lun = physid & 7;
266 if(match->flags & SC_MORE_LUS)
267 sw->empty[targ] |= (1<<lun);
268 else
269 sw->empty[targ] = 0xff;
270 }
271 }
272 }
273 }
274
275 /*
276 * not quite perfect. If we have two "drive ?" entries, this will
277 * probe through all the devices twice. It should have realized that
278 * any device that is not found the first time won't exist later on.
279 */
280 int
281 scsi_attach(int masunit, int mytarg, struct scsi_switch *sw,
282 int *physid, int *unit, int type)
283 {
284 struct scsidevs *match = (struct scsidevs *)0;
285 int targ, lun;
286 int ret=0;
287
288 /*printf("%s%d probing at targ %d lun %d..\n",
289 sw->name, masunit, *physid >> 3, *physid & 7);*/
290
291 if( *physid!=-1 ) {
292 targ = *physid >> 3;
293 lun = *physid & 7;
294
295 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) )
296 return 0;
297
298 match = scsi_probe(masunit, sw, *physid, type, 0);
299 if(match == (struct scsidevs *)-1) {
300 match = (struct scsidevs *)0;
301 if(lun==0)
302 sw->empty[targ] = 0xff;
303 else
304 sw->empty[targ] |= (1<<lun);
305 return 0;
306 }
307
308 sw->printed[targ] |= (1<<lun);
309 if(!match)
310 return 0;
311
312 ret = (*(match->attach_rtn))(masunit, sw, *physid, *unit);
313 goto success;
314 }
315
316 for(targ=0; targ<8; targ++) {
317 if(targ==mytarg)
318 continue;
319 for(lun=0; lun<8; lun++) {
320 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) )
321 continue;
322
323 *physid = targ*8 + lun;
324 match = scsi_probe(masunit, sw, *physid, type, 0);
325 if( match==(struct scsidevs *)-1) {
326 if(lun==0)
327 sw->empty[targ] = 0xff;
328 else
329 sw->empty[targ] |= (1<<lun);
330 match = (struct scsidevs *)0;
331 continue;
332 }
333 if(!match) {
334 sw->printed[targ] |= (1<<lun);
335 break;
336 }
337 ret = (*(match->attach_rtn))(masunit, sw, *physid, *unit);
338 if(ret)
339 goto success;
340 return 0;
341 }
342 }
343 *physid = -1; /* failed... */
344 return 0;
345
346 success:
347 targ = *physid >> 3;
348 lun = *physid & 7;
349 if(match->flags & SC_MORE_LUS) {
350 sw->used[targ] |= (1<<lun);
351 sw->printed[targ] |= (1<<lun);
352 } else {
353 sw->used[targ] = 0xff;
354 sw->printed[targ] = 0xff;
355 }
356 return ret;
357 }
358
359 /*
360 * Try make as good a match as possible with
361 * available sub drivers
362 */
363 struct scsidevs *
364 selectdev(int unit, int target, int lu, struct scsi_switch *sw, int qual,
365 int dtype, int remov, char *manu, char *model, char *rev, int type)
366 {
367 struct scsidevs *sdbest = (struct scsidevs *)0;
368 struct scsidevs *sdent = knowndevs;
369 int numents = sizeof(knowndevs)/sizeof(struct scsidevs);
370 int count = 0, sdbestes = 0;
371
372 dtype |= (qual << 5);
373
374 sdent--;
375 while( count++ < numents) {
376 sdent++;
377 if(dtype != sdent->dtype)
378 continue;
379 if(type != sdent->type)
380 continue;
381 if(sdbestes < 1) {
382 sdbestes = 1;
383 sdbest = sdent;
384 }
385 if(remov != sdent->removable)
386 continue;
387 if(sdbestes < 2) {
388 sdbestes = 2;
389 sdbest = sdent;
390 }
391 if(sdent->flags & SC_SHOWME)
392 printf("\n%s-\n%s-", sdent->manufacturer, manu);
393 if(strcmp(sdent->manufacturer, manu))
394 continue;
395 if(sdbestes < 3) {
396 sdbestes = 3;
397 sdbest = sdent;
398 }
399 if(sdent->flags & SC_SHOWME)
400 printf("\n%s-\n%s-",sdent->model, model);
401 if(strcmp(sdent->model, model))
402 continue;
403 if(sdbestes < 4) {
404 sdbestes = 4;
405 sdbest = sdent;
406 }
407 if(sdent->flags & SC_SHOWME)
408 printf("\n%s-\n%s-",sdent->version, rev);
409 if(strcmp(sdent->version, rev))
410 continue;
411 if(sdbestes < 5) {
412 sdbestes = 5;
413 sdbest = sdent;
414 break;
415 }
416 }
417 return sdbest;
418 }
419
420 /*
421 * Do a scsi operation asking a device if it is
422 * ready. Use the scsi_cmd routine in the switch
423 * table.
424 */
425 int
426 scsi_ready(int unit, int target, int lu,
427 struct scsi_switch *sw, int flags)
428 {
429 struct scsi_test_unit_ready scsi_cmd;
430 struct scsi_xfer scsi_xfer;
431 volatile int rval;
432 int key;
433
434 bzero(&scsi_cmd, sizeof(scsi_cmd));
435 bzero(&scsi_xfer, sizeof(scsi_xfer));
436 scsi_cmd.op_code = TEST_UNIT_READY;
437
438 scsi_xfer.flags = flags | INUSE;
439 scsi_xfer.adapter = unit;
440 scsi_xfer.targ = target;
441 scsi_xfer.lu = lu;
442 scsi_xfer.cmd = (struct scsi_generic *)&scsi_cmd;
443 scsi_xfer.retries = 8;
444 scsi_xfer.timeout = 10000;
445 scsi_xfer.cmdlen = sizeof(scsi_cmd);
446 scsi_xfer.data = 0;
447 scsi_xfer.datalen = 0;
448 scsi_xfer.resid = 0;
449 scsi_xfer.when_done = 0;
450 scsi_xfer.done_arg = 0;
451 retry: scsi_xfer.error = 0;
452
453 /* don't use interrupts! */
454
455 rval = (*(sw->scsi_cmd))(&scsi_xfer);
456 if (rval != COMPLETE) {
457 if(scsi_debug) {
458 printf("scsi error, rval = 0x%x\n", rval);
459 printf("code from driver: 0x%x\n", scsi_xfer.error);
460 }
461 switch(scsi_xfer.error) {
462 case XS_SENSE:
463 /*
464 * Any sense value is illegal except UNIT ATTENTION
465 * In which case we need to check again to get the
466 * correct response. (especially exabytes)
467 */
468 if(scsi_xfer.sense.error_class == 7 ) {
469 key = scsi_xfer.sense.ext.extended.sense_key ;
470 switch(key) {
471 case 2: /* not ready BUT PRESENT! */
472 return(COMPLETE);
473 case 6:
474 spinwait(1000);
475 if(scsi_xfer.retries--) {
476 scsi_xfer.flags &= ~ITSDONE;
477 goto retry;
478 }
479 return(COMPLETE);
480 default:
481 if(scsi_debug)
482 printf("%d:%d,key=%x.", target,
483 lu, key);
484 }
485 }
486 return(HAD_ERROR);
487 case XS_BUSY:
488 spinwait(1000);
489 if(scsi_xfer.retries--) {
490 scsi_xfer.flags &= ~ITSDONE;
491 goto retry;
492 }
493 return COMPLETE; /* it's busy so it's there */
494 case XS_TIMEOUT:
495 default:
496 return HAD_ERROR;
497 }
498 }
499 return COMPLETE;
500 }
501
502 /*
503 * Do a scsi operation asking a device what it is
504 * Use the scsi_cmd routine in the switch table.
505 */
506 int
507 scsi_inquire(int unit, int target, int lu, struct scsi_switch *sw,
508 u_char *inqbuf, int flags)
509 {
510 struct scsi_inquiry scsi_cmd;
511 struct scsi_xfer scsi_xfer;
512
513 bzero(&scsi_cmd, sizeof(scsi_cmd));
514 bzero(&scsi_xfer, sizeof(scsi_xfer));
515 scsi_cmd.op_code = INQUIRY;
516 scsi_cmd.length = sizeof(struct scsi_inquiry_data);
517
518 scsi_xfer.flags = flags | SCSI_DATA_IN | INUSE;
519 scsi_xfer.adapter = unit;
520 scsi_xfer.targ = target;
521 scsi_xfer.lu = lu;
522 scsi_xfer.retries = 8;
523 scsi_xfer.timeout = 10000;
524 scsi_xfer.cmd = (struct scsi_generic *)&scsi_cmd;
525 scsi_xfer.cmdlen = sizeof(struct scsi_inquiry);
526 scsi_xfer.data = inqbuf;
527 scsi_xfer.datalen = sizeof(struct scsi_inquiry_data);
528 scsi_xfer.resid = sizeof(struct scsi_inquiry_data);
529 scsi_xfer.when_done = 0;
530 scsi_xfer.done_arg = 0;
531
532 retry:
533 scsi_xfer.error=0;
534 /* don't use interrupts! */
535
536 if ((*(sw->scsi_cmd))(&scsi_xfer) != COMPLETE) {
537 if(scsi_debug)
538 printf("inquiry had error(0x%x) ",scsi_xfer.error);
539 switch(scsi_xfer.error) {
540 case XS_NOERROR:
541 break;
542 case XS_SENSE:
543 /*
544 * Any sense value is illegal except UNIT ATTENTION
545 * In which case we need to check again to get the
546 * correct response. (especially exabytes)
547 */
548 if( scsi_xfer.sense.error_class==7 &&
549 scsi_xfer.sense.ext.extended.sense_key==6) {
550 /* it's changed so it's there */
551 spinwait(1000);
552 if(scsi_xfer.retries--) {
553 scsi_xfer.flags &= ~ITSDONE;
554 goto retry;
555 }
556 return COMPLETE;
557 }
558 return HAD_ERROR;
559 case XS_BUSY:
560 spinwait(1000);
561 if(scsi_xfer.retries--) {
562 scsi_xfer.flags &= ~ITSDONE;
563 goto retry;
564 }
565 case XS_TIMEOUT:
566 default:
567 return(HAD_ERROR);
568 }
569 }
570 return COMPLETE;
571 }
572
573 /*
574 * convert a physical address to 3 bytes,
575 * MSB at the lowest address,
576 * LSB at the highest.
577 */
578 void
579 lto3b(u_long val, u_char *bytes)
580 {
581 *bytes++ = (val&0xff0000)>>16;
582 *bytes++ = (val&0xff00)>>8;
583 *bytes = val&0xff;
584 }
585
586 /*
587 * The reverse of lto3b
588 */
589 u_long
590 _3btol(u_char *bytes)
591 {
592 u_long rc;
593
594 rc = (*bytes++ << 16);
595 rc += (*bytes++ << 8);
596 rc += *bytes;
597 return rc;
598 }
599
600