Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/devhard.c

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


## diffname pc/devhard.c 1991/0802
## diff -e /dev/null /n/bootesdump/1991/0802/sys/src/9/safari/devhard.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

typedef	struct Drive		Drive;
typedef	struct Ident		Ident;
typedef	struct Controller	Controller;

enum
{
	/* ports */
	Pbase=		0x10,
	Pdata=		Pbase+0,	/* data port (16 bits) */
	Perror=		Pbase+1,	/* error port */
	Pcount=		Pbase+2,	/* sector count port */
	Psector=	Pbase+3,	/* sector number port */
	Pcyllsb=	Pbase+4,	/* least significant byte cylinder # */
	Pcylmsb=	Pbase+5,	/* most significant byte cylinder # */
	Pdh=		Pbase+6,	/* drive/head port */
	Pstatus=	Pbase+7,	/* status port */
	Pcmd=		Pbase+7,	/* cmd port */

	/* commands */
	Crecal=		0x10,
	Cread=		0x20,
	Cwrite=		0x30,
	Cident=		0xEC,

	/* file types */
	Qdir=		0,
	Qdata=		(1<<1),
	Qstruct=	(2<<1),
	Qmask=		(3<<1),
};

/*
 *  ident sector from drive
 */
struct Ident
{
	ushort	magic;		/* must be 0x0A5A */
	ushort	lcyls;		/* logical number of cylinders */
	ushort	rcyl;		/* number of removable cylinders */
	ushort	lheads;		/* logical number of heads */
	ushort	b2t;		/* unformatted bytes/track */
	ushort	b2s;		/* unformated bytes/sector */
	ushort	ls2t;		/* logical sectors/track */
	ushort	gap;		/* bytes in inter-sector gaps */
	ushort	sync;		/* bytes in sync fields */
	ushort	magic2;		/* must be 0x0000 */
	ushort	serial[10];	/* serial number */
	ushort	type;		/* controller type (0x0003) */
	ushort	bsize;		/* buffer size/512 */
	ushort	ecc;		/* ecc bytes returned by read long */
	ushort	firm[4];	/* firmware revision */
	ushort	model[20];	/* model number */
	ushort	s2i;		/* number of sectors/interrupt */
	ushort	dwtf;		/* double word transfer flag */
	ushort	alernate;
	ushort	piomode;
	ushort	dmamode;
	ushort	reserved[76];
	ushort	ncyls;		/* native number of cylinders */
	ushort	nheads;		/* native number of heads, sectors */
	ushort	dlcyls;		/* default logical number of cyinders */
	ushort	dlheads;	/* default logical number of heads, sectors */
	ushort	interface;
	ushort	power;		/* 0xFFFF if power commands supported */
	ushort	flags;
	ushort	ageprog;	/* MSB = age, LSB = program */
	ushort	reserved2[120];
};

/*
 *  a hard drive
 */
struct Drive
{
	int	dev;
	ulong	cap;		/* drive capacity */
	int	bytes;		/* bytes/sector */
	int	cyl;		/* current cylinder */
	int	confused;	/* needs to be recalibrated (or worse) */

	int	tcyl;		/* target cylinder */
	int	thead;		/* target head */
	int	tsec;		/* target sector */
	long	len;		/* size of xfer */

	Ident	id;
};

/*
 *  a controller for 2 drives
 */
struct Controller
{
	QLock;			/* exclusive access to the drive */

	int	intr;		/* true if interrupt occured */
	Rendez	r;		/* wait here for command termination */
	int	confused;	/* needs to be recalibrated (or worse) */

	Drive	d[2];
};

Controller	hard;

Dirtab harddir[]={
	"hddata",		{Qdata},	0,	0600,
	"hdstruct",		{Qstruct},	8,	0600,
};
#define NHDIR	(sizeof(harddir)/sizeof(Dirtab))

void
hardreset(void)
{
	hard.d[0].dev = 0;
	hard.d[1].dev = 1;
	setvec(Hardvec, hardintr);
}

void
hardinit(void)
{
}

Chan*
hardattach(char *spec)
{
	return devattach('f', spec);
}

Chan*
hardclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
hardwalk(Chan *c, char *name)
{
	return devwalk(c, name, harddir, NHDIR, devgen);
}

void
hardstat(Chan *c, char *dp)
{
	devstat(c, dp, harddir, NHDIR, devgen);
}

Chan*
hardopen(Chan *c, int omode)
{
	return devopen(c, omode, harddir, NHDIR, devgen);
}

void
hardcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
hardclose(Chan *c)
{
}

void
hardremove(Chan *c)
{
	error(Eperm);
}

void
hardwstat(Chan *c, char *dp)
{
	error(Eperm);
}

static void
ul2user(uchar *a, ulong x)
{
	a[0] = x >> 24;
	a[1] = x >> 16;
	a[2] = x >> 8;
	a[3] = x;
}

long
hardread(Chan *c, void *a, long n)
{
	Drive *dp;
	long rv, i;
	uchar *aa = a;

	if(c->qid.path == CHDIR)
		return devdirread(c, a, n, harddir, NHDIR, devgen);

	rv = 0;
	dp = &hard.d[c->qid.path & ~Qmask];
	switch ((int)(c->qid.path & Qmask)) {
	case Qdata:
		for(rv = 0; rv < n; rv += i){
			i = hardxfer(dp, Fread, aa+rv, c->offset+rv, n-rv);
			if(i <= 0)
				break;
		}
		break;
	case Qstruct:
		hardident(dp);
		if (n < 2*sizeof(ulong))
			error(Ebadarg);
		if (c->offset >= 2*sizeof(ulong))
			return 0;
		rv = 2*sizeof(ulong);
		ul2user((uchar*)a, dp->cap);
		ul2user((uchar*)a+sizeof(ulong), dp->bytes);
		break;
	default:
		panic("hardread: bad qid");
	}
	return rv;
}

long
hardwrite(Chan *c, void *a, long n)
{
	Drive *dp;
	long rv, i;
	uchar *aa = a;

	rv = 0;
	dp = &hard.d[c->qid.path & ~Qmask];
	switch ((int)(c->qid.path & Qmask)) {
	case Qdata:
		for(rv = 0; rv < n; rv += i){
			i = hardxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv);
			if(i <= 0)
				break;
		}
		break;
	case Qstruct:
		error(Eperm);
		break;
	default:
		panic("hardwrite: bad qid");
	}
	return rv;
}

/*
 *  did an interrupt happen?
 */
static int
interrupted(Drive *dp)
{
	return hard.intr;
}

/*
 *  get parameters from the drive
 */
hardident(Drive *dp)
{
	hard.intr = 0;
	outb(Pdh, dp->dev<<4);
	outb(Pcmd, Cident);
}

long
hardxfer(Drive *dp, int cmd, void *va, long off, long len)
{
	errors("not implemented");
}

.
## diffname pc/devhard.c 1991/0803
## diff -e /n/bootesdump/1991/0802/sys/src/9/safari/devhard.c /n/bootesdump/1991/0803/sys/src/9/safari/devhard.c
278a
}

/*
 *  take/clear a disk interrupt
 */
static void
hardintr(Ureg *ur)
{
	hard.status = inb(Pstatus);
	hard.intr = 1;
	print("hardintr\n");
	wakeup(&hard.r);
.
275c
static long
.
272a
	sleep(&hard.r, interrupted, 0);
	insw(Pdata, &hard.id, 512);
	qunlock(&hard);
.
269a
	qlock(&hard);
.
267a
static long
.
260c
interrupted(void *a)
.
215a
		dp->cap = 512 * dp->id->lcyls * dp->id->lheads *dp->id->ls2t;
		dp->bytes = 512;
.
118a
static void	hardintr(Ureg*);
static long	hardxfer(Drive*, int, void*, long, long);
static long	hardident(Drive*);

.
## diffname pc/devhard.c 1991/0809
## diff -e /n/bootesdump/1991/0803/sys/src/9/safari/devhard.c /n/bootesdump/1991/0809/sys/src/9/safari/devhard.c
301a
}

/*
 *  calculate physical address of a logical byte offset into the disk
 *
 *  truncate dp->len if it crosses a cylinder boundary
 */
static void
hardpos(Drive *dp, long off)
{
	int lsec;
	int end;
	int cyl;

	lsec = off/dp->bytes;
	dp->tcyl = lsec/(dp->sectors*dp->heads);
	dp->tsec = (lsec % dp->sectors) + 1;
	dp->thead = (lsec/dp->sectors) % dp->heads;

	/*
	 *  can't read across cylinder boundaries.
	 *  if so, decrement the bytes to be read.
	 */
	lsec = (off+dp->len)/dp->bytes;
	cyl = lsec/(dp->sectors*dp->heads);
	if(cyl != dp->tcyl){
		dp->len -= (lsec % dp->sectors)*dp->bytes;
		dp->len -= ((lsec/dp->sectors) % dp->heads)*dp->bytes*dp->sectors;
	}
.
300c
print("hardintr\n");
.
298a
	if(hard.status & Sbusy)
		panic("disk busy");
.
289c
	int secs;
	int i;
	uchar *aa = va;

	if(off % dp->bytes)
		errors("bad offset");
	if(len % dp->bytes)
		errors("bad length");

	if(waserror()){
		qunlock(&hard);
		nexterror();
	}
	qlock(&hard);
	dp->len = len;
	hardpos(dp, off);
	secs = dp->len/dp->bytes;

	outb(Pcount, secs);
	outb(Psector, dp->tsec);
	outb(Pdh, (1<<5) | (dp->dev<<4) | dp->thead);
	outb(Pcyllsb, dp->tcyl);
	outb(Pcylmsb, dp->tcyl>>8);
	outb(Pcmd, cmd);

	if(cmd == Cwrite)
		outss(Pdata, aa, dp->bytes/2);
	for(i = 0; i < secs; i++){
		hard.intr = 0;
		sleep(&hard.r, interrupted, 0);
		if(hard.status & Serr)
			errors("disk error");
		if(cmd == Cread){
			if((hard.status & Sdrq) == 0)
				panic("disk read");
			inss(Pdata, aa + i*dp->bytes, dp->bytes/2);
		} else {
			if((hard.status & Sdrq) == 0){
				if(i+1 != secs)
					panic("disk write");
			} else
				outss(Pdata, aa + (i+1)*dp->bytes, dp->bytes/2);
		}
	}
	qunlock(&hard);
.
282,283c
print("getting hard drive ident\n");
	inss(Pdata, &hard.id, 512/2);
print(" magic %lux lcyls %d rcyl %d lheads %d b2t %d b2s %d ls2t %d\n",
  hard.id.magic, hard.id.lcyls, hard.id.rcyl, hard.id.lheads,
  hard.id.b2t, hard.id.b2s, hard.id.ls2t);
.
280a
print("waiting for hard drive interupt\n");
.
277c
print("identify hard drive\n");
.
248c
			i = hardxfer(dp, Cwrite, aa+rv, c->offset+rv, n-rv);
.
219,221d
213c
			i = hardxfer(dp, Cread, aa+rv, c->offset+rv, n-rv);
.
138a
	Drive *dp;

	qlock(&hard);
	for(dp = hard.d; dp < &hard.d[conf.nhard]; dp++){
		if(!waserror()){
			hardident(dp);
			dp->cyl = hard.id.lcyls;
			dp->heads = hard.id.lheads;
			dp->sectors = hard.id.ls2t;
			dp->bytes = 512;
			dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
			dp->online = 1;
		}
	}
.
133a
	qunlock(&hard);
.
126,127c
	Drive *dp;

	hard.d = ialloc(conf.nhard * sizeof(Drive), 0);
	for(dp = hard.d; dp < &hard.d[conf.nhard]; dp++){
		dp->dev = dp - hard.d;
		dp->online = 0;
	}

.
121a
static void	hardpos(Drive*, long);
.
108c
	Drive	*d;
	Ident	id;
.
104a
	int	status;		/* status of last interupt */
.
93,94d
86,87c
	int	sectors;	/* sectors/track */
	int	heads;		/* heads/cyl */
	long	cyl;		/* cylinders/drive */
.
83a
	int	confused;	/* needs to be recalibrated (or worse) */
	int	online;

.
24a
	 Sbusy=		 (1<<7),
	 Sready=	 (1<<6),
	 Sdrq=		 (1<<5),
	 Serr=		 (1<<0),
.
## diffname pc/devhard.c 1991/0810
## diff -e /n/bootesdump/1991/0809/sys/src/9/safari/devhard.c /n/bootesdump/1991/0810/sys/src/9/safari/devhard.c
377d
312,314d
310d
308d
304d
169c
	qunlock(&hard);
	return devattach('h', spec);
.
166a
			poperror();
.
16c
	Pbase=		0x1F0,
.
## diffname pc/devhard.c 1991/0811
## diff -e /n/bootesdump/1991/0810/sys/src/9/safari/devhard.c /n/bootesdump/1991/0811/sys/src/9/safari/devhard.c
404d
402a
	wakeup(&cp->r);
.
397,401c
	cp = &hardc[0];

	cp->status = inb(cp->pbase+Pstatus);
	switch(cp->cmd){
	case Cwrite:
		if(cp->status & Serr){
			cp->cmd = 0;
			cp->error = inb(cp->pbase+Perror);
			wakeup(&cp->r);
			return;
		}
		cp->sofar++;
		if(cp->sofar != cp->secs){
			while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
				;
			outss(cp->pbase+Pdata, &cp->buf[cp->sofar*cp->dp->bytes],
				cp->dp->bytes/2);
		} else{
			cp->cmd = 0;
			wakeup(&cp->r);
		}
		break;
	case Cread:
	case Cident:
		if(cp->status & Serr){
			cp->cmd = 0;
			cp->error = inb(cp->pbase+Perror);
			wakeup(&cp->r);
			return;
		}
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			;
		inss(cp->pbase+Pdata, &cp->buf[cp->sofar*cp->dp->bytes],
			cp->dp->bytes/2);
		cp->sofar++;
		if(cp->sofar == cp->secs){
			cp->cmd = 0;
			wakeup(&cp->r);
		}
		break;
	default:
		print("wierd disk interrupt\n");
		break;
.
394,395c
 	 *  BUG!! if there is ever more than one controller, we need a way to
	 *	  distinguish which interrupted
.
392a
	cp->len = 512;
	cp->secs = 1;
	cp->sofar = 0;
	cp->cmd = Cident;
	outb(cp->pbase+Pdh, (1<<5) | dp->drive<<4);
	outb(cp->pbase+Pcmd, Cident);
	sleep(&cp->r, cmddone, cp);
	if(cp->status & Serr){
print("bad disk magic\n");
		errors("disk I/O error");
	}
	memmove(&dp->id, cp->buf, cp->len);

	if(dp->id.magic != 0xA5A){
print("bad disk magic\n");
		errors("bad disk magic");
	}

if((dp->id.interface & 0x4000) == 0)
	print("lookaheads disabled\n");	

	poperror();
	qunlock(cp);
}

/*
 *  we get an interrupt for every sector transferred
 */
static void
hardintr(Ureg *ur)
{
	Controller *cp;

.
388,391c
	cp = dp->cp;
	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}
.
384,386c
	Controller *cp;
.
381,382c
static long
hardident(Drive *dp)
.
377,379c
 *  get parameters from the drive
.
369,373c
	Controller *cp = dp->cp;

	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}

	outb(cp->pbase+Pbmode, on ? 0xAA : 0x55);
	outb(cp->pbase+Pdh, (1<<5) | dp->drive<<4);
	outb(cp->pbase+Pcmd, Csetbuf);

	poperror();
	qunlock(cp);
.
367c
hardsetbuf(Drive *dp, int on)
.
364c
 *  set read ahead mode (1 == on, 0 == off)
.
360c
	sleep(&cp->r, cmddone, cp);
	if(cp->status & Serr){
print("hd%d err: status %lux, err %lux\n", dp-hard, cp->status, cp->error);
print("\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead);
print("\tsecs %d, sofar %d\n", cp->secs, cp->sofar);
		errors("disk I/O error");
	}
	if(cmd == Cread)
		memmove(va, cp->buf, cp->len);

	poperror();
	qunlock(cp);
	return cp->len;
.
341,358c
	/*
	 *  can't xfer across cylinder boundaries.
	 */
	lsec = (off+len)/dp->bytes;
	cyl = lsec/(dp->sectors*dp->heads);
	if(cyl == cp->tcyl)
		cp->len = len;
	else
		cp->len = cyl*dp->sectors*dp->heads*dp->bytes - off;

	/*
	 *  wait for the controller to accept commands
	 */
	while(inb(cp->pbase+Pstatus) & Sbusy)
		;

	/*
	 *  start the transfer
	 */
	cp->secs = cp->len/dp->bytes;
	cp->sofar = 0;
	cp->cmd = cmd;
	outb(cp->pbase+Pcount, cp->secs);
	outb(cp->pbase+Psector, cp->tsec);
	outb(cp->pbase+Pdh, (1<<5) | (dp->drive<<4) | cp->thead);
	outb(cp->pbase+Pcyllsb, cp->tcyl);
	outb(cp->pbase+Pcylmsb, cp->tcyl>>8);
	outb(cp->pbase+Pcmd, cmd);

	if(cmd == Cwrite){
		memmove(cp->buf, va, cp->len);
		outss(Pdata, cp->buf, dp->bytes/2);
.
334,339c
	/*
	 *  calculate the physical address of off
	 */
	lsec = off/dp->bytes;
	cp->tcyl = lsec/(dp->sectors*dp->heads);
	cp->tsec = (lsec % dp->sectors) + 1;
	cp->thead = (lsec/dp->sectors) % dp->heads;
.
329,332d
326c
		qunlock(cp);
.
324a
	cp = dp->cp;
	qlock(cp);
.
323c
		errors("bad length");	/* BUG - this shouldn't be a problem */
	if(off % dp->bytes)
		errors("bad offset");	/* BUG - this shouldn't be a problem */
.
320,321c
	if(dp->online == 0)
		errors("disk offline");
.
316,318c
	Controller *cp;
	int err;
	int lsec;
	int cyl;
.
304,313d
301c
 *  start a disk transfer.  hardintr will performa all the iterative
 *  parts.
.
297c
	Controller *cp;

	return cp->cmd == 0;
.
295c
cmddone(void *a)
.
273c
	dp = &hard[c->qid.path & ~Qmask];
.
241c
	dp = &hard[c->qid.path & ~Qmask];
.
238c
		return devdirread(c, a, n, harddir, conf.nhard*NHDIR, devgen);
.
195c
	return devopen(c, omode, harddir, conf.nhard*NHDIR, devgen);
.
189c
	devstat(c, dp, harddir, conf.nhard*NHDIR, devgen);
.
183c
	return devwalk(c, name, harddir, conf.nhard*NHDIR, devgen);
.
170c

.
168c
		} else
			dp->online = 0;
.
165a
			harddir[NHDIR*dp->drive].length = dp->cap;
print("drive %d online\n", dp - hard);
.
161,163c
			dp->cyl = dp->id.lcyls;
			dp->heads = dp->id.lheads;
			dp->sectors = dp->id.ls2t;
.
159a
			hardsetbuf(dp, 1);
.
157,158c
	for(dp = hard; dp < &hard[conf.nhard]; dp++){
.
151a
/*
 *  Get the characteristics of each drive.  Mark unresponsive ones
 *  off line.
 */
.
149d
142,143d
140a
		dp->cp = cp;
		if((drive&1) == 0){
			cp->buf = ialloc(Maxxfer, 0);
			cp->cmd = 0;
			cp->pbase = Pbase + (cp-hardc)*8;	/* BUG!! guessing */
			setvec(Hardvec + (cp-hardc)*8, hardintr); /* BUG!! guessing */
		}
		sprint(harddir[drive*2].name, "hd%ddata", drive);
		dir->length = 0;
		dir->qid.path = Qdata + drive;
		dir->perm = 0600;
		dir++;
		sprint(dir->name, "hd%dstruct", drive);
		dir->length = 8;
		dir->qid.path = Qstruct + drive;
		dir->perm = 0600;
		dir++;
.
137,139c
	hard = ialloc(conf.nhard * sizeof(Drive), 0);
	hardc = ialloc(((conf.nhard+1)/2 + 1) * sizeof(Controller), 0);
	dir = harddir = ialloc(NHDIR * conf.nhard * sizeof(Dirtab), 0);
	
	for(drive = 0; drive < conf.nhard; drive++){
		dp = &hard[drive];
		cp = &hardc[drive/2];
		dp->drive = drive&1;
.
135a
	Controller *cp;
	int drive;
	Dirtab *dir;
.
131a
/*
 *  we assume drives 0 and 1 are on the first controller, 2 and 3 on the
 *  second, etc.
 */
.
130c
static void	hardsetbuf(Drive*, int);
.
121,126d
119c
Controller	*hardc;
Drive		*hard;
Dirtab 		*harddir;
#define NHDIR	2	/* directory entries/drive */
.
115,116c
	/*
	 *  current operation
	 */
	int	cmd;		/* current command */
	Rendez	r;		/* wait here for command termination */
	char	*buf;		/* xfer buffer */
	int	tcyl;		/* target cylinder */
	int	thead;		/* target head */
	int	tsec;		/* target sector */
	int	tbyte;		/* target byte */
	int	len;		/* length of transfer (bytes) */
	int	secs;		/* sectors to be xferred */
	int	sofar;		/* bytes transferred so far */
	int	status;
	int	error;
	Drive	*dp;		/* drive being accessed */
.
113a
	int	pbase;		/* base port */
.
110,112d
97,100c
	Ident	id;		/* disk properties */
.
87c
	Controller *cp;
	int	drive;
.
39,41c
	Qdata=		(1<<4),
	Qstruct=	(2<<4),
	Qmask=		(3<<4),

	Maxxfer=	4*1024,		/* maximum transfer size/cmd */
.
35a
	Csetbuf=	0xEF,
.
29c
	Pcmd=		7,	/* cmd port (write) */
.
17,24c
	Pdata=		0,	/* data port (16 bits) */
	Perror=		1,	/* error port (read) */
	Pbmode=		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 */
	Pstatus=	7,	/* status port (read) */
.
## diffname pc/devhard.c 1991/0812
## diff -e /n/bootesdump/1991/0811/sys/src/9/safari/devhard.c /n/bootesdump/1991/0812/sys/src/9/safari/devhard.c
546d
## diffname pc/devhard.c 1991/0813
## diff -e /n/bootesdump/1991/0812/sys/src/9/safari/devhard.c /n/bootesdump/1991/0813/sys/src/9/safari/devhard.c
533c
			if(++loop > 10000)
				panic("hardintr 2");
.
531a
		loop = 0;
.
516c
				if(++loop > 10000)
					panic("hardintr 1");
.
496a
	long loop;
.
490a
 *  read partition table
 */
static void
hardpart(Drive *dp)
{
	Partition *pp;
	Ptable *pt;
	uchar buf[1024];

	pp = &dp->p[0];
	strcpy(pp->name, "disk");
	pp->start = 0;
	pp->end = pp->cap / dp->bytes;

	qlock(dp->cp);
	hardxfer(dp, Cread, buf, pp->end - 1, dp->bytes);
	
	qunlock(dp->cp);
}

/*
.
483,485d
469c
	cp->dp = dp;
	outb(cp->pbase+Pdh, (dp->drive<<4));
.
464a
	cmdreadywait(cp);

.
445a
	sleep(&cp->r, cmddone, cp);

.
442,443c
	cmdreadywait(cp);

	outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55);
	outb(cp->pbase+Pdh, (dp->drive<<4));
.
404c
	outb(cp->pbase+Pdh, (dp->drive<<4) | cp->thead);
.
401a
	cp->dp = dp;
.
390,394c
	cmdreadywait(cp);
.
346a
 *  wait for the controller to be ready to accept a command
 */
static void
cmdreadywait(Controller *cp)
{
	long start;

	start = m->ticks;
	while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready)
		if(TK2MS(m->ticks - start) > 1){
print("cmdreadywait failed\n");
			errors("disk not responding");
		}
}

/*
.
341c
	Controller *cp = a;
.
208d
201a
			hardpart(dp);
.
199a
			dp->bytes = 512;
.
142a
static int
hardgen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
{
	Qid qid;
	int drive;
	char *name;
	Drive *dp;
	Partition *pp;
	ulong l;

	qid.vers = 0;
	drive = s/(Npart+1);
	s = s % (Npart+1);
	if(drive >= conf.nhard)
		return -1;
	dp = &hard[drive];

	if(s == 0){
		sprint(name, "hd%dparition", drive);
		qid.path = MKQID(Qpart, drive, 0);
		l = dp->npart * sizeof(Partition);
	} else if(s-1 < p.npart){
		pp = &dp->p[s-1];
		sprint(name, "hd%d%s", drive, pp->name);
		qid.path = MKQID(Qdata, drive, s-1);
		l = (pp->end - pp->start) * dp->cp->bytes;
	} else
		return 0;

	devdir(c, qid, name, l, 0600, dirp);
	return 1;
}
.
141a
static void	hardpart(Drive*);
.
96c
	ulong	cap;		/* total bytes */
.
94a
	int	npart;		/* number of real partitions */
	Partition p[Npart];
.
85a
struct Partition
{
	ulong	start;
	ulong	end;
	uchar	name[NAMELEN];
};

struct Ptable 
{
	uchar		magic[4];	/* ascii "disk" */
	uchar		n[4];		/* number of partitions */
	struct
	{
		uchar	start[4];	/* starting block */
		uchar	end[4];		/* ending block */
		uchar	name[NAMELEN];
	} p[1];
};

.
46a
#define PART(x)		((x)&0x3)
#define DRIVE(x)	(((x)>>3)&0x7)
#define MKQID(t,d,p)	((t) | ((d)<<3) | (p))
.
45a
	Npart=		8+1,		/* 8 sub partitions and one for the disk */
.
41,43c
	Qdata=		(1<<(3+3)),
	Qpart=		(2<<(3+3)),
	Qmask=		(3<<(3+3)),
.
28c
	 Sdrq=		 (1<<3),
.
19c
	Pprecomp=	1,	/* buffer mode port (write) */
.
11a
typedef struct Partition	Partition;
typedef struct Ptable		Ptable;
.
## diffname pc/devhard.c 1991/0814
## diff -e /n/bootesdump/1991/0813/sys/src/9/safari/devhard.c /n/bootesdump/1991/0814/sys/src/9/safari/devhard.c
646c
		print("weird disk interrupt\n");
.
644a
	case Csetbuf:
		cp->cmd = 0;
		wakeup(&cp->r);
		break;
.
583,586c
	if(waserror()){
		print("error in hardpart\n");
		nexterror();
	}

	hardxfer(dp, pp, Cread, buf, (pp->end - 1)*dp->bytes, dp->bytes);
	buf[dp->bytes] = 0;

	n = getfields(buf, line, Npart+1, '\n');
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) != 0){
		print("bad partition table 1\n");
		goto out;
	}
	for(i = 1; i < n; i++){
		pp++;
		if(getfields(line[i], field, 3, 0) != 3){
			print("bad partition field\n");
			goto out;
		}
		if(strlen(field[0]) > NAMELEN){
			print("bad partition name\n");
			goto out;
		}
		strcpy(pp->name, field[0]);
		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){
			print("bad partition limit\n");
			goto out;
		}
print("partition %s from %d to %d\n", pp->name, pp->start, pp->end);
		dp->npart++;
	}
out:
	poperror();
.
581c
	pp->end = dp->cap / dp->bytes;
	pp++;
	strcpy(pp->name, "partition");
	pp->start = dp->p[0].end - 1;
	pp->end = dp->p[0].end;
	dp->npart = 2;
.
575,576c
	char *line[Npart+1];
	char *field[3];
	char buf[1024];
	ulong n;
	int i;
.
570a
#define MAGIC "plan9 partitions"
.
569c
 *  read partition table.  The partition table is just ascii strings.
.
538a
print("waserror in hardident\n");
.
517a
	cp->cmd = Csetbuf;
.
460a
	lsec += pp->start;
	if(lsec > pp->end)
		errors("xfer past end of partition\n");
.
452a
	lsec += pp->start;
	if(lsec >= pp->end)
		errors("xfer past end of partition\n");
.
441a
print("hardxfer %ld %ld\n", off, len);
print("hardxfer part %s %ld %ld\n", pp->name, pp->start, pp->end);

.
428c
hardxfer(Drive *dp, Partition *pp, int cmd, void *va, long off, long len)
.
387,388c
	case Qpart:
.
382c
			pp = &dp->p[PART(c->qid.path)];
			i = hardxfer(dp, pp, Cwrite, aa+rv, c->offset+rv, n-rv);
.
375a
	Partition *pp;
.
355,362c
	case Qpart:
.
350c
			pp = &dp->p[PART(c->qid.path)];
			i = hardxfer(dp, pp, Cread, aa+rv, c->offset+rv, n-rv);
.
343c
		return devdirread(c, a, n, 0, 0, hardgen);
.
340a
	Partition *pp;
.
326,334d
300c
	return devopen(c, omode, 0, 0, hardgen);
.
294c
	devstat(c, dp, 0, 0, hardgen);
.
288c
	return devwalk(c, name, 0, 0, hardgen);
.
270a
			hardpart(dp);
.
269d
263d
231,240d
217d
213d
202a

.
195,196c
		qid.path = MKQID(Qdata, drive, s);
		l = (pp->end - pp->start) * dp->bytes;
.
188,193c
	if(s < dp->npart){
		pp = &dp->p[s];
.
182,183c
	drive = s/Npart;
	s = s % Npart;
.
176c
	char name[NAMELEN];
.
166c
static long	hardxfer(Drive*, Partition*, int, void*, long, long);
.
162,163d
99,110d
96c
	char	name[NAMELEN+1];
.
48c
	Npart=		8+2,		/* 8 sub partitions, disk, and partiiton */
.
13d
## diffname pc/devhard.c 1991/0815
## diff -e /n/bootesdump/1991/0814/sys/src/9/safari/devhard.c /n/bootesdump/1991/0815/sys/src/9/safari/devhard.c
646,647c
		cp->sofar += cp->dp->bytes;
		if(cp->sofar >= cp->len){
.
513c
	cp->toskip = 0;
.
437c
	cp->toskip = off % dp->bytes;
.
422c
	lsec = (off+len+dp->bytes-1)/dp->bytes;
.
420c
	 *  can't xfer across cylinder boundaries or end of disk
.
398,400d
393,396c
	if(len > Maxxfer)
		len = Maxxfer;
.
141a
	int	toskip;		/* bytes to skip over */
.
140c
	int	toxfer;		/* bytes to be xferred */
.
## diffname pc/devhard.c 1991/0817
## diff -e /n/bootesdump/1991/0815/sys/src/9/safari/devhard.c /n/bootesdump/1991/0817/sys/src/9/safari/devhard.c
642,643c
		cp->sofar++;
		if(cp->sofar >= cp->nsecs){
.
621,622c
			outss(cp->pbase+Pdata, &cp->buf[cp->sofar*dp->bytes],
				dp->bytes/2);
.
617c
		if(cp->sofar < cp->nsecs){
.
605a
	dp = cp->dp;
.
598a
	Drive *dp;
.
588a
	qunlock(cp);
.
582c
print("bad partition limit\n");
.
575c
print("bad partition name\n");
.
571c
print("bad partition field\n");
.
565c
print("bad partition magic\n");
.
563c
	n = getfields(cp->buf, line, Npart+1, '\n');
.
560,561c
	hardxfer(dp, pp, Cread, 0, dp->bytes);
	cp->buf[dp->bytes-1] = 0;
.
555a
		qunlock(cp);
.
554a
	cp = dp->cp;
	qlock(cp);
.
541d
538a
	Controller *cp;
.
520c
	memmove(&dp->id, cp->buf, dp->bytes);
.
508,509c
	cp->nsecs = 1;
.
458,460c
	return cp->nsecs*dp->bytes;
.
455,456d
452c
print("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
.
448a

.
447a

.
445,446c
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			if(++loop > 10000)
				panic("hardxfer");
		outss(cp->pbase+Pdata, cp->buf, dp->bytes/2);
.
437c
	cp->sofar = 0;
print("xfer:\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead);
print("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
	outb(cp->pbase+Pcount, cp->nsecs);
.
433,434d
418,426c
	if(lsec+len > pp->end)
		len = pp->end - lsec;
	cp->nsecs = len;
.
416c
	 *  can't xfer past end of disk
.
410c
		return 0;
.
407,408c
	cp = dp->cp;
	lsec = start + pp->start;
.
405c
	 *  calculate physical address
.
397,403d
395a
	len = (len + dp->bytes - 1) / dp->bytes;
.
393a

	/*
	 *  cut transfer size down to disk buffer size
	 */
	start = start / dp->bytes;
.
390a
	int loop;
.
389c
	long lsec;
.
385c
hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len)
.
381c
 *  transfer a number of sectors.  hardintr will perform all the iterative
.
349a
	/*
	 *  if not starting on a sector boundary,
	 *  read in the first sector before writing
	 *  it out.
	 */
	i = c->offset % dp->bytes;
	if(i){
		hardxfer(dp, pp, Cread, c->offset-i, dp->bytes);
		if(i+n > dp->bytes)
			rv = dp->bytes - i;
		else
			rv = n;
		memmove(cp->buf+i, aa, rv);
		hardxfer(dp, pp, Cwrite, c->offset-i, dp->bytes);
	} else
		rv = 0;

	/*
	 *  write out the full sectors
	 */
	for(; rv + dp->bytes <= n; rv += i){
		i = n - rv;
		if(i > Maxxfer)
			i = Maxxfer;
		memmove(cp->buf, aa+rv, i);
		i = hardxfer(dp, pp, Cwrite, c->offset+rv, i);
		if(i == 0)
			break;
	}

	/*
	 *  if not ending on a sector boundary,
	 *  read in the last sector before writing
	 *  it out.
	 */
	if(n > rv){
		hardxfer(dp, pp, Cread, c->offset+rv, dp->bytes);
		memmove(cp->buf, aa+rv, n - rv);
		hardxfer(dp, pp, Cwrite, c->offset+rv, dp->bytes);
		rv = n;
	}
	qunlock(cp);
	poperror();

.
334,348c
	if(c->qid.path == CHDIR)
		errors("can't write directory");

	dp = &hard[DRIVE(c->qid.path)];
	pp = &dp->p[PART(c->qid.path)];
	cp = dp->cp;

	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
.
332a
	Controller *cp;
.
322a
	skip = c->offset % dp->bytes;
	for(rv = 0; rv < n; rv += i){
		i = hardxfer(dp, pp, Cread, c->offset+rv-skip, n-rv+skip);
		if(i == 0)
			break;
		i -= skip;
		if(i > n - rv)
			i = n - rv;
		memmove(aa+rv, cp->buf + skip, i);
		skip = 0;
	}
	qunlock(cp);
	poperror();

.
307,321c
	dp = &hard[DRIVE(c->qid.path)];
	pp = &dp->p[PART(c->qid.path)];
	cp = dp->cp;

	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
.
302a
	Controller *cp;
.
300a
	int skip;
.
177c
		qid.path = MKQID(drive, s);
.
152c
static long	hardxfer(Drive*, Partition*, int, long, long);
.
142d
139,140c
	int	nsecs;		/* length of transfer (sectors) */
.
51c
#define MKQID(d,p)	(((d)<<3) | (p))
.
42,44d
## diffname pc/devhard.c 1991/0818
## diff -e /n/bootesdump/1991/0817/sys/src/9/safari/devhard.c /n/bootesdump/1991/0818/sys/src/9/safari/devhard.c
626c
			break;
.
619c
			break;
.
615c
			break;
.
## diffname pc/devhard.c 1991/0819
## diff -e /n/bootesdump/1991/0818/sys/src/9/safari/devhard.c /n/bootesdump/1991/0819/sys/src/9/safari/devhard.c
617,621c
		strncpy(pp->name, field[0], NAMELEN);
.
605a
	/*
	 *  parse partition table.
	 */
.
595,602c
	/*
	 *  read partition table from disk, null terminate
	 */
.
584a
	cp = dp->cp;
	qlock(cp);
	if(waserror()){
		qunlock(cp);
		print("error in hardpart\n");
		nexterror();
	}

	/*
	 *  we always have a partition for the whole disk
	 *  and one for the partition table
	 */
.
475,476c
/*print("xfer:\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead);
print("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);/**/
.
171a
		name[NAMELEN] = 0;
.
157c
	char name[NAMELEN+4];
.
## diffname pc/devhard.c 1991/0820
## diff -e /n/bootesdump/1991/0819/sys/src/9/safari/devhard.c /n/bootesdump/1991/0820/sys/src/9/safari/devhard.c
693,694c
		inss(cp->pbase+Pdata, &cp->buf[cp->sofar*dp->bytes],
			dp->bytes/2);
.
635d
632d
624,625c
		if(getfields(line[i], field, 3, ' ') != 3){
.
619d
476c
print("xfer:\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead);
.
391c
		rv += partial;
.
389c
		memmove(cp->buf, aa+rv, partial);
.
387c
	if(partial){
.
372c
	partial = (n - rv) % dp->bytes;
	n -= partial;
	for(; rv < n; rv += i){
.
364,365c
		memmove(cp->buf+partial, aa, rv);
		hardxfer(dp, pp, Cwrite, c->offset-partial, dp->bytes);
.
357,361c
	partial = c->offset % dp->bytes;
	if(partial){
		hardxfer(dp, pp, Cread, c->offset-partial, dp->bytes);
		if(partial+n > dp->bytes)
			rv = dp->bytes - partial;
.
335c
	long rv, i, partial;
.
321a
{int j;

 print("0x%lux(%d) <- ", aa+rv, i);
 for(j = 0; j<32; j++)
	print("%.2ux ", cp->buf[j+skip]);
 print("\n");
}
.
## diffname pc/devhard.c 1991/0821
## diff -e /n/bootesdump/1991/0820/sys/src/9/safari/devhard.c /n/bootesdump/1991/0821/sys/src/9/safari/devhard.c
675a
			loop = 0;
.
665c
	loop = 0;
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy)
		if(++loop > 10000)
			panic("hardintr 0");
.
657a
	x = spllo();	/* let in other interrupts */

.
656a
	int x;
.
485c
	cp->status = 0;
/*print("xfer:\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead);
.
322,328d
177a
	pp = &dp->p[s];
	sprint(name, "hd%d%s", drive, pp->name);
	name[NAMELEN] = 0;
	qid.path = MKQID(drive, s);
	l = (pp->end - pp->start) * dp->bytes;
.
169,175c
	if(s >= dp->npart)
.
46,48c
#define PART(x)		((x)&0xF)
#define DRIVE(x)	(((x)>>4)&0x7)
#define MKQID(d,p)	(((d)<<4) | (p))
.
44c
	Npart=		8+2,		/* 8 sub partitions, disk, and partition */
.
## diffname pc/devhard.c 1991/0906
## diff -e /n/bootesdump/1991/0821/sys/src/9/safari/devhard.c /n/bootesdump/1991/0906/sys/src/9/safari/devhard.c
652c
	spllo();	/* let in other interrupts */
.
650d
## diffname pc/devhard.c 1991/0919
## diff -e /n/bootesdump/1991/0906/sys/src/9/safari/devhard.c /n/bootesdump/1991/0919/sys/src/9/safari/devhard.c
177c
	devdir(c, qid, name, l, 0666, dirp);
.
## diffname pc/devhard.c 1991/0921
## diff -e /n/bootesdump/1991/0919/sys/src/9/safari/devhard.c /n/bootesdump/1991/0921/sys/src/9/safari/devhard.c
241c
	return devattach('w', spec);
.
## diffname pc/devhard.c 1991/1109
## diff -e /n/bootesdump/1991/0921/sys/src/9/safari/devhard.c /n/bootesdump/1991/1109/sys/src/9/safari/devhard.c
177c
	devdir(c, qid, name, l, eve, 0666, dirp);
.
## diffname pc/devhard.c 1991/1211
## diff -e /n/bootesdump/1991/1109/sys/src/9/safari/devhard.c /n/bootesdump/1991/1211/sys/src/9/safari/devhard.c
564,568d
560c
		print("bad disk ident status\n");
.
545d
229,231c
			switch(dp->id.magic){
			case 0xA5A:	/* conner drive on the AT&T NSX (safari) */
				dp->cyl = dp->id.lcyls;
				dp->heads = dp->id.lheads;
				dp->sectors = dp->id.ls2t;
				break;
			case 0x324A:	/* hard drive on the AT&T 6386 */
				dp->cyl = dp->id.lcyls - 4;
				dp->heads = dp->id.lheads;
				dp->sectors = dp->id.ls2t - 1;
				break;
			default:
				print("unknown hard disk type\n");
				errors("unknown hard disk type");
			}
.
## diffname pc/devhard.c 1992/0111
## diff -e /n/bootesdump/1991/1211/sys/src/9/safari/devhard.c /n/bootesdump/1992/0111/sys/src/9/safari/devhard.c
7c
#include	"../port/error.h"
.
## diffname pc/devhard.c 1992/0114
## diff -e /n/bootesdump/1992/0111/sys/src/9/safari/devhard.c /n/bootesdump/1992/0114/sys/src/9/safari/devhard.c
572c
		error(Eio);
.
513c
		error(Eio);
.
453c
		error(Eio);
.
435c
			error(Eio);
.
352c
		error(Eisdir);
.
242c
				error(Egreg);
.
## diffname pc/devhard.c 1992/0219
## diff -e /n/bootesdump/1992/0114/sys/src/9/safari/devhard.c /n/bootesdump/1992/0219/sys/src/9/safari/devhard.c
642d
634,640d
626,632c
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			pp++;
			if(getfields(line[i], field, 3, ' ') != 3)
				break;
			strncpy(pp->name, field[0], NAMELEN);
			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++;
.
## diffname pc/devhard.c 1992/0220
## diff -e /n/bootesdump/1992/0219/sys/src/9/safari/devhard.c /n/bootesdump/1992/0220/sys/src/9/safari/devhard.c
460a
	if(cmd == Cread && len > Maxread)
		len = Maxread;
.
43a
	Maxread=	1024,		/* maximum transfer size/read */
.
## diffname pc/devhard.c 1992/0321
## diff -e /n/bootesdump/1992/0220/sys/src/9/safari/devhard.c /n/bootesdump/1992/0321/sys/src/9/safari/devhard.c
2c
#include	"../port/lib.h"
.
## diffname pc/devhard.c 1992/0402
## diff -e /n/bootesdump/1992/0321/sys/src/9/safari/devhard.c /n/bootesdump/1992/0402/sys/src/9/safari/devhard.c
570c
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4));
.
539,540c
	outb(cp->pbase+Pprecomp, on ? 0xAA : 0xFF);
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4));
.
497c
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | cp->thead);
.
234a
				hardsetbuf(dp, 1);
.
228c
			hardsetbuf(dp, 0);
.
## diffname pc/devhard.c 1992/0423
## diff -e /n/bootesdump/1992/0402/sys/src/9/safari/devhard.c /n/bootesdump/1992/0423/sys/src/9/safari/devhard.c
716c
		print("weird disk interrupt, cmd=%02x\n",
			cp->cmd);
.
254c
	drivecomment=0;	/* only the first time */
.
242,244c
			default:	/* others: we hope this works */
				if (drivecomment) {
					print("unknown hard disk type, magic=%04x\n",
						dp->id.magic);
					print(" lcyls=%d lheads=%d sectors=%d\n",
						dp->id.lcyls, dp->id.lheads, dp->id.ls2t);
					print(" ncyls=%d nheads=%d dlcyls=%d dlheads=%d\n",
						dp->id.ncyls, dp->id.nheads, dp->id.dlcyls,
						dp->id.dlheads);
				}
				dp->cyl = dp->id.lcyls;
				dp->heads = dp->id.lheads;
				dp->sectors = dp->id.ls2t;
				break;
.
223a
	static int drivecomment=1;
.
56c
	ushort	magic;		/* drive type magic */
.
## diffname pc/devhard.c 1992/0424
## diff -e /n/bootesdump/1992/0423/sys/src/9/safari/devhard.c /n/bootesdump/1992/0424/sys/src/9/safari/devhard.c
728,729c
		print("weird disk interrupt, cmd=%02x, status=%02x\n",
			cp->cmd, cp->status);
.
726a
	case 0:	/*
		 * These don't seem to mean anything.  Should we wakeup?
		 */
		break;
.
249,251d
247c
					print("  cyl=%d h=%d sec=%d\n",
.
245c
					print("unknown hard disk type, magic=%04x",
.
## diffname pc/devhard.c 1992/0425
## diff -e /n/bootesdump/1992/0424/sys/src/9/safari/devhard.c /n/bootesdump/1992/0425/sys/src/9/safari/devhard.c
724,726c
	case 0:
		print("interrupt cmd=0, lastcmd=%02x status=%02x\n",
			cp->lastcmd, cp->status);
.
720a
		cp->lastcmd = cp->cmd;
.
715a
			cp->lastcmd = cp->cmd;
.
710,711c
			if(++loop > 10000) {
				print("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
		}
.
702a
			cp->lastcmd = cp->cmd;
.
701a
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sbusy) != 0)
			if(++loop > 10000) {
				print("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: wait busy");
		}
.
695a
			cp->lastcmd = cp->cmd;
.
691,692c
				if(++loop > 10000) {
					print("cmd=%lux status=%lux\n",
						cp->cmd, inb(cp->pbase+Pstatus));
					panic("hardintr: write");
				}
.
681a
			cp->lastcmd = cp->cmd;
.
677,678c
		if(++loop > 10000) {
			print("cmd=%lux status=%lux\n",
				cp->cmd, inb(cp->pbase+Pstatus));
			panic("hardintr: wait busy");
		}
.
203a
			cp->lastcmd = cp->cmd;
.
130a
	int	lastcmd;	/* debugging info */
.
## diffname pc/devhard.c 1992/0429
## diff -e /n/bootesdump/1992/0425/sys/src/9/safari/devhard.c /n/bootesdump/1992/0429/sys/src/9/safari/devhard.c
745a
		break;
	case Cident2:
		cp->lastcmd = cp->cmd;
		cp->cmd = 0;
.
738c
			if (cp->cmd == Cread)
				cp->cmd = 0;
			else
				cp->cmd = Cident2;
.
590c
	/*
	 * this function appears to respond with an extra interrupt after
	 * the indent information is read, except on the safari.  The following
	 * delay gives this extra interrupt a chance to happen while we are quiet.
	 * Otherwise, the interrupt may come during a subsequent read or write,
	 * causing a panic and much confusion.
	 */
	if (cp->cmd == Cident2)
		tsleep(&cp->r, return0, 0, 10);
	cp->cmd = 0;
.
37a
	Cident2=	0xFF,	/* pseudo command for post Cident interrupt */
.
## diffname pc/devhard.c 1992/0509
## diff -e /n/bootesdump/1992/0429/sys/src/9/safari/devhard.c /n/bootesdump/1992/0509/sys/src/9/safari/devhard.c
663a
	if(dp->repl.p)
		hardreplinit(dp);
.
656a
			if(strncmp(pp->name, "repl", NAMELEN) == 0)
				dp->repl.p = pp;
.
651c
	if(strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
.
641a
	 * initialise the bad-block replacement info
	 */
	dp->repl.p = 0;

	/*
.
608d
605a
 *  Read block replacement table.
 *  The table is just ascii block numbers.
 */
static void
hardreplinit(Drive *dp)
{
	Controller *cp;
	char *line[Nrepl+1];
	char *field[1];
	ulong n;
	int i;

	/*
	 *  check the partition is big enough
	 */
	if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){
		dp->repl.p = 0;
		return;
	}

	cp = dp->cp;

	/*
	 *  read replacement table from disk, null terminate
	 */
	hardxfer(dp, dp->repl.p, Cread, 0, dp->bytes);
	cp->buf[dp->bytes-1] = 0;

	/*
	 *  parse replacement table.
	 */
	n = getfields(cp->buf, line, Nrepl+1, '\n');
	if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){
		dp->repl.p = 0;
		return;
	}
	for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){
		if(getfields(line[i], field, 1, ' ') != 1)
			break;
		if((dp->repl.blk[dp->repl.nrepl] = strtoul(field[1], 0, 0)) <= 0)
			break;
	}
}

/*
.
604a

.
526c
print("hd%d err: lsec %ld status %lux, err %lux\n", dp-hard, lsec, cp->status, cp->error);
.
506,507c

.
107a
	Repl	repl;
.
96a
struct Repl
{
	Partition *p;
	int	nrepl;
	ulong	blk[Nrepl];
};

#define PARTMAGIC	"plan9 partitions"
#define REPLMAGIC	"block replacements"

.
46a
	Nrepl=		16,		/* maximum replacement blocks */
.
45c
	Maxread=	4*1024,		/* maximum transfer size/read */
.
12a
typedef struct Repl		Repl;
.
## diffname pc/devhard.c 1992/0512
## diff -e /n/bootesdump/1992/0509/sys/src/9/safari/devhard.c /n/bootesdump/1992/0512/sys/src/9/safari/devhard.c
46c
	Maxread=	1*1024,		/* maximum transfer size/read */
.
## diffname pc/devhard.c 1992/0513
## diff -e /n/bootesdump/1992/0512/sys/src/9/safari/devhard.c /n/bootesdump/1992/0513/sys/src/9/safari/devhard.c
658c
		dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0);
		if(dp->repl.blk[dp->repl.nrepl] <= 0)
.
544c
	return cp->sofar*dp->bytes;
.
538,540c
		print("hd%d err: lblk %ld status %lux, err %lux\n",
			dp-hard, lblk, cp->status, cp->error);
		print("\tcyl %d, sec %d, head %d\n", cyl, sec, head);
		print("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
		hardrepl(dp, lblk+cp->sofar);
.
520,524c
	outb(cp->pbase+Pcount, cp->nsecs-cp->sofar);
	outb(cp->pbase+Psector, sec);
	outb(cp->pbase+Pdh, 0x20 | head);
	outb(cp->pbase+Pcyllsb, cyl);
	outb(cp->pbase+Pcylmsb, cyl>>8);
.
517d
506,507c
	if(lblk+len > pp->end)
		len = pp->end - lblk;
.
499,501c
	cyl = lblk/(dp->sectors*dp->heads);
	sec = (lblk % dp->sectors) + 1;
	head = (dp->drive<<4) | ((lblk/dp->sectors) % dp->heads);
.
495,497c
	lblk = start + pp->start;
	if(lblk >= pp->end)
.
491a
retry:
	if(len == 0)
		return cp->sofar*dp->bytes;
.
481a
	cp = dp->cp;
	cp->sofar = 0;

.
475,476c
	long lblk;
	int cyl, sec, head;
.
465a
static void
hardrepl(Drive *dp, long bblk)
{
	int i;

	if(dp->repl.p == 0)
		return;
	for(i = 0; i < dp->repl.nrepl; i++){
		if(dp->repl.blk[i] == bblk)
			print("found bblk %ld at offset %ld\n", bblk, i);
	}
}

.
153c
	int	sofar;		/* sectors transferred so far */
.
148,151d
48c
	Nrepl=		64,		/* maximum replacement blocks */
.
## diffname pc/devhard.c 1992/0514
## diff -e /n/bootesdump/1992/0513/sys/src/9/safari/devhard.c /n/bootesdump/1992/0514/sys/src/9/safari/devhard.c
828c
		cp->nsecs--;
		if(cp->nsecs == 0){
.
796c
			cp->nsecs--;
		} else {
.
786c
		if(cp->nsecs){
.
775a
	if(cp->status & (Sdwf|Scorr))
		print("hardintr: cmd=#%lux, status=#%lux\n", cp->cmd, cp->status);
.
545a
		cp->nsecs--;
.
533c
	outb(cp->pbase+Pcount, cp->nsecs);
.
531a
	cmdreadywait(cp);
.
529,530d
524c
	cp->cmd = cmd;
	cp->dp = dp;
.
30a
	 Scorr=		 (1<<2),
.
29a
	 Sdwf=		 (1<<5),
.
## diffname pc/devhard.c 1992/05141
## diff -e /n/bootesdump/1992/0514/sys/src/9/safari/devhard.c /n/bootesdump/1992/05141/sys/src/9/safari/devhard.c
834,835c
		if(cp->sofar >= cp->nsecs){
.
801,802c
		} else{
.
791c
		if(cp->sofar < cp->nsecs){
.
779,780d
548d
535c
	outb(cp->pbase+Pcount, cp->nsecs-cp->sofar);
.
533d
531a
	cp->cmd = cmd;
	cp->dp = dp;
.
526,527c
	cmdreadywait(cp);
.
32d
30d
## diffname pc/devhard.c 1992/0519
## diff -e /n/bootesdump/1992/05141/sys/src/9/safari/devhard.c /n/bootesdump/1992/0519/sys/src/9/safari/devhard.c
261a
			case 0x427a:	/* for now: a list of those that work */
.
## diffname pc/devhard.c 1992/0625
## diff -e /n/bootesdump/1992/0519/sys/src/9/safari/devhard.c /n/bootesdump/1992/0625/sys/src/9/safari/devhard.c
214c
			cp->buf = xalloc(Maxxfer);
.
204,205c
	hard = xalloc(conf.nhard * sizeof(Drive));
	hardc = xalloc(((conf.nhard+1)/2 + 1) * sizeof(Controller));
.
## diffname pc/devhard.c 1992/0711
## diff -e /n/bootesdump/1992/0625/sys/src/9/safari/devhard.c /n/bootesdump/1992/0711/sys/src/9/safari/devhard.c
760a
	USED(ur);
.
593c
static void
.
484d
323a
	USED(c, dp);
.
317a
	USED(c);
.
312a
	USED(c);
.
306a
	USED(c, name, omode, perm);
.
173a
	USED(tab, ntab);
.
160c
static void	hardident(Drive*);
.
## diffname pc/devhard.c 1992/0815
## diff -e /n/bootesdump/1992/0808/sys/src/9/safari/devhard.c /n/bootesdump/1992/0815/sys/src/9/pc/devhard.c
831,832d
824,829c
		addr = cp->buf;
		if(addr){
			addr += cp->sofar*dp->bytes;
			inss(cp->pbase+Pdata, addr, dp->bytes/2);
.
815a
			}
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			if(++loop > 10000) {
				print("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
.
800,801c
			addr = cp->buf;
			if(addr){
				addr += cp->sofar*dp->bytes;
				outss(cp->pbase+Pdata, addr, dp->bytes/2);
			}
.
763a
	char *addr;
.
751,752d
748a
	free(buf);
	poperror();

.
733c
	n = getfields(buf, line, Npart+1, '\n');
.
727,728c
	hardxfer(dp, pp, Cread, 0, dp->bytes, buf);
	buf[dp->bytes-1] = 0;
.
723a
	buf = smalloc(Maxxfer);
	if(waserror()){
		free(buf);
		nexterror();
	}

.
697,704d
695a
	char *buf;
.
691d
675,681c
	free(buf);
	poperror();
.
673c
	} else {
		for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){
			if(getfields(line[i], field, 1, ' ') != 1)
				break;
			dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0);
			if(dp->repl.blk[dp->repl.nrepl] <= 0)
				break;
		}
.
670c
	n = getfields(buf, line, Nrepl+1, '\n');
.
664,665c
	hardxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf);
	buf[dp->bytes-1] = 0;
.
659c
	buf = smalloc(Maxxfer);
	if(waserror()){
		free(buf);
		nexterror();
	}
.
649a
	char *buf;
.
645d
632a
	cp->buf = 0;
.
622c
	memmove(&dp->id, buf, dp->bytes);
.
614a
	cp->buf = buf;
.
602a
	buf = smalloc(Maxxfer);
.
600a
	char *buf;
.
562a
	cp->buf = 0;
	qunlock(cp);
	poperror();
.
522a
	 *  go for it
	 */
	cp = dp->cp;
	qlock(cp);
	cp->sofar = 0;
	cp->buf = buf;
	if(waserror()){
		cp->buf = 0;
		qunlock(cp);
		nexterror();
	}

	/*
.
511c
		return 0;

.
508,509d
496,498d
486c
hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf)
.
435c

	free(buf);
.
430,432c
		hardxfer(dp, pp, Cread, c->offset+rv, dp->bytes, buf);
		memmove(buf, aa+rv, partial);
		hardxfer(dp, pp, Cwrite, c->offset+rv, dp->bytes, buf);
.
418,419c
		memmove(buf, aa+rv, i);
		i = hardxfer(dp, pp, Cwrite, c->offset+rv, i, buf);
.
404,405c
		memmove(buf+partial, aa, rv);
		hardxfer(dp, pp, Cwrite, c->offset-partial, dp->bytes, buf);
.
399c
		hardxfer(dp, pp, Cread, c->offset-partial, dp->bytes, buf);
.
391a

.
389c
		free(buf);
.
385,387c
	buf = smalloc(Maxxfer);
.
378c
	char *buf;
.
365c

	free(buf);
.
362c
		memmove(aa+rv, buf + skip, i);
.
356c
		i = hardxfer(dp, pp, Cread, c->offset+rv-skip, n-rv+skip, buf);
.
353a

	dp = &hard[DRIVE(c->qid.path)];
	pp = &dp->p[PART(c->qid.path)];

.
351c
		free(buf);
.
345,349c
	buf = smalloc(Maxxfer);
.
340c
	char *buf;
.
215c
			cp->buf = 0;
.
159c
static long	hardxfer(Drive*, Partition*, int, long, long, char*);
.
45,46c
	Maxxfer=	512,		/* maximum transfer size/cmd */
	Maxread=	512,		/* maximum transfer size/read */
.
## diffname pc/devhard.c 1992/0826
## diff -e /n/bootesdump/1992/0815/sys/src/9/pc/devhard.c /n/bootesdump/1992/0826/sys/src/9/pc/devhard.c
836,842d
817,818c
			while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0)
				if(++loop > 100) {
.
804a
	}
.
799,800c
	while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){
		if(++loop > 100) {
.
789d
649a
	free(buf);
.
641c
	 * the ident information is read, except on the safari.  The following
.
602a
	if(cp->status & Serr)
		print("hd%d setbuf err: status %lux, err %lux\n",
			dp-hard, cp->status, cp->error);

.
597c
	outb(cp->pbase+Pprecomp, 0xAA);
.
584c
hardsetbuf(Drive *dp)
.
581c
 *  set read ahead mode
.
503,504d
249c
				hardsetbuf(dp);
.
242d
161c
static void	hardsetbuf(Drive*);
.
45,46c
	Maxxfer=	32*512,		/* maximum transfer size/cmd */
.
## diffname pc/devhard.c 1992/0901
## diff -e /n/bootesdump/1992/0826/sys/src/9/pc/devhard.c /n/bootesdump/1992/0901/sys/src/9/pc/devhard.c
840c
				DPRINT("cmd=%lux status=%lux\n",
.
820c
					DPRINT("cmd=%lux status=%lux\n",
.
801c
			DPRINT("cmd=%lux status=%lux\n",
.
635c
		DPRINT("bad disk ident status\n");
.
600c
		DPRINT("hd%d setbuf err: status %lux, err %lux\n",
.
564,565c
		DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head);
		DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
.
562c
		DPRINT("hd%d err: lblk %ld status %lux, err %lux\n",
.
476c
			DPRINT("found bblk %ld at offset %ld\n", bblk, i);
.
462c
			DPRINT("cmdreadywait failed\n");
.
8a
#define DPRINT if(0)print

.
## diffname pc/devhard.c 1992/0902
## diff -e /n/bootesdump/1992/0901/sys/src/9/pc/devhard.c /n/bootesdump/1992/0902/sys/src/9/pc/devhard.c
876,879d
867a
	case Cinitparam:
.
609a
 *  set the drive parameters
 */
static void
hardinitparam(Drive *dp)
{
	Controller *cp = dp->cp;

	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}

	cmdreadywait(cp);

	cp->cmd = Cinitparam;
	outb(cp->pbase+Psector, dp->sectors);
	outb(cp->pbase+Pdh, 0x20 | (dp->heads-1) | (dp->drive<<4));
	outb(cp->pbase+Pcmd, Cinitparam);

	sleep(&cp->r, cmddone, cp);

	if(cp->status & Serr)
		DPRINT("hd%d initparam err: status %lux, err %lux\n",
			dp-hard, cp->status, cp->error);

	poperror();
	qunlock(cp);
}

/*
.
595c
	outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55);
.
582c
hardsetbuf(Drive *dp, int on)
.
272c
			/*
			 *  Try reading the partition table (last disk sector).
			 *  If an error occurs set the drive parameters and try
			 *  again.  This works if the parameters reported
			 *  by the disk are the physical parameters rather than
			 *  the current logical ones (as they are on the NCR 3170).
			 *
			 *  We don't routinely set the parameters since it confuses
			 *  some disks (on the Gateway and AT&T Safari for example).
			 */
			if(waserror()){
				hardinitparam(dp);	/* set drive parameters */
				hardpart();
			} else {
				hardpart();
				poperror();
			}
.
257,263d
245,251c
			case 0x324A:	/* hard drive on the AT&T 6386, it lies */
.
243a
			hardsetbuf(dp, 1);
			/*
			 *  for now use the configuration word to identify the
			 *  wayward 6386 disk.  BUG!!!  This word isn't
			 *  meant to identify disks, but we have nothing
			 *  better.
			 */
.
242c
			/*
			 *  the following is magic to determine the parameters
			 *  (number of cylinders/sectors/heads) on an IDE drive.
			 *  I haven't found a method that is guaranteed to work.
			 *  For some drives, it may be necessary to compile the
			 *  numbers into this driver and circumvent this code.
			 *  The BIOS disk type & tables doesn't help since the
			 *  types are inconsistent from one BIOS to the next.
			 */
			dp->bytes = 512;	/* until we know better */
			hardsetbuf(dp, 0);	/* turned off during ident */
.
162c
static void	hardsetbuf(Drive*, int);
static void	hardinitparam(Drive*);
.
42a
	Cinitparam=	0x91,
.
## diffname pc/devhard.c 1992/0903
## diff -e /n/bootesdump/1992/0902/sys/src/9/pc/devhard.c /n/bootesdump/1992/0903/sys/src/9/pc/devhard.c
709a
/*
 *  probe the given sector to see if it exists
 */
static int
hardprobe(Drive *dp, int cyl, int sec, int head)
{
	Controller *cp;
	char *buf;
	int rv;

	cp = dp->cp;
	buf = smalloc(Maxxfer);
	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}

	cmdreadywait(cp);

	cp->cmd = Cread;
	cp->dp = dp;
	cp->status = 0;
	cp->nsecs = 1;

	outb(cp->pbase+Pcount, 1);
	outb(cp->pbase+Psector, sec+1);
	outb(cp->pbase+Pdh, 0x20 | head);
	outb(cp->pbase+Pcyllsb, cyl);
	outb(cp->pbase+Pcylmsb, cyl>>8);
	outb(cp->pbase+Pcmd, Cread);

	sleep(&cp->r, cmddone, cp);

	if(cp->status & Serr)
		rv = -1;
	else
		rv = 0;

	cp->buf = 0;
	free(buf);
	poperror();
	qunlock(cp);
	return rv;
}

/*
 *  figure out the drive parameters
 */
static void
hardparams(Drive *dp)
{
	int i, hi, lo;

	/*
	 *  first try the easy way, ask the drive and make sure it
	 *  isn't lying.
	 */
	dp->bytes = 512;
	hardident(dp);
	if(hardprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0)
		return;

	/*
	 *  the drive lied, determine parameters by seeing which ones
	 *  work to read sectors.
	 */
	for(i = 0; i < 32; i++)
		if(hardprobe(dp, 0, 0, i) < 0)
			break;
	dp->heads = i;
	for(i = 0; i < 128; i++)
		if(hardprobe(dp, 0, i, 0) < 0)
			break;
	dp->sectors = i;
	for(i = 512; ; i += 512)
		if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
			break;
	lo = i - 512;
	hi = i;
	for(; hi-lo > 1;){
		i = lo + (hi - lo)/2;
		if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
			hi = i;
		else
			lo = i;
	}
	dp->cyl = lo + 1;
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
}
.
702a

	dp->cyl = ip->lcyls;
	dp->heads = ip->lheads;
	dp->sectors = ip->ls2t;
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
.
693c
	ip = (Ident*)buf;

.
669a
	Ident *ip;
.
639,661d
637c
	ushort	magic;		/* drive type magic */
	ushort	lcyls;		/* logical number of cylinders */
	ushort	rcyl;		/* number of removable cylinders */
	ushort	lheads;		/* logical number of heads */
	ushort	b2t;		/* unformatted bytes/track */
	ushort	b2s;		/* unformated bytes/sector */
	ushort	ls2t;		/* logical sectors/track */
	ushort	gap;		/* bytes in inter-sector gaps */
	ushort	sync;		/* bytes in sync fields */
	ushort	magic2;		/* must be 0x0000 */
	ushort	serial[10];	/* serial number */
	ushort	type;		/* controller type (0x0003) */
	ushort	bsize;		/* buffer size/512 */
	ushort	ecc;		/* ecc bytes returned by read long */
	ushort	firm[4];	/* firmware revision */
	ushort	model[20];	/* model number */
	ushort	s2i;		/* number of sectors/interrupt */
	ushort	dwtf;		/* double word transfer flag */
	ushort	alernate;
	ushort	piomode;
	ushort	dmamode;
	ushort	reserved[76];
	ushort	ncyls;		/* native number of cylinders */
	ushort	nheads;		/* native number of heads, sectors */
	ushort	dlcyls;		/* default logical number of cyinders */
	ushort	dlheads;	/* default logical number of heads, sectors */
	ushort	interface;
	ushort	power;		/* 0xFFFF if power commands supported */
	ushort	flags;
	ushort	ageprog;	/* MSB = age, LSB = program */
	ushort	reserved2[120];
};
.
634,635c
struct Ident
.
632c
 *  ident sector from drive
.
299d
278,297c
			hardsetbuf(dp, 1);
		}

		/*
		 *  read Plan 9 partition table
		 */
		hardpart(dp);
		poperror();
.
243,276c
		if(waserror()){
			dp->online = 0;
			continue;
		}
		if(!dp->online){
			hardparams(dp);
.
240d
165a
static int	hardprobe(Drive*, int, int, int);
.
164c
static void	hardparams(Drive*);
.
129,130d
56,93d
9c
#define DPRINT if(1)print
.
## diffname pc/devhard.c 1992/0906
## diff -e /n/bootesdump/1992/0903/sys/src/9/pc/devhard.c /n/bootesdump/1992/0906/sys/src/9/pc/devhard.c
834c
	if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
.
## diffname pc/devhard.c 1992/1001
## diff -e /n/bootesdump/1992/0906/sys/src/9/pc/devhard.c /n/bootesdump/1992/1001/sys/src/9/pc/devhard.c
934a
		if(cp->sofar > cp->nsecs)
			print("hardintr %d %d\n", cp->sofar, cp->nsecs);
.
666a
	cp->sofar = 0;
.
656a
		free(buf);
.
614a
	splx(s);

.
607a
	s = splhi();
.
596a
	int s;
.
516c
	return len;
.
512a
	len = cp->sofar*dp->bytes;
.
502a
	poperror();
	if(loop)
		nexterror();
.
501a
	/*
	 *  wait for command to complete.  if we get a note,
	 *  remember it but keep waiting to let the disk finish
	 *  the current command.
	 */
	loop = 0;
	while(waserror()){
		DPRINT("interrupted hardxfer\n");
		if(loop++ > 10){
			print("hard disk error\n");
			nexterror();
		}
	}
.
500a
	splx(s);
.
493d
486,487c
	outb(cp->pbase+Pcount, cp->nsecs);
.
482a
	s = splhi();
	cp->sofar = 0;
	cp->buf = buf;
	cp->nsecs = len;
.
481c
	 *  splhi to make command atomic
.
471,477d
463,464d
458,460d
453a
	if(lblk+len > pp->end)
		len = pp->end - lblk;
.
433c
	int loop, s;
.
404c
		if(TK2MS(m->ticks - start) > 5){
.
332a
if(a&KZERO)print("wr k 0x%lux d 0x%lux\n", a, n);

.
328a
		print("hard write error\n");
.
291a
if(a&KZERO)print("rd k 0x%lux d 0x%lux\n", a, n);

.
287a
		print("hard read error\n");
.
170c
	hardc = xalloc(((conf.nhard+1)/2) * sizeof(Controller));
.
48c
	Maxxfer=	BY2PG,		/* maximum transfer size/cmd */
.
## diffname pc/devhard.c 1992/1002
## diff -e /n/bootesdump/1992/1001/sys/src/9/pc/devhard.c /n/bootesdump/1992/1002/sys/src/9/pc/devhard.c
379c
		hardxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf);
.
377c
		hardxfer(dp, pp, Cread, offset+rv, dp->bytes, buf);
.
366c
		i = hardxfer(dp, pp, Cwrite, offset+rv, i, buf);
.
352c
		hardxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf);
.
346c
		hardxfer(dp, pp, Cread, offset-partial, dp->bytes, buf);
.
344c
	partial = offset % dp->bytes;
.
337,338d
332d
317c
hardwrite(Chan *c, void *a, long n, ulong offset)
.
300c
		i = hardxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf);
.
298c
	skip = offset % dp->bytes;
.
293,294d
288d
274c
hardread(Chan *c, void *a, long n, ulong offset)
.
8a
#include	"devtab.h"

.
## diffname pc/devhard.c 1992/1103
## diff -e /n/bootesdump/1992/1002/sys/src/9/pc/devhard.c /n/bootesdump/1992/1103/sys/src/9/pc/devhard.c
688c
	outb(cp->pbase+Pdh, 0x20 | head | (dp->drive<<4));
.
484c
	outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | head);
.
460c
	head =  ((lblk/dp->sectors) % dp->heads);
.
173a
	/*
	 *  read nvram for number of hard 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;

.
169a
	uchar equip;
.
## diffname pc/devhard.c 1992/1104
## diff -e /n/bootesdump/1992/1103/sys/src/9/pc/devhard.c /n/bootesdump/1992/1104/sys/src/9/pc/devhard.c
985c
		print("weird disk interrupt, cmd=%.2ux, status=%.2ux\n",
.
## diffname pc/devhard.c 1992/1119
## diff -e /n/bootesdump/1992/1104/sys/src/9/pc/devhard.c /n/bootesdump/1992/1119/sys/src/9/pc/devhard.c
985,986c
		print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n",
			cp->cmd, cp->lastcmd, cp->status);
.
661a
	cp->lastcmd = cp->cmd;
.
566c
			dp-hard, cp->status, cp->error);/**/
.
564c
/*	if(cp->status & Serr)
.
228a
		qunlock(dp);
.
218a
		qlock(dp);
.
216a
			qunlock(dp);
.
79a
	QLock;

.
## diffname pc/devhard.c 1993/0114
## diff -e /n/bootesdump/1992/1119/sys/src/9/pc/devhard.c /n/bootesdump/1993/0114/sys/src/9/pc/devhard.c
236c
	return devattach('H', spec);
.
## diffname pc/devhard.c 1993/0915
## diff -e /n/bootesdump/1993/0114/sys/src/9/pc/devhard.c /n/fornaxdump/1993/0915/sys/src/brazil/pc/devhard.c
961a
		}
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			if(++loop > 10000) {
				DPRINT("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
.
949,955d
867d
862a
	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--;
		hardxfer(dp, pp, Cread, 0, dp->bytes, buf);
		buf[dp->bytes-1] = 0;
		n = getfields(buf, line, Npart+1, '\n');
	}
.
859c
	 *  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.
.
510a
	if(stat & Serr)
		error(Eio);
.
509c
	} else
		stat = 0;
.
505c
		while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0)
.
450c
	int loop, s, stat;
.
158c
	devdir(c, qid, name, l, eve, 0660, dirp);
.
## diffname pc/devhard.c 1993/1124
## diff -e /n/fornaxdump/1993/0915/sys/src/brazil/pc/devhard.c /n/fornaxdump/1993/1124/sys/src/brazil/pc/devhard.c
923c
	 *	  distinguish which interrupted (use arg).
.
919c
	USED(ur, arg);
.
912c
hardintr(Ureg *ur, void *arg)
.
197c
			setvec(Hardvec + (cp-hardc)*8, hardintr, 0); /* BUG!! guessing */
.
124c
static void	hardintr(Ureg*, void*);
.
## diffname pc/devhard.c 1994/0128
## diff -e /n/fornaxdump/1993/1124/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0128/sys/src/brazil/pc/devhard.c
1011a
	}
}

void
hardclock(void)
{
	int drive;
	Drive *dp;
	Controller *cp;
	int diff;

	if(spindowntime <= 0)
		return;

	for(drive = 0; drive < conf.nhard; drive++){
		dp = &hard[drive];
		cp = dp->cp;
		if(canqlock(cp) == 0)
			continue;

		diff = TK2SEC(m->ticks - dp->usetime);
		switch(dp->state){
		case Sspinning:
			if(diff >= spindowntime){
				cp->cmd = Cstandby;
				outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | 0);
				outb(cp->pbase+Pcmd, cp->cmd);
				dp->state = Sstandby;
			}
			break;
		}
		qunlock(dp->cp);
.
528a
	dp->state = Sspinning;
	dp->usetime = m->ticks;
.
421c
		if(TK2MS(m->ticks - start) > 10){
.
176a
	p = getconf("spindowntime");
	if(p)
		spindowntime = atoi(p);
	
.
172a
	char *p;
.
122a
static int	spindowntime;
.
96a
enum
{
	Sspinning,
	Sstandby,
	Sidle,
	Spowerdown,
};

.
88a
	ulong	usetime;
	int	state;
.
46a
	/* conner specific commands */
	Cstandby=	0xE0,
	Cidle=		0xE1,
	Cpowerdown=	0xE3,

.
## diffname pc/devhard.c 1994/0205
## diff -e /n/fornaxdump/1994/0128/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0205/sys/src/brazil/pc/devhard.c
1059a
				outb(cp->pbase+Pcount, 0);
.
104,111d
51a
	/* disk states */
	Sspinning,
	Sstandby,
	Sidle,
	Spowerdown,

.
48c
	Cstandby=	0xE2,
.
## diffname pc/devhard.c 1994/0222
## diff -e /n/fornaxdump/1994/0205/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0222/sys/src/brazil/pc/devhard.c
910,919c
			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++;
			}
.
856a
	sprint(dp->vol, "hd%d", dp - hard);

.
168c
	sprint(name, "%s%s", dp->vol, pp->name);
.
101a
	char	vol[NAMELEN];
.
## diffname pc/devhard.c 1994/0413
## diff -e /n/fornaxdump/1994/0222/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0413/sys/src/brazil/pc/devhard.c
1002,1008d
995a
		loop = 0;
		while((cp->status & (Serr|Sdrq)) == 0){
			if(++loop > 10000) {
				DPRINT("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
			}
			cp->status = inb(cp->pbase+Pstatus);
		}
.
## diffname pc/devhard.c 1994/0428
## diff -e /n/fornaxdump/1994/0413/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0428/sys/src/brazil/pc/devhard.c
719c
	cmdreadywait(dp);
.
659c
	cmdreadywait(dp);
.
585c
	cmdreadywait(dp);
.
505c
	cmdreadywait(dp);
.
441c
		if(TK2MS(m->ticks - start) > period){
.
438a
	/* give it 2 seconds to spin down and up */
	if(dp->state == Sspinning)
		period = 10;
	else
		period = 2000;

.
437a
	int period;
	Controller *cp = dp->cp;
.
435c
cmdreadywait(Drive *dp)
.
## diffname pc/devhard.c 1994/0505
## diff -e /n/fornaxdump/1994/0428/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0505/sys/src/brazil/pc/devhard.c
1038a
	case Cidle:
	case Cstandby:
	case Cpowerdown:
.
## diffname pc/devhard.c 1994/0913
## diff -e /n/fornaxdump/1994/0505/sys/src/brazil/pc/devhard.c /n/fornaxdump/1994/0913/sys/src/brazil/pc/devhard.c
293c
	Drive *d;
	Partition *p;

	if(c->mode != OWRITE && c->mode != ORDWR)
		return;

	d = &hard[DRIVE(c->qid.path)];
	p = &d->p[PART(c->qid.path)];
	if(strcmp(p->name, "partition") != 0)
		return;

	if(waserror()){
		qunlock(d);
		nexterror();
	}
	qlock(d);
	hardpart(d);
	qunlock(d);
	poperror();
.
## diffname pc/devhard.c 1995/0107
## diff -e /n/fornaxdump/1994/0913/sys/src/brazil/pc/devhard.c /n/fornaxdump/1995/0107/sys/src/brazil/pc/devhard.c
1104d
1093,1102c
		if((dp->state == Sspinning) && (diff >= spindowntime)){
			ilock(cp);
			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);
			dp->state = Sstandby;
.
1089,1090d
1072a

	iunlock(cp);
.
1036c
			break;
.
998c
			break;
.
990a

.
982a
	ilock(cp);

.
758a
	iunlock(cp);
.
746a
	ilock(cp);
.
695c
	iunlock(cp);
.
687c
	ilock(cp);
.
675d
616a
	iunlock(cp);
.
612a
	ilock(cp);
.
557c
	iunlock(cp);

.
548a

.
542a

.
536c
	dp->usetime = m->ticks;
	cmdreadywait(dp);

	ilock(cp);
.
534c
	 * Make sure hardclock() doesn't
	 * interfere.
.
531,532d
496c
	int loop, stat;
.
450c
 * Wait for the controller to be ready to accept a command.
 * This is protected from intereference by hardclock() by
 * setting dp->usetime before it is called.
.
243a
			/*
			 * Make sure hardclock() doesn't
			 * interfere.
			 */
			dp->usetime = m->ticks;
.
219a
	
	if(conf.nhard && (p = getconf("spindowntime")))
		spindowntime = atoi(p);
.
193,196d
117a
	Lock;			/* exclusive access to the registers */

.
116c
	QLock;			/* exclusive access to the controller */
.
## diffname pc/devhard.c 1995/0108
## diff -e /n/fornaxdump/1995/0107/sys/src/brazil/pc/devhard.c /n/fornaxdump/1995/0108/sys/src/brazil/pc/devhard.c
441a
}

long
hardbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
373a
Block*
hardbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname pc/devhard.c 1995/0117
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/pc/devhard.c /n/fornaxdump/1995/0117/sys/src/brazil/pc/devhard.c
967c
			switch(getfields(line[i], field, 3, " ")) {
.
958c
		n = getfields(buf, line, Npart+1, "\n");
.
951c
	n = getfields(buf, line, Npart+1, "\n");
.
888c
			if(getfields(line[i], field, 1, " ") != 1)
.
883c
	n = getfields(buf, line, Nrepl+1, "\n");
.
## diffname pc/devhard.c 1995/0726
## diff -e /n/fornaxdump/1995/0117/sys/src/brazil/pc/devhard.c /n/fornaxdump/1995/0726/sys/src/brazil/pc/devhard.c
292d
290c
hardcreate(Chan*, char*, int, ulong)
.
## diffname pc/devhard.c 1995/0912 # deleted
## diff -e /n/fornaxdump/1995/0726/sys/src/brazil/pc/devhard.c /n/fornaxdump/1995/0912/sys/src/brazil/pc/devhard.c
1,1133d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].