xref: /netbsd-src/sys/dev/scsipi/scsiconf.c (revision 811e6386f8c5e4a3521c7003da29ec8673e344fa)
1 /*
2  * Written by Julian Elischer (julian@tfs.com)
3  * Hacked by Theo de Raadt <deraadt@fsa.ca>
4  * for TRW Financial Systems for use under the MACH(2.5) operating system.
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 *)-1;
130 
131 	if( scsi_inquire(masunit, targ, lun, sw, (u_char *)&inqbuf,
132 	    SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
133 		return (struct scsidevs *)-1;
134 
135 	if( inqbuf.device_qualifier==3 && inqbuf.device_type==T_NODEVICE)
136 		return (struct scsidevs *)-1;
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 -1;
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 -1;
306 		}
307 
308 		sw->printed[targ] |= (1<<lun);
309 		if(!match)
310 			return -1;
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==0)
339 				goto success;
340 			return -1;
341 		}
342 	}
343 	*physid = -1;	/* failed... */
344 	return -1;
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 0;
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