scsiconf.c revision 1.9 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.9 1993/05/27 10:14:02 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 *)-1;
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 sw->printed[targ] |= (1<<lun);
239 return ret;
240 }
241
242 void
243 scsi_warn(int masunit, int mytarg, struct scsi_switch *sw)
244 {
245 struct scsidevs *match = (struct scsidevs *)0;
246 int physid;
247 int targ, lun;
248
249 for(targ=0; targ<8; targ++) {
250 if(targ==mytarg)
251 continue;
252 for(lun=0; lun<8; lun++) {
253 /* check if device already used, or empty */
254 if( sw->empty[targ] & (1<<lun) )
255 continue;
256 if( sw->used[targ] & (1<<lun) )
257 continue;
258
259 physid = targ*8 + lun;
260 match = scsi_probe(masunit, sw, physid, 0, 0);
261
262 if(match == (struct scsidevs *)-1) {
263 if(lun==0)
264 sw->empty[targ] = 0xff;
265 else
266 sw->empty[targ] = 0xff;
267 continue;
268 }
269 if(match) {
270 targ = physid >> 3;
271 lun = physid & 7;
272 if(match->flags & SC_MORE_LUS)
273 sw->empty[targ] |= (1<<lun);
274 else
275 sw->empty[targ] = 0xff;
276 }
277 }
278 }
279 }
280
281 /*
282 * not quite perfect. If we have two "drive ?" entries, this will
283 * probe through all the devices twice. It should have realized that
284 * any device that is not found the first time won't exist later on.
285 */
286 int
287 scsi_attach(int masunit, int mytarg, struct scsi_switch *sw,
288 int *physid, int *unit, int type)
289 {
290 struct scsidevs *match = (struct scsidevs *)0;
291 int targ, lun;
292 int ret=0;
293
294 /*printf("%s%d probing at targ %d lun %d..\n",
295 sw->name, masunit, *physid >> 3, *physid & 7);*/
296
297 if( *physid!=-1 ) {
298 targ = *physid >> 3;
299 lun = *physid & 7;
300
301 if( (sw->empty[targ] & (1<<lun)) || (sw->used[targ] & (1<<lun)) )
302 return 0;
303
304 match = scsi_probe(masunit, sw, *physid, type, 0);
305 if(match == (struct scsidevs *)-1) {
306 match = (struct scsidevs *)0;
307 if(lun==0)
308 sw->empty[targ] = 0xff;
309 else
310 sw->empty[targ] |= (1<<lun);
311 return 0;
312 }
313
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 break;
340 ret = (*(match->attach_rtn))(masunit, sw, *physid, unit);
341 if(ret)
342 goto success;
343 return 0;
344 }
345 }
346 *physid = -1; /* failed... */
347 return 0;
348
349 success:
350 targ = *physid >> 3;
351 lun = *physid & 7;
352 if(match->flags & SC_MORE_LUS)
353 sw->used[targ] |= (1<<lun);
354 else
355 sw->used[targ] = 0xff;
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