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