henesyinit from p9fd787fda5 years agoHistory
1135 lines · 22.8 KB · C
RawDownload
#include "all.h"#include "io.h"#include "mem.h" #define DEBUG	0#define DPRINT	if(DEBUG)print#define IDEBUG	0#define IDPRINT if(IDEBUG)print typedef	struct Drive		Drive;typedef	struct Ident		Ident;typedef	struct Controller	Controller; enum{	/* ports */	Pbase0=		0x1F0,	/* primary */	Pbase1=		0x170,	/* secondary */	Pbase2=		0x1E8,	/* tertiary */	Pbase3=		0x168,	/* quaternary */	Pdata=		0,	/* data port (16 bits) */	Perror=		1,	/* error port (read) */	 Eabort=	(1<<2),	Pfeature=	1,	/* buffer mode port (write) */	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 */	 DHmagic=	0xA0,	 DHslave=	0x10,	Pstatus=	7,	/* status port (read) */	 Sbusy=		 (1<<7),	 Sready=	 (1<<6),	 Sdrq=		 (1<<3),	 Serr=		 (1<<0),	Pcmd=		7,	/* cmd port (write) */ 	/* commands */	Crecal=		0x10,	Cread=		0x20,	Cwrite=		0x30,	Cident=		0xEC,	Cident2=	0xFF,	/* pseudo command for post Cident interrupt */	Csetbuf=	0xEF, 	Cpktcmd=	0xA0,	Cidentd=	0xA1,	Ctur=		0x00,	Creqsense=	0x03,	Ccapacity=	0x25,	Cread2=		0x28,	Cwrite2=	0x2A, 	ATAtimo=	6000,		/* ms to wait for things to complete */	ATAPItimo=	10000, 	NCtlr=		4,	NDrive=		NCtlr*2, 	Maxloop=	1000000,}; /* *  ident sector from drive.  this is from ANSI X3.221-1994 */struct Ident{	ushort	config;		/* general configuration info */	ushort	cyls;		/* # of cylinders (default) */	ushort	reserved0;	ushort	heads;		/* # of heads (default) */	ushort	b2t;		/* unformatted bytes/track */	ushort	b2s;		/* unformated bytes/sector */	ushort	s2t;		/* sectors/track (default) */	ushort	reserved1[3];/* 10 */	ushort	serial[10];	/* serial number */	ushort	type;		/* buffer type */	ushort	bsize;		/* buffer size/512 */	ushort	ecc;		/* ecc bytes returned by read long */	ushort	firm[4];	/* firmware revision */	ushort	model[20];	/* model number *//* 47 */	ushort	s2i;		/* number of sectors/interrupt */	ushort	dwtf;		/* double word transfer flag */	ushort	capabilities;	ushort	reserved2;	ushort	piomode;	ushort	dmamode;	ushort	cvalid;		/* (cvald&1) if next 4 words are valid */	ushort	ccyls;		/* current # cylinders */	ushort	cheads;		/* current # heads */	ushort	cs2t;		/* current sectors/track */	ushort	ccap[2];	/* current capacity in sectors */	ushort	cs2i;		/* current number of sectors/interrupt *//* 60 */	ushort	lbasecs[2];	/* # LBA user addressable sectors */	ushort	dmasingle;	ushort	dmadouble;/* 64 */	ushort	reserved3[64];	ushort	vendor[32];	/* vendor specific */	ushort	reserved4[96];}; enum {	Maxxfer		= 16*1024,	/* maximum transfer size/cmd */	Npart		= 8+2,		/* 8 sub partitions, disk, and partition */}; typedef struct {	ulong	start;	ulong	end;	char	name[NAMELEN+1];} Partition; typedef struct {	int	online;	int	npart;		/* number of real partitions */	Partition p[Npart];	ulong	offset;	Partition *current;	/* current partition */ 	ulong	cap;		/* total sectors */	int	bytes;		/* bytes/sector */	int	sectors;	/* sectors/track */	int	heads;		/* heads/cyl */	long	cyl;		/* cylinders/drive */ 	char	lba;		/* true if drive has logical block addressing */	char	multi;		/* non-zero if drive does multiple block xfers */} Disc; /* *  an ata drive */struct Drive{	Controller *cp;	uchar	driveno;	uchar	dh;	uchar	atapi;		/* ATAPI */	uchar	drqintr;	/* ATAPI */	ulong	vers;		/* ATAPI */ 	int	partok; 	Disc;}; /* *  a controller for 2 drives */struct Controller{	int	pbase;		/* base port */	uchar	ctlrno; 	/*	 *  current operation	 */	int	cmd;		/* current command */	uchar	cmdblk[12];	/* ATAPI */	int	len;		/* ATAPI */	int	count;		/* ATAPI */	uchar	lastcmd;	/* debugging info */	uchar	*buf;		/* xfer buffer */	int	tcyl;		/* target cylinder */	int	thead;		/* target head */	int	tsec;		/* target sector */	int	tbyte;		/* target byte */	int	nsecs;		/* length of transfer (sectors) */	int	sofar;		/* sectors transferred so far */	int	status;	int	error;	Drive	*dp;		/* drive being accessed */}; static int atactlrmask;static Controller *atactlr[NCtlr];static int atadrivemask;static Drive *atadrive[NDrive];static int pbase[NCtlr] = {	Pbase0, Pbase1, Pbase2, Pbase3,};static int defirq[NCtlr] = {	14, 15, 0, 0,}; static void	ataintr(Ureg*, void*);static long	ataxfer(Drive*, Partition*, int, ulong, long);static int	ataident(Drive*);static Drive*	atapart(Drive*);static int	ataparams(Drive*);static void	atarecal(Drive*);static int	ataprobe(Drive*, int, int, int);static Drive*	atapipart(Drive*);static void	atapiintr(Controller*);static long	atapiio(Drive*, long); static voidatactlrprobe(int ctlrno, int irq){	Controller *ctlr;	Drive *drive;	int driveno, port; 	if(atactlrmask & (1<<ctlrno))		return;	atactlrmask |= 1<<ctlrno; 	port = pbase[ctlrno];	outb(port+Pdh, DHmagic);	delay(1);	if((inb(port+Pdh) & 0xFF) != DHmagic){		DPRINT("ata%d: DHmagic not ok\n", ctlrno);		return;	}	DPRINT("ata%d: DHmagic ok\n", ctlrno); 	atactlr[ctlrno] = ialloc(sizeof(Controller), 0);	ctlr = atactlr[ctlrno];	ctlr->pbase = port;	ctlr->ctlrno = ctlrno;	ctlr->buf = ialloc(Maxxfer, 0);	inb(ctlr->pbase+Pstatus);	setvec(irq, ataintr, ctlr); 	driveno = ctlrno*2;	atadrive[driveno] = ialloc(sizeof(Drive), 0);	drive = atadrive[driveno];	drive->cp = ctlr;	drive->driveno = driveno;	drive->dh = DHmagic; 	driveno++;	atadrive[driveno] = ialloc(sizeof(Drive), 0);	drive = atadrive[driveno];	drive->cp = ctlr;	drive->driveno = driveno;	drive->dh = DHmagic|DHslave;} static Drive*atadriveprobe(int driveno){	Drive *drive;	int ctlrno;	ISAConf isa; 	ctlrno = driveno/2;	if(atactlr[ctlrno] == 0){		if(atactlrmask & (1<<ctlrno))			return 0;		memset(&isa, 0, sizeof(ISAConf));		if(isaconfig("ata", ctlrno, &isa) == 0)			return 0;		if(ctlrno && isa.irq)			atactlrprobe(ctlrno, Int0vec+isa.irq);		if(atactlr[ctlrno] == 0)			return 0;	} 	drive = atadrive[driveno];	if(drive->online == 0){		if(atadrivemask & (1<<driveno))			return 0;		atadrivemask |= 1<<driveno;		if(ataparams(drive))			return 0;		if(drive->lba)			print("hd%d: LBA %lud sectors\n",				drive->driveno, drive->cap);		else			print("hd%d: CHS %ld/%d/%d %lud sectors\n",				drive->driveno, drive->cyl, drive->heads,				drive->sectors, drive->cap);		drive->online = 1;	} 	return atapart(drive);} intatainit(void){	ISAConf isa;	int ctlrno; 	for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){		memset(&isa, 0, sizeof(ISAConf));		if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno > 1)			continue;		if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0)			continue;		atactlrprobe(ctlrno, Int0vec+isa.irq);	}	DPRINT("atainit: mask 0x%ux 0x%ux\n", atactlrmask, atadrivemask); 	return 0xFF;} longataseek(int driveno, long offset){	Drive *drive; 	if((drive = atadriveprobe(driveno)) == 0)		return -1;	drive->offset = offset;	return offset;} /* *  did an interrupt happen? */static voidatawait(Controller *cp, int timo){	ulong start;	int x; 	x = spllo();	start = m->ticks;	while(TK2MS(m->ticks - start) < timo){		if(cp->cmd == 0)			break;		if(cp->cmd == Cident2 && TK2MS(m->ticks - start) >= 1000)			break;	}	if(TK2MS(m->ticks - start) >= timo){		DPRINT("atawait timed out 0x%ux\n", inb(cp->pbase+Pstatus));		ataintr(0, cp);	}	splx(x);} intsetatapart(int driveno, char *p){	Partition *pp;	Drive *dp; 	if((dp = atadriveprobe(driveno)) == 0)		return 0; 	for(pp = dp->p; pp < &dp->p[dp->npart]; pp++)		if(strcmp(pp->name, p) == 0){			dp->current = pp;			return 1;		}	return 0;} longataread(int driveno, void *a, long n){	Drive *dp;	long rv, i;	int skip;	uchar *aa = a;	Partition *pp;	Controller *cp; 	if((dp = atadriveprobe(driveno)) == 0)		return 0; 	pp = dp->current;	if(pp == 0)		return -1;	cp = dp->cp; 	skip = dp->offset % dp->bytes;	for(rv = 0; rv < n; rv += i){		i = ataxfer(dp, pp, Cread, dp->offset+rv-skip, n-rv+skip);		if(i == 0)			break;		if(i < 0)			return -1;		i -= skip;		if(i > n - rv)			i = n - rv;		memmove(aa+rv, cp->buf + skip, i);		skip = 0;	}	dp->offset += rv; 	return rv;} longatawrite(int driveno, void *a, long n){	Drive *dp;	long rv, i, partial;	uchar *aa = a;	Partition *pp;	Controller *cp; 	if((dp = atadriveprobe(driveno)) == 0)		return 0; 	pp = dp->current;	if(pp == 0)		return -1;	cp = dp->cp; 	/*	 *  if not starting on a sector boundary,	 *  read in the first sector before writing	 *  it out.	 */	partial = dp->offset % dp->bytes;	if(partial){		ataxfer(dp, pp, Cread, dp->offset-partial, dp->bytes);		if(partial+n > dp->bytes)			rv = dp->bytes - partial;		else			rv = n;		memmove(cp->buf+partial, aa, rv);		if(ataxfer(dp, pp, Cwrite, dp->offset-partial, dp->bytes) < 0)			return -1;	} else		rv = 0; 	/*	 *  write out the full sectors	 */	partial = (n - rv) % dp->bytes;	n -= partial;	for(; rv < n; rv += i){		i = n - rv;		if(i > Maxxfer)			i = Maxxfer;		memmove(cp->buf, aa+rv, i);		i = ataxfer(dp, pp, Cwrite, dp->offset+rv, i);		if(i == 0)			break;		if(i < 0)			return -1;	} 	/*	 *  if not ending on a sector boundary,	 *  read in the last sector before writing	 *  it out.	 */	if(partial){		if(ataxfer(dp, pp, Cread, dp->offset+rv, dp->bytes) < 0)			return -1;		memmove(cp->buf, aa+rv, partial);		if(ataxfer(dp, pp, Cwrite, dp->offset+rv, dp->bytes) < 0)			return -1;		rv += partial;	}	dp->offset += rv;	return rv;} /* *  wait for the controller to be ready to accept a command */static intcmdreadywait(Drive *drive){	ulong end;	uchar dh, status;	Controller *ctlr; 	ctlr = drive->cp;	end = m->ticks+MS2TK(10)+1;	dh = (inb(ctlr->pbase+Pdh) & DHslave)^(drive->dh & DHslave);		status = 0;	while(m->ticks < end){		status = inb(ctlr->pbase+Pstatus);		if(status & Sbusy)			continue;		if(dh){			outb(ctlr->pbase+Pdh, drive->dh);			dh = 0;			continue;		}		if(drive->atapi || (status & Sready))			return 0;	}	USED(status); 	DPRINT("hd%d: cmdreadywait failed 0x%ux\n", drive->driveno, status);	outb(ctlr->pbase+Pdh, DHmagic);	return -1;} /* *  transfer a number of sectors.  ataintr will perform all the iterative *  parts. */static longataxfer(Drive *dp, Partition *pp, int cmd, ulong start, long len)

Lines 1–500 of 1135.