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