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