Home | History | Annotate | Line # | Download | only in scsipi
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