~kris/9p

9hist

20c6e14cf2601a37f4f42f22387fb3b07900297d — David du Colombier 27 years ago ae2c157
Plan 9 from Bell Labs 1998-11-26
2 files changed, 273 insertions(+), 171 deletions(-)

M pc/devata.c
M pc/ether82557.c
M pc/devata.c => pc/devata.c +269 -171
@@ 2,6 2,7 @@
 * This has gotten a bit messy with the addition of multiple controller
 * and ATAPI support; needs a rewrite before adding any 'ctl' functions.
 * The register locking needs looked at.
 * The PCI hacks are truly awful.
 */
#include	"u.h"
#include	"../port/lib.h"


@@ 27,10 28,6 @@ typedef struct Atapicmd		Atapicmd;
enum
{
	/* ports */
	Pbase0=		0x1F0,	/* primary */
	Pbase1=		0x170,	/* secondary */
	Pbase2=		0x1E8,	/* tertiary */
	Pbase3=		0x168,	/* quaternary */
	Pdata=		0,	/* data port (16 bits) */
	Perror=		1,	/* error port (read) */
	 Eabort=	(1<<2),


@@ 50,7 47,7 @@ enum
	 Serr=		 (1<<0),
	Pcmd=		7,	/* cmd port (write) */

	Pctrl=		0x206,	/* device control, alternate status */
	Pctl=		2,	/* device control, alternate status */
	 nIEN=		(1<<1),
	 Srst=		(1<<2),



@@ 86,7 83,7 @@ enum

	Hardtimeout=	6000,		/* disk access timeout (ms) */
	Atapitimeout=	10000,		/* disk access timeout (ms) */
	NCtlr=		4,
	NCtlr=		8,		/* not really */
	NDrive=		NCtlr*2,

	/* cd files */


@@ 175,7 172,8 @@ struct Controller

	Lock	reglock;	/* exclusive access to the registers */

	int	pbase;		/* base port */
	int	cmdport;	/* base port */
	int	ctlport;
	uchar	ctlrno;
	int	tbdf;



@@ 203,12 201,26 @@ static QLock atactlrlock[NCtlr];
static Drive *atadrive[NDrive];
static int spindownmask;
static int have640b;
static int pbase[NCtlr] = {
	Pbase0, Pbase1, Pbase2, Pbase3,
};
static int defirq[NCtlr] = {
	14, 15, 0, 0,

typedef struct Atadev Atadev;
typedef struct Atadev {
	int	cmdport;
	int	ctlport;
	int	irq;

	Pcidev*	p;
	void	(*ienable)(Atadev*);
} Atadev;

static void pc87415ienable(Atadev*);

static Atadev atadev[NCtlr] = {
	{ 0x1F0, 0x3F4, 14, },	/* primary */
	{ 0x170, 0x374, 15, },	/* secondary */
	{ 0x1E8, 0x3EC,  0, },	/* tertiary */
	{ 0x168, 0x36C,  0, },	/* quaternary */
};
static int natadev = 4;

static void	ataintr(Ureg*, void*);
static long	ataxfer(Drive*, Partition*, int, vlong, long, uchar*);


@@ 259,56 271,99 @@ atagen(Chan* c, Dirtab*, int, int s, Dir* dirp)
}

static void
cmd640b(void)
pc87415ienable(Atadev* devp)
{
	Pcidev *p;
	int r;
	int x;

	/*
	 * Look for CMD640B dual PCI controllers. Amongst other
	 * bugs only one of the controllers can be active at a time.
	 * Unfortunately there's no way to tell which pair of
	 * controllers this is, so if one is found then all controller
	 * pairs are synchronised.
	 */
	p = 0;
	while(p = pcimatch(p, 0x1095, 0x0640)){
		have640b++;
		/*
		 * If one is found, make sure read-ahead is disabled on all
		 * drives and that the 2nd controller is enabled:
		 *   reg 0x51:	bit 7 - drive 1 read ahead disable
		 *  		bit 6 - drive 0 read ahead disable
		 *  		bit 3 - 2nd controller enable
		 *   reg 0x57:	bit 3 - drive 1 read ahead disable
		 *  		bit 2 - drive 0 read ahead disable
		 */
		r = pcicfgr8(p, 0x51);
		r |= 0xC8;
		pcicfgw8(p, 0x51, r);
		r = pcicfgr8(p, 0x57);
		r |= 0x0C;
		pcicfgw8(p, 0x57, r);
	}
	p = devp->p;
	if(p == nil)
		return;

	x = pcicfgr32(p, 0x40);
	if(devp->cmdport == (p->mem[0].bar & ~0x01))
		x &= ~0x00000100;
	else
		x &= ~0x00000200;
	pcicfgw32(p, 0x40, x);
}

static void
rz1000(void)
atareset(void)
{
	Pcidev *p;
	ulong r;

	/*
	 * Look for PC-Tech RZ1000 controllers and turn off prefetch.
	 * This is overkill, but cheap.
	 */
	p = 0;
	while(p = pcimatch(p, 0x1042, 0)){
		if(p->did != 0x1000 && p->did != 0x1001)
			continue;
		r = pcicfgr32(p, 0x40);
		r &= ~0x2000;
		pcicfgw32(p, 0x40, r);
	int ccrp, r;

	p = nil;
	while(p = pcimatch(p, 0, 0)){
		if(p->vid == 0x1095 && p->did == 0x0640){
			/*
			 * CMD640B dual PCI controllers. Amongst other
			 * bugs only one of the controllers can be active at a time.
			 * Unfortunately there's no way to tell which pair of
			 * controllers this is, so if one is found then all controller
			 * pairs are synchronised.
			 */
			have640b++;

			/*
			 * Make sure read-ahead is disabled on all
			 * drives and that the 2nd controller is enabled:
			 *   reg 0x51:	bit 7 - drive 1 read ahead disable
			 *  		bit 6 - drive 0 read ahead disable
			 *  		bit 3 - 2nd controller enable
			 *   reg 0x57:	bit 3 - drive 1 read ahead disable
			 *  		bit 2 - drive 0 read ahead disable
			 */
			r = pcicfgr8(p, 0x51);
			r |= 0xC8;
			pcicfgw8(p, 0x51, r);
			r = pcicfgr8(p, 0x57);
			r |= 0x0C;
			pcicfgw8(p, 0x57, r);
		}
		else if(p->vid == 0x1042 && (p->did == 0x1000 || p->did == 0x1001)){
			/*
			 * PC-Tech RZ1000 controllers.
			 * Turn off prefetch.
			 * This is overkill, but cheap.
			 */
			r = pcicfgr32(p, 0x40);
			r &= ~0x2000;
			pcicfgw32(p, 0x40, r);
		}
		else if(p->vid == 0x100B && p->did == 0x0002){
			/*
			 * National Semiconductor PC87415.
			 * Disable interrupts on both channels until
			 * after they are probed for drives.
			 * This must be called before interrupts are
			 * enabled in case the IRQ is being shared.
			 */
			pcicfgw32(p, 0x40, 0x00000300);

			/*
			 * Add any native-mode channels to the list to
			 * be probed.
			 */
			ccrp = pcicfgr8(p, PciCCRp);
			if((ccrp & 0x01) && natadev < nelem(atadev)){
				atadev[natadev].cmdport = p->mem[0].bar & ~0x01;
				atadev[natadev].ctlport = p->mem[1].bar & ~0x01;
				atadev[natadev].irq = p->intl;
				atadev[natadev].p = p;
				atadev[natadev].ienable = pc87415ienable;
				natadev++;
			}
			if((ccrp & 0x04) && natadev < nelem(atadev)){
				atadev[natadev].cmdport = p->mem[2].bar & ~0x01;
				atadev[natadev].ctlport = p->mem[3].bar & ~0x01;
				atadev[natadev].irq = p->intl;
				atadev[natadev].p = p;
				atadev[natadev].ienable = pc87415ienable;
				natadev++;
			}
		}
	}
}



@@ 318,7 373,7 @@ atactlrwait(Controller* ctlr, uchar pdh, uchar ready, ulong ticks)
	int port;
	uchar dh, status;

	port = ctlr->pbase;
	port = ctlr->cmdport;
	dh = (inb(port+Pdh) & DHslave)^(pdh & DHslave);
	ticks += m->ticks+1;



@@ 365,31 420,39 @@ atadrivealloc(Controller* ctlr, int driveno, int atapi)
}

static int
atactlrprobe(int ctlrno, int irq, int resetok)
atactlrprobe(int ctlrno, Atadev* devp, int irq, int resetok)
{
	Controller *ctlr;
	int atapi, mask, once, port;
	int atapi, cmdport, ctlport, mask, once, timo;
	uchar error, status, msb, lsb;

	cmdport = devp->cmdport;
	ctlport = devp->ctlport;

	/*
	 * Check the existence of a controller by verifying a sensible
	 * value can be written to and read from the drive/head register.
	 * We define the primary/secondary/tertiary and quaternary controller
	 * port addresses to be at fixed values.
	 * If it's OK, allocate and initialise a Controller structure.
	 */
	port = pbase[ctlrno];
	outb(port+Pdh, DHmagic);
	microdelay(1);
	status = inb(port+Pdh) & 0xFF;
	DPRINT("ata%d: port 0x%uX\n", ctlrno, cmdport);
	outb(cmdport+Pdh, DHmagic);
	for(timo = 30000; timo; timo--){
		microdelay(1);
		status = inb(cmdport+Pdh);
		if(status == DHmagic)
			break;
	}
	status = inb(cmdport+Pdh);
	if(status != DHmagic){
		DPRINT("ata%d: DHmagic not ok == 0x%uX\n", ctlrno, status);
		DPRINT("ata%d: DHmagic not ok == 0x%uX, 0x%uX\n",
			ctlrno, status, inb(cmdport+Pstatus));
		return -1;
	}
	DPRINT("ata%d: DHmagic ok\n", ctlrno);
	if((ctlr = xalloc(sizeof(Controller))) == 0)
		return -1;
	ctlr->pbase = port;
	ctlr->cmdport = cmdport;
	ctlr->ctlport = ctlport;
	ctlr->ctlrno = ctlrno;
	ctlr->tbdf = BUSUNKNOWN;
	ctlr->lastcmd = 0xFF;


@@ 400,45 463,45 @@ atactlrprobe(int ctlrno, int irq, int resetok)
	 * Issuing a device reset here would possibly destroy any BIOS
	 * drive remapping and, anyway, some controllers (Vibra16) don't
	 * seem to implement the control-block registers; do it if requested.
	 * Unfortunately the vector must be set at this point as the Cedd
	 * command will generate an interrupt, which means the ataintr routine
	 * will be left on the interrupt call chain even if there are no
	 * drives found.
	 * At least one controller/ATAPI-drive combination doesn't respond
	 * to the Cedd (Micronics M54Li + Sanyo CRD-254P) so let's check for the
	 * ATAPI signature straight off. If we find it there will be no probe
	 * done for a slave. Tough.
	 */
	if(resetok){
		outb(port+Pctrl, Srst|nIEN);
	if(resetok && ctlport){
		outb(ctlport+Pctl, Srst|nIEN);
		delay(10);
		outb(port+Pctrl, 0);
		outb(ctlport+Pctl, 0);
		if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20))){
			DPRINT("ata%d: Srst status 0x%uX/0x%uX/0x%uX\n", ctlrno,
				inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb));
				inb(cmdport+Pstatus), inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb));
			xfree(ctlr);
			return -1;
		}
	}

	/*
	 * Disable interrupts.
	 */
	outb(ctlport+Pctl, nIEN);

	once = 1;
retry:
	atapi = 0;
	mask = 0;
	status = inb(port+Pstatus);
	status = inb(cmdport+Pstatus);
	DPRINT("ata%d: ATAPI 0x%uX 0x%uX 0x%uX\n", ctlrno, status,
		inb(port+Pcylmsb), inb(port+Pcyllsb));
	if(/*status == 0 &&*/ inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){
		inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb));
	USED(status);
	if(/*status == 0 &&*/ inb(cmdport+Pcylmsb) == 0xEB && inb(cmdport+Pcyllsb) == 0x14){
		DPRINT("ata%d: ATAPI ok\n", ctlrno);
		if(once)
			intrenable(irq, ataintr, ctlr, ctlr->tbdf);
		atapi |= 0x01;
		mask |= 0x01;
		goto atapislave;
	}
	if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1)) || waserror()){
	if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1))){
		DPRINT("ata%d: Cedd status 0x%uX/0x%uX/0x%uX\n", ctlrno,
			inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb));
			inb(cmdport+Pstatus), inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb));
		if(once){
			once = 0;
			ctlr->cmd = 0;


@@ 447,12 510,34 @@ retry:
		xfree(ctlr);
		return -1;
	}
	if(once)
		intrenable(irq, ataintr, ctlr, ctlr->tbdf);

	/*
	 * Can only get here if controller is not busy.
	 * If there are drives Sbusy will be set within 400nS.
	 * Wait for the command to complete (6 seconds max).
	 */
	ctlr->cmd = Cedd;
	outb(port+Pcmd, Cedd);
	atasleep(ctlr, Hardtimeout);
	poperror();
	outb(cmdport+Pcmd, Cedd);
	microdelay(1);
	status = inb(cmdport+Pstatus);
	if(!(status & Sbusy)){
		DPRINT("ata%d: !busy 1 0x%uX\n", ctlrno, status);
		xfree(ctlr);
		return -1;
	}
	for(timo = 6000; timo; timo--){
		status = inb(cmdport+Pstatus);
		if(!(status & Sbusy))
			break;
		delay(1);
	}
	DPRINT("ata%d: timo %d\n", ctlrno, 6000-timo);
	status = inb(cmdport+Pstatus);
	if(status & Sbusy){
		DPRINT("ata%d: busy 2 0x%uX\n", ctlrno, status);
		xfree(ctlr);
		return -1;
	}

	/*
	 * The diagnostic returns a code in the error register, good


@@ 474,33 559,34 @@ retry:
	 *	signature may be gone.
	 * When checking status, mask off the IDX bit.
	 */
	error = inb(port+Perror);
	error = inb(cmdport+Perror);
	DPRINT("ata%d: master diag status 0x%uX, error 0x%uX\n",
		ctlr->ctlrno, inb(port+Pstatus), error);
		ctlr->ctlrno, inb(cmdport+Pstatus), error);
	if((error & ~0x80) == 0x01)
		mask |= 0x01;

atapislave:
	outb(port+Pdh, DHmagic|DHslave);
	outb(cmdport+Pdh, DHmagic|DHslave);
	microdelay(1);
	status = inb(port+Pstatus);
	error = inb(port+Perror);
	status = inb(cmdport+Pstatus);
	error = inb(cmdport+Perror);
	DPRINT("ata%d: slave diag status 0x%uX, error 0x%uX\n",
		ctlr->ctlrno, status, error);
	if((status & ~0x02) && (status & (Sbusy|Serr)) == 0 && (error & ~0x80) == 0x01)
		mask |= 0x02;
	else if(status == 0){
		msb = inb(port+Pcylmsb);
		lsb = inb(port+Pcyllsb);
		msb = inb(cmdport+Pcylmsb);
		lsb = inb(cmdport+Pcyllsb);
		DPRINT("ata%d: ATAPI slave 0x%uX 0x%uX 0x%uX\n", ctlrno, status,
			inb(port+Pcylmsb), inb(port+Pcyllsb));
			inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb));
		if(msb == 0xEB && lsb == 0x14){
			atapi |= 0x02;
			mask |= 0x02;
		}
	}
	outb(cmdport+Pdh, DHmagic);

//skipedd:
//skipslave:
	if(mask == 0){
		xfree(ctlr);
		return -1;


@@ 517,29 603,38 @@ atapislave:
	if(mask & 0x02)
		atadrivealloc(ctlr, ctlrno*2+1, atapi & 0x02);

	print("#H%d: cmdport 0x%uX ctlport 0x%uX irq %d mask 0x%uX atapi 0x%uX\n",
		ctlrno, cmdport, ctlport,  irq, mask, atapi);
	intrenable(irq, ataintr, ctlr, ctlr->tbdf);
	inb(cmdport+Pstatus);
	outb(ctlport+Pctl, 0);
	if(devp->ienable)
		devp->ienable(devp);

	return 0;
}

static void
atactlrreset(void)
{
	int ctlrno, driveno, i, resetok, slave, spindown;
	int ctlrno, devno, driveno, i, resetok, slave, spindown;
	ISAConf isa;
	Atadev *devp;

	cmd640b();
	rz1000();

	for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){
	ctlrno = 0;
	for(devno = 0; devno < natadev; devno++){
		devp = &atadev[devno];
		memset(&isa, 0, sizeof(ISAConf));
		if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno)
		isaconfig("ata", ctlrno, &isa);
		if(isa.port && isa.port != devp->cmdport)
			continue;
		if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0)
		if(isa.irq == 0 && (isa.irq = devp->irq) == 0)
			continue;

		driveno = resetok = spindown = 0;
		for(i = 0; i < isa.nopt; i++){
			DPRINT("ata%d: opt %s\n", ctlrno, isa.opt[i]);
			if(strncmp(isa.opt[i], "spindown", 8) == 0){
			if(cistrncmp(isa.opt[i], "spindown", 8) == 0){
				if(isa.opt[i][9] != '=')
					continue;
				if(isa.opt[i][8] == '0')


@@ 554,12 649,13 @@ atactlrreset(void)
					spindown = (Hardtimeout+2000)/1000;
				driveno = ctlrno*2+slave;
			}
			else if(strcmp(isa.opt[i], "reset") == 0)
			else if(cistrcmp(isa.opt[i], "reset") == 0)
				resetok = 1;
		}

		if(atactlrprobe(ctlrno, isa.irq, resetok))
		if(atactlrprobe(ctlrno, devp, isa.irq, resetok))
			continue;
		ctlrno++;

		if(spindown == 0 || atadrive[driveno] == 0)
			continue;


@@ 1038,22 1134,22 @@ ataxfer(Drive *dp, Partition *pp, int cmd, vlong off, long len, uchar *buf)
	cp->dp = dp;
	cp->status = 0;

	outb(cp->pbase+Pcount, cp->nsecs);
	outb(cp->pbase+Psector, sec);
	outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head);
	outb(cp->pbase+Pcyllsb, cyl);
	outb(cp->pbase+Pcylmsb, cyl>>8);
	outb(cp->pbase+Pcmd, cmd);
	outb(cp->cmdport+Pcount, cp->nsecs);
	outb(cp->cmdport+Psector, sec);
	outb(cp->cmdport+Pdh, dp->dh | (dp->lba<<6) | head);
	outb(cp->cmdport+Pcyllsb, cyl);
	outb(cp->cmdport+Pcylmsb, cyl>>8);
	outb(cp->cmdport+Pcmd, cmd);

	if(cmd == Cwrite){
		loop = 0;
		microdelay(1);
		while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0){
		while((stat = inb(cp->cmdport+Pstatus) & (Serr|Sdrq)) == 0){
			microdelay(1);
			if(++loop > 10000)
				panic("%s: ataxfer", dp->vol);
		}
		outss(cp->pbase+Pdata, cp->buf, dp->bytes/2);
		outss(cp->cmdport+Pdata, cp->buf, dp->bytes/2);
	} else
		stat = 0;
	IUNLOCK(&cp->reglock);


@@ 1123,9 1219,9 @@ atafeature(Drive *dp, uchar arg)
	ILOCK(&cp->reglock);
	cp->cmd = Cfeature;
	cp->dp = dp;
	outb(cp->pbase+Pfeature, arg);
	outb(cp->pbase+Pdh, dp->dh);
	outb(cp->pbase+Pcmd, Cfeature);
	outb(cp->cmdport+Pfeature, arg);
	outb(cp->cmdport+Pdh, dp->dh);
	outb(cp->cmdport+Pcmd, Cfeature);
	IUNLOCK(&cp->reglock);

	atasleep(cp, Hardtimeout);


@@ 1216,8 1312,8 @@ retryatapi:
	cp->cmd = cmd;
	cp->dp = dp;
	cp->buf = buf;
	outb(cp->pbase+Pdh, dp->dh);
	outb(cp->pbase+Pcmd, cmd);
	outb(cp->cmdport+Pdh, dp->dh);
	outb(cp->cmdport+Pcmd, cmd);
	IUNLOCK(&cp->reglock);

	DPRINT("%s: ident command 0x%uX sent\n", dp->vol, cmd);


@@ 1273,8 1369,10 @@ retryatapi:
		dp->cyl = ip->ccyls;
		dp->heads = ip->cheads;
		dp->sectors = ip->cs2t;
		XPRINT("%s: changed to %ld cyl %d head %d sec\n",
			dp->vol, dp->cyl, dp->heads, dp->sectors);
		XPRINT("%s: %d/%d/%d changed to %ld/%d/%d CHS\n",
			dp->vol,
			ip->cyls, ip->heads, ip->s2t,
			dp->cyl, dp->heads, dp->sectors);
	}

	lbasecs = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16);


@@ 1337,12 1435,12 @@ ataprobe(Drive *dp, int cyl, int sec, int head)
	cp->sofar = 0;
	cp->buf = buf;

	outb(cp->pbase+Pcount, 1);
	outb(cp->pbase+Psector, sec+1);
	outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head);
	outb(cp->pbase+Pcyllsb, cyl);
	outb(cp->pbase+Pcylmsb, cyl>>8);
	outb(cp->pbase+Pcmd, Cread);
	outb(cp->cmdport+Pcount, 1);
	outb(cp->cmdport+Psector, sec+1);
	outb(cp->cmdport+Pdh, dp->dh | (dp->lba<<6) | head);
	outb(cp->cmdport+Pcyllsb, cyl);
	outb(cp->cmdport+Pcylmsb, cyl>>8);
	outb(cp->cmdport+Pcmd, Cread);
	IUNLOCK(&cp->reglock);

	atasleep(cp, Hardtimeout);


@@ 1612,10 1710,10 @@ ataintr(Ureg*, void* arg)
	ILOCK(&cp->reglock);

	loop = 0;
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){
	while((cp->status = inb(cp->cmdport+Pstatus)) & Sbusy){
		if(++loop > Maxloop){
			print("ata%d: cmd=0x%uX, lastcmd=0x%uX status=0x%uX\n",
				cp->ctlrno, cp->cmd, cp->lastcmd, inb(cp->pbase+Pstatus));
				cp->ctlrno, cp->cmd, cp->lastcmd, inb(cp->cmdport+Pstatus));
			panic("%s: wait busy\n", dp->vol);
		}
		microdelay(1);


@@ 1626,23 1724,23 @@ ataintr(Ureg*, void* arg)
		if(cp->status & Serr){
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			cp->error = inb(cp->pbase+Perror);
			cp->error = inb(cp->cmdport+Perror);
			wakeup(&cp->r);
			break;
		}
		cp->sofar++;
		if(cp->sofar < cp->nsecs){
			loop = 0;
			while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0){
			while(((cp->status = inb(cp->cmdport+Pstatus)) & Sdrq) == 0){
				if(++loop > Maxloop)
					panic("%s: write cmd=%lux status=%lux\n",
						dp->vol, cp->cmd, inb(cp->pbase+Pstatus));
						dp->vol, cp->cmd, inb(cp->cmdport+Pstatus));
				microdelay(1);
			}
			addr = cp->buf;
			if(addr){
				addr += cp->sofar*dp->bytes;
				outss(cp->pbase+Pdata, addr, dp->bytes/2);
				outss(cp->cmdport+Pdata, addr, dp->bytes/2);
			}
		} else{
			cp->lastcmd = cp->cmd;


@@ 1657,24 1755,24 @@ ataintr(Ureg*, void* arg)
		while((cp->status & (Serr|Sdrq)) == 0){
			if(++loop > Maxloop){
				print("%s: read/ident cmd=0x%uX status=0x%uX\n",
					dp->vol, cp->cmd, inb(cp->pbase+Pstatus));
					dp->vol, cp->cmd, inb(cp->cmdport+Pstatus));
				cp->status |= Serr;
				break;
			}
			microdelay(1);
			cp->status = inb(cp->pbase+Pstatus);
			cp->status = inb(cp->cmdport+Pstatus);
		}
		if(cp->status & Serr){
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			cp->error = inb(cp->pbase+Perror);
			cp->error = inb(cp->cmdport+Perror);
			wakeup(&cp->r);
			break;
		}
		addr = cp->buf;
		if(addr){
			addr += cp->sofar*dp->bytes;
			inss(cp->pbase+Pdata, addr, dp->bytes/2);
			inss(cp->cmdport+Pdata, addr, dp->bytes/2);
		}
		cp->sofar++;
		if(cp->sofar > cp->nsecs)


@@ 1685,7 1783,7 @@ ataintr(Ureg*, void* arg)
			//	cp->cmd = Cident2;
			//else
				cp->cmd = 0;
			inb(cp->pbase+Pstatus);
			inb(cp->cmdport+Pstatus);
			wakeup(&cp->r);
		}
		break;


@@ 1708,11 1806,11 @@ ataintr(Ureg*, void* arg)
		if(cp->cmd == 0 && cp->lastcmd == Cpktcmd)
			break;
		if(cp->status & Serr)
			cp->error = inb(cp->pbase+Perror);
			cp->error = inb(cp->cmdport+Perror);
		print("%s: weird interrupt, cmd=%.2ux, lastcmd=%.2ux, ",
			dp->vol, cp->cmd, cp->lastcmd);
		print("status=%.2ux, error=%.2ux, count=%.2ux\n",
			cp->ctlrno, cp->error, inb(cp->pbase+Pcount));
			cp->ctlrno, cp->error, inb(cp->cmdport+Pcount));
		break;
	}



@@ 1741,9 1839,9 @@ ataclock(void)
			DPRINT("%s: spindown\n", dp->vol);
			ILOCK(&cp->reglock);
			cp->cmd = Cstandby;
			outb(cp->pbase+Pcount, 0);
			outb(cp->pbase+Pdh, dp->dh);
			outb(cp->pbase+Pcmd, cp->cmd);
			outb(cp->cmdport+Pcount, 0);
			outb(cp->cmdport+Pdh, dp->dh);
			outb(cp->cmdport+Pcmd, cp->cmd);
			IUNLOCK(&cp->reglock);
			dp->state = Sstandby;
		}


@@ 1756,23 1854,23 @@ isatapi(Drive *dp)
	Controller *cp;

	cp = dp->cp;
	outb(cp->pbase+Pdh, dp->dh);
	outb(cp->cmdport+Pdh, dp->dh);
	DPRINT("%s: isatapi %d\n", dp->vol, dp->atapi);
	outb(cp->pbase+Pcmd, 0x08);
	outb(cp->cmdport+Pcmd, 0x08);
	if(atactlrwait(dp->cp, DHmagic, 0, MS2TK(100))){
		DPRINT("%s: isatapi ctlrwait status 0x%uX\n", dp->vol, inb(cp->pbase+Pstatus));
		DPRINT("%s: isatapi ctlrwait status 0x%uX\n", dp->vol, inb(cp->cmdport+Pstatus));
		return 0;
	}
	dp->atapi = 0;
	dp->bytes = 512;
	microdelay(1);
	if(inb(cp->pbase+Pstatus)){
		DPRINT("%s: isatapi status 0x%uX\n", dp->vol, inb(cp->pbase+Pstatus));
	if(inb(cp->cmdport+Pstatus)){
		DPRINT("%s: isatapi status 0x%uX\n", dp->vol, inb(cp->cmdport+Pstatus));
		return 0;
	}
	if(inb(cp->pbase+Pcylmsb) != 0xEB || inb(cp->pbase+Pcyllsb) != 0x14){
	if(inb(cp->cmdport+Pcylmsb) != 0xEB || inb(cp->cmdport+Pcyllsb) != 0x14){
		DPRINT("%s: isatapi cyl 0x%uX 0x%uX\n",
			dp->vol, inb(cp->pbase+Pcylmsb), inb(cp->pbase+Pcyllsb));
			dp->vol, inb(cp->cmdport+Pcylmsb), inb(cp->cmdport+Pcyllsb));
		return 0;
	}
	dp->atapi = 1;


@@ 1800,24 1898,24 @@ atapiexec(Drive *dp)
	cp->sofar = 0;
	cp->error = 0;
	cp->cmd = Cpktcmd;
	outb(cp->pbase+Pcount, 0);
	outb(cp->pbase+Psector, 0);
	outb(cp->pbase+Pfeature, 0);
	outb(cp->pbase+Pcyllsb, cp->len);
	outb(cp->pbase+Pcylmsb, cp->len>>8);
	outb(cp->pbase+Pdh, dp->dh);
	outb(cp->pbase+Pcmd, cp->cmd);
	outb(cp->cmdport+Pcount, 0);
	outb(cp->cmdport+Psector, 0);
	outb(cp->cmdport+Pfeature, 0);
	outb(cp->cmdport+Pcyllsb, cp->len);
	outb(cp->cmdport+Pcylmsb, cp->len>>8);
	outb(cp->cmdport+Pdh, dp->dh);
	outb(cp->cmdport+Pcmd, cp->cmd);

	if(dp->drqintr == 0){
		microdelay(1);
		for(loop = 0; (inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0; loop++){
		for(loop = 0; (inb(cp->cmdport+Pstatus) & (Serr|Sdrq)) == 0; loop++){
			microdelay(1);
			if(loop < 10000)
				continue;
			panic("%s: cmddrqwait: cmd=%lux status=%lux\n",
				dp->vol, cp->cmd, inb(cp->pbase+Pstatus));
				dp->vol, cp->cmd, inb(cp->cmdport+Pstatus));
		}
		outss(cp->pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2);
		outss(cp->cmdport+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2);
	}
	IUNLOCK(&cp->reglock);



@@ 2063,10 2161,10 @@ static void
atapiintr(Controller *cp)
{
	uchar cause;
	int count, loop, pbase;
	int count, loop, cmdport;

	pbase = cp->pbase;
	cause = inb(pbase+Pcount) & 0x03;
	cmdport = cp->cmdport;
	cause = inb(cmdport+Pcount) & 0x03;
	DPRINT("%s: atapiintr 0x%uX\n", cp->dp->vol, cause);
	switch(cause){



@@ 2074,11 2172,11 @@ atapiintr(Controller *cp)
		if(cp->status & Serr){
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			cp->error = inb(pbase+Perror);
			cp->error = inb(cmdport+Perror);
			wakeup(&cp->r); 
			break;
		}
		outss(pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2);
		outss(cmdport+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2);
		break;

	case 0:						/* data out */


@@ 2087,7 2185,7 @@ atapiintr(Controller *cp)
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			if(cp->status & Serr)
				cp->error = inb(pbase+Perror);
				cp->error = inb(cmdport+Perror);
			wakeup(&cp->r);	 
			break;	
		}


@@ 2098,24 2196,24 @@ atapiintr(Controller *cp)
				break;
			}
			microdelay(1);
			cp->status = inb(pbase+Pstatus);
			cp->status = inb(cmdport+Pstatus);
		}
		if(cp->status & Serr){
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			cp->error = inb(pbase+Perror);
			cp->error = inb(cmdport+Perror);
			print("%s: Cpktcmd status=0x%uX, error=0x%uX\n",
				cp->dp->vol, cp->status, cp->error);
			wakeup(&cp->r);
			break;
		}
		count = inb(pbase+Pcyllsb)|(inb(pbase+Pcylmsb)<<8);
		count = inb(cmdport+Pcyllsb)|(inb(cmdport+Pcylmsb)<<8);
		if(cp->count+count > Maxxfer)
			panic("hd%d: count %d, already %d\n", count, cp->count);
		if(cause == 0)
			outss(pbase+Pdata, cp->buf+cp->count, count/2);
			outss(cmdport+Pdata, cp->buf+cp->count, count/2);
		else
			inss(pbase+Pdata, cp->buf+cp->count, count/2);
			inss(cmdport+Pdata, cp->buf+cp->count, count/2);
		cp->count += count;
		break;



@@ 2123,7 2221,7 @@ atapiintr(Controller *cp)
		cp->lastcmd = cp->cmd;
		cp->cmd = 0;
		if(cp->status & Serr)
			cp->error = inb(cp->pbase+Perror);
			cp->error = inb(cp->cmdport+Perror);
		wakeup(&cp->r);	
		break;
	}


@@ 2133,7 2231,7 @@ Dev atadevtab = {
	'H',
	"ata",

	devreset,
	atareset,
	devinit,
	ataattach,
	devclone,

M pc/ether82557.c => pc/ether82557.c +4 -0
@@ 362,6 362,9 @@ attach(Ether* ether)
	ctlr = ether->ctlr;
	lock(&ctlr->slock);
	if(ctlr->state == 0){
		ilock(&ctlr->rlock);
		csr8w(ctlr, Interrupt, 0);
		iunlock(&ctlr->rlock);
		command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp));
		ctlr->state = 1;



@@ 970,6 973,7 @@ reset(Ether* ether)
	ilock(&ctlr->rlock);
	csr32w(ctlr, Port, 0);
	delay(1);
	csr8w(ctlr, Interrupt, InterruptM);
	iunlock(&ctlr->rlock);

	command(ctlr, LoadRUB, 0);