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