~kris/9p

9hist

4b04b212e5c631597a1f0954ac2e88a70967c96b — David du Colombier 32 years ago 6a9c500
Plan 9 from Bell Labs 1994-09-08
6 files changed, 381 insertions(+), 61 deletions(-)

M pc/dat.h
M pc/fns.h
M pc/io.h
M pc/scsi.c
M port/devns16552.c
M port/portdat.h
M pc/dat.h => pc/dat.h +15 -0
@@ 187,6 187,21 @@ struct ISAConf {
	uchar	ea[6];
};

enum {
	MaxScsi		= 4,
	NTarget		= 8,
};

struct Target {
	int	ctlrno;
	int	target;
	uchar*	inq;
	uchar*	scratch;

	int	ok;
};
typedef int 	(*Scsiio)(Target*, int, uchar*, int, void*, int*);

#define MAXPCMCIA 8			/* maximum number of PCMCIA cards */
#define BOOTLINE ((char *)0x80000100)	/*  bootline passed by boot program */


M pc/fns.h => pc/fns.h +9 -0
@@ 118,3 118,12 @@ Block*	iallocb(int);
void*	ifroute(ulong);
ulong	ifunroute(ulong);
void	parseip(char*, char*);

#define	scsialloc(n)	mallocz((n)+512, 0)
#define scsifree(p)	free(p)

void	addscsicard(char*, Scsiio (*)(int, ISAConf*));
int	scsistart(Target*, char, int);
int	scsireqsense(Target*, char, int);
int	scsicap(Target*, char, ulong*, ulong*);
int	scsibio(Target*, char, int, void*, long, long, long);

M pc/io.h => pc/io.h +8 -1
@@ 18,10 18,17 @@ enum
	 Floppyvec=	Int0vec+6,	/*  floppy interrupts */
	 Parallelvec=	Int0vec+7,	/*  parallel port interrupts */
	Int1vec=	Int0vec+8,
	 Ethervec=	Int0vec+10,	/*  ethernet interrupt */
	 Vector9=	Int0vec+9,	/*  unassigned */
	 Vector10=	Int0vec+10,	/*  unassigned, usually ethernet */
	 Vector11=	Int0vec+11,	/*  unassigned, usually scsi */
	 Mousevec=	Int0vec+12,	/*  mouse interrupt */
	 Matherr2vec=	Int0vec+13,	/*  math coprocessor */
	 Hardvec=	Int0vec+14,	/*  hard disk */
	 Vector15=	Int0vec+15,	/*  unassigned */

	Syscallvec=	64,
};

enum {
	MaxEISA		= 16,
};

M pc/scsi.c => pc/scsi.c +307 -48
@@ 4,81 4,340 @@
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"

/*
 * Known to devscsi.c.
int scsidebugs[8];
int scsiownid = CtlrID;
 */
enum {
	Ninq		= 255,
	Nscratch	= 255,

	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];

void
initscsi(void)
addscsicard(char *t, Scsiio (*r)(int, ISAConf*))
{
}
	static int ncard;

/*
 * 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;
	if(ncard == MaxScsi)
		panic("too many scsi cards\n");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
}

void
scsibufreset(ulong datasize)
scsireset(void)
{
	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);
}

int
scsiexec(Target *tp, int rw, uchar *cmd, int cbytes, void *data, int *dbytes)
{
	bufdatasize = datasize;
	return (*scsi[tp->ctlrno]->io)(tp, rw, cmd, cbytes, data, dbytes);
}

Scsibuf *
scsibuf(void)
Target*
scsiunit(int ctlr, int unit)
{
	Scsibuf *b;
	Target *t;

	b = smalloc(sizeof(*b));
	b->virt = smalloc(bufdatasize);
	b->phys = (void *)(PADDR(b->virt));
	return b;
	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;
}

void
scsifree(Scsibuf *b)
static void
scsiprobe(Ctlr *ctlr)
{
	free(b->virt);
	free(b);
	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;
	}
}

/*
 * Hack for devvid
 */
Scsibuf *
scsialloc(ulong n)
static void
inventory(void)
{
	Scsibuf *b;
	int i;
	static Lock ilock;
	static int inited;

	lock(&ilock);
	if(inited) {
		unlock(&ilock);
		return;
	}
	inited = 1;
	unlock(&ilock);

	b = smalloc(sizeof(*b));
	b->virt = smalloc(n);
	b->phys = (void *)(PADDR(b->virt));
	return b;
	for(i = 0; i < MaxScsi; i++){
		if(scsi[i])
			scsiprobe(scsi[i]);
	}
}

extern int (*aha1542reset(void))(Scsi*, int);
extern int (*ultra14freset(void))(Scsi*, int);
int
scsiinv(int devno, int type, Target **rt, uchar **inq, char *id)
{
	Target *t;
	int ctlr, unit;

	inventory();

static int (*exec)(Scsi*, int);
	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;
}

int
scsiexec(Scsi *p, int rflag)
scsistart(Target *t, char lun, int s)
{
	if(exec == 0)
		error(Enonexist);
	return (*exec)(p, rflag);
	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);
}

void
resetscsi(void)
int
scsicap(Target *t, char lun, ulong *size, ulong *bsize)
{
	if(exec = aha1542reset())
		return;
	exec = ultra14freset();
	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;
}

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;
}


M port/devns16552.c => port/devns16552.c +40 -12
@@ 228,26 228,28 @@ ns16552break(Uart *p, int ms)
void
ns16552fifoon(Uart *p)
{
	ulong i, x, c;
	ulong i, x;

	if(p->nofifo)
		return;

	x = splhi();

	/* empty buffer */
	c = 0;				/* c is to to avoid an unused warning */
	for(i = 0; i < 16; i++)
		c = uartrdreg(p, Data);
	USED(c);
	ns16552intr(p->dev);
	/* reset fifos */
	uartwrreg(p, Fifoctl, Fclear);

	/* empty buffer and interrupt conditions */
	for(i = 0; i < 16; i++){
		if(uartrdreg(p, Istat))
			;
		if(uartrdreg(p, Data))
			;
	}
  
	/* turn on fifo */
	p->fifoon = 1;
	uartwrreg(p, Fifoctl, Fena|Ftrig);

	ns16552intr(p->dev);
	USED(c);
	if((p->istat & Fenabd) == 0){
		/* didn't work, must be an earlier chip type */
		p->nofifo = 1;


@@ 483,19 485,45 @@ ns16552special(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, 
}

/*
 *  reset the interface
 */
void
ns16552shake(Uart *p)
{
	int xonoff, modem;

	xonoff = p->xonoff;
	modem = p->modem;
	ns16552disable(p);
	ns16552enable(p);
	p->xonoff = xonoff;
	ns16552mflow(p, modem);
}

/*
 *  handle an interrupt to a single uart
 */
void
ns16552intr(int dev)
{
	uchar ch;
	int s, l, loops;
	int s, l, loops, shakes;
	Uart *p = uart[dev];

	shakes = 0;
	for(loops = 0;; loops++){
		if(loops > 100000)
			panic("ns16552intr");
		p->istat = s = uartrdreg(p, Istat);
		if(loops > 50000){
			if(shakes++ < 3){
				/* try resetting the interface */
				ns16552shake(p);
				continue;
			}
			print("lstat %ux mstat %ux istat %ux iena %ux ferr %d oerr %d",
				uartrdreg(p, Lstat), uartrdreg(p, Mstat),
				s, uartrdreg(p, Iena), p->frame, p->overrun);
			panic("ns16552intr");
		}
		switch(s&0x3f){
		case 6:	/* receiver line status */
			l = uartrdreg(p, Lstat);

M port/portdat.h => port/portdat.h +2 -0
@@ 667,6 667,8 @@ enum
/* Things scsi */
enum
{
	STtimeout	=-3,
	STownid		=-2,
	STharderr	=-1,	/* Command status error returns */
	STok		= 0,
	STcheck		= 2,