Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/power/scsi.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname power/scsi.c 1992/1208
## diff -e /dev/null /n/bootesdump/1992/1208/sys/src/9/power/scsi.c
0a
#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 */
	  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;
	Rendez;
	ulong	flags;
	uchar	sync;
	uchar	transfer;
	Target	*active;		/* link on active list */

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

	struct {			/* DMA things */
		ulong	dmaaddr;
		ulong	dmalen;
		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*);

/*
 * Set up and start a data transfer.
 * We don't load the command phase here as
 * we may be continuing a stopped operation.
 */
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->addr = Rsync;
	*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.
	 */
	*dev->addr = Rownid;
	*dev->data = tp->clen;
	*dev->addr = Rcdb;

print("start %d cdb: ", tp->target);
	for(count = 0; count < tp->clen; count++) {
		*dev->data = tp->cdb[count];
		print("%2.2lux ", tp->cdb[count]);
	}
print("\n");
	dmamap(tp);

	/*
	 * Select and transfer.
	 */
	*dev->addr = Rcmd;
	*dev->data = 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;

	*dev->addr = Rcmdphase;
	*dev->data = 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->addr = Rdestid;
	*dev->data = tp->target;
	*dev->addr = Rcmd;
	*dev->data = CselectATN;
}

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

static int
scsiio(int nbus, int unit, int rw, uchar *cmd, int cbytes, void *data, int dbytes)
{
	ulong s;
	int status;
	Target *ctlr, **l, *f, *tp;

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

	qlock(tp);
	tp->flags |= Fbusy;
	tp->rflag = rw;
	tp->dmaaddr = (ulong)data;
	tp->dmalen = dbytes;
	tp->status = 0x6002;
	memmove(tp->cdb, cmd, cbytes);
	tp->clen = cbytes;

	s = splhi();
	qlock(ctlr);

	/*
	 * 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);
	}

	qunlock(ctlr);
	splx(s);

	/*
	 * Wait for the request to complete
	 * and return the status.
	 */
	sleep(tp, done, tp);

	status = tp->status;
	qunlock(tp);
print("status: #%4.4lux\n", status);
	return status;
}

int
scsiexec(Scsi *p, int read)
{
	int rw, s;
	ulong clen, dlen;

	clen = p->cmd.lim - p->cmd.base;
	dlen = p->data.lim - p->data.base;

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

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

	s = scsiio(1, p->target, rw, p->cmd.base, clen, p->data.base, dlen);
	p->status = s;
	return s;
}

/*
 * 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 = 1;

	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);
		return;
	}
	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 */
		delay(7);
		*dev->addr = Rcmd;
		*dev->data = Catn;
		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);
		*dev->addr = Rcmd;
		*dev->data = 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;
		*dev->addr = Rcmd;
		*dev->data = 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:
		*dev->addr = Rcmd;
		*dev->data = Csbt|Ctinfo;
		*dev->addr = Rdata;
		while((*dev->addr & Dbr) == 0){
			if(*dev->addr & Intrpend)
				return 0;
		}
		*dev->data = Mnop;
		break;

	case 0x20:					/* transfer info paused */
		delay(7);
		*dev->addr = Rcmd;
		*dev->data = Cnack;
		break;

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

	default:
		return 1;
	}
	return 0;
}

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

	*tp->dmafls = 1;

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

	tp->dmaaddr += tp->dmalen - count;
	tp->dmalen = count;

	*dev->addr = Rcmd;
	*dev->data = tp->transfer;
}

int
scsistatus(Target *ctlr)
{
	ulong status;

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

	return status;
}

void
scsiintr(int ctlrno)
{
	uchar status, x;
	Target *ctlr, *tp;

	ctlr = &target[ctlrno][CtlrID];
	tp = ctlr->active;

	*ctlr->addr = Rstatus;
	status = *ctlr->data;
print("scsiintr: #%2.2lux\n", status);
	if(tp == 0)
		return;

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

	case 0x16:				/* select-and-transfer complete */
		/*
		 * The target status comes back in the Rlun
		 * register. Returned status is combined
		 * with the final command phase, which
		 * should be 0x60.
		 */
		tp->status = scsistatus(ctlr);	/* target status */
		complete(ctlr);
		return;

	case 0x21:					/* save data pointers */
		saveptr(tp);
		return;

	case 0x4B:					/* unexpected status phase */
		*ctlr->addr = Rcmdphase;
		*ctlr->data = 0x46;			/*  */
		*ctlr->addr = Rtchi;
		*ctlr->data = 0;
		*ctlr->data = 0;
		*ctlr->data = 0;
		*ctlr->addr = Rcmd;
		*ctlr->data = tp->transfer;
		return;

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

	case 0x81:
		*ctlr->addr = Rsrcid;
		x = *ctlr->data;
		if(x & Siv){				/* source ID valid */
			reselect(ctlr, x & 0x07);
			*ctlr->addr = Rcmdphase;
			*ctlr->data = 0x44;		/* reselected by target */
			start(ctlr->active);
			return;
		}
		break;

	default:
		if((tp->flags & Fidentifying) && identify(tp, status) == 0)
			return;
		break;
	}
	delay(1000);
	print("scsi intr status #%.2ux\n", status);
	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);
	}
	panic("scsiintr\n");
}

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;
print("scsi init\n");
	/*
	 * 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)
{
}
.
## diffname power/scsi.c 1992/1209
## diff -e /n/bootesdump/1992/1208/sys/src/9/power/scsi.c /n/bootesdump/1992/1209/sys/src/9/power/scsi.c
715c

.
676a
	*ctlr->addr = Rsrcid;
.
675d
669c
	ctlr->flags = Freselect|Fidentified;
.
606,607c
			ctlr->active->cmdphase = 0x44;	/* reselected by target */
.
593,594c
			tp->cmdphase = 0x00;		/* complete retry */
.
582c
		if(phase <= 0x3c)
			*ctlr->data = 0x41;	/* resume no data */
		else
			*ctlr->data = 0x46;	/* collect status */
.
580c
	case 0x4B:				/* unexpected status phase */
		saveptr(tp);
.
577a
		*ctlr->addr = Rcmd;
		*ctlr->data = tp->transfer;
.
576c
	case 0x21:				/* save data pointers */
.
571a
		saveptr(tp);
.
558a
	case 0x00:				/* reset interrupt */
		return;

.
554,556d
551a
	if(*ctlr->addr & 0x20)
		print("busy\n");

	*ctlr->addr = Rcmdphase;
	phase = *ctlr->data;

.
546c
	uchar status, x, phase;
.
526,528c
	tp->dmatx += tx;
.
524c
	tx = tp->dmalen - count;
	tp->dmaaddr += tx;
.
510a
	ulong count, tx;
.
509d
495,496c
		tp->cmdphase = 0x30;		/* command phase has begun */
.
483c
	case 0x20:				/* transfer info paused */
.
426,427c
	case 0x1F:				/* transfer complete - MSGIN */
	case 0x4F:				/* unexpected MSGIN */
.
399c
		tp->sync = 0x00;		/* asynchronous transfer mode */
.
393c
	case 0x8E:				/* service required - MSGOUT */
.
387c
	case 0x11:				/* select complete */
.
282,284c
	p->status = scsiio(1, p, rw);

	return p->status;
.
272,274d
269,270c
	int rw;
.
262c

.
260a
	p->data.ptr += tp->dmatx;

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

.
229,230d
226,227c
	tp->dmaaddr = (ulong)p->data.base;
	tp->dmalen = p->data.lim - p->data.base;
	tp->dmatx = 0;
.
220c
	tp = &target[nbus][p->target];
.
214c
scsiio(int nbus, Scsi *p, int rw)
.
200a
	*dev->data = 0x00;				/* cmdphase */
.
185,186c
	tp->cmdphase = 0x00;
.
162d
157,160c
		for(count = 0; count < tp->clen; count++)
			*dev->data = tp->cdb[count];
.
153,155c
	if(tp->cmdphase < 0x40) {
		*dev->addr = Rownid;
		*dev->data = tp->clen;
		*dev->addr = Rcdb;
.
132c
	*dev->data = tp->cmdphase;
.
116,118c
 * Set up and start a data transfer. This maybe
 * a continuation.
.
75a
		ulong	dmatx;
.
66a
	uchar	cmdphase;

.
## diffname power/scsi.c 1992/1210
## diff -e /n/bootesdump/1992/1209/sys/src/9/power/scsi.c /n/bootesdump/1992/1210/sys/src/9/power/scsi.c
260c
	tsleep(tp, done, tp, 60*5*1000);

	if(!done(tp)) {
		print("scsi%d: Timeout! cmd=#%2.2lux\n", nbus, tp->cdb[0]);
		scsiregs(ctlr);
	}
.
212a
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);
	}
}

.
## diffname power/scsi.c 1992/1213
## diff -e /n/bootesdump/1992/1210/sys/src/9/power/scsi.c /n/bootesdump/1992/1213/sys/src/9/power/scsi.c
301c
	p->status = scsiio(0, p, rw);
.
## diffname power/scsi.c 1992/1217
## diff -e /n/bootesdump/1992/1213/sys/src/9/power/scsi.c /n/bootesdump/1992/1217/sys/src/9/power/scsi.c
655c
	panic("\nscsiintr");
}

void
scsiintr(int ctlrno)
{
	Target *ctlr;

	ctlr = &target[ctlrno][CtlrID];

	lock(&ctlr->regs);
	scsiprocessint(ctlrno, ctlr);
	unlock(&ctlr->regs);
.
653c
			print("#%.2ux: #%2.2ux ", x, *ctlr->data);
.
651c
			print("#%.2ux: #%2.2ux\n", x, *ctlr->data);
.
646,648c
	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);
.
641a
		if(tp == 0) {
			print("scsi%d: bogus sr #%2.2lux phase #%2.2lux\n",
					ctlrno, status, phase);
			return;
		}
.
639c
		reselect(ctlr, sid & 0x07);
		ctlr->active->cmdphase = 0x45;	/* reselected by target */
		start(ctlr->active);
		return;
.
631,637c
		*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;
.
623c
			tp->cmdphase = 0x00;	/* complete retry */
.
621c
	case 0x85:				/* disconnect */
.
613,618c
		issue(ctlr, tp->transfer);
.
602,603c
		issue(ctlr, tp->transfer);
.
589,594d
581a
	switch(status) {
.
578,580c
	if((aux&0x40) && status != 0x81)
		print("lci but not reconnect #%2.2lux\n", status);
.
574c
	*ctlr->addr = Rsrcid;
	sid = *ctlr->data;
.
571a
	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);

.
569,570c
	while(*ctlr->addr & 0x20)		/* Wait for busy to clear */
		;
.
566d
563,564c
	Target *tp;
	uchar aux, status, sid, phase, x;
.
560,561c
static void
scsiprocessint(int ctlrno, Target *ctlr)
.
541a
	*dev->addr = Rtchi;
	*dev->data = 0;
	*dev->data = 0;
	*dev->data = 0;

.
530c
	*tp->dmafls = 0;
.
502,505c
	case 0x20:					/* transfer info paused */
		issue(dev, Cnack);
.
492,493c
		/*
		 * 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);
.
466,467c
		issue(dev, Ctinfo);
.
424,425c
		issue(dev, Ctinfo);
.
407,409c
		/*
		 * This is what WD calls an 'extended interrupt',
		 * the next interrupt (0x8E) is already in the
		 * pipe, we don't have to do anything.
		 */
.
367,369c
	else
		ctlr->flags &= ~Fbusy;
.
365c
	if(ctlr->active)
.
338c
	*tp->dmafls = 0;
.
267c
	unlock(&ctlr->regs);
.
249c
	lock(&ctlr->regs);
.
243a
	tp->lun = p->lun;
.
203,204c
	issue(dev, CselectATN);
.
168,169c
	issue(dev, tp->transfer);
.
117a
static void
issue(Target *ctlr, uchar cmd)
{
	while(*ctlr->addr & Cip)
		;
	*ctlr->addr = Rcmd;
	*ctlr->data = cmd;
}

.
62a
	Lock	regs;
.
36a
	  Cip		=   0x10,	/* command in progress */
.
## diffname power/scsi.c 1994/0513 # deleted
## diff -e /n/bootesdump/1992/1217/sys/src/9/power/scsi.c /n/fornaxdump/1994/0513/sys/src/brazil/power/scsi.c
1,838d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.