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

1995/1206/pc/devata.c (diff list | history)

1995/0908/sys/src/9/pc/devata.c:1,31995/1206/sys/src/9/pc/devata.c:1,7 (short | long | prev | next)
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    
	} 
} 


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