plan 9 kernel history: overview | file list | diff list

1994/0908/pc/scsi.c (diff list | history)

1993/0915/sys/src/9/pc/scsi.c:4,841994/0908/sys/src/9/pc/scsi.c:4,343 (short | long | prev | next)
1993/0915    
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1994/0908    
#include "ureg.h" 
1993/0915    
#include "../port/error.h" 
1994/0908    
#include "../port/netif.h" 
1993/0915    
 
/* 
 * Known to devscsi.c. 
int scsidebugs[8]; 
int scsiownid = CtlrID; 
 */ 
1994/0908    
enum { 
	Ninq		= 255, 
	Nscratch	= 255, 
1993/0915    
 
1994/0908    
	CMDreqsense	= 0x03, 
	CMDinquire	= 0x12, 
}; 
 
typedef struct { 
	ISAConf; 
	Scsiio	io; 
 
	Target	target[NTarget]; 
} Ctlr; 
 
static Ctlr *scsi[MaxScsi]; 
 
static struct { 
	char	*type; 
	Scsiio	(*reset)(int, ISAConf*); 
} cards[MaxScsi+1]; 
 
1993/0915    
void 
initscsi(void) 
1994/0908    
addscsicard(char *t, Scsiio (*r)(int, ISAConf*)) 
1993/0915    
{ 
1994/0908    
	static int ncard; 
 
	if(ncard == MaxScsi) 
		panic("too many scsi cards\n"); 
	cards[ncard].type = t; 
	cards[ncard].reset = r; 
	ncard++; 
1993/0915    
} 
 
/* 
 * Quick hack. Need to do a better job of dynamic initialisation 
 * for machines with peculiar memory/cache restictions. 
 * Also, what about 16Mb address limit on the Adaptec? 
 */ 
static ulong bufdatasize; 
                 
void 
scsibufreset(ulong datasize) 
1994/0908    
scsireset(void) 
1993/0915    
{ 
	bufdatasize = datasize; 
1994/0908    
	Ctlr *ctlr; 
	int ctlrno, n, t; 
 
	for(ctlr = 0, ctlrno = 0; ctlrno < MaxScsi; ctlrno++){ 
		if(ctlr == 0) 
			ctlr = malloc(sizeof(Ctlr)); 
		memset(ctlr, 0, sizeof(Ctlr)); 
		if(isaconfig("scsi", ctlrno, ctlr) == 0) 
			continue; 
		for(n = 0; cards[n].type; n++){ 
			if(strcmp(cards[n].type, ctlr->type)) 
				continue; 
			if((ctlr->io = (*cards[n].reset)(ctlrno, ctlr)) == 0) 
				break; 
 
			print("scsi%d: %s: port %lux irq %d addr %lux size %d\n", 
				ctlrno, ctlr->type, ctlr->port, 
				ctlr->irq, ctlr->mem, ctlr->size); 
 
			for(t = 0; t < NTarget; t++){ 
				ctlr->target[t].ctlrno = ctlrno; 
				ctlr->target[t].target = t; 
				ctlr->target[t].inq = xalloc(Ninq); 
				ctlr->target[t].scratch = xalloc(Nscratch); 
			} 
 
			scsi[ctlrno] = ctlr; 
			ctlr = 0; 
			break; 
		} 
	} 
	if(ctlr) 
		free(ctlr); 
1993/0915    
} 
 
Scsibuf * 
scsibuf(void) 
1994/0908    
int 
scsiexec(Target *tp, int rw, uchar *cmd, int cbytes, void *data, int *dbytes) 
1993/0915    
{ 
	Scsibuf *b; 
1994/0908    
	return (*scsi[tp->ctlrno]->io)(tp, rw, cmd, cbytes, data, dbytes); 
} 
1993/0915    
 
	b = smalloc(sizeof(*b)); 
	b->virt = smalloc(bufdatasize); 
	b->phys = (void *)(PADDR(b->virt)); 
	return b; 
1994/0908    
Target* 
scsiunit(int ctlr, int unit) 
{ 
	Target *t; 
 
	if(ctlr < 0 || ctlr >= MaxScsi || scsi[ctlr] == 0) 
		return 0; 
	if(unit < 0 || unit >= NTarget) 
		return 0; 
	t = &scsi[ctlr]->target[unit]; 
	if(t->ok == 0) 
		return 0; 
	return t; 
1993/0915    
} 
 
void 
scsifree(Scsibuf *b) 
1994/0908    
static void 
scsiprobe(Ctlr *ctlr) 
1993/0915    
{ 
	free(b->virt); 
	free(b); 
1994/0908    
	Target *tp; 
	uchar cmd[6]; 
	int i, s, nbytes; 
 
	for(i = 0; i < NTarget; i++) { 
		tp = &ctlr->target[i]; 
 
		/* 
		 * Test unit ready 
		 */ 
		memset(cmd, 0, sizeof(cmd)); 
		s = scsiexec(tp, SCSIread, cmd, sizeof(cmd), 0, 0); 
		if(s < 0) 
			continue; 
 
		/* 
		 * Determine if the drive exists and is not ready or 
		 * is simply not responding 
		 */ 
		if((s = scsireqsense(tp, 0, 0)) != STok){ 
			print("scsi%d: unit %d unavailable, status %d\n", tp->ctlrno, i, s); 
			continue; 
		} 
 
		/* 
		 * Inquire to find out what the device is 
		 * Drivers then use the result to attach to targets 
		 */ 
		memset(tp->inq, 0, Ninq); 
		cmd[0] = CMDinquire; 
		cmd[4] = Ninq; 
		nbytes = Ninq; 
		s = scsiexec(tp, SCSIread, cmd, sizeof(cmd), tp->inq, &nbytes); 
		if(s < 0) { 
			print("scsi%d: unit %d inquire failed, status %d\n", tp->ctlrno, i, s); 
			continue; 
		} 
		print("scsi%d: unit %d %s\n", tp->ctlrno, i, tp->inq+8); 
		tp->ok = 1; 
	} 
1993/0915    
} 
 
/* 
 * Hack for devvid 
 */ 
Scsibuf * 
scsialloc(ulong n) 
1994/0908    
static void 
inventory(void) 
1993/0915    
{ 
	Scsibuf *b; 
1994/0908    
	int i; 
	static Lock ilock; 
	static int inited; 
1993/0915    
 
	b = smalloc(sizeof(*b)); 
	b->virt = smalloc(n); 
	b->phys = (void *)(PADDR(b->virt)); 
	return b; 
1994/0908    
	lock(&ilock); 
	if(inited) { 
		unlock(&ilock); 
		return; 
	} 
	inited = 1; 
	unlock(&ilock); 
 
	for(i = 0; i < MaxScsi; i++){ 
		if(scsi[i]) 
			scsiprobe(scsi[i]); 
	} 
1993/0915    
} 
 
extern int (*aha1542reset(void))(Scsi*, int); 
extern int (*ultra14freset(void))(Scsi*, int); 
1994/0908    
int 
scsiinv(int devno, int type, Target **rt, uchar **inq, char *id) 
{ 
	Target *t; 
	int ctlr, unit; 
1993/0915    
 
static int (*exec)(Scsi*, int); 
1994/0908    
	inventory(); 
1993/0915    
 
1994/0908    
	for(;;){ 
		ctlr = devno/NTarget; 
		unit = devno%NTarget; 
		if(ctlr >= MaxScsi || scsi[ctlr] == 0) 
			return -1; 
 
		t = &scsi[ctlr]->target[unit]; 
		devno++; 
		if(t->ok && (t->inq[0]&0x0F) == type){ 
			*rt = t; 
			*inq = t->inq; 
			sprint(id, "scsi%d: unit %d", ctlr, unit); 
			return devno; 
		} 
	} 
	return -1; 
} 
 
1993/0915    
int 
scsiexec(Scsi *p, int rflag) 
1994/0908    
scsistart(Target *t, char lun, int s) 
1993/0915    
{ 
	if(exec == 0) 
		error(Enonexist); 
	return (*exec)(p, rflag); 
1994/0908    
	uchar cmd[6]; 
 
	memset(cmd, 0, sizeof cmd); 
	cmd[0] = 0x1b; 
	cmd[1] = lun<<5; 
	cmd[4] = s ? 1 : 0; 
	return scsiexec(t, SCSIread, cmd, sizeof(cmd), 0, 0); 
1993/0915    
} 
 
void 
resetscsi(void) 
1994/0908    
int 
scsicap(Target *t, char lun, ulong *size, ulong *bsize) 
1993/0915    
{ 
	if(exec = aha1542reset()) 
		return; 
	exec = ultra14freset(); 
1994/0908    
	int s, nbytes; 
	uchar cmd[10], *d; 
 
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = 0x25; 
	cmd[1] = lun<<5; 
 
	d = malloc(8); 
	if(d == 0) 
		return -1; 
 
	nbytes = 8; 
	s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); 
	if(s < 0) { 
		free(d); 
		return s; 
	} 
	*size  = (d[0]<<24)|(d[1]<<16)|(d[2]<<8)|(d[3]<<0); 
	*bsize = (d[4]<<24)|(d[5]<<16)|(d[6]<<8)|(d[7]<<0); 
	free(d); 
	return 0; 
1993/0915    
} 
1994/0908    
 
int 
scsibio(Target *t, char lun, int dir, void *b, long n, long bsize, long bno) 
{ 
	uchar cmd[10]; 
	int s, cdbsiz, nbytes; 
 
	memset(cmd, 0, sizeof cmd); 
	if(bno <= 0x1fffff && n < 256) { 
		cmd[0] = 0x0A; 
		if(dir == SCSIread) 
			cmd[0] = 0x08; 
		cmd[1] = (lun<<5) | bno >> 16; 
		cmd[2] = bno >> 8; 
		cmd[3] = bno; 
		cmd[4] = n; 
		cdbsiz = 6; 
	} 
	else { 
		cmd[0] = 0x2A; 
		if(dir == SCSIread) 
			cmd[0] = 0x28; 
		cmd[1] = (lun<<5); 
		cmd[2] = bno >> 24; 
		cmd[3] = bno >> 16; 
		cmd[4] = bno >> 8; 
		cmd[5] = bno; 
		cmd[7] = n>>8; 
		cmd[8] = n; 
		cdbsiz = 10; 
	} 
	nbytes = n*bsize; 
	s = scsiexec(t, dir, cmd, cdbsiz, b, &nbytes); 
	if(s < 0) { 
		scsireqsense(t, lun, 0); 
		return -1; 
	} 
	return nbytes; 
} 
 
static char *key[] = 
{ 
	"no sense", 
	"recovered error", 
	"not ready", 
	"medium error", 
	"hardware error", 
	"illegal request", 
	"unit attention", 
	"data protect", 
	"blank check", 
	"vendor specific", 
	"copy aborted", 
	"aborted command", 
	"equal", 
	"volume overflow", 
	"miscompare", 
	"reserved" 
}; 
 
int 
scsireqsense(Target *tp, char lun, int quiet) 
{ 
	char *s; 
	int sr, try, nbytes; 
	uchar cmd[6], *sense; 
 
	sense = tp->scratch; 
 
	for(try = 0; try < 5; try++) { 
		memset(cmd, 0, sizeof(cmd)); 
		cmd[0] = CMDreqsense; 
		cmd[1] = lun<<5; 
		cmd[4] = Nscratch; 
		memset(sense, 0, sizeof(sense)); 
 
		nbytes = Nscratch; 
		sr = scsiexec(tp, SCSIread, cmd, sizeof(cmd), sense, &nbytes); 
		if(sr != STok) 
			return sr; 
 
		/* 
		 * Unit attention. We can handle that. 
		 */ 
		if((sense[2] & 0x0F) == 0x00 || (sense[2] & 0x0F) == 0x06) 
			return STok; 
 
		/* 
		 * Recovered error. Why bother telling me. 
		 */ 
		if((sense[2] & 0x0F) == 0x01) 
			return STok; 
 
		/* 
		 * Unit is becoming ready 
		 */ 
		if(sense[12] != 0x04 || sense[13] != 0x01) 
			break; 
 
		delay(5000); 
	} 
 
	if(quiet) 
		return STcheck; 
 
	s = key[sense[2]&0xf]; 
	print("scsi%d: unit %d reqsense: '%s' code #%2.2ux #%2.2ux\n", 
		tp->ctlrno, tp->target, s, sense[12], sense[13]); 
	return STcheck; 
} 
 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)