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