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

1998/0106/pc/devata.c (diff list | history)

1995/0213/sys/src/9/pc/devata.c:118,1241995/0214/sys/src/9/pc/devata.c:118,124 (short | long)
BUG fix/clarity fix?: explicitly name reglock so that ilock can be explicitly told to use the lock, not the qlock. XXX check compiler
rsc Fri Mar 4 12:44:25 2005
1995/0213    
{ 
	QLock;			/* exclusive access to the controller */ 
 
	Lock;			/* exclusive access to the registers */ 
1995/0214    
	Lock	reglock;	/* exclusive access to the registers */ 
1995/0213    
 
	int	confused;	/* needs to be recalibrated (or worse) */ 
	int	pbase;		/* base port */ 
1995/0213/sys/src/9/pc/devata.c:566,5721995/0214/sys/src/9/pc/devata.c:566,572
1995/0213    
	dp->usetime = m->ticks; 
	cmdreadywait(dp); 
 
	ilock(cp); 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->sofar = 0; 
	cp->buf = buf; 
	cp->nsecs = len; 
1995/0213/sys/src/9/pc/devata.c:589,5951995/0214/sys/src/9/pc/devata.c:589,595
1995/0213    
		outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); 
	} else 
		stat = 0; 
	iunlock(cp); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	if(stat & Serr) 
		error(Eio); 
1995/0213/sys/src/9/pc/devata.c:646,6571995/0214/sys/src/9/pc/devata.c:646,657
1995/0213    
 
	cmdreadywait(dp); 
 
	ilock(cp); 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->cmd = Csetbuf; 
	outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55);	/* read look ahead */ 
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); 
	outb(cp->pbase+Pcmd, Csetbuf); 
	iunlock(cp); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
 
1995/0213/sys/src/9/pc/devata.c:727,7331995/0214/sys/src/9/pc/devata.c:727,733
1995/0213    
 
	cmdreadywait(dp); 
 
	ilock(cp); 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->nsecs = 1; 
	cp->sofar = 0; 
	cp->cmd = Cident; 
1995/0213/sys/src/9/pc/devata.c:735,7411995/0214/sys/src/9/pc/devata.c:735,741
1995/0213    
	cp->buf = buf; 
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); 
	outb(cp->pbase+Pcmd, Cident); 
	iunlock(cp); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
	if(cp->status & Serr){ 
1995/0213/sys/src/9/pc/devata.c:812,8181995/0214/sys/src/9/pc/devata.c:812,818
1995/0213    
 
	cmdreadywait(dp); 
 
	ilock(cp); 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->cmd = Cread; 
	cp->dp = dp; 
	cp->status = 0; 
1995/0213/sys/src/9/pc/devata.c:825,8311995/0214/sys/src/9/pc/devata.c:825,831
1995/0213    
	outb(cp->pbase+Pcyllsb, cyl); 
	outb(cp->pbase+Pcylmsb, cyl>>8); 
	outb(cp->pbase+Pcmd, Cread); 
	iunlock(cp); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
 
1995/0213/sys/src/9/pc/devata.c:1058,10641995/0214/sys/src/9/pc/devata.c:1058,1064
1995/0213    
	cp = &atac[0]; 
	dp = cp->dp; 
 
	ilock(cp); 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
 
	loop = 0; 
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ 
1995/0213/sys/src/9/pc/devata.c:1152,11581995/0214/sys/src/9/pc/devata.c:1152,1158
1995/0213    
		break; 
	} 
 
	iunlock(cp); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
} 
 
void 
1995/0213/sys/src/9/pc/devata.c:1172,11831995/0214/sys/src/9/pc/devata.c:1172,1183
1995/0213    
 
		diff = TK2SEC(m->ticks - dp->usetime); 
		if((dp->state == Sspinning) && (diff >= spindowntime)){ 
			ilock(cp); 
1995/0214    
			ilock(&cp->reglock); 
1995/0213    
			cp->cmd = Cstandby; 
			outb(cp->pbase+Pcount, 0); 
			outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | 0); 
			outb(cp->pbase+Pcmd, cp->cmd); 
			iunlock(cp); 
1995/0214    
			iunlock(&cp->reglock); 
1995/0213    
			dp->state = Sstandby; 
		} 
	} 
1995/0214/sys/src/9/pc/devata.c:8,141995/0215/sys/src/9/pc/devata.c:8,14 (short | long)
disable debugging prints BUG fix: ignore drives that are not online.
remove conf.nhard; configure all existing drives.
HW BUG fix: use DHmagic to make sure or in 0xA0 not just 0x20 on head register.
rsc Fri Mar 4 12:44:25 2005
1995/0213    
 
#include	"devtab.h" 
 
#define DPRINT if(1)print 
1995/0215    
#define DPRINT if(0)print 
1995/0213    
 
typedef	struct Drive		Drive; 
typedef	struct Ident		Ident; 
1995/0214/sys/src/9/pc/devata.c:55,601995/0215/sys/src/9/pc/devata.c:55,63
1995/0213    
	Sidle, 
	Spowerdown, 
 
1995/0215    
	/* something we have to or into the drive/head reg */ 
	DHmagic=	0xA0, 
 
1995/0213    
	/* file types */ 
	Qdir=		0, 
 
1995/0214/sys/src/9/pc/devata.c:167,1731995/0215/sys/src/9/pc/devata.c:170,176
1995/0213    
		return -1; 
	dp = &ata[drive]; 
 
	if(s >= dp->npart) 
1995/0215    
	if(dp->online == 0 || s >= dp->npart) 
1995/0213    
		return 0; 
 
	pp = &dp->p[s]; 
1995/0214/sys/src/9/pc/devata.c:179,2251995/0215/sys/src/9/pc/devata.c:182,223
1995/0213    
	return 1; 
} 
 
/* 
 *  we assume drives 0 and 1 are on the first controller, 2 and 3 on the 
 *  second, etc. 
 */ 
void 
atareset(void) 
{ 
	Drive *dp; 
	Controller *cp; 
	int drive; 
	uchar equip; 
	char *p; 
 
	ata = xalloc(conf.nhard * sizeof(Drive)); 
	atac = xalloc(((conf.nhard+1)/2) * sizeof(Controller)); 
	                 
	/* 
	 *  read nvram for number of ata drives (2 max) 
	 */ 
	equip = nvramread(0x12); 
	if(conf.nhard > 0 && (equip>>4) == 0) 
		conf.nhard = 0; 
	if(conf.nhard > 1 && (equip&0xf) == 0) 
		conf.nhard = 1; 
	if(conf.nhard > 2) 
		conf.nhard = 2; 
1995/0215    
	if(equip == 0) 
		equip = 0x10;		/* the Globalyst 250 lies */ 
1995/0213    
 
	for(drive = 0; drive < conf.nhard; drive++){ 
		dp = &ata[drive]; 
		cp = &atac[drive/2]; 
		dp->drive = drive&1; 
1995/0215    
	ata = xalloc(2 * sizeof(Drive)); 
	atac = xalloc(sizeof(Controller)); 
 
	cp = atac; 
	cp->buf = 0; 
	cp->lastcmd = cp->cmd; 
	cp->cmd = 0; 
	cp->pbase = Pbase; 
	setvec(Hardvec, ataintr, 0); 
 
	dp = ata; 
	if(equip & 0xf0){ 
		dp->drive = 0; 
1995/0213    
		dp->online = 0; 
		dp->cp = cp; 
		if((drive&1) == 0){ 
			cp->buf = 0; 
			cp->lastcmd = cp->cmd; 
			cp->cmd = 0; 
			cp->pbase = Pbase; 
			setvec(Hardvec, ataintr, 0); 
		} 
1995/0215    
		dp++; 
1995/0213    
	} 
1995/0215    
	if((equip & 0x0f)){ 
		dp->drive = 1; 
		dp->online = 0; 
		dp->cp = cp; 
		dp++; 
	} 
	conf.nhard = dp - ata; 
1995/0213    
	 
	if(conf.nhard && (p = getconf("spindowntime"))) 
		spindowntime = atoi(p); 
1995/0214/sys/src/9/pc/devata.c:576,5821995/0215/sys/src/9/pc/devata.c:574,580
1995/0213    
 
	outb(cp->pbase+Pcount, cp->nsecs); 
	outb(cp->pbase+Psector, sec); 
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | (dp->lba<<6) | head); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head); 
1995/0213    
	outb(cp->pbase+Pcyllsb, cyl); 
	outb(cp->pbase+Pcylmsb, cyl>>8); 
	outb(cp->pbase+Pcmd, cmd); 
1995/0214/sys/src/9/pc/devata.c:649,6551995/0215/sys/src/9/pc/devata.c:647,653
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->cmd = Csetbuf; 
	outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55);	/* read look ahead */ 
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 
1995/0213    
	outb(cp->pbase+Pcmd, Csetbuf); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
1995/0214/sys/src/9/pc/devata.c:733,7391995/0215/sys/src/9/pc/devata.c:731,737
1995/0213    
	cp->cmd = Cident; 
	cp->dp = dp; 
	cp->buf = buf; 
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 
1995/0213    
	outb(cp->pbase+Pcmd, Cident); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
1995/0214/sys/src/9/pc/devata.c:761,7681995/0215/sys/src/9/pc/devata.c:759,765
1995/0213    
		dp->lba = 1; 
		dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 
		dp->cap = dp->bytes * dp->sectors; 
		print("ata%d model %s with %d lba sectors\n", dp->drive, 
			id, dp->sectors); 
1995/0215    
print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors); 
1995/0213    
	} else { 
		dp->lba = 0; 
 
1995/0214/sys/src/9/pc/devata.c:770,7771995/0215/sys/src/9/pc/devata.c:767,774
1995/0213    
		dp->cyl = ip->cyls; 
		dp->heads = ip->heads; 
		dp->sectors = ip->s2t; 
		print("ata%d model %s with default %d cyl %d head %d sec\n", dp->drive, 
			id, dp->cyl, dp->heads, dp->sectors); 
1995/0215    
/*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive, 
			id, dp->cyl, dp->heads, dp->sectors);/**/ 
1995/0213    
 
		if(ip->cvalid&(1<<0)){ 
			/* use current settings */ 
1995/0214/sys/src/9/pc/devata.c:778,7851995/0215/sys/src/9/pc/devata.c:775,781
1995/0213    
			dp->cyl = ip->ccyls; 
			dp->heads = ip->cheads; 
			dp->sectors = ip->cs2t; 
			print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, 
				dp->heads, dp->sectors); 
1995/0215    
/*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/ 
1995/0213    
		} 
		dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; 
	} 
1995/0214/sys/src/9/pc/devata.c:821,8271995/0215/sys/src/9/pc/devata.c:817,823
1995/0213    
 
	outb(cp->pbase+Pcount, 1); 
	outb(cp->pbase+Psector, sec+1); 
	outb(cp->pbase+Pdh, 0x20 | head | (dp->drive<<4)); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); 
1995/0213    
	outb(cp->pbase+Pcyllsb, cyl); 
	outb(cp->pbase+Pcylmsb, cyl>>8); 
	outb(cp->pbase+Pcmd, Cread); 
1995/0214/sys/src/9/pc/devata.c:857,8631995/0215/sys/src/9/pc/devata.c:853,859
1995/0213    
	ataident(dp); 
	if(dp->lba){ 
		i = dp->sectors - 1; 
		if(ataprobe(dp, (i>>8)&0xffff, i&0xff, (i>>24)&0xf) == 0) 
1995/0215    
		if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0) 
1995/0213    
			return; 
	} else { 
		if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0) 
1995/0214/sys/src/9/pc/devata.c:868,8741995/0215/sys/src/9/pc/devata.c:864,870
1995/0213    
	 *  the drive lied, determine parameters by seeing which ones 
	 *  work to read sectors. 
	 */ 
print("ata%d lied.  probing...\n", dp->drive); 
1995/0215    
print("ata%d probing...\n", dp->drive); 
1995/0213    
	dp->lba = 0; 
	for(i = 0; i < 32; i++) 
		if(ataprobe(dp, 0, 0, i) < 0) 
1995/0214/sys/src/9/pc/devata.c:1038,10431995/0215/sys/src/9/pc/devata.c:1034,1044
1995/0213    
		atareplinit(dp); 
} 
 
1995/0215    
enum 
{ 
	Maxloop=	10000, 
}; 
 
1995/0213    
/* 
 *  we get an interrupt for every sector transferred 
 */ 
1995/0214/sys/src/9/pc/devata.c:1062,10681995/0215/sys/src/9/pc/devata.c:1063,1069
1995/0213    
 
	loop = 0; 
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ 
		if(++loop > 100) { 
1995/0215    
		if(++loop > Maxloop) { 
1995/0213    
			DPRINT("cmd=%lux status=%lux\n", 
				cp->cmd, inb(cp->pbase+Pstatus)); 
			panic("ataintr: wait busy"); 
1995/0214/sys/src/9/pc/devata.c:1082,10881995/0215/sys/src/9/pc/devata.c:1083,1089
1995/0213    
		if(cp->sofar < cp->nsecs){ 
			loop = 0; 
			while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) 
				if(++loop > 100) { 
1995/0215    
				if(++loop > Maxloop) { 
1995/0213    
					DPRINT("cmd=%lux status=%lux\n", 
						cp->cmd, inb(cp->pbase+Pstatus)); 
					panic("ataintr: write"); 
1995/0214/sys/src/9/pc/devata.c:1102,11081995/0215/sys/src/9/pc/devata.c:1103,1109
1995/0213    
	case Cident: 
		loop = 0; 
		while((cp->status & (Serr|Sdrq)) == 0){ 
			if(++loop > 10000) { 
1995/0215    
			if(++loop > Maxloop) { 
1995/0213    
				DPRINT("cmd=%lux status=%lux\n", 
					cp->cmd, inb(cp->pbase+Pstatus)); 
				panic("ataintr: read/ident"); 
1995/0214/sys/src/9/pc/devata.c:1175,11811995/0215/sys/src/9/pc/devata.c:1176,1182
1995/0214    
			ilock(&cp->reglock); 
1995/0213    
			cp->cmd = Cstandby; 
			outb(cp->pbase+Pcount, 0); 
			outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | 0); 
1995/0215    
			outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); 
1995/0213    
			outb(cp->pbase+Pcmd, cp->cmd); 
1995/0214    
			iunlock(&cp->reglock); 
1995/0213    
			dp->state = Sstandby; 
1995/0215/sys/src/9/pc/devata.c:759,7651995/0222/sys/src/9/pc/devata.c:759,765 (short | long)
disable debugging prints
rsc Fri Mar 4 12:44:25 2005
1995/0213    
		dp->lba = 1; 
		dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 
		dp->cap = dp->bytes * dp->sectors; 
1995/0215    
print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors); 
1995/0222    
/*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ 
1995/0213    
	} else { 
		dp->lba = 0; 
 
1995/0222/sys/src/9/pc/devata.c:290,2981995/0726/sys/src/9/pc/devata.c:290,297 (short | long)
anonymize
rsc Fri Mar 4 12:44:25 2005
1995/0213    
} 
 
void 
atacreate(Chan *c, char *name, int omode, ulong perm) 
1995/0726    
atacreate(Chan*, char*, int, ulong) 
1995/0213    
{ 
	USED(c, name, omode, perm); 
	error(Eperm); 
} 
 
1995/0726/sys/src/9/pc/devata.c:813,8181995/0728/sys/src/9/pc/devata.c:813,819 (short | long)
HW BUG double fix: empty buffer always; also set cp->buf even though we don't need to in ataprobe. (Either would fix the HW bug).
rsc Fri Mar 4 12:44:25 2005
1995/0213    
	cp->status = 0; 
	cp->nsecs = 1; 
	cp->sofar = 0; 
1995/0728    
	cp->buf = buf; 
1995/0213    
 
	outb(cp->pbase+Pcount, 1); 
	outb(cp->pbase+Psector, sec+1); 
1995/0726/sys/src/9/pc/devata.c:1120,11251995/0728/sys/src/9/pc/devata.c:1121,1130
1995/0213    
		if(addr){ 
			addr += cp->sofar*dp->bytes; 
			inss(cp->pbase+Pdata, addr, dp->bytes/2); 
1995/0728    
		} else { 
			/* old drives/controllers hang unless the buffer is emptied */ 
			for(loop = dp->bytes/2; --loop >= 0;) 
				ins(cp->pbase+Pdata); 
1995/0213    
		} 
		cp->sofar++; 
		if(cp->sofar > cp->nsecs) 
1995/0728/sys/src/9/pc/devata.c:19,251995/0818/sys/src/9/pc/devata.c:19,26 (short | long)
deanonymize atacreate (XXX).
look for drives on both controllers. add atasleep, which has a timeout.
HW BUG fix: make Hardtimeout 4 seconds, not 10ms. HW BUG fix: use atasleep everywhere, in case of buggy controllers. HW BUG fix: ignore lbasecs if all 'F's. HW BUG fix: increase Maxloop XXX. HW BUG fix? do not read buffer if no cp->buf. (XXX look for cmd with cp->buf==0.
rsc Fri Mar 4 12:44:25 2005
1995/0213    
enum 
{ 
	/* ports */ 
	Pbase=		0x1F0, 
1995/0818    
	Pbase0=		0x1F0, 
	Pbase1=		0x170, 
1995/0213    
	Pdata=		0,	/* data port (16 bits) */ 
	Perror=		1,	/* error port (read) */ 
	Pprecomp=	1,	/* buffer mode port (write) */ 
1995/0728/sys/src/9/pc/devata.c:64,691995/0818/sys/src/9/pc/devata.c:65,72
1995/0213    
	Maxxfer=	BY2PG,		/* maximum transfer size/cmd */ 
	Npart=		8+2,		/* 8 sub partitions, disk, and partition */ 
	Nrepl=		64,		/* maximum replacement blocks */ 
1995/0818    
 
	Hardtimeout=	4000,		/* disk access timeout */ 
1995/0213    
}; 
#define PART(x)		((x)&0xF) 
#define DRIVE(x)	(((x)>>4)&0x7) 
1995/0728/sys/src/9/pc/devata.c:201,2081995/0818/sys/src/9/pc/devata.c:204,211
1995/0215    
	cp->buf = 0; 
	cp->lastcmd = cp->cmd; 
	cp->cmd = 0; 
	cp->pbase = Pbase; 
	setvec(Hardvec, ataintr, 0); 
1995/0818    
	cp->pbase = Pbase0; 
	setvec(ATAvec0, ataintr, 0); 
1995/0215    
 
	dp = ata; 
	if(equip & 0xf0){ 
1995/0728/sys/src/9/pc/devata.c:290,2971995/0818/sys/src/9/pc/devata.c:293,301
1995/0213    
} 
 
void 
1995/0726    
atacreate(Chan*, char*, int, ulong) 
1995/0818    
atacreate(Chan *c, char *name, int omode, ulong perm) 
1995/0213    
{ 
1995/0818    
	USED(c, name, omode, perm); 
1995/0213    
	error(Eperm); 
} 
 
1995/0728/sys/src/9/pc/devata.c:505,5101995/0818/sys/src/9/pc/devata.c:509,525
1995/0213    
	} 
} 
 
1995/0818    
static void 
atasleep(Controller *cp) 
{ 
	tsleep(&cp->r, cmddone, cp, Hardtimeout); 
	if(cp->cmd && cp->cmd != Cident2){ 
		DPRINT("hard drive timeout\n"); 
		error("ata drive timeout"); 
	} 
} 
 
 
1995/0213    
/* 
 *  transfer a number of sectors.  ataintr will perform all the iterative 
 *  parts. 
1995/0728/sys/src/9/pc/devata.c:548,5531995/0818/sys/src/9/pc/devata.c:563,570
1995/0213    
		head = ((lblk/dp->sectors) % dp->heads); 
	} 
 
1995/0818    
/*print("ataxfer cyl %d sec %d head %d\n", cyl, sec, head);/**/ 
 
1995/0213    
	cp = dp->cp; 
	qlock(cp); 
	if(waserror()){ 
1995/0728/sys/src/9/pc/devata.c:604,6101995/0818/sys/src/9/pc/devata.c:621,627
1995/0213    
			nexterror(); 
		} 
	} 
	sleep(&cp->r, cmddone, cp); 
1995/0818    
	atasleep(cp); 
1995/0213    
	dp->state = Sspinning; 
	dp->usetime = m->ticks; 
	poperror(); 
1995/0728/sys/src/9/pc/devata.c:650,6561995/0818/sys/src/9/pc/devata.c:667,673
1995/0213    
	outb(cp->pbase+Pcmd, Csetbuf); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
1995/0818    
	atasleep(cp); 
1995/0213    
 
/*	if(cp->status & Serr) 
		DPRINT("hd%d setbuf err: status %lux, err %lux\n", 
1995/0728/sys/src/9/pc/devata.c:713,7181995/0818/sys/src/9/pc/devata.c:730,736
1995/0213    
	char *buf; 
	Ident *ip; 
	char id[21]; 
1995/0818    
	ulong lbasecs; 
1995/0213    
 
	cp = dp->cp; 
	buf = smalloc(Maxxfer); 
1995/0728/sys/src/9/pc/devata.c:734,7401995/0818/sys/src/9/pc/devata.c:752,759
1995/0213    
	outb(cp->pbase+Pcmd, Cident); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
1995/0818    
	atasleep(cp); 
 
1995/0213    
	if(cp->status & Serr){ 
		DPRINT("bad disk ident status\n"); 
		error(Eio); 
1995/0728/sys/src/9/pc/devata.c:749,7621995/0818/sys/src/9/pc/devata.c:768,782
1995/0213    
	 * causing a panic and much confusion. 
	 */ 
	if (cp->cmd == Cident2) 
		tsleep(&cp->r, return0, 0, 10); 
1995/0818    
		tsleep(&cp->r, return0, 0, Hardtimeout); 
1995/0213    
 
	memmove(id, ip->model, sizeof(id)-1); 
	id[sizeof(id)-1] = 0; 
 
	if(ip->capabilities & (1<<9)){ 
1995/0818    
	lbasecs = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 
	if((ip->capabilities & (1<<9)) && (lbasecs & 0xf0000000) == 0){ 
1995/0213    
		dp->lba = 1; 
		dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 
1995/0818    
		dp->sectors = lbasecs; 
1995/0213    
		dp->cap = dp->bytes * dp->sectors; 
1995/0222    
/*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ 
1995/0213    
	} else { 
1995/0728/sys/src/9/pc/devata.c:823,8291995/0818/sys/src/9/pc/devata.c:843,849
1995/0213    
	outb(cp->pbase+Pcmd, Cread); 
1995/0214    
	iunlock(&cp->reglock); 
1995/0213    
 
	sleep(&cp->r, cmddone, cp); 
1995/0818    
	atasleep(cp); 
1995/0213    
 
	if(cp->status & Serr) 
		rv = -1; 
1995/0728/sys/src/9/pc/devata.c:864,8701995/0818/sys/src/9/pc/devata.c:884,889
1995/0213    
	 *  the drive lied, determine parameters by seeing which ones 
	 *  work to read sectors. 
	 */ 
1995/0215    
print("ata%d probing...\n", dp->drive); 
1995/0213    
	dp->lba = 0; 
	for(i = 0; i < 32; i++) 
		if(ataprobe(dp, 0, 0, i) < 0) 
1995/0728/sys/src/9/pc/devata.c:1036,10421995/0818/sys/src/9/pc/devata.c:1055,1061
1995/0213    
 
1995/0215    
enum 
{ 
	Maxloop=	10000, 
1995/0818    
	Maxloop=	1000000, 
1995/0215    
}; 
 
1995/0213    
/* 
1995/0728/sys/src/9/pc/devata.c:1063,10731995/0818/sys/src/9/pc/devata.c:1082,1090
1995/0213    
 
	loop = 0; 
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ 
1995/0215    
		if(++loop > Maxloop) { 
1995/0213    
			DPRINT("cmd=%lux status=%lux\n", 
1995/0818    
		if(++loop > Maxloop) 
			panic("ataintr: wait busy cmd=%lux status=%lux", 
1995/0213    
				cp->cmd, inb(cp->pbase+Pstatus)); 
			panic("ataintr: wait busy"); 
		} 
	} 
 
	switch(cp->cmd){ 
1995/0728/sys/src/9/pc/devata.c:1083,10931995/0818/sys/src/9/pc/devata.c:1100,1108
1995/0213    
		if(cp->sofar < cp->nsecs){ 
			loop = 0; 
			while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) 
1995/0215    
				if(++loop > Maxloop) { 
1995/0213    
					DPRINT("cmd=%lux status=%lux\n", 
1995/0818    
				if(++loop > Maxloop) 
					panic("ataintr: write cmd=%lux status=%lux\n", 
1995/0213    
						cp->cmd, inb(cp->pbase+Pstatus)); 
					panic("ataintr: write"); 
				} 
			addr = cp->buf; 
			if(addr){ 
				addr += cp->sofar*dp->bytes; 
1995/0728/sys/src/9/pc/devata.c:1103,11121995/0818/sys/src/9/pc/devata.c:1118,1128
1995/0213    
	case Cident: 
		loop = 0; 
		while((cp->status & (Serr|Sdrq)) == 0){ 
1995/0215    
			if(++loop > Maxloop) { 
1995/0213    
				DPRINT("cmd=%lux status=%lux\n", 
1995/0818    
			if(++loop > Maxloop){ 
				print("ataintr: read/ident cmd=%lux status=%lux\n", 
1995/0213    
					cp->cmd, inb(cp->pbase+Pstatus)); 
				panic("ataintr: read/ident"); 
1995/0818    
				cp->status |= Serr; 
				break; 
1995/0213    
			} 
			cp->status = inb(cp->pbase+Pstatus); 
		} 
1995/0728/sys/src/9/pc/devata.c:1121,11301995/0818/sys/src/9/pc/devata.c:1137,1142
1995/0213    
		if(addr){ 
			addr += cp->sofar*dp->bytes; 
			inss(cp->pbase+Pdata, addr, dp->bytes/2); 
1995/0728    
		} else { 
			/* old drives/controllers hang unless the buffer is emptied */ 
			for(loop = dp->bytes/2; --loop >= 0;) 
				ins(cp->pbase+Pdata); 
1995/0213    
		} 
		cp->sofar++; 
		if(cp->sofar > cp->nsecs) 
1995/0818/sys/src/9/pc/devata.c:885,8951995/0908/sys/src/9/pc/devata.c:885,895 (short | long)
HW bug fix: probe for fewer heads, sectors per track.
rsc Fri Mar 4 12:44:25 2005
1995/0213    
	 *  work to read sectors. 
	 */ 
	dp->lba = 0; 
	for(i = 0; i < 32; i++) 
1995/0908    
	for(i = 0; i < 16; i++) 
1995/0213    
		if(ataprobe(dp, 0, 0, i) < 0) 
			break; 
	dp->heads = i; 
	for(i = 0; i < 128; i++) 
1995/0908    
	for(i = 0; i < 64; i++) 
1995/0213    
		if(ataprobe(dp, 0, i, 0) < 0) 
			break; 
	dp->sectors = i; 
1995/0908/sys/src/9/pc/devata.c:1,31995/1206/sys/src/9/pc/devata.c:1,7 (short | long)
1995/1206    
/* 
 * This has gotten a bit messy with the addition of multiple controller 
 * and ATAPI support; needs a rewrite before adding any 'ctl' functions. 
 */ 
1995/0213    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
1995/0908/sys/src/9/pc/devata.c:9,141995/1206/sys/src/9/pc/devata.c:13,21
1995/0213    
#include	"devtab.h" 
 
1995/0215    
#define DPRINT if(0)print 
1995/1206    
#define XPRINT if(0)print 
#define ILOCK(x) 
#define IUNLOCK(x) 
1995/0213    
 
typedef	struct Drive		Drive; 
typedef	struct Ident		Ident; 
1995/0908/sys/src/9/pc/devata.c:19,731995/1206/sys/src/9/pc/devata.c:26,87
1995/0213    
enum 
{ 
	/* ports */ 
1995/0818    
	Pbase0=		0x1F0, 
	Pbase1=		0x170, 
1995/1206    
	Pbase0=		0x1F0,	/* primary */ 
	Pbase1=		0x170,	/* secondary */ 
	Pbase2=		0x1E8,	/* tertiary */ 
	Pbase3=		0x168,	/* quaternary */ 
1995/0213    
	Pdata=		0,	/* data port (16 bits) */ 
	Perror=		1,	/* error port (read) */ 
	Pprecomp=	1,	/* buffer mode port (write) */ 
1995/1206    
	 Eabort=	(1<<2), 
	Pfeature=	1,	/* buffer mode port (write) */ 
1995/0213    
	Pcount=		2,	/* sector count port */ 
	Psector=	3,	/* sector number port */ 
	Pcyllsb=	4,	/* least significant byte cylinder # */ 
	Pcylmsb=	5,	/* most significant byte cylinder # */ 
	Pdh=		6,	/* drive/head port */ 
1995/1206    
	 DHmagic=	0xA0, 
	 DHslave=	0x10, 
1995/0213    
	Pstatus=	7,	/* status port (read) */ 
	 Sbusy=		 (1<<7), 
	 Sready=	 (1<<6), 
1995/1206    
	 Sdf=		 (1<<5), 
1995/0213    
	 Sdrq=		 (1<<3), 
	 Serr=		 (1<<0), 
	Pcmd=		7,	/* cmd port (write) */ 
 
	/* commands */ 
	Crecal=		0x10, 
1995/1206    
	Cfirst=		0xFF,	/* pseudo command for initialisation */ 
1995/0213    
	Cread=		0x20, 
	Cwrite=		0x30, 
1995/1206    
	Cedd=		0x90,	/* execute device diagnostics */ 
1995/0213    
	Cident=		0xEC, 
	Cident2=	0xFF,	/* pseudo command for post Cident interrupt */ 
	Csetbuf=	0xEF, 
	Cinitparam=	0x91, 
1995/1206    
	Cident2=	0xFE,	/* pseudo command for post Cident interrupt */ 
	Cfeature=	0xEF, 
1995/0213    
 
	/* conner specific commands */ 
	Cstandby=	0xE2, 
	Cidle=		0xE1, 
	Cpowerdown=	0xE3, 
 
1995/1206    
	Cpktcmd=	0xA0, 
	Cidentd=	0xA1, 
	Ccapacity=	0x25, 
	Cread2=		0x28, 
 
1995/0213    
	/* disk states */ 
	Sspinning, 
	Sstandby, 
	Sidle, 
	Spowerdown, 
 
1995/0215    
	/* something we have to or into the drive/head reg */ 
	DHmagic=	0xA0, 
                 
1995/0213    
	/* file types */ 
	Qdir=		0, 
 
	Maxxfer=	BY2PG,		/* maximum transfer size/cmd */ 
	Npart=		8+2,		/* 8 sub partitions, disk, and partition */ 
1995/1206    
	Npart=		20+2,		/* 8 sub partitions, disk, and partition */ 
1995/0213    
	Nrepl=		64,		/* maximum replacement blocks */ 
1995/0818    
 
	Hardtimeout=	4000,		/* disk access timeout */ 
1995/1206    
	Hardtimeout=	30000,		/* disk access timeout (ms) */ 
 
	NCtlr=		4, 
	NDrive=		NCtlr*2, 
1995/0213    
}; 
1995/1206    
 
1995/0213    
#define PART(x)		((x)&0xF) 
#define DRIVE(x)	(((x)>>4)&0x7) 
#define MKQID(d,p)	(((d)<<4) | (p)) 
1995/0908/sys/src/9/pc/devata.c:97,1061995/1206/sys/src/9/pc/devata.c:111,123
1995/0213    
	QLock; 
 
	Controller *cp; 
	int	drive; 
	int	confused;	/* needs to be recalibrated (or worse) */ 
	int	online; 
1995/1206    
	uchar	driveno; 
	uchar	dh;		/* DHmagic|Am-I-A-Slave */ 
	uchar	atapi; 
	uchar	online; 
 
1995/0213    
	int	npart;		/* number of real partitions */ 
1995/1206    
	int	partok; 
1995/0213    
	Partition p[Npart]; 
	Repl	repl; 
	ulong	usetime; 
1995/0908/sys/src/9/pc/devata.c:112,1201995/1206/sys/src/9/pc/devata.c:129,142
1995/0213    
	int	sectors;	/* sectors/track */ 
	int	heads;		/* heads/cyl */ 
	long	cyl;		/* cylinders/drive */ 
1995/1206    
	ulong	lbasecs; 
1995/0213    
 
	char	lba;		/* true if drive has logical block addressing */ 
	char	multi;		/* non-zero if drive does multiple block xfers */ 
1995/1206    
	uchar	lba;		/* true if drive has logical block addressing */ 
	uchar	multi;		/* true if drive can do multiple block xfers (unused) */ 
	uchar	drqintr;	/* ATAPI */ 
	ulong	vers;		/* ATAPI */ 
 
	int	spindown; 
1995/0213    
}; 
 
/* 
1995/0908/sys/src/9/pc/devata.c:122,1621995/1206/sys/src/9/pc/devata.c:144,204
1995/0213    
 */ 
struct Controller 
{ 
	QLock;			/* exclusive access to the controller */ 
1995/1206    
	QLock*	ctlrlock;	/* exclusive access to the controller */ 
1995/0213    
 
1995/0214    
	Lock	reglock;	/* exclusive access to the registers */ 
1995/0213    
 
	int	confused;	/* needs to be recalibrated (or worse) */ 
	int	pbase;		/* base port */ 
1995/1206    
	uchar	ctlrno; 
	uchar	noatapi; 
1995/0213    
 
	/* 
	 *  current operation 
	 */ 
	int	cmd;		/* current command */ 
	int	lastcmd;	/* debugging info */ 
	Rendez	r;		/* wait here for command termination */ 
	char	*buf;		/* xfer buffer */ 
1995/1206    
	uchar	cmd;		/* current command */ 
	uchar	cmdblk[12];	/* ATAPI */ 
	int	len;		/* ATAPI */ 
	int	count;		/* ATAPI */ 
	uchar	lastcmd;	/* debugging info */ 
	uchar	status; 
	uchar	error; 
	uchar*	buf;		/* xfer buffer */ 
1995/0213    
	int	nsecs;		/* length of transfer (sectors) */ 
	int	sofar;		/* sectors transferred so far */ 
	int	status; 
	int	error; 
	Drive	*dp;		/* drive being accessed */ 
1995/1206    
	Drive*	dp;		/* drive being accessed */ 
1995/0213    
}; 
 
Controller	*atac; 
Drive		*ata; 
static int	spindowntime; 
1995/1206    
static QLock ataprobelock; 
static int ataprobedone; 
static Controller *atactlr[NCtlr]; 
static QLock atactlrlock[NCtlr]; 
static Drive *atadrive[NDrive]; 
static int spindownmask; 
static int have640b = -1; 
static int pbase[NCtlr] = { 
	Pbase0, Pbase1, Pbase2, Pbase3, 
}; 
static int defirq[NCtlr] = { 
	14, 15, 0, 0, 
}; 
1995/0213    
 
static void	ataintr(Ureg*, void*); 
static long	ataxfer(Drive*, Partition*, int, long, long, char*); 
1995/1206    
static long	ataxfer(Drive*, Partition*, int, long, long, uchar*); 
1995/0213    
static void	ataident(Drive*); 
static void	atasetbuf(Drive*, int); 
1995/1206    
static void	atafeature(Drive*, uchar); 
1995/0213    
static void	ataparams(Drive*); 
static void	atapart(Drive*); 
static int	ataprobe(Drive*, int, int, int); 
1995/1206    
static void	atasleep(Controller*); 
1995/0213    
 
1995/1206    
static int	isatapi(Drive*); 
static long	atapirwio(Chan*, char*, ulong, ulong); 
static void	atapipart(Drive*); 
static void	atapiintr(Controller*); 
 
1995/0213    
static int 
atagen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp) 
1995/1206    
atagen(Chan *c, Dirtab*, long, long s, Dir *dirp) 
1995/0213    
{ 
	Qid qid; 
	int drive; 
1995/0908/sys/src/9/pc/devata.c:165,1771995/1206/sys/src/9/pc/devata.c:207,221
1995/0213    
	Partition *pp; 
	ulong l; 
 
	USED(tab, ntab); 
	qid.vers = 0; 
	drive = s/Npart; 
	s = s % Npart; 
	if(drive >= conf.nhard) 
1995/1206    
 
	if(drive >= NDrive) 
1995/0213    
		return -1; 
	dp = &ata[drive]; 
1995/1206    
	if(atadrive[drive] == 0) 
		return 0; 
	dp = atadrive[drive]; 
1995/0213    
 
1995/0215    
	if(dp->online == 0 || s >= dp->npart) 
1995/0213    
		return 0; 
1995/0908/sys/src/9/pc/devata.c:185,2321995/1206/sys/src/9/pc/devata.c:229,525
1995/0213    
	return 1; 
} 
 
void 
atareset(void) 
1995/1206    
static void 
cmd640b(void) 
1995/0213    
{ 
	Drive *dp; 
	Controller *cp; 
	uchar equip; 
	char *p; 
1995/1206    
	PCIcfg* pcicfg; 
	uchar r50[12]; 
	int devno; 
	extern void pcicfgw8(int, int, int, int, void*, int); 
1995/0213    
 
	equip = nvramread(0x12); 
1995/0215    
	if(equip == 0) 
		equip = 0x10;		/* the Globalyst 250 lies */ 
1995/1206    
	/* 
	 * 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. 
	 */ 
	pcicfg = malloc(sizeof(PCIcfg)); 
	pcicfg->vid = 0x1095; 
	pcicfg->did = 0x0640; 
	devno = 0; 
	while((devno = pcimatch(0, devno, pcicfg)) != -1){ 
		have640b = devno-1; 
		/* 
		 * 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 
		 * Doing byte-writes to PCI configuration space is not in the 
		 * spec... 
		 */ 
		pcicfgr(0, have640b, 0, 0x50, r50, sizeof(r50)); 
		r50[0x01] |= 0xC8; 
		pcicfgw8(0, have640b, 0, 0x51, &r50[0x01], sizeof(r50[0x01])); 
		r50[0x07] |= 0x0C; 
		pcicfgw8(0, have640b, 0, 0x57, &r50[0x07], sizeof(r50[0x07])); 
	} 
	free(pcicfg); 
} 
1995/0213    
 
1995/0215    
	ata = xalloc(2 * sizeof(Drive)); 
	atac = xalloc(sizeof(Controller)); 
1995/1206    
static void 
rz1000(void) 
{ 
	PCIcfg* pcicfg; 
	ulong r40; 
	int devno; 
1995/0215    
 
	cp = atac; 
	cp->buf = 0; 
	cp->lastcmd = cp->cmd; 
	cp->cmd = 0; 
1995/0818    
	cp->pbase = Pbase0; 
	setvec(ATAvec0, ataintr, 0); 
1995/1206    
	/* 
	 * Look for PC-Tech RZ1000 controllers and turn off prefetch. 
	 * This is overkill, but cheap. 
	 */ 
	pcicfg = malloc(sizeof(PCIcfg)); 
	pcicfg->vid = 0x1042; 
	pcicfg->did = 0; 
	devno = 0; 
	while((devno = pcimatch(0, devno, pcicfg)) != -1){ 
		if(pcicfg->did != 0x1000 && pcicfg->did != 0x1001) 
			continue; 
		pcicfgr(0, devno-1, 0, 0x40, &r40, sizeof(r40)); 
		r40 &= ~0x2000; 
		pcicfgw(0, devno-1, 0, 0x40, &r40, sizeof(r40)); 
	} 
	free(pcicfg); 
} 
1995/0215    
 
	dp = ata; 
	if(equip & 0xf0){ 
		dp->drive = 0; 
1995/0213    
		dp->online = 0; 
		dp->cp = cp; 
1995/0215    
		dp++; 
1995/1206    
static int 
atactlrwait(Controller* ctlr, uchar pdh, uchar ready, ulong ticks) 
{ 
	int port; 
	uchar dh, status; 
 
	port = ctlr->pbase; 
	dh = (inb(port+Pdh) & DHslave)^(pdh & DHslave); 
	ticks += m->ticks+1; 
 
	do{ 
		status = inb(port+Pstatus); 
		if(status & Sbusy) 
			continue; 
		if(dh){ 
			outb(port+Pdh, pdh); 
			dh = 0; 
			continue; 
		} 
		if((status & ready) == ready) 
			return 0; 
	}while(m->ticks < ticks); 
 
	DPRINT("ata%d: ctlrwait failed %uX\n", ctlr->ctlrno, status); 
	outb(port+Pdh, DHmagic); 
	return 1; 
} 
 
static void 
atadrivealloc(Controller* ctlr, int driveno, int atapi) 
{ 
	Drive *drive; 
 
	if((drive = xalloc(sizeof(Drive))) == 0){ 
		DPRINT("ata%d: can't xalloc drive0\n", ctlr->ctlrno); 
		return; 
1995/0213    
	} 
1995/0215    
	if((equip & 0x0f)){ 
		dp->drive = 1; 
		dp->online = 0; 
		dp->cp = cp; 
		dp++; 
1995/1206    
	drive->cp = ctlr; 
	drive->driveno = driveno; 
	sprint(drive->vol, "hd%d", drive->driveno); 
	drive->dh = DHmagic; 
	if(driveno & 0x01) 
		drive->dh |= DHslave; 
	drive->vers = 1; 
	if(atapi) 
		drive->atapi = 1; 
 
	atadrive[driveno] = drive; 
} 
 
static int 
atactlrprobe(int ctlrno, int irq) 
{ 
	Controller *ctlr; 
	int atapi, mask, port; 
	uchar error, status; 
 
	/* 
	 * 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); 
	if((inb(port+Pdh) & 0xFF) != DHmagic){ 
		DPRINT("ata%d: DHmagic not ok\n", ctlrno); 
		return -1; 
1995/0215    
	} 
	conf.nhard = dp - ata; 
1995/1206    
	DPRINT("ata%d: DHmagic ok\n", ctlrno); 
	if((ctlr = xalloc(sizeof(Controller))) == 0) 
		return -1; 
	ctlr->pbase = port; 
	ctlr->ctlrno = ctlrno; 
	ctlr->lastcmd = 0xFF; 
 
	/* 
	 * Attempt to check the existence of drives on the controller 
	 * by issuing a 'check device diagnostics' command. 
	 * 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. 
	 * 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 Edd (Micronics M54Li + Sanyo CDR-XXX) so let's check for the 
	 * ATAPI signature straight off. If we find it there will be no probe 
	 * done for a slave. Tough. 
	 */ 
	atapi = 0; 
	mask = 0; 
	status = inb(port+Pstatus); 
	DPRINT("ata%d: ATAPI %uX %uX %uX\n", ctlrno, status, 
		inb(port+Pcylmsb), inb(port+Pcyllsb)); 
	if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ 
		DPRINT("ata%d: ATAPI ok\n", ctlrno); 
		setvec(irq, ataintr, ctlr); 
		atapi |= 0x01; 
		mask |= 0x01; 
		goto skipedd; 
	} 
	if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1)) || waserror()){ 
		xfree(ctlr); 
		return -1; 
	} 
	setvec(irq, ataintr, ctlr); 
	ctlr->cmd = Cedd; 
	outb(port+Pcmd, Cedd); 
	atasleep(ctlr); 
	poperror(); 
 
	/* 
	 * The diagnostic returns a code in the error register, good 
	 * status is bits 6-0 == 0x01. 
	 * The existence of the slave is more difficult to determine, 
	 * different generations of controllers may respond in different 
	 * ways. The standards here offer little light but only more and 
	 * more heat: 
	 *   1) the slave must be done and have dropped Sbusy by now (six 
	 *	seconds for the master, 5 seconds for the slave). If it 
	 *	hasn't, then it has either failed or the controller is 
	 *	broken in some way (e.g. Vibra16 returns status of 0xFF); 
	 *   2) theory says the status of a non-existent slave should be 0. 
	 *	Of course, it's valid for all the bits to be 0 for a slave 
	 *	that exists too... 
	 *   3) a valid ATAPI drive can have status 0 and the ATAPI signature 
	 *	in the cylinder registers after reset. Of course, if the drive 
	 *	has been messed about by the BIOS or some other O/S then the 
	 *	signature may be gone. 
	 */ 
	error = inb(port+Perror); 
	DPRINT("ata%d: master diag error %ux\n", ctlr->ctlrno, error); 
	if((error & ~0x80) == 0x01) 
		mask |= 0x01; 
 
	outb(port+Pdh, DHmagic|DHslave); 
	microdelay(1); 
	status = inb(port+Pstatus); 
	error = inb(port+Perror); 
	DPRINT("ata%d: slave diag status %ux, error %ux\n", ctlr->ctlrno, status, error); 
	if(status && (status & (Sbusy|Serr)) == 0 && (error & ~0x80) == 0x01) 
		mask |= 0x02; 
	else if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ 
		atapi |= 0x02; 
		mask |= 0x02; 
	} 
 
skipedd: 
	if(mask == 0){ 
		xfree(ctlr); 
		return -1; 
	} 
	atactlr[ctlrno] = ctlr; 
 
	if(have640b >= 0 && (ctlrno & 0x01)) 
		ctlr->ctlrlock = &atactlrlock[ctlrno-1]; 
	else 
		ctlr->ctlrlock = &atactlrlock[ctlrno]; 
 
	if(mask & 0x01) 
		atadrivealloc(ctlr, ctlrno*2, atapi & 0x01); 
	if(mask & 0x02) 
		atadrivealloc(ctlr, ctlrno*2+1, atapi & 0x02); 
 
	return 0; 
} 
 
void 
atactlrreset(void) 
{ 
	int ctlrno, driveno, i, slave, spindown; 
	ISAConf isa; 
 
	cmd640b(); 
	rz1000(); 
 
	for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){ 
		memset(&isa, 0, sizeof(ISAConf)); 
		if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno) 
			continue; 
		if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) 
			continue; 
 
		if(atactlrprobe(ctlrno, Int0vec+isa.irq)) 
			continue; 
1995/0213    
	 
	if(conf.nhard && (p = getconf("spindowntime"))) 
		spindowntime = atoi(p); 
1995/1206    
		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(isa.opt[i][9] != '=') 
					continue; 
				if(isa.opt[i][8] == '0') 
					slave = 0; 
				else if(isa.opt[i][8] == '1') 
					slave = 1; 
				else 
					continue; 
				driveno = ctlrno*2+slave; 
				if(atadrive[driveno] == 0) 
					continue; 
				if((spindown = strtol(&isa.opt[i][10], 0, 0)) == 0) 
					continue; 
				if(spindown < (Hardtimeout+2000)/1000) 
					spindown = (Hardtimeout+2000)/1000; 
				atadrive[driveno]->spindown = spindown; 
				spindownmask |= (1<<driveno); 
				DPRINT("ata%d: opt spindownmask %ux\n", 
					ctlrno, spindownmask); 
			} 
			else if(strcmp(isa.opt[i], "noatapi") == 0) 
				atactlr[ctlrno]->noatapi = 1; 
		} 
	} 
1995/0213    
} 
 
void 
1995/1206    
atareset(void) 
{ 
} 
 
void 
1995/0213    
atainit(void) 
{ 
} 
1995/0908/sys/src/9/pc/devata.c:238,2461995/1206/sys/src/9/pc/devata.c:531,551
1995/0213    
Chan* 
ataattach(char *spec) 
{ 
1995/1206    
	int driveno; 
1995/0213    
	Drive *dp; 
 
	for(dp = ata; dp < &ata[conf.nhard]; dp++){ 
1995/1206    
	DPRINT("ataattach\n"); 
 
	qlock(&ataprobelock); 
	if(ataprobedone == 0){ 
		atactlrreset(); 
		ataprobedone = 1; 
	} 
	qunlock(&ataprobelock); 
 
	for(driveno = 0; driveno < NDrive; driveno++){ 
		if((dp = atadrive[driveno]) == 0) 
			continue; 
1995/0213    
		if(waserror()){ 
			dp->online = 0; 
			qunlock(dp); 
1995/0908/sys/src/9/pc/devata.c:248,2671995/1206/sys/src/9/pc/devata.c:553,572
1995/0213    
		} 
		qlock(dp); 
		if(!dp->online){ 
			/* 
			 * Make sure ataclock() doesn't 
			 * interfere. 
			 */ 
			dp->usetime = m->ticks; 
			ataparams(dp); 
			dp->online = 1; 
			atasetbuf(dp, 1); 
1995/1206    
			atafeature(dp, 0xAA);	/* read look ahead */ 
1995/0213    
		} 
 
		/* 
		 *  read Plan 9 partition table 
		 */ 
		atapart(dp); 
1995/1206    
		if(dp->partok == 0){ 
			if(dp->atapi) 
				atapipart(dp); 
			else 
				atapart(dp); 
		} 
1995/0213    
		qunlock(dp); 
		poperror(); 
	} 
1995/0908/sys/src/9/pc/devata.c:293,3011995/1206/sys/src/9/pc/devata.c:598,605
1995/0213    
} 
 
void 
1995/0818    
atacreate(Chan *c, char *name, int omode, ulong perm) 
1995/1206    
atacreate(Chan*, char*, int, ulong) 
1995/0213    
{ 
1995/0818    
	USED(c, name, omode, perm); 
1995/0213    
	error(Eperm); 
} 
 
1995/0908/sys/src/9/pc/devata.c:302,3391995/1206/sys/src/9/pc/devata.c:606,642
1995/0213    
void 
ataclose(Chan *c) 
{ 
	Drive *d; 
1995/1206    
	Drive *dp; 
1995/0213    
	Partition *p; 
 
	if(c->mode != OWRITE && c->mode != ORDWR) 
		return; 
 
	d = &ata[DRIVE(c->qid.path)]; 
	p = &d->p[PART(c->qid.path)]; 
1995/1206    
	dp = atadrive[DRIVE(c->qid.path)]; 
	p = &dp->p[PART(c->qid.path)]; 
1995/0213    
	if(strcmp(p->name, "partition") != 0) 
		return; 
 
	if(waserror()){ 
		qunlock(d); 
1995/1206    
		qunlock(dp); 
1995/0213    
		nexterror(); 
	} 
	qlock(d); 
	atapart(d); 
	qunlock(d); 
1995/1206    
	qlock(dp); 
	dp->partok = 0; 
	atapart(dp); 
	qunlock(dp); 
1995/0213    
	poperror(); 
} 
 
void 
ataremove(Chan *c) 
1995/1206    
ataremove(Chan*) 
1995/0213    
{ 
	USED(c); 
	error(Eperm); 
} 
 
void 
atawstat(Chan *c, char *dp) 
1995/1206    
atawstat(Chan*, char*) 
1995/0213    
{ 
	USED(c, dp); 
	error(Eperm); 
} 
 
1995/0908/sys/src/9/pc/devata.c:345,3551995/1206/sys/src/9/pc/devata.c:648,675
1995/0213    
	int skip; 
	uchar *aa = a; 
	Partition *pp; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
 
	if(c->qid.path == CHDIR) 
		return devdirread(c, a, n, 0, 0, atagen); 
 
1995/1206    
	dp = atadrive[DRIVE(c->qid.path)]; 
	if(dp->atapi){ 
		if(dp->online == 0) 
			error(Eio); 
		if(waserror()){ 
			qunlock(dp); 
			nexterror(); 
		} 
		qlock(dp); 
		if(dp->partok == 0) 
			atapipart(dp); 
		qunlock(dp); 
		poperror(); 
		return atapirwio(c, a, n, offset); 
	} 
	pp = &dp->p[PART(c->qid.path)]; 
 
1995/0213    
	buf = smalloc(Maxxfer); 
	if(waserror()){ 
		free(buf); 
1995/0908/sys/src/9/pc/devata.c:356,3641995/1206/sys/src/9/pc/devata.c:676,681
1995/0213    
		nexterror(); 
	} 
 
	dp = &ata[DRIVE(c->qid.path)]; 
	pp = &dp->p[PART(c->qid.path)]; 
                 
	skip = offset % dp->bytes; 
	for(rv = 0; rv < n; rv += i){ 
		i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); 
1995/0908/sys/src/9/pc/devata.c:390,4021995/1206/sys/src/9/pc/devata.c:707,722
1995/0213    
	long rv, i, partial; 
	uchar *aa = a; 
	Partition *pp; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
 
	if(c->qid.path == CHDIR) 
		error(Eisdir); 
 
	dp = &ata[DRIVE(c->qid.path)]; 
1995/1206    
	dp = atadrive[DRIVE(c->qid.path)]; 
	if(dp->atapi) 
		error(Eperm); 
1995/0213    
	pp = &dp->p[PART(c->qid.path)]; 
1995/1206    
 
1995/0213    
	buf = smalloc(Maxxfer); 
	if(waserror()){ 
		free(buf); 
1995/0908/sys/src/9/pc/devata.c:472,4991995/1206/sys/src/9/pc/devata.c:792,817
1995/0213    
 
/* 
 * Wait for the controller to be ready to accept a command. 
 * This is protected from intereference by ataclock() by 
 * setting dp->usetime before it is called. 
 */ 
static void 
1995/1206    
static int 
1995/0213    
cmdreadywait(Drive *dp) 
{ 
	long start; 
	int period; 
	Controller *cp = dp->cp; 
1995/1206    
	ulong ticks; 
	uchar ready; 
1995/0213    
 
	/* give it 2 seconds to spin down and up */ 
1995/1206    
	dp->usetime = m->ticks; 
1995/0213    
	if(dp->state == Sspinning) 
		period = 10; 
1995/1206    
		ticks = MS2TK(10); 
1995/0213    
	else 
		period = 2000; 
1995/1206    
		ticks = MS2TK(2000); 
1995/0213    
 
	start = m->ticks; 
	while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) 
		if(TK2MS(m->ticks - start) > period){ 
			DPRINT("cmdreadywait failed\n"); 
			error(Eio); 
		} 
1995/1206    
	if(dp->atapi) 
		ready = 0; 
	else 
		ready = Sready; 
 
	return atactlrwait(dp->cp, dp->dh, ready, ticks); 
1995/0213    
} 
 
static void 
1995/0908/sys/src/9/pc/devata.c:505,5111995/1206/sys/src/9/pc/devata.c:823,829
1995/0213    
		return; 
	for(i = 0; i < dp->repl.nrepl; i++){ 
		if(dp->repl.blk[i] == bblk) 
			DPRINT("found bblk %ld at offset %ld\n", bblk, i); 
1995/1206    
			DPRINT("%s: found bblk %ld at offset %ld\n", dp->vol, bblk, i); 
1995/0213    
	} 
} 
 
1995/0908/sys/src/9/pc/devata.c:514,5201995/1206/sys/src/9/pc/devata.c:832,838
1995/0818    
{ 
	tsleep(&cp->r, cmddone, cp, Hardtimeout); 
	if(cp->cmd && cp->cmd != Cident2){ 
		DPRINT("hard drive timeout\n"); 
1995/1206    
		DPRINT("ata%d: cmd 0x%uX timeout\n", cp->ctlrno, cp->cmd); 
1995/0818    
		error("ata drive timeout"); 
	} 
} 
1995/0908/sys/src/9/pc/devata.c:525,5311995/1206/sys/src/9/pc/devata.c:843,849
1995/0213    
 *  parts. 
 */ 
static long 
ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) 
1995/1206    
ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, uchar *buf) 
1995/0213    
{ 
	Controller *cp; 
	long lblk; 
1995/0908/sys/src/9/pc/devata.c:563,5861995/1206/sys/src/9/pc/devata.c:881,902
1995/0213    
		head = ((lblk/dp->sectors) % dp->heads); 
	} 
 
1995/0818    
/*print("ataxfer cyl %d sec %d head %d\n", cyl, sec, head);/**/ 
1995/1206    
	XPRINT("%s: ataxfer cyl %d sec %d head %d len %d\n", dp->vol, cyl, sec, head, len); 
1995/0818    
 
1995/0213    
	cp = dp->cp; 
	qlock(cp); 
1995/1206    
	qlock(cp->ctlrlock); 
1995/0213    
	if(waserror()){ 
1995/1206    
		cp->dp = 0; 
1995/0213    
		cp->buf = 0; 
		qunlock(cp); 
1995/1206    
		qunlock(cp->ctlrlock); 
1995/0213    
		nexterror(); 
	} 
 
	/* 
	 * Make sure hardclock() doesn't 
	 * interfere. 
	 */ 
	dp->usetime = m->ticks; 
	cmdreadywait(dp); 
1995/1206    
	if(cmdreadywait(dp)){ 
		error(Eio); 
	} 
1995/0213    
 
1995/0214    
	ilock(&cp->reglock); 
1995/1206    
	ILOCK(&cp->reglock); 
1995/0213    
	cp->sofar = 0; 
	cp->buf = buf; 
	cp->nsecs = len; 
1995/0908/sys/src/9/pc/devata.c:590,5961995/1206/sys/src/9/pc/devata.c:906,912
1995/0213    
 
	outb(cp->pbase+Pcount, cp->nsecs); 
	outb(cp->pbase+Psector, sec); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head); 
1995/1206    
	outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head); 
1995/0213    
	outb(cp->pbase+Pcyllsb, cyl); 
	outb(cp->pbase+Pcylmsb, cyl>>8); 
	outb(cp->pbase+Pcmd, cmd); 
1995/0908/sys/src/9/pc/devata.c:597,6091995/1206/sys/src/9/pc/devata.c:913,926
1995/0213    
 
	if(cmd == Cwrite){ 
		loop = 0; 
1995/1206    
		microdelay(1); 
1995/0213    
		while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0) 
			if(++loop > 10000) 
				panic("ataxfer"); 
1995/1206    
				panic("%s: ataxfer", dp->vol); 
1995/0213    
		outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); 
	} else 
		stat = 0; 
1995/0214    
	iunlock(&cp->reglock); 
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
 
	if(stat & Serr) 
		error(Eio); 
1995/0908/sys/src/9/pc/devata.c:615,6441995/1206/sys/src/9/pc/devata.c:932,962
1995/0213    
	 */ 
	loop = 0; 
	while(waserror()){ 
		DPRINT("interrupted ataxfer\n"); 
1995/1206    
		DPRINT("%s: interrupted ataxfer\n", dp->vol); 
1995/0213    
		if(loop++ > 10){ 
			print("ata disk error\n"); 
1995/1206    
			print("%s: disk error\n", dp->vol); 
1995/0213    
			nexterror(); 
		} 
	} 
1995/0818    
	atasleep(cp); 
1995/0213    
	dp->state = Sspinning; 
	dp->usetime = m->ticks; 
1995/1206    
	dp->state = Sspinning; 
1995/0213    
	poperror(); 
	if(loop) 
		nexterror(); 
 
	if(cp->status & Serr){ 
		DPRINT("hd%d err: lblk %ld status %lux, err %lux\n", 
			dp-ata, lblk, cp->status, cp->error); 
1995/1206    
		DPRINT("%s err: lblk %ld status %lux, err %lux\n", 
			dp->vol, lblk, cp->status, cp->error); 
1995/0213    
		DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head); 
		DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar); 
		atarepl(dp, lblk+cp->sofar); 
		error(Eio); 
	} 
1995/1206    
	cp->dp = 0; 
1995/0213    
	cp->buf = 0; 
	len = cp->sofar*dp->bytes; 
	qunlock(cp); 
1995/1206    
	qunlock(cp->ctlrlock); 
1995/0213    
	poperror(); 
 
	return len; 
1995/0908/sys/src/9/pc/devata.c:648,6801995/1206/sys/src/9/pc/devata.c:966,1006
1995/0213    
 *  set read ahead mode 
 */ 
static void 
atasetbuf(Drive *dp, int on) 
1995/1206    
atafeature(Drive *dp, uchar arg) 
1995/0213    
{ 
	Controller *cp = dp->cp; 
 
	qlock(cp); 
1995/1206    
	if(dp->atapi) 
		return; 
 
	qlock(cp->ctlrlock); 
1995/0213    
	if(waserror()){ 
		qunlock(cp); 
1995/1206    
		cp->dp = 0; 
		qunlock(cp->ctlrlock); 
1995/0213    
		nexterror(); 
	} 
 
	cmdreadywait(dp); 
1995/1206    
	if(cmdreadywait(dp)){ 
		error(Eio); 
	} 
1995/0213    
 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
	cp->cmd = Csetbuf; 
	outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55);	/* read look ahead */ 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 
1995/0213    
	outb(cp->pbase+Pcmd, Csetbuf); 
1995/0214    
	iunlock(&cp->reglock); 
1995/1206    
	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); 
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/0818    
	atasleep(cp); 
1995/0213    
 
/*	if(cp->status & Serr) 
		DPRINT("hd%d setbuf err: status %lux, err %lux\n", 
			dp-ata, cp->status, cp->error);/**/ 
1995/1206    
	if(cp->status & Serr) 
		DPRINT("%s: setbuf err: status %lux, err %lux\n", 
			dp->vol, cp->status, cp->error); 
1995/0213    
 
1995/1206    
	cp->dp = 0; 
1995/0213    
	poperror(); 
	qunlock(cp); 
1995/1206    
	qunlock(cp->ctlrlock); 
1995/0213    
} 
 
/* 
1995/0908/sys/src/9/pc/devata.c:727,7611995/1206/sys/src/9/pc/devata.c:1053,1108
1995/0213    
ataident(Drive *dp) 
{ 
	Controller *cp; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
	Ident *ip; 
	char id[21]; 
1995/0818    
	ulong lbasecs; 
1995/1206    
	uchar cmd; 
1995/0213    
 
	cp = dp->cp; 
	buf = smalloc(Maxxfer); 
	qlock(cp); 
1995/1206    
	qlock(cp->ctlrlock); 
1995/0213    
	if(waserror()){ 
		qunlock(cp); 
1995/1206    
		cp->dp = 0; 
		free(buf); 
		qunlock(cp->ctlrlock); 
1995/0213    
		nexterror(); 
	} 
 
	cmdreadywait(dp); 
1995/1206    
	if(dp->atapi || isatapi(dp)) 
		cmd = Cidentd; 
	else{ 
		cmd = Cident; 
		if(cmdreadywait(dp)){ 
			dp->atapi = 1; 
			if(isatapi(dp) == 0) 
				error(Eio); 
			cmd = Cidentd; 
		} 
	} 
1995/0213    
 
1995/0214    
	ilock(&cp->reglock); 
1995/1206    
retryatapi: 
	ILOCK(&cp->reglock); 
1995/0213    
	cp->nsecs = 1; 
	cp->sofar = 0; 
	cp->cmd = Cident; 
1995/1206    
	cp->cmd = cmd; 
1995/0213    
	cp->dp = dp; 
	cp->buf = buf; 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 
1995/0213    
	outb(cp->pbase+Pcmd, Cident); 
1995/0214    
	iunlock(&cp->reglock); 
1995/1206    
	outb(cp->pbase+Pdh, dp->dh); 
	outb(cp->pbase+Pcmd, cmd); 
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/0818    
	atasleep(cp); 
 
1995/0213    
	if(cp->status & Serr){ 
		DPRINT("bad disk ident status\n"); 
1995/1206    
		DPRINT("%s: bad disk ident status\n", dp->vol); 
		if(dp->atapi == 0 && (cp->error & Eabort)){ 
			dp->atapi = 1; 
			if(isatapi(dp)){ 
				cmd = Cidentd; 
				goto retryatapi; 
			} 
		} 
1995/0213    
		error(Eio); 
	} 
	ip = (Ident*)buf; 
1995/0908/sys/src/9/pc/devata.c:773,8091995/1206/sys/src/9/pc/devata.c:1120,1173
1995/0213    
	memmove(id, ip->model, sizeof(id)-1); 
	id[sizeof(id)-1] = 0; 
 
1995/1206    
	DPRINT("%s: config 0x%uX capabilities 0x%uX\n", 
		dp->vol, ip->config, ip->capabilities); 
	if(dp->atapi){ 
		dp->bytes = 2048; 
		if((ip->config & 0x0060) == 0x0020) 
			dp->drqintr = 1; 
	} 
	if(dp->spindown && (ip->capabilities & (1<<13))) 
		dp->spindown /= 5; 
 
	/* use default (unformatted) settings */ 
	dp->cyl = ip->cyls; 
	dp->heads = ip->heads; 
	dp->sectors = ip->s2t; 
	DPRINT("%s: %s %d/%d/%d CHS %d bytes\n", 
		dp->vol, id, dp->cyl, dp->heads, dp->sectors, dp->cap); 
 
	if(ip->cvalid&(1<<0)){ 
		/* use current settings */ 
		dp->cyl = ip->ccyls; 
		dp->heads = ip->cheads; 
		dp->sectors = ip->cs2t; 
		DPRINT("%s: changed to %d cyl %d head %d sec\n", 
			dp->vol, dp->cyl, dp->heads, dp->sectors); 
	} 
 
1995/0818    
	lbasecs = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 
	if((ip->capabilities & (1<<9)) && (lbasecs & 0xf0000000) == 0){ 
1995/0213    
		dp->lba = 1; 
1995/0818    
		dp->sectors = lbasecs; 
1995/0213    
		dp->cap = dp->bytes * dp->sectors; 
1995/0222    
/*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ 
1995/1206    
		dp->lbasecs = lbasecs; 
		dp->cap = dp->bytes * dp->lbasecs; 
		DPRINT("%s: LBA: %s %d sectors %d bytes\n", 
			dp->vol, id, dp->lbasecs, dp->cap); 
1995/0213    
	} else { 
		dp->lba = 0; 
                 
		/* use default (unformatted) settings */ 
		dp->cyl = ip->cyls; 
		dp->heads = ip->heads; 
		dp->sectors = ip->s2t; 
1995/0215    
/*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive, 
			id, dp->cyl, dp->heads, dp->sectors);/**/ 
1995/0213    
                 
		if(ip->cvalid&(1<<0)){ 
			/* use current settings */ 
			dp->cyl = ip->ccyls; 
			dp->heads = ip->cheads; 
			dp->sectors = ip->cs2t; 
1995/0215    
/*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/ 
1995/0213    
		} 
1995/1206    
		dp->lbasecs = 0; 
1995/0213    
		dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; 
	} 
	cp->lastcmd = cp->cmd; 
	cp->cmd = 0; 
1995/1206    
 
	if(cp->cmd){ 
		cp->lastcmd = cp->cmd; 
		cp->cmd = 0; 
	} 
	cp->dp = 0; 
1995/0213    
	cp->buf = 0; 
	free(buf); 
	poperror(); 
	qunlock(cp); 
1995/1206    
	qunlock(cp->ctlrlock); 
1995/0213    
} 
 
/* 
1995/0908/sys/src/9/pc/devata.c:813,8331995/1206/sys/src/9/pc/devata.c:1177,1200
1995/0213    
ataprobe(Drive *dp, int cyl, int sec, int head) 
{ 
	Controller *cp; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
	int rv; 
 
	cp = dp->cp; 
	buf = smalloc(Maxxfer); 
	qlock(cp); 
1995/1206    
	qlock(cp->ctlrlock); 
1995/0213    
	if(waserror()){ 
1995/1206    
		cp->dp = 0; 
1995/0213    
		free(buf); 
		qunlock(cp); 
1995/1206    
		qunlock(cp->ctlrlock); 
1995/0213    
		nexterror(); 
	} 
 
	cmdreadywait(dp); 
1995/1206    
	if(cmdreadywait(dp)){ 
		error(Eio); 
	} 
1995/0213    
 
1995/0214    
	ilock(&cp->reglock); 
1995/1206    
	ILOCK(&cp->reglock); 
1995/0213    
	cp->cmd = Cread; 
	cp->dp = dp; 
	cp->status = 0; 
1995/0908/sys/src/9/pc/devata.c:837,8591995/1206/sys/src/9/pc/devata.c:1204,1230
1995/0213    
 
	outb(cp->pbase+Pcount, 1); 
	outb(cp->pbase+Psector, sec+1); 
1995/0215    
	outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); 
1995/1206    
	outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head); 
1995/0213    
	outb(cp->pbase+Pcyllsb, cyl); 
	outb(cp->pbase+Pcylmsb, cyl>>8); 
	outb(cp->pbase+Pcmd, Cread); 
1995/0214    
	iunlock(&cp->reglock); 
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/0818    
	atasleep(cp); 
1995/0213    
 
	if(cp->status & Serr) 
1995/1206    
	if(cp->status & Serr){ 
		DPRINT("%s: probe err: status %lux, err %lux\n", 
			dp->vol, cp->status, cp->error); 
1995/0213    
		rv = -1; 
1995/1206    
	} 
1995/0213    
	else 
		rv = 0; 
 
1995/1206    
	cp->dp = 0; 
1995/0213    
	cp->buf = 0; 
	free(buf); 
	poperror(); 
	qunlock(cp); 
1995/1206    
	qunlock(cp->ctlrlock); 
1995/0213    
	return rv; 
} 
 
1995/0908/sys/src/9/pc/devata.c:871,8781995/1206/sys/src/9/pc/devata.c:1242,1251
1995/0213    
	 */ 
	dp->bytes = 512; 
	ataident(dp); 
1995/1206    
	if(dp->atapi) 
		return; 
1995/0213    
	if(dp->lba){ 
		i = dp->sectors - 1; 
1995/1206    
		i = dp->lbasecs - 1; 
1995/0215    
		if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0) 
1995/0213    
			return; 
	} else { 
1995/0908/sys/src/9/pc/devata.c:907,9121995/1206/sys/src/9/pc/devata.c:1280,1289
1995/0213    
	} 
	dp->cyl = lo + 1; 
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; 
1995/1206    
	DPRINT("%s: probed: %d/%d/%d CHS %d bytes\n", 
		dp->vol, dp->cyl, dp->heads, dp->sectors, dp->cap); 
	if(dp->cyl == 0 || dp->heads == 0 || dp->sectors == 0) 
		error(Eio); 
1995/0213    
} 
 
/* 
1995/0908/sys/src/9/pc/devata.c:920,9261995/1206/sys/src/9/pc/devata.c:1297,1303
1995/0213    
	char *field[1]; 
	ulong n; 
	int i; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
 
	/* 
	 *  check the partition is big enough 
1995/0908/sys/src/9/pc/devata.c:945,9511995/1206/sys/src/9/pc/devata.c:1322,1328
1995/0213    
	/* 
	 *  parse replacement table. 
	 */ 
	n = getfields(buf, line, Nrepl+1, "\n"); 
1995/1206    
	n = getfields((char*)buf, line, Nrepl+1, "\n"); 
1995/0213    
	if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){ 
		dp->repl.p = 0; 
	} else { 
1995/0908/sys/src/9/pc/devata.c:969,9811995/1206/sys/src/9/pc/devata.c:1346,1361
1995/0213    
{ 
	Partition *pp; 
	char *line[Npart+1]; 
	char *field[3]; 
1995/1206    
	char *field[3], namebuf[NAMELEN], *p; 
1995/0213    
	ulong n; 
	int i; 
	char *buf; 
1995/1206    
	uchar *buf; 
1995/0213    
 
	sprint(dp->vol, "hd%d", dp - ata); 
1995/1206    
	DPRINT("%s: partok %d\n", dp->vol, dp->partok); 
1995/0213    
 
1995/1206    
	if(dp->partok) 
		return; 
 
1995/0213    
	/* 
	 *  we always have a partition for the whole disk 
	 *  and one for the partition table 
1995/0908/sys/src/9/pc/devata.c:988,9931995/1206/sys/src/9/pc/devata.c:1368,1374
1995/0213    
	strcpy(pp->name, "partition"); 
	pp->start = dp->p[0].end - 1; 
	pp->end = dp->p[0].end; 
1995/1206    
	pp++; 
1995/0213    
	dp->npart = 2; 
 
	/* 
1995/0908/sys/src/9/pc/devata.c:997,10541995/1206/sys/src/9/pc/devata.c:1378,1447
1995/0213    
 
	buf = smalloc(Maxxfer); 
	if(waserror()){ 
1995/1206    
		DPRINT("%s: atapart error\n", dp->vol); 
1995/0213    
		free(buf); 
		nexterror(); 
	} 
 
1995/1206    
 
1995/0213    
	/* 
	 *  read last sector from disk, null terminate.  This used 
	 *  to be the sector we used for the partition tables. 
	 *  However, this sector is special on some PC's so we've 
	 *  started to use the second last sector as the partition 
	 *  table instead.  To avoid reconfiguring all our old systems 
	 *  we first look to see if there is a valid partition 
	 *  table in the last sector.  If so, we use it.  Otherwise 
	 *  we switch to the second last. 
1995/1206    
	 * Check if the partitions are described in plan9.ini. 
	 * If not, read the disc. 
1995/0213    
	 */ 
	ataxfer(dp, pp, Cread, 0, dp->bytes, buf); 
	buf[dp->bytes-1] = 0; 
	n = getfields(buf, line, Npart+1, "\n"); 
	if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 
		dp->p[0].end--; 
		dp->p[1].start--; 
		dp->p[1].end--; 
		ataxfer(dp, pp, Cread, 0, dp->bytes, buf); 
1995/1206    
	sprint(namebuf, "%spartition", dp->vol); 
	if((p = getconf(namebuf)) == 0){	 
		/* 
		 *  read last sector from disk, null terminate.  This used 
		 *  to be the sector we used for the partition tables. 
		 *  However, this sector is special on some PC's so we've 
		 *  started to use the second last sector as the partition 
		 *  table instead.  To avoid reconfiguring all our old systems 
		 *  we first look to see if there is a valid partition 
		 *  table in the last sector.  If so, we use it.  Otherwise 
		 *  we switch to the second last. 
		 */ 
		ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
1995/0213    
		buf[dp->bytes-1] = 0; 
		n = getfields(buf, line, Npart+1, "\n"); 
1995/1206    
		n = getfields((char*)buf, line, Npart+1, "\n"); 
		if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 
			dp->p[0].end--; 
			dp->p[1].start--; 
			dp->p[1].end--; 
			ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
			buf[dp->bytes-1] = 0; 
			n = getfields((char*)buf, line, Npart+1, "\n"); 
		} 
1995/0213    
	} 
1995/1206    
	else{ 
		strcpy((char*)buf, p); 
		n = getfields((char*)buf, line, Npart+1, "\n"); 
	} 
1995/0213    
 
	/* 
	 *  parse partition table. 
	 */ 
	if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/1206    
	if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/0213    
		for(i = 1; i < n; i++){ 
1995/1206    
			if(getfields(line[i], field, 3, " ") != 3) 
				break; 
			if(pp >= &dp->p[Npart]) 
				break; 
			strncpy(pp->name, field[0], NAMELEN); 
			if(strncmp(pp->name, "repl", NAMELEN) == 0) 
				dp->repl.p = pp; 
			pp->start = strtoul(field[1], 0, 0); 
			pp->end = strtoul(field[2], 0, 0); 
			if(pp->start > pp->end || pp->start >= dp->p[0].end) 
				break; 
1995/0213    
			pp++; 
			switch(getfields(line[i], field, 3, " ")) { 
			case 2: 
				if(strcmp(field[0], "unit") == 0) 
					strncpy(dp->vol, field[1], NAMELEN); 
				break;	 
			case 3: 
				strncpy(pp->name, field[0], NAMELEN); 
				if(strncmp(pp->name, "repl", NAMELEN) == 0) 
					dp->repl.p = pp; 
				pp->start = strtoul(field[1], 0, 0); 
				pp->end = strtoul(field[2], 0, 0); 
				if(pp->start > pp->end || pp->start >= dp->p[0].end) 
					break; 
				dp->npart++; 
			} 
		} 
	} 
1995/1206    
	dp->npart = pp - dp->p; 
1995/0213    
	free(buf); 
	poperror(); 
 
1995/1206    
	dp->partok = 1; 
 
1995/0213    
	if(dp->repl.p) 
		atareplinit(dp); 
} 
1995/0908/sys/src/9/pc/devata.c:1062,10901995/1206/sys/src/9/pc/devata.c:1455,1480
1995/0213    
 *  we get an interrupt for every sector transferred 
 */ 
static void 
ataintr(Ureg *ur, void *arg) 
1995/1206    
ataintr(Ureg*, void* arg) 
1995/0213    
{ 
	Controller *cp; 
	Drive *dp; 
	long loop; 
	char *addr; 
1995/1206    
	int loop; 
	uchar *addr; 
1995/0213    
 
	USED(ur, arg); 
1995/1206    
	cp = arg; 
	if((dp = cp->dp) == 0 && cp->cmd != Cedd) 
		return; 
1995/0213    
 
	/* 
 	 *  BUG!! if there is ever more than one controller, we need a way to 
	 *	  distinguish which interrupted (use arg). 
	 */ 
	cp = &atac[0]; 
	dp = cp->dp; 
1995/1206    
	ILOCK(&cp->reglock); 
1995/0213    
 
1995/0214    
	ilock(&cp->reglock); 
1995/0213    
                 
	loop = 0; 
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ 
1995/0818    
		if(++loop > Maxloop) 
			panic("ataintr: wait busy cmd=%lux status=%lux", 
1995/0213    
				cp->cmd, inb(cp->pbase+Pstatus)); 
1995/1206    
		if(++loop > Maxloop){ 
			print("ata%d: cmd=%lux, lastcmd=%lux status=%lux\n", 
				cp->ctlrno, cp->cmd, cp->lastcmd, inb(cp->pbase+Pstatus)); 
			panic("%s: wait busy\n", dp->vol); 
		} 
1995/0213    
	} 
 
	switch(cp->cmd){ 
1995/0908/sys/src/9/pc/devata.c:1101,11081995/1206/sys/src/9/pc/devata.c:1491,1498
1995/0213    
			loop = 0; 
			while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) 
1995/0818    
				if(++loop > Maxloop) 
					panic("ataintr: write cmd=%lux status=%lux\n", 
1995/0213    
						cp->cmd, inb(cp->pbase+Pstatus)); 
1995/1206    
					panic("%s: write cmd=%lux status=%lux\n", 
						dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); 
1995/0213    
			addr = cp->buf; 
			if(addr){ 
				addr += cp->sofar*dp->bytes; 
1995/0908/sys/src/9/pc/devata.c:1116,11261995/1206/sys/src/9/pc/devata.c:1506,1517
1995/0213    
		break; 
	case Cread: 
	case Cident: 
1995/1206    
	case Cidentd: 
1995/0213    
		loop = 0; 
		while((cp->status & (Serr|Sdrq)) == 0){ 
1995/0818    
			if(++loop > Maxloop){ 
				print("ataintr: read/ident cmd=%lux status=%lux\n", 
1995/0213    
					cp->cmd, inb(cp->pbase+Pstatus)); 
1995/1206    
				print("%s: read/ident cmd=%lux status=%lux\n", 
					dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); 
1995/0818    
				cp->status |= Serr; 
				break; 
1995/0213    
			} 
1995/0908/sys/src/9/pc/devata.c:1140,11601995/1206/sys/src/9/pc/devata.c:1531,1554
1995/0213    
		} 
		cp->sofar++; 
		if(cp->sofar > cp->nsecs) 
			print("ataintr %d %d\n", cp->sofar, cp->nsecs); 
1995/1206    
			print("%s: intr %d %d\n", dp->vol, cp->sofar, cp->nsecs); 
1995/0213    
		if(cp->sofar >= cp->nsecs){ 
			cp->lastcmd = cp->cmd; 
			if (cp->cmd == Cread) 
				cp->cmd = 0; 
			else 
1995/1206    
			if(cp->cmd == Cidentd) 
1995/0213    
				cp->cmd = Cident2; 
1995/1206    
			else if(cp->cmd == Cident && (cp->status & Sready) == 0) 
				cp->cmd = Cident2; 
			else 
				cp->cmd = 0; 
			inb(cp->pbase+Pstatus); 
			DPRINT("status %uX, alt %uX\n", 
				inb(cp->pbase+Pstatus), inb(cp->pbase+0x206)); 
1995/0213    
			wakeup(&cp->r); 
		} 
		break; 
	case Cinitparam: 
	case Csetbuf: 
	case Cidle: 
1995/1206    
	case Cfeature: 
1995/0213    
	case Cstandby: 
	case Cpowerdown: 
1995/1206    
	case Cedd: 
1995/0213    
		cp->lastcmd = cp->cmd; 
		cp->cmd = 0; 
		wakeup(&cp->r); 
1995/0908/sys/src/9/pc/devata.c:1163,12011995/1206/sys/src/9/pc/devata.c:1557,1923
1995/0213    
		cp->lastcmd = cp->cmd; 
		cp->cmd = 0; 
		break; 
1995/1206    
	case Cpktcmd: 
		atapiintr(cp); 
		break; 
1995/0213    
	default: 
		print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n", 
			cp->cmd, cp->lastcmd, cp->status); 
1995/1206    
		if(cp->cmd == 0 && cp->lastcmd == Cpktcmd && cp->cmdblk[0] == Ccapacity) 
			break; 
		if(cp->status & Serr) 
			cp->error = inb(cp->pbase+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)); 
1995/0213    
		break; 
	} 
 
1995/0214    
	iunlock(&cp->reglock); 
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
} 
 
void 
hardclock(void) 
{ 
	int drive; 
1995/1206    
	int driveno, mask; 
1995/0213    
	Drive *dp; 
	Controller *cp; 
	int diff; 
 
	if(spindowntime <= 0) 
1995/1206    
	if((mask = spindownmask) == 0) 
1995/0213    
		return; 
 
	for(drive = 0; drive < conf.nhard; drive++){ 
		dp = &ata[drive]; 
1995/1206    
	for(driveno = 0; driveno < NDrive && mask; driveno++){ 
		mask &= ~(1<<driveno); 
		if((dp = atadrive[driveno]) == 0) 
			continue; 
1995/0213    
		cp = dp->cp; 
 
		diff = TK2SEC(m->ticks - dp->usetime); 
		if((dp->state == Sspinning) && (diff >= spindowntime)){ 
1995/0214    
			ilock(&cp->reglock); 
1995/1206    
		if((dp->state == Sspinning) && (diff >= dp->spindown)){ 
			DPRINT("%s: spindown\n", dp->vol); 
			ILOCK(&cp->reglock); 
1995/0213    
			cp->cmd = Cstandby; 
			outb(cp->pbase+Pcount, 0); 
1995/0215    
			outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); 
1995/1206    
			outb(cp->pbase+Pdh, dp->dh); 
1995/0213    
			outb(cp->pbase+Pcmd, cp->cmd); 
1995/0214    
			iunlock(&cp->reglock); 
1995/1206    
			IUNLOCK(&cp->reglock); 
1995/0213    
			dp->state = Sstandby; 
		} 
1995/1206    
	} 
} 
 
static int 
isatapi(Drive *dp) 
{ 
	Controller *cp; 
 
	cp = dp->cp; 
	outb(cp->pbase+Pdh, dp->dh); 
	DPRINT("%s: isatapi %d\n", dp->vol, dp->atapi); 
	if(dp->atapi){ 
		outb(cp->pbase+Pcmd, 0x08); 
		delay(20); 
	} 
	dp->atapi = 0; 
	dp->bytes = 512; 
	microdelay(1); 
	if(inb(cp->pbase+Pstatus)){ 
		DPRINT("%s: isatapi status %ux\n", dp->vol, inb(cp->pbase+Pstatus)); 
		return 0; 
	} 
	if(inb(cp->pbase+Pcylmsb) != 0xEB || inb(cp->pbase+Pcyllsb) != 0x14){ 
		DPRINT("%s: isatapi cyl %ux %ux\n", 
			dp->vol, inb(cp->pbase+Pcylmsb), inb(cp->pbase+Pcyllsb)); 
		return 0; 
	} 
	dp->atapi = 1; 
	sprint(dp->vol, "atapi%d", dp->driveno); 
	dp->spindown = 0; 
	spindownmask &= ~(1<<dp->driveno); 
	return 1; 
} 
 
static void 
atapiexec(Drive *dp) 
{ 
	Controller *cp; 
	int loop; 
 
	cp = dp->cp; 
 
	if(cmdreadywait(dp)){ 
		error(Eio); 
	} 
	 
	ILOCK(&cp->reglock); 
	cp->nsecs = 1; 
	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); 
 
	if(dp->drqintr == 0){ 
		microdelay(1); 
		for(loop = 0; (inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0; loop++){ 
			if(loop < 10000) 
				continue; 
			panic("%s: cmddrqwait: cmd=%lux status=%lux\n", 
				dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); 
		} 
		outss(cp->pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); 
	} 
	IUNLOCK(&cp->reglock); 
 
	loop = 0; 
	while(waserror()){ 
		DPRINT("%s: interrupted atapiexec\n", dp->vol); 
		if(loop++ > 10){ 
			print("%s: disk error\n", dp->vol); 
			nexterror(); 
		} 
	} 
	atasleep(cp); 
	poperror(); 
	if(loop) 
		nexterror(); 
 
	if(cp->status & Serr){ 
		DPRINT("%s: Bad packet command %ux\n", dp->vol, cp->error); 
		error(Eio); 
	} 
} 
 
static long 
atapiio(Drive *dp, char *a, ulong len, ulong offset) 
{ 
	ulong bn, n, o, m; 
	Controller *cp; 
	uchar *buf; 
	int retrycount; 
 
	cp = dp->cp; 
 
	buf = smalloc(Maxxfer); 
	qlock(cp->ctlrlock); 
	retrycount = 1; 
retry: 
	if(waserror()){ 
		dp->partok = 0; 
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ 
			dp->vers++; 
			if(retrycount){ 
				retrycount--; 
				goto retry; 
			} 
		} 
		cp->dp = 0; 
		free(buf); 
		qunlock(cp->ctlrlock); 
		nexterror(); 
	} 
 
	cp->buf = buf; 
	cp->dp = dp; 
	cp->len = dp->bytes; 
 
	n = len; 
	while(n > 0){ 
		bn = offset / dp->bytes; 
		if(offset > dp->cap-dp->bytes) 
			break; 
		o = offset % dp->bytes; 
		m = dp->bytes - o; 
		if(m > n) 
			m = n; 
		memset(cp->cmdblk, 0, 12); 
		cp->cmdblk[0] = Cread2; 
		cp->cmdblk[2] = bn >> 24; 
		cp->cmdblk[3] = bn >> 16; 
		cp->cmdblk[4] = bn >> 8; 
		cp->cmdblk[5] = bn; 
		cp->cmdblk[7] = 0; 
		cp->cmdblk[8] = 1; 
		atapiexec(dp); 
		if(cp->count != dp->bytes){ 
			print("short read\n"); 
			break; 
		} 
		memmove(a, cp->buf + o, m); 
		n -= m; 
		offset += m; 
		a += m; 
	} 
	poperror(); 
	free(buf); 
	cp->dp = 0; 
	qunlock(cp->ctlrlock); 
	return len-n; 
} 
 
static long 
atapirwio(Chan *c, char *a, ulong len, ulong offset) 
{ 
	Drive *dp; 
	ulong vers; 
	long rv; 
 
	dp = atadrive[DRIVE(c->qid.path)]; 
 
	qlock(dp); 
	if(waserror()){ 
		qunlock(dp); 
		nexterror(); 
	} 
 
	vers = c->qid.vers; 
	c->qid.vers = dp->vers; 
	if(vers && vers != dp->vers) 
		error(Eio); 
	rv = atapiio(dp, a, len, offset); 
 
	poperror(); 
	qunlock(dp); 
	return rv; 
} 
 
static void 
atapipart(Drive *dp) 
{ 
	Controller *cp; 
	uchar *buf, err; 
	Partition *pp; 
	int retrycount; 
 
	cp = dp->cp; 
 
	pp = &dp->p[0]; 
	strcpy(pp->name, "disk"); 
	pp->start = 0; 
	pp->end = 0; 
	dp->npart = 1; 
 
	buf = smalloc(Maxxfer); 
	qlock(cp->ctlrlock); 
	retrycount = 1; 
retry: 
	if(waserror()){ 
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ 
			dp->vers++; 
			if(retrycount){ 
				retrycount--; 
				goto retry; 
			} 
		} 
		cp->dp = 0; 
		free(buf); 
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x20) 
			err = cp->error; 
		else 
			err = 0; 
		qunlock(cp->ctlrlock); 
		if(err == 0x20) 
			return; 
		nexterror(); 
	} 
 
	cp->buf = buf; 
	cp->dp = dp; 
 
	cp->len = 8; 
	cp->count = 0; 
	memset(cp->cmdblk, 0, sizeof(cp->cmdblk)); 
	cp->cmdblk[0] = Ccapacity; 
	atapiexec(dp); 
	if(cp->count != 8){ 
		print("cmd=%2.2uX, lastcmd=%2.2uX ", cp->cmd, cp->lastcmd); 
		print("cdsize count %d, status 0x%2.2uX, error 0x%2.2uX\n", 
			cp->count, cp->status, cp->error); 
		error(Eio); 
	} 
	dp->lbasecs = (cp->buf[0]<<24)|(cp->buf[1]<<16)|(cp->buf[2]<<8)|cp->buf[3]; 
	dp->cap = dp->lbasecs*dp->bytes; 
	cp->dp = 0; 
	free(cp->buf); 
	poperror(); 
	qunlock(cp->ctlrlock); 
 
	pp->end = dp->cap / dp->bytes; 
	dp->partok = 1; 
} 
 
static void 
atapiintr(Controller *cp) 
{ 
	uchar cause; 
	int count, loop, pbase; 
	uchar *addr; 
 
	pbase = cp->pbase; 
	cause = inb(pbase+Pcount) & 0x03; 
	DPRINT("%s: atapiintr %uX\n", cp->dp->vol, cause); 
	switch(cause){ 
 
	case 0:						/* data out */ 
		cp->status |= Serr; 
		/*FALLTHROUGH*/ 
	case 1:						/* command */ 
		if(cp->status & Serr){ 
			cp->lastcmd = cp->cmd; 
			cp->cmd = 0; 
			cp->error = inb(pbase+Perror); 
			wakeup(&cp->r);  
			break; 
		} 
		outss(pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); 
		break; 
 
	case 2:						/* data in */ 
		addr = cp->buf; 
		if(addr == 0){ 
			cp->lastcmd = cp->cmd; 
			cp->cmd = 0; 
			if(cp->status & Serr) 
				cp->error = inb(pbase+Perror); 
			wakeup(&cp->r);	  
			break;	 
		} 
		loop = 0; 
		while((cp->status & (Serr|Sdrq)) == 0){ 
			if(++loop > Maxloop){ 
				cp->status |= Serr; 
				break; 
			} 
			cp->status = inb(pbase+Pstatus); 
		} 
		if(cp->status & Serr){ 
			cp->lastcmd = cp->cmd; 
			cp->cmd = 0; 
			cp->error = inb(pbase+Perror); 
			print("%s: Cpktcmd status=%uX, error=%uX\n", 
				cp->dp->vol, cp->status, cp->error); 
			wakeup(&cp->r); 
			break; 
		} 
		count = inb(pbase+Pcyllsb)|(inb(pbase+Pcylmsb)<<8); 
		if (count > Maxxfer)  
			count = Maxxfer; 
		inss(pbase+Pdata, addr, count/2); 
		cp->count = count; 
		cp->lastcmd = cp->cmd;  
		break; 
 
	case 3:						/* status */ 
		cp->lastcmd = cp->cmd; 
		cp->cmd = 0; 
		if(cp->status & Serr) 
			cp->error = inb(cp->pbase+Perror); 
		wakeup(&cp->r);	 
		break; 
1995/0213    
	} 
} 
1995/1206/sys/src/9/pc/devata.c:76,821995/1208/sys/src/9/pc/devata.c:76,82 (short | long)
1995/1206    
	Npart=		20+2,		/* 8 sub partitions, disk, and partition */ 
1995/0213    
	Nrepl=		64,		/* maximum replacement blocks */ 
1995/0818    
 
1995/1206    
	Hardtimeout=	30000,		/* disk access timeout (ms) */ 
1995/1208    
	Hardtimeout=	6000,		/* disk access timeout (ms) */ 
1995/1206    
 
	NCtlr=		4, 
	NDrive=		NCtlr*2, 
1995/1206/sys/src/9/pc/devata.c:339,3461995/1208/sys/src/9/pc/devata.c:339,348
1995/1206    
	if(driveno & 0x01) 
		drive->dh |= DHslave; 
	drive->vers = 1; 
	if(atapi) 
1995/1208    
	if(atapi){ 
		sprint(drive->vol, "atapi%d", drive->driveno); 
1995/1206    
		drive->atapi = 1; 
1995/1208    
	} 
1995/1206    
 
	atadrive[driveno] = drive; 
} 
1995/1206/sys/src/9/pc/devata.c:384,3901995/1208/sys/src/9/pc/devata.c:386,392
1995/1206    
	 * 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 Edd (Micronics M54Li + Sanyo CDR-XXX) so let's check for the 
1995/1208    
	 * to the Cedd (Micronics M54Li + Sanyo CRD-254P) so let's check for the 
1995/1206    
	 * ATAPI signature straight off. If we find it there will be no probe 
	 * done for a slave. Tough. 
	 */ 
1995/1206/sys/src/9/pc/devata.c:401,4061995/1208/sys/src/9/pc/devata.c:403,410
1995/1206    
		goto skipedd; 
	} 
	if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1)) || waserror()){ 
1995/1208    
		DPRINT("ata%d: Cedd status %ux/%ux/%ux\n", 
			ctlrno, inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
1995/1206    
		xfree(ctlr); 
		return -1; 
	} 
1995/1206/sys/src/9/pc/devata.c:1069,10861995/1208/sys/src/9/pc/devata.c:1073,1079
1995/0213    
		nexterror(); 
	} 
 
1995/1206    
	if(dp->atapi || isatapi(dp)) 
		cmd = Cidentd; 
	else{ 
		cmd = Cident; 
		if(cmdreadywait(dp)){ 
			dp->atapi = 1; 
			if(isatapi(dp) == 0) 
				error(Eio); 
			cmd = Cidentd; 
		} 
	} 
1995/0213    
                 
1995/1208    
	cmd = Cident; 
1995/1206    
retryatapi: 
	ILOCK(&cp->reglock); 
1995/0213    
	cp->nsecs = 1; 
1995/1206/sys/src/9/pc/devata.c:1092,11031995/1208/sys/src/9/pc/devata.c:1085,1096
1995/1206    
	outb(cp->pbase+Pcmd, cmd); 
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/1208    
	DPRINT("%s: ident command %ux sent\n", dp->vol, cmd); 
1995/0818    
	atasleep(cp); 
 
1995/0213    
	if(cp->status & Serr){ 
1995/1206    
		DPRINT("%s: bad disk ident status\n", dp->vol); 
		if(dp->atapi == 0 && (cp->error & Eabort)){ 
			dp->atapi = 1; 
1995/1208    
		if(cp->error & Eabort){ 
1995/1206    
			if(isatapi(dp)){ 
				cmd = Cidentd; 
				goto retryatapi; 
1995/1206/sys/src/9/pc/devata.c:1134,11401995/1208/sys/src/9/pc/devata.c:1127,1133
1995/1206    
	dp->cyl = ip->cyls; 
	dp->heads = ip->heads; 
	dp->sectors = ip->s2t; 
	DPRINT("%s: %s %d/%d/%d CHS %d bytes\n", 
1995/1208    
	XPRINT("%s: %s %d/%d/%d CHS %d bytes\n", 
1995/1206    
		dp->vol, id, dp->cyl, dp->heads, dp->sectors, dp->cap); 
 
	if(ip->cvalid&(1<<0)){ 
1995/1206/sys/src/9/pc/devata.c:1142,11481995/1208/sys/src/9/pc/devata.c:1135,1141
1995/1206    
		dp->cyl = ip->ccyls; 
		dp->heads = ip->cheads; 
		dp->sectors = ip->cs2t; 
		DPRINT("%s: changed to %d cyl %d head %d sec\n", 
1995/1208    
		XPRINT("%s: changed to %d cyl %d head %d sec\n", 
1995/1206    
			dp->vol, dp->cyl, dp->heads, dp->sectors); 
	} 
 
1995/1206/sys/src/9/pc/devata.c:1151,11571995/1208/sys/src/9/pc/devata.c:1144,1150
1995/0213    
		dp->lba = 1; 
1995/1206    
		dp->lbasecs = lbasecs; 
		dp->cap = dp->bytes * dp->lbasecs; 
		DPRINT("%s: LBA: %s %d sectors %d bytes\n", 
1995/1208    
		XPRINT("%s: LBA: %s %d sectors %d bytes\n", 
1995/1206    
			dp->vol, id, dp->lbasecs, dp->cap); 
1995/0213    
	} else { 
		dp->lba = 0; 
1995/1206/sys/src/9/pc/devata.c:1534,15481995/1208/sys/src/9/pc/devata.c:1527,1544
1995/1206    
			print("%s: intr %d %d\n", dp->vol, cp->sofar, cp->nsecs); 
1995/0213    
		if(cp->sofar >= cp->nsecs){ 
			cp->lastcmd = cp->cmd; 
1995/1208    
#ifdef notdef 
1995/1206    
			if(cp->cmd == Cidentd) 
1995/0213    
				cp->cmd = Cident2; 
1995/1206    
			else if(cp->cmd == Cident && (cp->status & Sready) == 0) 
				cp->cmd = Cident2; 
1995/1208    
#else 
			if(cp->cmd != Cread && (cp->status & (Sbusy|Sready)) != Sready) 
				cp->cmd = Cident2; 
#endif /* notdef */ 
1995/1206    
			else 
				cp->cmd = 0; 
			inb(cp->pbase+Pstatus); 
			DPRINT("status %uX, alt %uX\n", 
				inb(cp->pbase+Pstatus), inb(cp->pbase+0x206)); 
1995/0213    
			wakeup(&cp->r); 
		} 
		break; 
1995/1206/sys/src/9/pc/devata.c:1614,16221995/1208/sys/src/9/pc/devata.c:1610,1619
1995/1206    
	cp = dp->cp; 
	outb(cp->pbase+Pdh, dp->dh); 
	DPRINT("%s: isatapi %d\n", dp->vol, dp->atapi); 
	if(dp->atapi){ 
		outb(cp->pbase+Pcmd, 0x08); 
		delay(20); 
1995/1208    
	outb(cp->pbase+Pcmd, 0x08); 
	if(atactlrwait(dp->cp, DHmagic, 0, MS2TK(100))){ 
		DPRINT("%s: isatapi ctlrwait status %ux\n", dp->vol, inb(cp->pbase+Pstatus)); 
		return 0; 
1995/1206    
	} 
	dp->atapi = 0; 
	dp->bytes = 512; 
1995/1206/sys/src/9/pc/devata.c:1688,16941995/1208/sys/src/9/pc/devata.c:1685,1691
1995/1206    
		nexterror(); 
 
	if(cp->status & Serr){ 
		DPRINT("%s: Bad packet command %ux\n", dp->vol, cp->error); 
1995/1208    
		DPRINT("%s: Bad packet command %ux, error %ux\n", dp->vol, cp->cmdblk[0], cp->error); 
1995/1206    
		error(Eio); 
	} 
} 
1995/1206/sys/src/9/pc/devata.c:1705,17111995/1208/sys/src/9/pc/devata.c:1702,1708
1995/1206    
 
	buf = smalloc(Maxxfer); 
	qlock(cp->ctlrlock); 
	retrycount = 1; 
1995/1208    
	retrycount = 2; 
1995/1206    
retry: 
	if(waserror()){ 
		dp->partok = 0; 
1995/1206/sys/src/9/pc/devata.c:1804,18101995/1208/sys/src/9/pc/devata.c:1801,1807
1995/1206    
 
	buf = smalloc(Maxxfer); 
	qlock(cp->ctlrlock); 
	retrycount = 1; 
1995/1208    
	retrycount = 2; 
1995/1206    
retry: 
	if(waserror()){ 
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ 
1995/1206/sys/src/9/pc/devata.c:1817,18231995/1208/sys/src/9/pc/devata.c:1814,1820
1995/1206    
		cp->dp = 0; 
		free(buf); 
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x20) 
			err = cp->error; 
1995/1208    
			err = cp->error & 0xF0; 
1995/1206    
		else 
			err = 0; 
		qunlock(cp->ctlrlock); 
1995/1208/sys/src/9/pc/devata.c:190,1961995/1209/sys/src/9/pc/devata.c:190,196 (short | long)
1995/0213    
static void	ataparams(Drive*); 
static void	atapart(Drive*); 
static int	ataprobe(Drive*, int, int, int); 
1995/1206    
static void	atasleep(Controller*); 
1995/1209    
static void	atasleep(Controller*, int); 
1995/0213    
 
1995/1206    
static int	isatapi(Drive*); 
static long	atapirwio(Chan*, char*, ulong, ulong); 
1995/1208/sys/src/9/pc/devata.c:411,4171995/1209/sys/src/9/pc/devata.c:411,417
1995/1206    
	setvec(irq, ataintr, ctlr); 
	ctlr->cmd = Cedd; 
	outb(port+Pcmd, Cedd); 
	atasleep(ctlr); 
1995/1209    
	atasleep(ctlr, Hardtimeout); 
1995/1206    
	poperror(); 
 
	/* 
1995/1208/sys/src/9/pc/devata.c:832,8401995/1209/sys/src/9/pc/devata.c:832,840
1995/0213    
} 
 
1995/0818    
static void 
atasleep(Controller *cp) 
1995/1209    
atasleep(Controller *cp, int ms) 
1995/0818    
{ 
	tsleep(&cp->r, cmddone, cp, Hardtimeout); 
1995/1209    
	tsleep(&cp->r, cmddone, cp, ms); 
1995/0818    
	if(cp->cmd && cp->cmd != Cident2){ 
1995/1206    
		DPRINT("ata%d: cmd 0x%uX timeout\n", cp->ctlrno, cp->cmd); 
1995/0818    
		error("ata drive timeout"); 
1995/1208/sys/src/9/pc/devata.c:942,9481995/1209/sys/src/9/pc/devata.c:942,948
1995/0213    
			nexterror(); 
		} 
	} 
1995/0818    
	atasleep(cp); 
1995/1209    
	atasleep(cp, Hardtimeout); 
1995/0213    
	dp->usetime = m->ticks; 
1995/1206    
	dp->state = Sspinning; 
1995/0213    
	poperror(); 
1995/1208/sys/src/9/pc/devata.c:996,10021995/1209/sys/src/9/pc/devata.c:996,1002
1995/1206    
	outb(cp->pbase+Pcmd, Cfeature); 
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/0818    
	atasleep(cp); 
1995/1209    
	atasleep(cp, Hardtimeout); 
1995/0213    
 
1995/1206    
	if(cp->status & Serr) 
		DPRINT("%s: setbuf err: status %lux, err %lux\n", 
1995/1208/sys/src/9/pc/devata.c:1086,10921995/1209/sys/src/9/pc/devata.c:1086,1092
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/1208    
	DPRINT("%s: ident command %ux sent\n", dp->vol, cmd); 
1995/0818    
	atasleep(cp); 
1995/1209    
	atasleep(cp, 1000); 
1995/0818    
 
1995/0213    
	if(cp->status & Serr){ 
1995/1206    
		DPRINT("%s: bad disk ident status\n", dp->vol); 
1995/1208/sys/src/9/pc/devata.c:1203,12091995/1209/sys/src/9/pc/devata.c:1203,1209
1995/0213    
	outb(cp->pbase+Pcmd, Cread); 
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/0818    
	atasleep(cp); 
1995/1209    
	atasleep(cp, Hardtimeout); 
1995/0213    
 
1995/1206    
	if(cp->status & Serr){ 
		DPRINT("%s: probe err: status %lux, err %lux\n", 
1995/1208/sys/src/9/pc/devata.c:1527,15411995/1209/sys/src/9/pc/devata.c:1527,1534
1995/1206    
			print("%s: intr %d %d\n", dp->vol, cp->sofar, cp->nsecs); 
1995/0213    
		if(cp->sofar >= cp->nsecs){ 
			cp->lastcmd = cp->cmd; 
1995/1208    
#ifdef notdef 
1995/1206    
			if(cp->cmd == Cidentd) 
1995/1209    
			if(cp->cmd != Cread) 
1995/0213    
				cp->cmd = Cident2; 
1995/1206    
			else if(cp->cmd == Cident && (cp->status & Sready) == 0) 
				cp->cmd = Cident2; 
1995/1208    
#else 
			if(cp->cmd != Cread && (cp->status & (Sbusy|Sready)) != Sready) 
				cp->cmd = Cident2; 
#endif /* notdef */ 
1995/1206    
			else 
				cp->cmd = 0; 
			inb(cp->pbase+Pstatus); 
1995/1208/sys/src/9/pc/devata.c:1679,16851995/1209/sys/src/9/pc/devata.c:1672,1678
1995/1206    
			nexterror(); 
		} 
	} 
	atasleep(cp); 
1995/1209    
	atasleep(cp, Hardtimeout); 
1995/1206    
	poperror(); 
	if(loop) 
		nexterror(); 
1995/1209/sys/src/9/pc/devata.c:1384,14081995/1218/sys/src/9/pc/devata.c:1384,1414 (short | long)
1995/1206    
	sprint(namebuf, "%spartition", dp->vol); 
	if((p = getconf(namebuf)) == 0){	 
		/* 
		 *  read last sector from disk, null terminate.  This used 
		 *  to be the sector we used for the partition tables. 
1995/1218    
		 *  Read second last sector from disk, null terminate. 
		 *  The last sector used to hold the partition tables. 
1995/1206    
		 *  However, this sector is special on some PC's so we've 
		 *  started to use the second last sector as the partition 
		 *  table instead.  To avoid reconfiguring all our old systems 
		 *  we first look to see if there is a valid partition 
		 *  table in the last sector.  If so, we use it.  Otherwise 
		 *  we switch to the second last. 
1995/1218    
		 *  we still check if there is a valid partition table in 
		 *  the last sector if none is found in the second last. 
1995/1206    
		 */ 
		ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
1995/1218    
		ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-1, dp->bytes, buf); 
1995/0213    
		buf[dp->bytes-1] = 0; 
1995/1206    
		n = getfields((char*)buf, line, Npart+1, "\n"); 
		if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 
1995/1218    
		if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/1206    
			dp->p[0].end--; 
			dp->p[1].start--; 
			dp->p[1].end--; 
1995/1218    
		} 
		else{ 
1995/1206    
			ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
			buf[dp->bytes-1] = 0; 
			n = getfields((char*)buf, line, Npart+1, "\n"); 
1995/1218    
			if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 
				dp->p[0].end--; 
				dp->p[1].start--; 
				dp->p[1].end--; 
			} 
1995/1206    
		} 
1995/0213    
	} 
1995/1206    
	else{ 
1995/1218/sys/src/9/pc/devata.c:1392,13981995/1219/sys/src/9/pc/devata.c:1392,1399 (short | long)
1995/1218    
		 *  we still check if there is a valid partition table in 
		 *  the last sector if none is found in the second last. 
1995/1206    
		 */ 
1995/1218    
		ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-1, dp->bytes, buf); 
1995/1219    
print("R%d|", dp->p[0].end-2); 
		ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-2, dp->bytes, buf); 
1995/0213    
		buf[dp->bytes-1] = 0; 
1995/1206    
		n = getfields((char*)buf, line, Npart+1, "\n"); 
1995/1218    
		if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/1218/sys/src/9/pc/devata.c:1399,14061995/1219/sys/src/9/pc/devata.c:1400,1409
1995/1206    
			dp->p[0].end--; 
			dp->p[1].start--; 
			dp->p[1].end--; 
1995/1219    
print("OK%d|", dp->p[1].start); 
1995/1218    
		} 
		else{ 
1995/1219    
print("r%d|", dp->p[1].start); 
1995/1206    
			ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
			buf[dp->bytes-1] = 0; 
			n = getfields((char*)buf, line, Npart+1, "\n"); 
1995/1218/sys/src/9/pc/devata.c:1408,14141995/1219/sys/src/9/pc/devata.c:1411,1419
1995/1218    
				dp->p[0].end--; 
				dp->p[1].start--; 
				dp->p[1].end--; 
1995/1219    
print("nok%d|", dp->p[1].start); 
1995/1218    
			} 
1995/1219    
else print("ok%d|", dp->p[1].start); 
1995/1206    
		} 
1995/0213    
	} 
1995/1206    
	else{ 
1995/1219/sys/src/9/pc/devata.c:1392,14191995/1221/sys/src/9/pc/devata.c:1392,1414 (short | long)
1995/1218    
		 *  we still check if there is a valid partition table in 
		 *  the last sector if none is found in the second last. 
1995/1206    
		 */ 
1995/1219    
print("R%d|", dp->p[0].end-2); 
		ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-2, dp->bytes, buf); 
1995/1221    
		i = 0; 
		ataxfer(dp, &dp->p[0], Cread, (dp->p[0].end-2)*dp->bytes, dp->bytes, buf); 
1995/0213    
		buf[dp->bytes-1] = 0; 
1995/1206    
		n = getfields((char*)buf, line, Npart+1, "\n"); 
1995/1218    
		if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/1206    
			dp->p[0].end--; 
			dp->p[1].start--; 
			dp->p[1].end--; 
1995/1219    
print("OK%d|", dp->p[1].start); 
1995/1218    
		} 
1995/1221    
		if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0) 
			i = 1; 
1995/1218    
		else{ 
1995/1219    
print("r%d|", dp->p[1].start); 
1995/1206    
			ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
			buf[dp->bytes-1] = 0; 
			n = getfields((char*)buf, line, Npart+1, "\n"); 
1995/1218    
			if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 
				dp->p[0].end--; 
				dp->p[1].start--; 
				dp->p[1].end--; 
1995/1219    
print("nok%d|", dp->p[1].start); 
1995/1218    
			} 
1995/1219    
else print("ok%d|", dp->p[1].start); 
1995/1221    
			if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)) 
				i = 1; 
		} 
		if(i){ 
			dp->p[0].end--; 
			dp->p[1].start--; 
			dp->p[1].end--; 
1995/1206    
		} 
1995/0213    
	} 
1995/1206    
	else{ 
1995/1221/sys/src/9/pc/devata.c:62,671996/0112/sys/src/9/pc/devata.c:62,69 (short | long)
1995/0213    
 
1995/1206    
	Cpktcmd=	0xA0, 
	Cidentd=	0xA1, 
1996/0112    
	Ctur=		0x00, 
	Creqsense=	0x03, 
1995/1206    
	Ccapacity=	0x25, 
	Cread2=		0x28, 
 
1995/1221/sys/src/9/pc/devata.c:1073,10791996/0112/sys/src/9/pc/devata.c:1075,1084
1995/0213    
		nexterror(); 
	} 
 
1995/1208    
	cmd = Cident; 
1996/0112    
	if(dp->atapi) 
		cmd = Cidentd; 
	else 
		cmd = Cident; 
1995/1206    
retryatapi: 
	ILOCK(&cp->reglock); 
1995/0213    
	cp->nsecs = 1; 
1995/1221/sys/src/9/pc/devata.c:1803,18081996/0112/sys/src/9/pc/devata.c:1808,1814
1995/1208    
	retrycount = 2; 
1995/1206    
retry: 
	if(waserror()){ 
1996/0112    
		DPRINT("atapipart: cmd %uX error %uX\n", cp->cmd, cp->error); 
1995/1206    
		if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ 
			dp->vers++; 
			if(retrycount){ 
1995/1221/sys/src/9/pc/devata.c:1824,18291996/0112/sys/src/9/pc/devata.c:1830,1848
1995/1206    
 
	cp->buf = buf; 
	cp->dp = dp; 
1996/0112    
 
	cp->len = 18; 
	cp->count = 0; 
	memset(cp->cmdblk, 0, sizeof(cp->cmdblk)); 
	cp->cmdblk[0] = Creqsense; 
	cp->cmdblk[4] = 18; 
	atapiexec(dp); 
	if(cp->count != 18){ 
		print("cmd=%2.2uX, lastcmd=%2.2uX ", cp->cmd, cp->lastcmd); 
		print("cdsize count %d, status 0x%2.2uX, error 0x%2.2uX\n", 
			cp->count, cp->status, cp->error); 
		error(Eio); 
	} 
1995/1206    
 
	cp->len = 8; 
	cp->count = 0; 
1996/0112/sys/src/9/pc/devata.c:49,541996/0210/sys/src/9/pc/devata.c:49,58 (short | long)
1995/0213    
	 Serr=		 (1<<0), 
	Pcmd=		7,	/* cmd port (write) */ 
 
1996/0210    
	Pctrl=		0x206,	/* device control, alternate status */ 
	 nIEN=		(1<<1), 
	 Srst=		(1<<2), 
 
1995/0213    
	/* commands */ 
1995/1206    
	Cfirst=		0xFF,	/* pseudo command for initialisation */ 
1995/0213    
	Cread=		0x20, 
1996/0112/sys/src/9/pc/devata.c:152,1581996/0210/sys/src/9/pc/devata.c:156,162
1995/0213    
 
	int	pbase;		/* base port */ 
1995/1206    
	uchar	ctlrno; 
	uchar	noatapi; 
1996/0210    
	uchar	resetok; 
1995/0213    
 
	/* 
	 *  current operation 
1996/0112/sys/src/9/pc/devata.c:354,3601996/0210/sys/src/9/pc/devata.c:358,364
1995/1206    
{ 
	Controller *ctlr; 
	int atapi, mask, port; 
	uchar error, status; 
1996/0210    
	uchar error, status, msb, lsb; 
1995/1206    
 
	/* 
	 * Check the existence of a controller by verifying a sensible 
1996/0112/sys/src/9/pc/devata.c:377,3881996/0210/sys/src/9/pc/devata.c:381,393
1995/1206    
	ctlr->ctlrno = ctlrno; 
	ctlr->lastcmd = 0xFF; 
 
1996/0210    
 
1995/1206    
	/* 
	 * Attempt to check the existence of drives on the controller 
	 * by issuing a 'check device diagnostics' command. 
	 * 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. 
1996/0210    
	 * seem to implement the control-block registers; do it if requested. 
1995/1206    
	 * 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 
1996/0112/sys/src/9/pc/devata.c:392,3971996/0210/sys/src/9/pc/devata.c:397,413
1995/1206    
	 * ATAPI signature straight off. If we find it there will be no probe 
	 * done for a slave. Tough. 
	 */ 
1996/0210    
	if(ctlr->resetok){ 
		outb(port+Pctrl, Srst|nIEN); 
		microdelay(1); 
		outb(port+Pctrl, 0); 
		if(atactlrwait(ctlr, DHmagic, 0, 100)){ 
			DPRINT("ata%d: Srst status %ux/%ux/%ux\n", ctlrno, 
				inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
			xfree(ctlr); 
		} 
	} 
 
1995/1206    
	atapi = 0; 
	mask = 0; 
	status = inb(port+Pstatus); 
1996/0112/sys/src/9/pc/devata.c:405,4121996/0210/sys/src/9/pc/devata.c:421,428
1995/1206    
		goto skipedd; 
	} 
	if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1)) || waserror()){ 
1995/1208    
		DPRINT("ata%d: Cedd status %ux/%ux/%ux\n", 
			ctlrno, inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
1996/0210    
		DPRINT("ata%d: Cedd status %ux/%ux/%ux\n", ctlrno, 
			inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
1995/1206    
		xfree(ctlr); 
		return -1; 
	} 
1996/0112/sys/src/9/pc/devata.c:447,4551996/0210/sys/src/9/pc/devata.c:463,477
1995/1206    
	DPRINT("ata%d: slave diag status %ux, error %ux\n", ctlr->ctlrno, status, error); 
	if(status && (status & (Sbusy|Serr)) == 0 && (error & ~0x80) == 0x01) 
		mask |= 0x02; 
	else if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ 
		atapi |= 0x02; 
		mask |= 0x02; 
1996/0210    
	else if(status == 0){ 
		msb = inb(port+Pcylmsb); 
		lsb = inb(port+Pcyllsb); 
		DPRINT("ata%d: ATAPI slave %uX %uX %uX\n", ctlrno, status, 
			inb(port+Pcylmsb), inb(port+Pcyllsb)); 
		if(msb == 0xEB && lsb == 0x14){ 
			atapi |= 0x02; 
			mask |= 0x02; 
		} 
1995/1206    
	} 
 
skipedd: 
1996/0112/sys/src/9/pc/devata.c:514,5211996/0210/sys/src/9/pc/devata.c:536,543
1995/1206    
				DPRINT("ata%d: opt spindownmask %ux\n", 
					ctlrno, spindownmask); 
			} 
			else if(strcmp(isa.opt[i], "noatapi") == 0) 
				atactlr[ctlrno]->noatapi = 1; 
1996/0210    
			else if(strcmp(isa.opt[i], "reset") == 0) 
				atactlr[ctlrno]->resetok = 1; 
1995/1206    
		} 
	} 
1995/0213    
} 
1996/0112/sys/src/9/pc/devata.c:1091,10971996/0210/sys/src/9/pc/devata.c:1113,1122
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
 
1995/1208    
	DPRINT("%s: ident command %ux sent\n", dp->vol, cmd); 
1995/1209    
	atasleep(cp, 1000); 
1996/0210    
	if(cmd == Cident) 
		atasleep(cp, 3000); 
	else 
		atasleep(cp, 30000); 
1995/0818    
 
1995/0213    
	if(cp->status & Serr){ 
1995/1206    
		DPRINT("%s: bad disk ident status\n", dp->vol); 
1996/0210/sys/src/9/pc/devata.c:399,4071996/0215/sys/src/9/pc/devata.c:399,407 (short | long)
1995/1206    
	 */ 
1996/0210    
	if(ctlr->resetok){ 
		outb(port+Pctrl, Srst|nIEN); 
		microdelay(1); 
1996/0215    
		delay(10); 
1996/0210    
		outb(port+Pctrl, 0); 
		if(atactlrwait(ctlr, DHmagic, 0, 100)){ 
1996/0215    
		if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20)){ 
1996/0210    
			DPRINT("ata%d: Srst status %ux/%ux/%ux\n", ctlrno, 
				inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
			xfree(ctlr); 
1996/0210/sys/src/9/pc/devata.c:1116,11221996/0215/sys/src/9/pc/devata.c:1116,1122
1996/0210    
	if(cmd == Cident) 
		atasleep(cp, 3000); 
	else 
		atasleep(cp, 30000); 
1996/0215    
		atasleep(cp, 10000); 
1995/0818    
 
1995/0213    
	if(cp->status & Serr){ 
1995/1206    
		DPRINT("%s: bad disk ident status\n", dp->vol); 
1996/0215/sys/src/9/pc/devata.c:401,4071996/0216/sys/src/9/pc/devata.c:401,407 (short | long)
1996/0210    
		outb(port+Pctrl, Srst|nIEN); 
1996/0215    
		delay(10); 
1996/0210    
		outb(port+Pctrl, 0); 
1996/0215    
		if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20)){ 
1996/0216    
		if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20))){ 
1996/0210    
			DPRINT("ata%d: Srst status %ux/%ux/%ux\n", ctlrno, 
				inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); 
			xfree(ctlr); 
1996/0216/sys/src/9/pc/devata.c:10,161996/0223/sys/src/9/pc/devata.c:10,15 (short | long)
1995/0213    
#include	"io.h" 
#include	"../port/error.h" 
 
#include	"devtab.h" 
 
1995/0215    
#define DPRINT if(0)print 
1995/1206    
#define XPRINT if(0)print 
1996/0223/sys/src/9/pc/devata.c:1344,13551996/0315/sys/src/9/pc/devata.c:1344,1355 (short | long)
1995/0213    
	/* 
	 *  parse replacement table. 
	 */ 
1995/1206    
	n = getfields((char*)buf, line, Nrepl+1, "\n"); 
1996/0315    
	n = parsefields((char*)buf, line, Nrepl+1, "\n"); 
1995/0213    
	if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){ 
		dp->repl.p = 0; 
	} else { 
		for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){ 
			if(getfields(line[i], field, 1, " ") != 1) 
1996/0315    
			if(parsefields(line[i], field, 1, " ") != 1) 
1995/0213    
				break; 
			dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0); 
			if(dp->repl.blk[dp->repl.nrepl] <= 0) 
1996/0223/sys/src/9/pc/devata.c:1424,14361996/0315/sys/src/9/pc/devata.c:1424,1436
1995/1221    
		i = 0; 
		ataxfer(dp, &dp->p[0], Cread, (dp->p[0].end-2)*dp->bytes, dp->bytes, buf); 
1995/0213    
		buf[dp->bytes-1] = 0; 
1995/1206    
		n = getfields((char*)buf, line, Npart+1, "\n"); 
1996/0315    
		n = parsefields((char*)buf, line, Npart+1, "\n"); 
1995/1221    
		if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0) 
			i = 1; 
1995/1218    
		else{ 
1995/1206    
			ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); 
			buf[dp->bytes-1] = 0; 
			n = getfields((char*)buf, line, Npart+1, "\n"); 
1996/0315    
			n = parsefields((char*)buf, line, Npart+1, "\n"); 
1995/1221    
			if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)) 
				i = 1; 
		} 
1996/0223/sys/src/9/pc/devata.c:1442,14481996/0315/sys/src/9/pc/devata.c:1442,1448
1995/0213    
	} 
1995/1206    
	else{ 
		strcpy((char*)buf, p); 
		n = getfields((char*)buf, line, Npart+1, "\n"); 
1996/0315    
		n = parsefields((char*)buf, line, Npart+1, "\n"); 
1995/1206    
	} 
1995/0213    
 
	/* 
1996/0223/sys/src/9/pc/devata.c:1450,14561996/0315/sys/src/9/pc/devata.c:1450,1456
1995/0213    
	 */ 
1995/1206    
	if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 
1995/0213    
		for(i = 1; i < n; i++){ 
1995/1206    
			if(getfields(line[i], field, 3, " ") != 3) 
1996/0315    
			if(parsefields(line[i], field, 3, " ") != 3) 
1995/1206    
				break; 
			if(pp >= &dp->p[Npart]) 
				break; 
1996/0315/sys/src/9/pc/devata.c:640,6451996/0803/sys/src/9/pc/devata.c:640,647 (short | long)
1995/0213    
		return; 
 
1995/1206    
	dp = atadrive[DRIVE(c->qid.path)]; 
1996/0803    
	if(dp == 0) 
		return; 
1995/1206    
	p = &dp->p[PART(c->qid.path)]; 
1995/0213    
	if(strcmp(p->name, "partition") != 0) 
		return; 
1996/0803/sys/src/9/pc/devata.c:203,2091996/1225/sys/src/9/pc/devata.c:203,209 (short | long)
1995/1206    
static void	atapiintr(Controller*); 
 
1995/0213    
static int 
1995/1206    
atagen(Chan *c, Dirtab*, long, long s, Dir *dirp) 
1996/1225    
atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) 
1995/0213    
{ 
	Qid qid; 
	int drive; 
1996/1225/sys/src/9/pc/devata.c:155,1601997/0327/sys/src/9/pc/devata.c:155,161 (short | long)
1995/0213    
 
	int	pbase;		/* base port */ 
1995/1206    
	uchar	ctlrno; 
1997/0327    
	int	tbdf; 
1996/0210    
	uchar	resetok; 
1995/0213    
 
	/* 
1996/1225/sys/src/9/pc/devata.c:180,1861997/0327/sys/src/9/pc/devata.c:181,187
1995/1206    
static QLock atactlrlock[NCtlr]; 
static Drive *atadrive[NDrive]; 
static int spindownmask; 
static int have640b = -1; 
1997/0327    
static int have640b; 
1995/1206    
static int pbase[NCtlr] = { 
	Pbase0, Pbase1, Pbase2, Pbase3, 
}; 
1996/1225/sys/src/9/pc/devata.c:196,2011997/0327/sys/src/9/pc/devata.c:197,203
1995/0213    
static void	atapart(Drive*); 
static int	ataprobe(Drive*, int, int, int); 
1995/1209    
static void	atasleep(Controller*, int); 
1997/0327    
static void	ataclock(void); 
1995/0213    
 
1995/1206    
static int	isatapi(Drive*); 
static long	atapirwio(Chan*, char*, ulong, ulong); 
1996/1225/sys/src/9/pc/devata.c:203,2091997/0327/sys/src/9/pc/devata.c:205,211
1995/1206    
static void	atapiintr(Controller*); 
 
1995/0213    
static int 
1996/1225    
atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) 
1997/0327    
atagen(Chan* c, Dirtab*, int, int s, Dir* dirp) 
1995/0213    
{ 
	Qid qid; 
	int drive; 
1996/1225/sys/src/9/pc/devata.c:237,2461997/0327/sys/src/9/pc/devata.c:239,246
1995/1206    
static void 
cmd640b(void) 
1995/0213    
{ 
1995/1206    
	PCIcfg* pcicfg; 
	uchar r50[12]; 
	int devno; 
	extern void pcicfgw8(int, int, int, int, void*, int); 
1997/0327    
	Pcidev *p; 
	int r; 
1995/0213    
 
1995/1206    
	/* 
	 * Look for CMD640B dual PCI controllers. Amongst other 
1996/1225/sys/src/9/pc/devata.c:249,2601997/0327/sys/src/9/pc/devata.c:249,257
1995/1206    
	 * controllers this is, so if one is found then all controller 
	 * pairs are synchronised. 
	 */ 
	pcicfg = malloc(sizeof(PCIcfg)); 
	pcicfg->vid = 0x1095; 
	pcicfg->did = 0x0640; 
	devno = 0; 
	while((devno = pcimatch(0, devno, pcicfg)) != -1){ 
		have640b = devno-1; 
1997/0327    
	p = 0; 
	while(p = pcimatch(p, 0x1095, 0x0640)){ 
		have640b++; 
1995/1206    
		/* 
		 * If one is found, make sure read-ahead is disabled on all 
		 * drives and that the 2nd controller is enabled: 
1996/1225/sys/src/9/pc/devata.c:263,3031997/0327/sys/src/9/pc/devata.c:260,293
1995/1206    
		 *  		bit 3 - 2nd controller enable 
		 *   reg 0x57:	bit 3 - drive 1 read ahead disable 
		 *  		bit 2 - drive 0 read ahead disable 
		 * Doing byte-writes to PCI configuration space is not in the 
		 * spec... 
		 */ 
		pcicfgr(0, have640b, 0, 0x50, r50, sizeof(r50)); 
		r50[0x01] |= 0xC8; 
		pcicfgw8(0, have640b, 0, 0x51, &r50[0x01], sizeof(r50[0x01])); 
		r50[0x07] |= 0x0C; 
		pcicfgw8(0, have640b, 0, 0x57, &r50[0x07], sizeof(r50[0x07])); 
1997/0327    
		r = pcicfgr8(p, 0x51); 
		r |= 0xC8; 
		pcicfgw8(p, 0x51, r); 
		r = pcicfgr8(p, 0x57); 
		r |= 0x0C; 
		pcicfgw8(p, 0x57, r); 
1995/1206    
	} 
	free(pcicfg); 
} 
1995/0213    
 
1995/1206    
static void 
rz1000(void) 
{ 
	PCIcfg* pcicfg; 
	ulong r40; 
	int devno; 
1997/0327    
	Pcidev *p; 
	ulong r; 
1995/0215    
 
1995/1206    
	/* 
	 * Look for PC-Tech RZ1000 controllers and turn off prefetch. 
	 * This is overkill, but cheap. 
	 */ 
	pcicfg = malloc(sizeof(PCIcfg)); 
	pcicfg->vid = 0x1042; 
	pcicfg->did = 0; 
	devno = 0; 
	while((devno = pcimatch(0, devno, pcicfg)) != -1){ 
		if(pcicfg->did != 0x1000 && pcicfg->did != 0x1001) 
1997/0327    
	p = 0; 
	while(p = pcimatch(p, 0x1042, 0)){ 
		if(p->did != 0x1000 && p->did != 0x1001) 
1995/1206    
			continue; 
		pcicfgr(0, devno-1, 0, 0x40, &r40, sizeof(r40)); 
		r40 &= ~0x2000; 
		pcicfgw(0, devno-1, 0, 0x40, &r40, sizeof(r40)); 
1997/0327    
		r = pcicfgr32(p, 0x40); 
		r &= ~0x2000; 
		pcicfgw32(p, 0x40, r); 
1995/1206    
	} 
	free(pcicfg); 
} 
1995/0215    
 
1995/1206    
static int 
1996/1225/sys/src/9/pc/devata.c:378,3831997/0327/sys/src/9/pc/devata.c:368,374
1995/1206    
		return -1; 
	ctlr->pbase = port; 
	ctlr->ctlrno = ctlrno; 
1997/0327    
	ctlr->tbdf = BUSUNKNOWN; 
1995/1206    
	ctlr->lastcmd = 0xFF; 
 
1996/0210    
 
1996/1225/sys/src/9/pc/devata.c:414,4201997/0327/sys/src/9/pc/devata.c:405,411
1995/1206    
		inb(port+Pcylmsb), inb(port+Pcyllsb)); 
	if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ 
		DPRINT("ata%d: ATAPI ok\n", ctlrno); 
		setvec(irq, ataintr, ctlr); 
1997/0327    
		intrenable(irq, ataintr, ctlr, ctlr->tbdf); 
1995/1206    
		atapi |= 0x01; 
		mask |= 0x01; 
		goto skipedd; 
1996/1225/sys/src/9/pc/devata.c:425,4311997/0327/sys/src/9/pc/devata.c:416,422
1995/1206    
		xfree(ctlr); 
		return -1; 
	} 
	setvec(irq, ataintr, ctlr); 
1997/0327    
	intrenable(irq, ataintr, ctlr, ctlr->tbdf); 
1995/1206    
	ctlr->cmd = Cedd; 
	outb(port+Pcmd, Cedd); 
1995/1209    
	atasleep(ctlr, Hardtimeout); 
1996/1225/sys/src/9/pc/devata.c:480,4861997/0327/sys/src/9/pc/devata.c:471,477
1995/1206    
	} 
	atactlr[ctlrno] = ctlr; 
 
	if(have640b >= 0 && (ctlrno & 0x01)) 
1997/0327    
	if(have640b && (ctlrno & 0x01)) 
1995/1206    
		ctlr->ctlrlock = &atactlrlock[ctlrno-1]; 
	else 
		ctlr->ctlrlock = &atactlrlock[ctlrno]; 
1996/1225/sys/src/9/pc/devata.c:493,4991997/0327/sys/src/9/pc/devata.c:484,490
1995/1206    
	return 0; 
} 
 
void 
1997/0327    
static void 
1995/1206    
atactlrreset(void) 
{ 
	int ctlrno, driveno, i, slave, spindown; 
1996/1225/sys/src/9/pc/devata.c:509,5151997/0327/sys/src/9/pc/devata.c:500,506
1995/1206    
		if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) 
			continue; 
 
		if(atactlrprobe(ctlrno, Int0vec+isa.irq)) 
1997/0327    
		if(atactlrprobe(ctlrno, VectorPIC+isa.irq)) 
1995/1206    
			continue; 
1995/0213    
	 
1995/1206    
		for(i = 0; i < isa.nopt; i++){ 
1996/1225/sys/src/9/pc/devata.c:539,5621997/0327/sys/src/9/pc/devata.c:530,546
1996/0210    
				atactlr[ctlrno]->resetok = 1; 
1995/1206    
		} 
	} 
1995/0213    
} 
 
void 
1995/1206    
atareset(void) 
{ 
1997/0327    
	if(spindownmask) 
		addclock0link(ataclock); 
1995/1206    
} 
 
void 
1995/0213    
atainit(void) 
{ 
} 
                 
/* 
 *  Get the characteristics of each drive.  Mark unresponsive ones 
 *  off line. 
 */ 
Chan* 
ataattach(char *spec) 
1997/0327    
static Chan* 
ataattach(char* spec) 
1995/0213    
{ 
1995/1206    
	int driveno; 
1995/0213    
	Drive *dp; 
1996/1225/sys/src/9/pc/devata.c:600,6381997/0327/sys/src/9/pc/devata.c:584,610
1995/0213    
	return devattach('H', spec); 
} 
 
Chan* 
ataclone(Chan *c, Chan *nc) 
1997/0327    
static int 
atawalk(Chan* c, char* name) 
1995/0213    
{ 
	return devclone(c, nc); 
} 
                 
int 
atawalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, 0, 0, atagen); 
} 
 
void 
atastat(Chan *c, char *dp) 
1997/0327    
static void 
atastat(Chan* c, char* dp) 
1995/0213    
{ 
	devstat(c, dp, 0, 0, atagen); 
} 
 
Chan* 
ataopen(Chan *c, int omode) 
1997/0327    
static Chan* 
ataopen(Chan* c, int omode) 
1995/0213    
{ 
	return devopen(c, omode, 0, 0, atagen); 
} 
 
void 
1995/1206    
atacreate(Chan*, char*, int, ulong) 
1997/0327    
ataclose(Chan* c) 
1995/0213    
{ 
	error(Eperm); 
} 
                 
void 
ataclose(Chan *c) 
{ 
1995/1206    
	Drive *dp; 
1995/0213    
	Partition *p; 
 
1996/1225/sys/src/9/pc/devata.c:657,6771997/0327/sys/src/9/pc/devata.c:629,637
1995/0213    
	poperror(); 
} 
 
void 
1995/1206    
ataremove(Chan*) 
1997/0327    
static long 
ataread(Chan* c, void* a, long n, ulong offset) 
1995/0213    
{ 
	error(Eperm); 
} 
                 
void 
1995/1206    
atawstat(Chan*, char*) 
1995/0213    
{ 
	error(Eperm); 
} 
                 
long 
ataread(Chan *c, void *a, long n, ulong offset) 
{ 
	Drive *dp; 
	long rv, i; 
	int skip; 
1996/1225/sys/src/9/pc/devata.c:723,7351997/0327/sys/src/9/pc/devata.c:683,689
1995/0213    
	return rv; 
} 
 
Block* 
atabread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
                 
long 
1997/0327    
static long 
1995/0213    
atawrite(Chan *c, void *a, long n, ulong offset) 
{ 
	Drive *dp; 
1996/1225/sys/src/9/pc/devata.c:802,8131997/0327/sys/src/9/pc/devata.c:756,761
1995/0213    
	return rv; 
} 
 
long 
atabwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
} 
                 
/* 
 *  did an interrupt happen? 
 */ 
1996/1225/sys/src/9/pc/devata.c:1601,16081997/0327/sys/src/9/pc/devata.c:1549,1556
1995/1206    
	IUNLOCK(&cp->reglock); 
1995/0213    
} 
 
void 
hardclock(void) 
1997/0327    
static void 
ataclock(void) 
1995/0213    
{ 
1995/1206    
	int driveno, mask; 
1995/0213    
	Drive *dp; 
1996/1225/sys/src/9/pc/devata.c:1962,19641997/0327/sys/src/9/pc/devata.c:1910,1930
1995/1206    
		break; 
1995/0213    
	} 
} 
1997/0327    
 
Dev atadevtab = { 
	devreset, 
	devinit, 
	ataattach, 
	devclone, 
	atawalk, 
	atastat, 
	ataopen, 
	devcreate, 
	ataclose, 
	ataread, 
	devbread, 
	atawrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 
1997/0327/sys/src/9/pc/devata.c:1912,19171997/0408/sys/src/9/pc/devata.c:1912,1920 (short | long)
1995/0213    
} 
1997/0327    
 
Dev atadevtab = { 
1997/0408    
	'H', 
	"ata", 
 
1997/0327    
	devreset, 
	devinit, 
	ataattach, 
1997/0408/sys/src/9/pc/devata.c:190,1961997/0812/sys/src/9/pc/devata.c:190,196 (short | long)
1995/1206    
}; 
1995/0213    
 
static void	ataintr(Ureg*, void*); 
1995/1206    
static long	ataxfer(Drive*, Partition*, int, long, long, uchar*); 
1997/0812    
static long	ataxfer(Drive*, Partition*, int, ulong, long, uchar*); 
1995/0213    
static void	ataident(Drive*); 
1995/1206    
static void	atafeature(Drive*, uchar); 
1995/0213    
static void	ataparams(Drive*); 
1997/0408/sys/src/9/pc/devata.c:820,8261997/0812/sys/src/9/pc/devata.c:820,826
1995/0213    
 *  parts. 
 */ 
static long 
1995/1206    
ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, uchar *buf) 
1997/0812    
ataxfer(Drive *dp, Partition *pp, int cmd, ulong start, long len, uchar *buf) 
1995/0213    
{ 
	Controller *cp; 
	long lblk; 
1997/0812/sys/src/9/pc/devata.c:11,171997/0815/sys/src/9/pc/devata.c:11,17 (short | long)
1995/0213    
#include	"../port/error.h" 
 
 
1995/0215    
#define DPRINT if(0)print 
1997/0815    
#define DPRINT if(1)print 
1995/1206    
#define XPRINT if(0)print 
#define ILOCK(x) 
#define IUNLOCK(x) 
1997/0812/sys/src/9/pc/devata.c:156,1621997/0815/sys/src/9/pc/devata.c:156,161
1995/0213    
	int	pbase;		/* base port */ 
1995/1206    
	uchar	ctlrno; 
1997/0327    
	int	tbdf; 
1996/0210    
	uchar	resetok; 
1995/0213    
 
	/* 
	 *  current operation 
1997/0812/sys/src/9/pc/devata.c:343,3491997/0815/sys/src/9/pc/devata.c:342,348
1995/1206    
} 
 
static int 
atactlrprobe(int ctlrno, int irq) 
1997/0815    
atactlrprobe(int ctlrno, int irq, int resetok) 
1995/1206    
{ 
	Controller *ctlr; 
	int atapi, mask, port; 
1997/0812/sys/src/9/pc/devata.c:359,3661997/0815/sys/src/9/pc/devata.c:358,366
1995/1206    
	port = pbase[ctlrno]; 
	outb(port+Pdh, DHmagic); 
	microdelay(1); 
	if((inb(port+Pdh) & 0xFF) != DHmagic){ 
		DPRINT("ata%d: DHmagic not ok\n", ctlrno); 
1997/0815    
	status = inb(port+Pdh) & 0xFF; 
	if(status != DHmagic){ 
		DPRINT("ata%d: DHmagic not ok == %ux\n", ctlrno, status); 
1995/1206    
		return -1; 
1995/0215    
	} 
1995/1206    
	DPRINT("ata%d: DHmagic ok\n", ctlrno); 
1997/0812/sys/src/9/pc/devata.c:387,3931997/0815/sys/src/9/pc/devata.c:387,393
1995/1206    
	 * ATAPI signature straight off. If we find it there will be no probe 
	 * done for a slave. Tough. 
	 */ 
1996/0210    
	if(ctlr->resetok){ 
1997/0815    
	if(resetok){ 
1996/0210    
		outb(port+Pctrl, Srst|nIEN); 
1996/0215    
		delay(10); 
1996/0210    
		outb(port+Pctrl, 0); 
1997/0812/sys/src/9/pc/devata.c:487,4931997/0815/sys/src/9/pc/devata.c:487,493
1997/0327    
static void 
1995/1206    
atactlrreset(void) 
{ 
	int ctlrno, driveno, i, slave, spindown; 
1997/0815    
	int ctlrno, driveno, i, resetok, slave, spindown; 
1995/1206    
	ISAConf isa; 
 
	cmd640b(); 
1997/0812/sys/src/9/pc/devata.c:500,5081997/0815/sys/src/9/pc/devata.c:500,506
1995/1206    
		if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) 
			continue; 
 
1997/0327    
		if(atactlrprobe(ctlrno, VectorPIC+isa.irq)) 
1995/1206    
			continue; 
1995/0213    
	                 
1997/0815    
		driveno = resetok = spindown = 0; 
1995/1206    
		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){ 
1997/0812/sys/src/9/pc/devata.c:514,5341997/0815/sys/src/9/pc/devata.c:512,535
1995/1206    
					slave = 1; 
				else 
					continue; 
				driveno = ctlrno*2+slave; 
				if(atadrive[driveno] == 0) 
					continue; 
				if((spindown = strtol(&isa.opt[i][10], 0, 0)) == 0) 
					continue; 
				if(spindown < (Hardtimeout+2000)/1000) 
					spindown = (Hardtimeout+2000)/1000; 
				atadrive[driveno]->spindown = spindown; 
				spindownmask |= (1<<driveno); 
				DPRINT("ata%d: opt spindownmask %ux\n", 
					ctlrno, spindownmask); 
1997/0815    
				driveno = ctlrno*2+slave; 
1995/1206    
			} 
1996/0210    
			else if(strcmp(isa.opt[i], "reset") == 0) 
				atactlr[ctlrno]->resetok = 1; 
1997/0815    
				resetok = 1; 
1995/1206    
		} 
1997/0815    
 
		if(atactlrprobe(ctlrno, VectorPIC+isa.irq, resetok)) 
			continue; 
 
		if(spindown == 0 || atadrive[driveno] == 0) 
			continue; 
		atadrive[driveno]->spindown = spindown; 
		spindownmask |= (1<<driveno); 
		DPRINT("ata%d: opt spindownmask %ux\n", ctlrno, spindownmask); 
1995/1206    
	} 
1995/0213    
 
1997/0327    
	if(spindownmask) 
Too many diffs (26 > 25). Stopping.


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