~kris/9p

9hist

646b0c33c96c89cfa288dcaa5c10b7f6a7ed4255 — David du Colombier 32 years ago 0e6574b
Plan 9 from Bell Labs 1994-05-13
9 files changed, 43 insertions(+), 942 deletions(-)

M carrera/segment.h
M carrera/trap.c
M pc/devlpt.c
M pc/main.c
M pc/trap.c
M port/devmnt.c
D power/scsi.c
D power/scsibuf.c
M power/trap.c
M carrera/segment.h => carrera/segment.h +1 -0
@@ 8,5 8,6 @@ Physseg physseg[] =
	{ SG_BSS,	"memory",	0,		SEGMAXSIZE,	0, 0 },
	{ SG_PHYSICAL,	"eisaio",	Eisaphys,	64*1024,	0, 0 },
	{ SG_PHYSICAL,	"eisavga",	Eisavgaphys,	128*1024,	0, 0 },
	{ SG_PHYSICAL,	"bootrom",	0x1fc00000,	256*1024,	0, 0 },
	{ 0,		0,		0,		0,		0, 0 },
};

M carrera/trap.c => carrera/trap.c +8 -5
@@ 529,11 529,6 @@ noted(Ureg **urp, ulong arg0)
{
	Ureg *nur;

	nur = up->ureg;
	if(nur->status!=up->svstatus) {
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}
	qlock(&up->debug);
	if(!up->notified) {
		qunlock(&up->debug);


@@ 541,6 536,14 @@ noted(Ureg **urp, ulong arg0)
		pexit("Suicide", 0);
	}
	up->notified = 0;

	nur = up->ureg;
	if(nur->status!=up->svstatus) {
		qunlock(&up->debug);
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}

	memmove(*urp, up->ureg, sizeof(Ureg));
	(*urp)->r1 = up->svr1;
	switch(arg0) {

M pc/devlpt.c => pc/devlpt.c +1 -0
@@ 88,6 88,7 @@ lptattach(char *spec)
	static int set;

	if(!set){
		outb(lptbase[i-1]+Qpcr, 0);	/* turn off interrupts */
		set = 1;
		setvec(Parallelvec, lptintr, 0);
	}

M pc/main.c => pc/main.c +6 -0
@@ 287,6 287,7 @@ confinit(void)
	long *lp;
	char *cp;
	char *line[MAXCONF];
	extern int defmaxmsg;

	pcnt = 0;



@@ 310,6 311,11 @@ confinit(void)
		confval[nconf] = cp;
		if(strcmp(confname[nconf], "kernelpercent") == 0)
			pcnt = 100 - atoi(confval[nconf]);
		if(strcmp(confname[nconf], "defmaxmsg") == 0){
			i = atoi(confval[nconf]);
			if(i < defmaxmsg && i >=128)
				defmaxmsg = i;
		}
		nconf++;
	}
	/*

M pc/trap.c => pc/trap.c +16 -14
@@ 183,7 183,7 @@ trapinit(void)
	 *  Set the 8259 as master with edge triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int0ctl, (1<<4)|(1<<3)|(1<<0));	/* ICW1 - master, level triggered,
	outb(Int0ctl, (1<<4)|(0<<3)|(1<<0));	/* ICW1 - master, level triggered,
					  	 ICW4 will be sent */
	outb(Int0aux, Int0vec);		/* ICW2 - interrupt vector offset */
	outb(Int0aux, 0x04);		/* ICW3 - have slave on level 2 */


@@ 192,7 192,7 @@ trapinit(void)
	/*
	 *  Set up the second 8259 interrupt processor.
	 *  Make 8259 interrupts start at CPU vector Int0vec.
	 *  Set the 8259 as master with edge triggered
	 *  Set the 8259 as master with level triggered
	 *  input with fully nested interrupts.
	 */
	outb(Int1ctl, (1<<4)|(1<<3)|(1<<0));	/* ICW1 - master, level triggered,


@@ 529,21 529,23 @@ noted(Ureg *ur, ulong arg0)
{
	Ureg *nur;

	nur = up->ureg;		/* pointer to user returned Ureg struct */
	if(nur->cs!=up->svcs || nur->ss!=up->svss
	|| (nur->flags&0xff00)!=(up->svflags&0xff00)){
		pprint("bad noted ureg cs %ux ss %ux flags %ux\n", nur->cs, nur->ss,
			nur->flags);
    Die:
		pexit("Suicide", 0);
	}
	qlock(&up->debug);
	if(!up->notified){
		pprint("call to noted() when not notified\n");
	if(!up->notified) {
		qunlock(&up->debug);
		pprint("call to noted() when not notified\n");
		return;
	}
	up->notified = 0;

	nur = up->ureg;		/* pointer to user returned Ureg struct */
	if(nur->cs!=up->svcs || nur->ss!=up->svss ||
	  (nur->flags&0xff00)!=(up->svflags&0xff00)) {
		qunlock(&up->debug);
		pprint("bad noted ureg cs %ux ss %ux flags %ux\n",
				nur->cs, nur->ss, nur->flags);
			pexit("Suicide", 0);
	}

	nur->flags = (up->svflags&0xffffff00) | (nur->flags&0xff);
	memmove(ur, nur, sizeof(Ureg));
	switch(arg0){


@@ 551,7 553,7 @@ noted(Ureg *ur, ulong arg0)
		if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
			qunlock(&up->debug);
			goto Die;
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);
		return;


@@ 581,7 583,7 @@ execregs(ulong entry, ulong ssize, ulong nargs)
	ur = up->dbgreg;
	ur->usp = (ulong)sp;
	ur->pc = entry;
	return USTKTOP-BY2WD;			/* address of user-level clock */
	return USTKTOP-BY2WD;		/* address of user-level clock */
}

ulong

M port/devmnt.c => port/devmnt.c +3 -1
@@ 54,6 54,8 @@ void	mclose(Mnt*, Chan*);
void	mntrecover(Mnt*, Mntrpc*);
Chan*	mntchan(void);

int defmaxmsg = MAXFDATA;

enum
{
	Tagspace	= 1,


@@ 136,7 138,7 @@ mntattach(char *muxattach)
	m->rip = 0;
	m->c = c;
	m->c->flag |= CMSG;
	m->blocksize = MAXFDATA;	/**/
	m->blocksize = defmaxmsg;
	m->flags = bogus.flags & ~MCACHE;

	switch(devchar[m->c->type]) {

D power/scsi.c => power/scsi.c +0 -838
@@ 1,838 0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

enum
{
	Rownid		= 0x00,		/* own ID/CDB size register */
	  Eaf		=   0x08,	/* enable advanced features */
	  Fs16MHz	=   0x80,	/* frequency select */
	Rcontrol	= 0x01,		/* control register */
	  Hsp		=   0x01,	/* halt on scsi parity error */
	  Idi		=   0x04,	/* intermediate disconnect interrupt */
	  Edi		=   0x08,	/* ending disconnect interrupt */
	  BurstDma	=   0x20,	/* burst mode dma */
	Rtimeout	= 0x02,		/* timeout period register */
	Rcdb		= 0x03,		/* CDB first byte */
	Rlun		= 0x0F,		/* target LUN register */
	Rcmdphase	= 0x10,		/* command phase register */
	Rsync		= 0x11,		/* synchronous transfer register */
	Rtchi		= 0x12,		/* transfer count hi register */
	Rtcmi		= 0x13,		/* transfer count mi register */
	Rtclo		= 0x14,		/* transfer count lo register */
	Rdestid		= 0x15,		/* destination ID */
	  Dpd		=   0x40,	/* data-phase direction (read) */
	Rsrcid		= 0x16,		/* source ID */
	  Siv		=   0x08,	/* source ID is valid */
	  Er		=   0x80,	/* enable reselection */
	Rstatus		= 0x17,		/* scsi status register */
	Rcmd		= 0x18,		/* command register */
	Rdata		= 0x19,		/* data register */
	Raux		= 0x1F,		/* auxiliary status register */
	  Dbr		=   0x01,	/* data buffer ready */
	  Cip		=   0x10,	/* command in progress */
	  Intrpend	=   0x80,	/* interrupt pending */

	Creset		= 0x00,		/* reset */
	Catn		= 0x02,		/* assert ATN */
	Cnack		= 0x03,		/* negate ACK */
	CselectATN	= 0x06,		/* select with ATN */
	Cselect		= 0x07,		/* select without ATN */
	CtransferATN	= 0x08,		/* select with ATN and transfer */
	Ctransfer	= 0x09,		/* select without ATN and transfer */
	Ctinfo		= 0x20,		/* transfer info */
	Csbt		= 0x80,		/* single-byte transfer */

	Mcomplete	= 0x00,		/* complete */
	Msaveptr	= 0x02,		/* save pointers */
	Mdisconnect	= 0x04,		/* disconnect */
	Mabort		= 0x06,		/* abort */
	Mreject		= 0x07,		/* reject */
	Mnop		= 0x08,		/* nop */
	Mbdr		= 0x0C,		/* bus device reset */
	Midentify	= (0x80|0x40),	/* identify|disconnectok */
};

typedef struct Target Target;
struct Target
{
	QLock;
	Lock	regs;
	Rendez;
	ulong	flags;
	uchar	sync;
	uchar	transfer;
	uchar	cmdphase;

	Target	*active;		/* link on active list */

	int	target;			/* SCSI Unit and logical unit */
	int	lun;
	int	status;

	struct {			/* DMA things */
		ulong	dmaaddr;
		ulong	dmalen;
		ulong	dmatx;
		int	rflag;

		ulong	*dmacnt;
		uchar	*dmafls;
		ulong	dmamap;
	};

	uchar	cdb[16];
	int	clen;

	uchar	*addr;
	uchar	*data;
	Target	*base;

	Target	*ctlr;
};

enum
{
	NCtlr		= 2,
	NTarget		= 8,
	CtlrID		= 0,

	Fbusy		= 0x0001,
	Fidentified	= 0x0002,
	Fdisconnected	= 0x0004,
	Freselect	= 0x0008,
	Fcomplete	= 0x0010,
	Fsyncxfer	= 0x0100,
	Freadxfer	= 0x0200,
	Fdmaxfer	= 0x0400,
	Fretry		= 0x1000,
	Fidentifying	= 0x2000,
};

static Target target[NCtlr][NTarget];

static	void	dmamap(Target*);

static void
issue(Target *ctlr, uchar cmd)
{
	while(*ctlr->addr & Cip)
		;
	*ctlr->addr = Rcmd;
	*ctlr->data = cmd;
}

/*
 * Set up and start a data transfer. This maybe
 * a continuation.
 */
static void
start(Target *tp)
{
	ulong count;
	Target *dev = tp->ctlr;

	/*
	 * Set up the chip for the transfer.
	 * First the LUN and transfer mode.
	 */
	*dev->addr = Rlun;
	*dev->data = tp->lun;
	*dev->data = tp->cmdphase;
	*dev->data = tp->sync;

	/*
	 * Set up transfer count and targetID+direction.
	 * No need to set the address register here, we're
	 * already pointing to the right one.
	 */
	count = tp->dmalen;
	*dev->data = (count>>16) & 0xFF;
	*dev->data = (count>>8) & 0xFF;
	*dev->data = count & 0xFF;

	if(tp->rflag == 0)
		*dev->data = Dpd|tp->target;
	else
		*dev->data = tp->target;

	/*
	 * Load the command into the chip.
	 */
	if(tp->cmdphase < 0x40) {
		*dev->addr = Rownid;
		*dev->data = tp->clen;
		*dev->addr = Rcdb;

		for(count = 0; count < tp->clen; count++)
			*dev->data = tp->cdb[count];
	}
	dmamap(tp);

	/*
	 * Select and transfer.
	 */
	issue(dev, tp->transfer);
}

/*
 * Arbitrate for the bus and start a data transfer.
 * If this is the first time through for the target,
 * i.e. we haven't identified yet, just set up for
 * selection so we can try a synchronous negotiation.
 */
static void
arbitrate(Target *dev)
{
	Target *tp;

	tp = dev->active;

	tp->cmdphase = 0x00;

	if(tp->flags & Fidentified) {
		start(tp);
		return;
	}

	/*
	 * Fretry means that we will try this request again,
	 * but without initialising the command phase, so we will
	 * continue from where we left off.
	 */
	tp->flags |= Fidentifying|Fretry;
	*dev->addr = Rlun;
	*dev->data = tp->lun;
	*dev->data = 0x00;				/* cmdphase */
	*dev->addr = Rdestid;
	*dev->data = tp->target;
	issue(dev, CselectATN);
}

static int
done(void *arg)
{
	return (((Target*)arg)->flags & Fbusy) == 0;
}

static void
scsiregs(Target *ctlr)
{
	int x;

	print("scsi aux status #%.2ux\n", *ctlr->addr & 0xFF);
	for(*ctlr->addr = 0x00, x = 0x00; x < 0x19; x++){
		if((x & 0x07) == 0x07)
			print("#%.2ux: #%.2ux\n", x, *ctlr->data & 0xFF);
		else
			print("#%.2ux: #%.2ux ", x, *ctlr->data & 0xFF);
	}
}

static int
scsiio(int nbus, Scsi *p, int rw)
{
	ulong s;
	int status;
	Target *ctlr, **l, *f, *tp;

	tp = &target[nbus][p->target];
	ctlr = tp->ctlr;

	qlock(tp);
	tp->flags |= Fbusy;
	tp->rflag = rw;
	tp->dmaaddr = (ulong)p->data.base;
	tp->dmalen = p->data.lim - p->data.base;
	tp->dmatx = 0;
	tp->status = 0x6002;
	tp->lun = p->lun;

	tp->clen = p->cmd.lim - p->cmd.base;
	memmove(tp->cdb, p->cmd.base, tp->clen);

	s = splhi();
	lock(&ctlr->regs);

	/*
	 * Link the target onto the end of the
	 * ctlr active list and start the request if
	 * the controller is idle.
	 */
	tp->active = 0;
	l = &ctlr->active;
	for(f = *l; f; f = f->active)
		l = &f->active;
	*l = tp;

	if((ctlr->flags & Fbusy) == 0){
		ctlr->flags |= Fbusy;
		arbitrate(ctlr);
	}

	unlock(&ctlr->regs);
	splx(s);

	/*
	 * Wait for the request to complete
	 * and return the status.
	 */
	tsleep(tp, done, tp, 60*5*1000);

	if(!done(tp)) {
		print("scsi%d: Timeout! cmd=#%2.2lux\n", nbus, tp->cdb[0]);
		scsiregs(ctlr);
	}

	status = tp->status;
	p->data.ptr += tp->dmatx;

	qunlock(tp);

	return status;
}

int
scsiexec(Scsi *p, int read)
{
	int rw;

	rw = 1;
	if(read == ScsiIn)
		rw = 0;

	if(p->target == CtlrID)
		return 0x6002;

	p->status = scsiio(0, p, rw);

	return p->status;
}

/*
 * Target request complete.
 * Only called from interrupt level,
 * i.e. ctlr is 'locked'.
 */
static void
complete(Target *ctlr)
{
	Target *tp;

	tp = ctlr->active;
	tp->flags &= (Fretry|Fidentified|Fbusy);

	/*
	 * Retry (continue) the operation if necessary
	 * (used for initial identify), otherwise unlink from
	 * the ctlr active list.
	 */
	if(tp->flags & Fretry){
		tp->flags &= ~Fretry;
		start(tp);
		return;
	}

	ctlr->active = tp->active;

	/*
	 * All done with this target, wakeup scsiio.
	 * If there are other targets queued, start
	 * one up.
	 */
	tp->flags &= Fidentified;
	*tp->dmafls = 0;

	wakeup(tp);

	if(ctlr->active){
		arbitrate(ctlr);
		return;
	}
	ctlr->flags &= ~Fbusy;
}

/*
 * A target has disconnected.
 * Unlink it from the active list and
 * start another if possible.
 * Only called from interrupt level,
 * i.e. ctlr is 'locked'.
 */
static void
disconnect(Target *ctlr)
{
	Target *tp;

	tp = ctlr->active;
	tp->flags |= Fdisconnected;
	ctlr->active = tp->active;

	if(ctlr->active)
		arbitrate(ctlr);
	else
		ctlr->flags &= ~Fbusy;
}

/*
 * A target reselected, put it back
 * on the ctlr active list. We mark the ctlr
 * busy, it's the responsibility of the caller
 * to restart the transfer.
 * Only called from interrupt level,
 * i.e. ctlr is 'locked'.
 */
static void
reselect(Target *ctlr, uchar id)
{
	Target *tp;

	tp = &ctlr->base[id];
	tp->active = ctlr->active;
	ctlr->active = tp;
	ctlr->flags |= Fbusy;
	tp->flags &= ~Fdisconnected;
}

static int
identify(Target *tp, uchar status)
{
	int i, n;
	Target *dev;
	static uchar msgout[6] = {
		0x00, 0x01, 0x03, 0x01, 0x3F, 0x0C
	};
	uchar msgin[16];

	dev = tp->ctlr;

	switch(status){

	case 0x11:				/* select complete */
		/*
		 * This is what WD calls an 'extended interrupt',
		 * the next interrupt (0x8E) is already in the
		 * pipe, we don't have to do anything.
		 */
		break;

	case 0x8E:				/* service required - MSGOUT */
		/*
		 * Send a synchronous data transfer request.
		 * The target may act strangely here and not respond
		 * correctly.
		 */
		tp->sync = 0x00;		/* asynchronous transfer mode */
		tp->flags |= Fidentified;
		*dev->addr = Rtchi;
		*dev->data = 0x00;
		*dev->data = 0x00;
		*dev->data = sizeof(msgout);
		issue(dev, Ctinfo);
		msgout[0] = Midentify|tp->lun;
		*dev->addr = Rdata;
		n = 0;
		while(n < sizeof(msgout)) {
			/*
			 * Wait until the chip says ready.
			 * If an interrupt is indicated, something
			 * went wrong, so get out of here and let
			 * the interrupt happen.
			 */
			if(*dev->addr & Intrpend)
				return 0;
			if(*dev->addr & Dbr){
				*dev->data = msgout[n];
				n++;
			}
		}
		break;

	case 0x1F:				/* transfer complete - MSGIN */
	case 0x4F:				/* unexpected MSGIN */
		/*
		 * Collect the response. The first 3 bytes
		 * of an extended message are:
		 *  0. extended message code	(0x01)
		 *  1. extended message length	(0x03)
		 *  2. sync. tranfer req. code	(0x01)
		 * Only other defined code with length >1 is
		 * 'modify data pointer', which has length 7;
		 * we better not receive anything much longer...
		 * Adjust the number of bytes to collect once we see
		 * how long the response is (byte 2).
		 * If we collect anything other than an extended message
		 * or sync. transfer req. response, toss it
		 * and assume async.
		 */
		*dev->addr = Rtchi;
		*dev->data = 0x00;
		*dev->data = 0x00;
		*dev->data = 5;
		issue(dev, Ctinfo);
		*dev->addr = Rdata;
		for(i = sizeof(msgin)-1, n = 0; n < i; n++){
			while((*dev->addr & Dbr) == 0){
				if(*dev->addr & Intrpend)
					return 0;
			}
			msgin[n] = *dev->data;
			if(n == 1)
				i = msgin[1] + 2;
		}

		if(msgin[2] == 0x01 && (n = msgin[3]) && n != 0xFF){
			if(n < 0x40)
				n = 0x02;
			else if(n < 0x80)
				n = 0x04;
			else
				n = 0;
			n |= msgin[4]<<4;
			tp->sync = n;
		}
		break;

	case 0x4E:
		/*
		 * The target went to message-out phase, so send
		 * it a NOP to keep it happy.
		 * There seems to be no reason for this delay, other than
		 * that we just end up busy without an interrupt if it
		 * isn't there.
		 * I wish I understood this.
		 */
		delay(10);
		*dev->addr = Rstatus;
		n = *dev->data;
		USED(n);

		*dev->addr = Rtchi;
		*dev->data = 0x00;
		*dev->data = 0x00;
		*dev->data = 1;
		issue(dev, Ctinfo);
		*dev->addr = Rdata;
		while((*dev->addr & Dbr) == 0){
			if(*dev->addr & Intrpend)
				return 0;
		}
		*dev->data = Mnop;
		break;

	case 0x20:					/* transfer info paused */
		issue(dev, Cnack);
		break;

	case 0x1A:
	case 0x8A:
		/*
		 * Fretry should be set, so we will
		 * pick up from here.
		 */
		tp->cmdphase = 0x30;		/* command phase has begun */
		complete(dev);
		break;

	default:
		return 1;
	}
	return 0;
}

static void
saveptr(Target *tp)
{
	Target *dev;
	ulong count, tx;

	*tp->dmafls = 0;

	dev = tp->ctlr;
	/*
	 * The transfer count register contains the
	 * number of bytes NOT transferred.
	 */
	*dev->addr = Rtchi;
	count =  (*dev->data & 0xFF)<<16;
	count += (*dev->data & 0xFF)<<8;
	count += (*dev->data & 0xFF);

	*dev->addr = Rtchi;
	*dev->data = 0;
	*dev->data = 0;
	*dev->data = 0;

	tx = tp->dmalen - count;
	tp->dmaaddr += tx;
	tp->dmalen = count;
	tp->dmatx += tx;
}

int
scsistatus(Target *ctlr)
{
	ulong status;

	*ctlr->addr = Rlun;
	status = *ctlr->data & 0xFF;		/* target status */
	status |= *ctlr->data<<8;		/* command phase */

	return status;
}

static void
scsiprocessint(int ctlrno, Target *ctlr)
{
	Target *tp;
	uchar aux, status, sid, phase, x;

	tp = ctlr->active;

	while(*ctlr->addr & 0x20)		/* Wait for busy to clear */
		;

	aux = *ctlr->addr;
	if((aux&0x80) == 0) {
		print("scsi%d: bogus int #%2.2lux\n", ctlrno, *ctlr->addr);
		return;
	}
	if(aux & 0x02)
		print("scsi%d: parity error (ignored)\n", ctlrno);
	if(aux & 0x10)
		print("scsi%d: cip #%2.2lux\n", ctlrno, aux);

	*ctlr->addr = Rcmdphase;
	phase = *ctlr->data;
	*ctlr->addr = Rsrcid;
	sid = *ctlr->data;
	*ctlr->addr = Rstatus;
	status = *ctlr->data;

	if((aux&0x40) && status != 0x81)
		print("lci but not reconnect #%2.2lux\n", status);

	switch(status) {
	case 0x42:				/* timeout */
		tp->flags &= ~Fretry;
		scsistatus(ctlr);		/* Must read lun register */
		complete(ctlr);
		return;

	case 0x16:				/* select-and-transfer complete */
		saveptr(tp);
		tp->status = scsistatus(ctlr);	/* target status */
		complete(ctlr);
		return;

	case 0x21:				/* save data pointers */
		saveptr(tp);
		issue(ctlr, tp->transfer);
		return;

	case 0x4B:				/* unexpected status phase */
		saveptr(tp);
		*ctlr->addr = Rcmdphase;
		if(phase <= 0x3c)
			*ctlr->data = 0x41;	/* resume no data */
		else
			*ctlr->data = 0x46;	/* collect status */
		issue(ctlr, tp->transfer);
		return;

	case 0x85:				/* disconnect */
		if(tp->flags & Fidentifying){
			tp->cmdphase = 0x00;	/* complete retry */
			complete(ctlr);
			return;
		}
		disconnect(ctlr);
		return;

	case 0x81:
		*ctlr->addr = Rdata;
		x = *ctlr->data;		/* the identify message */
		USED(x);
		if((sid & Siv) == 0) {		/* source ID valid */
			print("scsi%d: invalid src id\n", ctlrno);
			break;
		}
		reselect(ctlr, sid & 0x07);
		ctlr->active->cmdphase = 0x45;	/* reselected by target */
		start(ctlr->active);
		return;

	default:
		if(tp == 0) {
			print("scsi%d: bogus sr #%2.2lux phase #%2.2lux\n",
					ctlrno, status, phase);
			return;
		}
		if((tp->flags & Fidentifying) && identify(tp, status) == 0)
			return;
		break;
	}
	print("scsi%d:\n", ctlrno);
	if(tp) print("unit %d cmd #%2.2lux flags #%4.4lux phase #%2.2lux\n",
			tp->target, tp->cdb[0], tp->flags, tp->cmdphase);
	print("scsi status #%.2ux phase #%2.2lux\n", status, phase);
	print("aux  status #%2.2ux was #%2.2lux\n", *ctlr->addr, aux);
	for(*ctlr->addr = 0x00, x = 0x00; x < 0x19; x++){
		if((x & 0x07) == 0x07)
			print("#%.2ux: #%2.2ux\n", x, *ctlr->data);
		else
			print("#%.2ux: #%2.2ux ", x, *ctlr->data);
	}
	panic("\nscsiintr");
}

void
scsiintr(int ctlrno)
{
	Target *ctlr;

	ctlr = &target[ctlrno][CtlrID];

	lock(&ctlr->regs);
	scsiprocessint(ctlrno, ctlr);
	unlock(&ctlr->regs);
}

void
scsiicltr(int ctlrnr, uchar *data, uchar *addr, ulong *cnt, uchar *fls, ulong map)
{
	int i;
	uchar status;
	Target *ctlr, *tp;

	ctlr = &target[ctlrnr][CtlrID];

	ctlr->data = data;
	ctlr->addr = addr;
	ctlr->base = target[ctlrnr];

	if(*ctlr->addr & Intrpend) {
		*ctlr->addr = Rstatus;
		status = *ctlr->data;
		USED(status);
	}

	/*
	 * Give the chip a soft reset. This will
	 * cause an interrupt. Wait for it and clear it.
	 */
	*ctlr->addr = Rownid;
	*ctlr->data = Fs16MHz|Eaf|CtlrID;
	*ctlr->addr = Rcmd;
	*ctlr->data = Creset;

	while((*ctlr->addr & Intrpend) == 0)
		delay(250);

	*ctlr->addr = Rstatus;
	status = *ctlr->data;
	USED(status);

	/*
	 * Freselect means enable the chip to
	 * respond to reselects.
	 */
	ctlr->flags = Freselect|Fidentified;

	*ctlr->addr = Rcontrol;
	*ctlr->data = BurstDma|Edi|Idi|Hsp;
	*ctlr->addr = Rtimeout;
	*ctlr->data = 40;				/* 200ms */

	*ctlr->addr = Rsrcid;
	if(ctlr->flags & Freselect)
		*ctlr->data = Er;
	else
		*ctlr->data = 0x00;

	for(i = 0; i < NTarget; i++){
		if(i == CtlrID)
			continue;

		tp = &target[ctlrnr][i];
		tp->lun = 0;
		tp->target = i;
		tp->ctlr = ctlr;
		tp->dmacnt = cnt;
		tp->dmafls = fls;
		tp->dmamap = map;

		if(ctlr->flags & Freselect){
			tp->flags = 0;
			tp->transfer = CtransferATN;
		}
		else {
			tp->flags = Fidentified;
			tp->transfer = Ctransfer;
		}
	}
}

/*
 * Called at boot time.
 * Initialise the hardware.
 * There will be an interrupt in reponse
 * to the reset.
 */
void
resetscsi(void)
{
	uchar m3;

	/*
	 * Reset both scsi busses
	 */
	m3 = MODEREG->promenet;
	m3 &= ~((1<<6)|(1<<7));
	MODEREG->promenet = m3 | (1<<6) | (1<<7);
	delay(500);
	MODEREG->promenet = m3;
	delay(100);

	scsiicltr(0, SCSI0DATA, SCSI0ADDR, SCSI0CNT, SCSI0FLS, 0x1fc0);
	scsiicltr(1, SCSI1DATA, SCSI1ADDR, SCSI1CNT, SCSI1FLS, 0x1f80);
}

static void
dmamap(Target *tp)
{
	ulong y, len, addr, index, off;

	*tp->dmafls = 1;

	len  = tp->dmalen;
	if(len == 0)
		return;

	addr = tp->dmaaddr;
	index = tp->dmamap;
	for(y = addr+len+BY2PG; addr < y; addr += BY2PG){
		*WRITEMAP = (index<<16)|(addr>>12)&0xFFFF;
		index++;
	}
	off = tp->dmaaddr & (BY2PG-1);
	if(tp->rflag == 0)
		off |= 1<<15;

	*tp->dmacnt = off;
}

/*
 * Known to devscsi.c.
 */
int scsidebugs[8];
int scsiownid = CtlrID;

void
initscsi(void)
{
}

D power/scsibuf.c => power/scsibuf.c +0 -79
@@ 1,79 0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"

/*
 * The following routines
 *	scsibufreset, scsibuf, scsifree and scsialloc
 * provide a pool of buffers used for scsi i/o.
 * This is simplistic at best, and opportunities for
 * deadlock abound.
 */
#define Nbuf	32

struct {
	Lock;
	Scsibuf	*free;
} scsibufalloc;

Scsibuf *
scsialloc(ulong n)
{
	void *x;
	Scsibuf *b;

	if(n > 512*1024)
		panic("scsialloc too big: %d", n);

	b = xalloc(sizeof(Scsibuf));
	x = xalloc(n);

	b->phys = x;
	b->virt = x;

	return b;
}

void
scsibufreset(ulong datasize)
{
	int i;

	for(i = 0; i < Nbuf; i++)
		scsifree(scsialloc(datasize));
}

/*
 * get a scsi io buffer of DATASIZE size
 */
Scsibuf *
scsibuf(void)
{
	Scsibuf *b;

	for(;;) {
		lock(&scsibufalloc);
		b = scsibufalloc.free;
		if(b != 0) {
			scsibufalloc.free = b->next;
			unlock(&scsibufalloc);
			return b;
		}
		unlock(&scsibufalloc);
		resrcwait(0);
	}
	return 0;		/* not reached */
}

void
scsifree(Scsibuf *b)
{
	lock(&scsibufalloc);
	b->next = scsibufalloc.free;
	scsibufalloc.free = b;
	unlock(&scsibufalloc);
}

M power/trap.c => power/trap.c +8 -5
@@ 438,11 438,6 @@ noted(Ureg **urp, ulong arg0)
{
	Ureg *nur;

	nur = up->ureg;
	if(nur->status != up->svstatus) {
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}
	qlock(&up->debug);
	if(!up->notified) {
		qunlock(&up->debug);


@@ 450,6 445,14 @@ noted(Ureg **urp, ulong arg0)
		pexit("Suicide", 0);
	}
	up->notified = 0;

	nur = up->ureg;
	if(nur->status != up->svstatus) {
		qunlock(&up->debug);
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}

	memmove(*urp, up->ureg, sizeof(Ureg));
	(*urp)->r1 = up->svr1;
	switch(arg0) {