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

1995/0725/pc/scsi.c (diff list | history)

pc/scsi.c on 1993/0915
1993/0915    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1994/0908    
#include "ureg.h" 
1993/0915    
#include "../port/error.h" 
 
1995/0722    
enum 
{ 
1994/0908    
	Ninq		= 255, 
	Nscratch	= 255, 
1993/0915    
 
1995/0329    
	CMDtest		= 0x00, 
1994/0908    
	CMDreqsense	= 0x03, 
1995/0329    
	CMDread6	= 0x08, 
	CMDwrite6	= 0x0A, 
1994/0908    
	CMDinquire	= 0x12, 
1995/0329    
	CMDstart	= 0x1B, 
	CMDread10	= 0x28, 
	CMDwrite10	= 0x2A, 
1994/0908    
}; 
 
1995/0722    
typedef struct 
{ 
1994/0908    
	ISAConf; 
	Scsiio	io; 
 
	Target	target[NTarget]; 
} Ctlr; 
 
1995/0723    
static	Ctlr*	scsi[MaxScsi]; 
1994/0908    
 
1995/0328    
typedef struct Link Link; 
1995/0722    
typedef struct Link 
{ 
1994/0908    
	char	*type; 
	Scsiio	(*reset)(int, ISAConf*); 
 
1995/0328    
	Link*	link; 
} Link; 
 
static Link *link; 
static int linkcount; 
 
1993/0915    
void 
1995/0328    
addscsilink(char *t, Scsiio (*r)(int, ISAConf*)) 
1993/0915    
{ 
1995/0328    
	Link *lp; 
1994/0908    
 
1995/0328    
	if((lp = xalloc(sizeof(Link))) == 0) 
		return; 
	lp->type = t; 
	lp->reset = r; 
 
	lp->link = link; 
	link = lp; 
	linkcount++; 
1993/0915    
} 
 
void 
1994/0908    
scsireset(void) 
1993/0915    
{ 
1994/0908    
	Ctlr *ctlr; 
1995/0328    
	int ctlrno, t; 
	Link *lp; 
1994/0908    
 
	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; 
1995/0328    
		for(lp = link; lp; lp = lp->link){ 
			if(strcmp(lp->type, ctlr->type)) 
1994/0908    
				continue; 
1995/0328    
			if((ctlr->io = (*lp->reset)(ctlrno, ctlr)) == 0) 
1994/0908    
				break; 
 
1995/0513    
			print("scsi%d: %s: port 0x%luX irq %d", 
1994/0908    
				ctlrno, ctlr->type, ctlr->port, 
				ctlr->irq, ctlr->mem, ctlr->size); 
1995/0328    
			if(ctlr->mem) 
1995/0513    
				print(" addr 0x%luX", ctlr->mem & ~KZERO); 
			if(ctlr->size) 
				print(" size 0x%luX", ctlr->size); 
1995/0328    
			print("\n"); 
1994/0908    
 
			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    
} 
 
1994/0908    
int 
1995/0324    
scsiexec(Target *t, int rw, uchar *cmd, int cbytes, void *data, int *dbytes) 
1993/0915    
{ 
1995/0324    
	return (*scsi[t->ctlrno]->io)(t, rw, cmd, cbytes, data, dbytes); 
1994/0908    
} 
1993/0915    
 
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    
} 
 
1994/0908    
static void 
scsiprobe(Ctlr *ctlr) 
1993/0915    
{ 
1995/0324    
	Target *t; 
1994/0908    
	int i, s, nbytes; 
 
	for(i = 0; i < NTarget; i++) { 
1995/0324    
		t = &ctlr->target[i]; 
1994/0908    
 
1995/0404    
		if(scsitest(t, 0) < 0) 
1994/0908    
			continue; 
 
		/* 
		 * Determine if the drive exists and is not ready or 
		 * is simply not responding 
		 */ 
1995/0405    
		nbytes = Nscratch; 
		s = scsireqsense(t, 0, t->scratch, &nbytes, 0); 
		if(s != STok){ 
1995/0324    
			print("scsi%d: unit %d unavailable, status %d\n", t->ctlrno, i, s); 
1994/0908    
			continue; 
		} 
 
		/* 
1995/0329    
		 * Inquire to find out what the device is. 
1994/0908    
		 * Drivers then use the result to attach to targets 
		 */ 
1995/0324    
		memset(t->inq, 0, Ninq); 
1994/0908    
		nbytes = Ninq; 
1995/0329    
		s = scsiinquiry(t, 0, t->inq, &nbytes); 
1994/0908    
		if(s < 0) { 
1995/0324    
			print("scsi%d: unit %d inquire failed, status %d\n", t->ctlrno, i, s); 
1994/0908    
			continue; 
		} 
1995/0405    
		print("scsi%d: unit %d: %s\n", t->ctlrno, i, t->inq+8); 
1995/0324    
		t->ok = 1; 
1994/0908    
	} 
1993/0915    
} 
 
1994/0908    
static void 
inventory(void) 
1993/0915    
{ 
1994/0908    
	int i; 
	static Lock ilock; 
	static int inited; 
1993/0915    
 
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    
} 
 
1994/0908    
int 
1995/0403    
scsiinv(int devno, int *type, Target **rt, uchar **inq, char *id) 
1994/0908    
{ 
	Target *t; 
1995/0403    
	int ctlr, *i, unit; 
1993/0915    
 
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++; 
1995/0403    
		if(t->ok){ 
			for(i = type; *i >= 0; i++){ 
				if((t->inq[0]&0x1F) != *i) 
					continue; 
				*rt = t; 
				*inq = t->inq; 
1995/0725    
				if(id) 
					sprint(id, "scsi%d: unit %d", ctlr, unit); 
1995/0403    
				return devno; 
			} 
1994/0908    
		} 
	} 
	return -1; 
1995/0404    
} 
 
 
int 
scsitest(Target *t, char lun) 
{ 
	uchar cmd[6]; 
 
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = CMDtest; 
	cmd[1] = lun<<5; 
	return scsiexec(t, SCSIread, cmd, sizeof(cmd), 0, 0); 
1994/0908    
} 
 
1993/0915    
int 
1994/0908    
scsistart(Target *t, char lun, int s) 
1993/0915    
{ 
1994/0908    
	uchar cmd[6]; 
 
	memset(cmd, 0, sizeof cmd); 
1995/0329    
	cmd[0] = CMDstart; 
1994/0908    
	cmd[1] = lun<<5; 
1995/0722    
	cmd[4] = s? 1: 0; 
1994/0908    
	return scsiexec(t, SCSIread, cmd, sizeof(cmd), 0, 0); 
1995/0329    
} 
 
int 
scsiinquiry(Target *t, char lun, void *data, int *datalen) 
{ 
	uchar cmd[6]; 
 
	memset(cmd, 0, sizeof cmd); 
	cmd[0] = CMDinquire; 
	cmd[1] = lun<<5; 
	cmd[4] = *datalen; 
	return scsiexec(t, SCSIread, cmd, sizeof(cmd), data, datalen); 
1993/0915    
} 
 
1994/0908    
int 
scsicap(Target *t, char lun, ulong *size, ulong *bsize) 
1993/0915    
{ 
1994/0908    
	int s, nbytes; 
	uchar cmd[10], *d; 
 
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = 0x25; 
	cmd[1] = lun<<5; 
 
1995/0723    
	nbytes = 8; 
	d = scsialloc(nbytes); 
1994/0908    
	if(d == 0) 
1995/0723    
		error(Enomem); 
1994/0908    
 
1995/0723    
	s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); 
	if(s == STok) { 
1995/0724    
		*size  = nhgetl(d+0); 
		*bsize = nhgetl(d+4); 
1994/0908    
	} 
1995/0723    
	scsifree(d); 
1995/0405    
	return s; 
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; 
1995/0724    
		hnputs(cmd+2, bno); 
1994/0908    
		cmd[4] = n; 
		cdbsiz = 6; 
	} 
	else { 
		cmd[0] = 0x2A; 
		if(dir == SCSIread) 
			cmd[0] = 0x28; 
		cmd[1] = (lun<<5); 
1995/0724    
		hnputl(cmd+2, bno); 
		hnputs(cmd+7, n); 
1994/0908    
		cdbsiz = 10; 
	} 
	nbytes = n*bsize; 
	s = scsiexec(t, dir, cmd, cdbsiz, b, &nbytes); 
	if(s < 0) { 
1995/0405    
		nbytes = Nscratch; 
		scsireqsense(t, lun, t->scratch, &nbytes, 0); 
1994/0908    
		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 
1995/0405    
scsireqsense(Target *t, char lun, void *data, int *nbytes, int quiet) 
1994/0908    
{ 
	char *s; 
1995/0405    
	int status, try; 
1994/0908    
	uchar cmd[6], *sense; 
 
1995/0405    
	sense = malloc(*nbytes); 
1994/0908    
 
	for(try = 0; try < 5; try++) { 
		memset(cmd, 0, sizeof(cmd)); 
		cmd[0] = CMDreqsense; 
		cmd[1] = lun<<5; 
1995/0405    
		cmd[4] = *nbytes; 
		memset(sense, 0, *nbytes); 
1994/0908    
 
1995/0405    
		status = scsiexec(t, SCSIread, cmd, sizeof(cmd), sense, nbytes); 
		if(status != STok){ 
			free(sense); 
			return status; 
		} 
		*nbytes = sense[0x07]+8; 
		memmove(data, sense, *nbytes); 
1994/0908    
 
		/* 
		 * Unit attention. We can handle that. 
		 */ 
1995/0405    
		if((sense[2] & 0x0F) == 0x00 || (sense[2] & 0x0F) == 0x06){ 
			free(sense); 
1994/0908    
			return STok; 
1995/0405    
		} 
1994/0908    
 
		/* 
		 * Recovered error. Why bother telling me. 
		 */ 
1995/0405    
		if((sense[2] & 0x0F) == 0x01){ 
			free(sense); 
1994/0908    
			return STok; 
1995/0405    
		} 
1994/0908    
 
		/* 
		 * Unit is becoming ready 
		 */ 
		if(sense[12] != 0x04 || sense[13] != 0x01) 
			break; 
 
		delay(5000); 
	} 
 
1995/0405    
	if(quiet == 0){ 
		s = key[sense[2]&0x0F]; 
		print("scsi%d: unit %d reqsense: '%s' code #%2.2ux #%2.2ux\n", 
			t->ctlrno, t->target, s, sense[12], sense[13]); 
	} 
	free(sense); 
1994/0908    
	return STcheck; 
} 
 
1995/0722    
int 
scsidiskinfo(Target *t, char lun, uchar *data) 
{ 
1995/0723    
	int s, nbytes; 
	uchar cmd[10], *d; 
1995/0722    
 
1995/0723    
	nbytes = 4; 
1995/0722    
 
1995/0723    
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = 0x43; 
	cmd[1] = lun<<5; 
1995/0724    
	hnputs(cmd+7, nbytes); 
1995/0722    
 
1995/0723    
	d = scsialloc(nbytes); 
	if(d == 0) 
		error(Enomem); 
1995/0722    
 
1995/0723    
	memset(d, 0, nbytes); 
	s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); 
	memmove(data, d, 4); 
	scsifree(d); 
1995/0722    
	return s; 
} 
 
int 
scsitrackinfo(Target *t, char lun, int track, uchar *data) 
{ 
	int s, nbytes; 
1995/0723    
	uchar cmd[10], *d; 
1995/0722    
 
	nbytes = 12; 
 
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = 0xe5; 
	cmd[1] = lun<<5; 
	cmd[5] = track; 
1995/0724    
	hnputs(cmd+7, nbytes); 
1995/0722    
 
1995/0723    
	d = scsialloc(nbytes); 
	if(d == 0) 
		error(Enomem); 
 
	memset(d, 0, nbytes); 
	s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); 
	memmove(data, d, 12); 
	scsifree(d); 
 
1995/0722    
	return s; 
1995/0723    
} 
 
int 
scsibufsize(Target *t, char lun, int size) 
{ 
	int s, nbytes; 
	uchar cmd[6], *d; 
 
 
	nbytes = 12; 
 
	memset(cmd, 0, sizeof(cmd)); 
	cmd[0] = 0x15; 
	cmd[1] = lun<<5; 
	cmd[4] = nbytes; 
 
	d = scsialloc(nbytes); 
	if(d == 0) 
		error(Enomem); 
 
	memset(d, 0, nbytes); 
	d[3] = 8; 
1995/0724    
	hnputl(d+8, size); 
1995/0723    
 
	s = scsiexec(t, SCSIwrite, cmd, sizeof(cmd), d, &nbytes); 
	scsifree(d); 
	return s; 
} 
 
int 
scsireadcdda(Target *t, char lun, void *b, long n, long bsize, long bno) 
{ 
	uchar cmd[10]; 
	int s, nbytes; 
 
	memset(cmd, 0, sizeof(cmd)); 
 
	cmd[0] = 0xd8; 
	cmd[1] = (lun<<5); 
1995/0724    
	hnputl(cmd+2, bno); 
	hnputl(cmd+6, n); 
1995/0723    
 
	nbytes = n*bsize; 
	s = scsiexec(t, SCSIread, cmd, sizeof(cmd), b, &nbytes); 
	if(s < 0) { 
		nbytes = Nscratch; 
		scsireqsense(t, lun, t->scratch, &nbytes, 0); 
		return -1; 
	} 
	return nbytes; 
1995/0722    
} 


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