SysIII/usr/src/uts/vax/io/hp.c

Compare this file to the similar file:
Show the results in this format:

/*
 * RP04/RP06 disk driver
 */

#include "sys/param.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/elog.h"
#include "sys/iobuf.h"
#include "sys/systm.h"
#include "sys/mba.h"

struct device
{
	int	hpcs1, hpds, hper1, hpmr;
	int	hpas, hpda, hpdt, hpla;
	int	hpsn, hpof, hpdc, hpcc;
	int	hper2, hper3, hpec1, hpec2;
};

#define	mbaddr	((struct mba *)0x8004e000)
#define	mbactl	(mbaddr->mba_ireg.mba_regs)
#define	mbadev	(mbaddr->mba_ereg)
#define	mbamap	(mbaddr->mba_map)

struct	size
{
	daddr_t	nblocks;
	int	cyloff;
} hp_sizes[8];

struct	iostat	hpstat[8];
struct	iobuf	hptab	= tabinit(HP0,0);
struct	iobuf	hputab[8] = {
		tabinit(HP0,&hpstat[0]),tabinit(HP0,&hpstat[1]),tabinit(HP0,&hpstat[2]),
		tabinit(HP0,&hpstat[3]),tabinit(HP0,&hpstat[4]),tabinit(HP0,&hpstat[5]),
		tabinit(HP0,&hpstat[6]),tabinit(HP0,&hpstat[7])
};

struct	buf	hpbuf;

#define	NSECT	22
#define	NTRAC	19
#define	SDIST	3
#define	RDIST	7
#define	GDIST	1

#define	GO	01
#define	RECAL	06
#define	DCLR	010
#define	RELEASE	012
#define	PRESET	020
#define	SEARCH	030
#define	WCOM	060
#define	RCOM	070

#define	ERR	040000	/* hpds - Error */
#define	MOL	010000	/* hpds - Medium online */
#define	VV	0100	/* hpds - volume valid */
#define	WLE	04000	/* hper1 - Write lock error */
#define	DCK	0100000	/* hper1 - Data check */
#define	FMT22	010000
#define	NED	0x40000

#define	wtime	b_flags
#define	WOK	0
#define	WABORT	1
#define	WNED	2
#define	WMOL	4
#define	WERR	30

#define	acts	io_s1
#define	qcnt	io_s2

#define	trksec	av_back
#define	cylin	b_resid

hpopen(dev)
{
	register struct iobuf *dp;

	if ((hptab.b_flags&B_ONCE)==0) {
		hptab.b_flags |= B_ONCE;
		hptab.io_mba = (physadr)&mbactl;
		hptimer();
	}
	dp = &hputab[dev>>3];
	dp->io_addr = (physadr)&mbadev[dev>>3];
	dp->io_mba = (physadr)&mbactl;
	dp->io_nreg = NDEVREG;
}

hpclose(dev)
{
}

hpstrategy(bp)
register struct buf *bp;
{
	register struct iobuf *dp;
	register struct buf *ap;
	daddr_t	last;
	register unit;
	int	co;

	unit = minor(bp->b_dev);
	last = hp_sizes[unit&07].nblocks;
	co = hp_sizes[unit&07].cyloff;
	unit >>= 3;
	dp = &hputab[unit];
	if (bp->b_blkno < 0 || bp->b_blkno >= last) {
		if (bp->b_blkno == last && bp->b_flags&B_READ)
			bp->b_resid = bp->b_bcount;
		else {
			bp->b_flags |= B_ERROR;
			bp->b_error = ENXIO;
		}
		iodone(bp);
		return;
	}
	bp->av_forw = NULL;
	bp->cylin = bp->b_blkno/(NSECT*NTRAC) + co;
	co = bp->b_blkno%(NSECT*NTRAC);
	*((int *)(&bp->trksec)) = ((co/NSECT)<<8)+(co%NSECT);
	hpstat[unit].io_ops++;
	spl6();
	dp->qcnt++;
	if (dp->b_actf == NULL) {
		dp->b_actf = bp;
		dp->b_actl = bp;
		dp->acts = (int)bp;
	} else {
		register struct buf *cp;

		if (((int)hpstat[unit].io_ops&07) == 0)
			dp->acts = (int)dp->b_actl;
		for (ap = (struct buf *)dp->acts; cp = ap->av_forw; ap = cp) {
			int s1, s2;

			if ((s1 = ap->cylin - bp->cylin)<0) s1 = -s1;
			if ((s2 = ap->cylin - cp->cylin)<0) s2 = -s2;
			if (s1 < s2)
				break;
		}
		ap->av_forw = bp;
		if ((bp->av_forw = cp) == NULL)
			hputab[unit].b_actl = bp;
	}
	if (hputab[unit].b_active == 0) {
		hpustart(unit);
		if (hptab.b_active == 0 && hptab.b_actf != NULL)
			hpstart();
	}
	spl0();
}

hpustart(unit)
{
	register struct buf *bp;
	register struct iobuf *dp;
	register struct device *rp;
	int	sn, dsn;

	dp = &hputab[unit];
	rp = (struct device *)&mbadev[unit];
	mbactl.mba_cr |= MBAIE;
	rp->hpas = 1<<unit;
	bp = dp->b_actf;
	if ((rp->hpds&MOL) == 0) {
		if (dp->wtime!=WOK)
			return;
		if (bp == NULL)
			dp->wtime = WOK;
		else if (mbactl.mba_sr&NED)
			dp->wtime = WNED;
		else if (!pwr_act)
			dp->wtime = WMOL;
		else
			dp->wtime = WERR;
		return;
	} else if (rp->hpds&ERR) {
		dp->b_dev = makedev(HP0,unit);
		fmtberr(dp,(bp==NULL)?0:hp_sizes[minor(bp->b_dev)&07].cyloff);
		rp->hpcs1 = DCLR|GO;
		if (rp->hpds&ERR || ++dp->b_errcnt > 16) {
			printf("hard err on RP04/5/6 drive %d %o %o %o %o\n",
			unit, rp->hpds, rp->hper1, rp->hper2, rp->hper3);
			dp->wtime = WERR;
			rp->hpas = 1<<unit;
			return;
		}
	}
	dp->wtime = WOK;
	if ((rp->hpds&VV) == 0) {
		rp->hpcs1 = PRESET|GO;
		rp->hpof = FMT22;
	}
	if (bp == NULL) {
		rp->hpcs1 = RELEASE|GO;
		return;
	}
	if ((dp->b_errcnt&07) == 05) {
		dp->b_errcnt++;
		rp->hpcs1 = RECAL|GO;
		return;
	}
	dp->b_active++;
	sn = (int)bp->trksec&0377;
	dsn = (sn<<2) - ((rp->hpla&0xffff)>>4) - GDIST;
	if (dsn<=0) dsn += NSECT*4;
	if (((bp->cylin - rp->hpcc) || dsn > RDIST*4) &&
	    dp->b_active<3) {
		rp->hpdc = bp->cylin;
		sn -= SDIST;
		if (sn<0) sn += NSECT;
		rp->hpda = sn;
	/* sector search, track ignored, lookahead SDIST */
		rp->hpcs1 = SEARCH|GO;
		if (dp->b_active == 1) {
			hpstat[unit].io_misc++;
		}
	} else {
		dp->b_forw = NULL;
		if (hptab.b_actf == NULL)
			hptab.b_actf = (struct buf *)dp;
		else
			hptab.b_actl->b_forw = (struct buf *)dp;
		hptab.b_actl = (struct buf *)dp;
	}
}

hpstart()
{
	register struct buf *bp;
	register struct iobuf *dp;
	register struct device *rp;
	register unit;

    loop:
	if ((dp = (struct iobuf *)hptab.b_actf) == NULL)
		return;
	if ((bp = dp->b_actf) == NULL) {
		hptab.b_actf = dp->b_forw;
		goto loop;
	}
	unit = minor(bp->b_dev)>>3;
	rp = (struct device *)&mbadev[unit];
	hptab.b_active++;
	rp->hpdc = bp->cylin;
	rp->hpda = (int)bp->trksec;
	blkacty |= (1<<HP0);
	mbastart(bp, rp, mbaddr);
}

hpintr(mbastat, as)
{
	register struct buf *bp;
	register unit;
	register struct device *rp;
	register struct iobuf *dp;

	if (hptab.b_active) {	/* data transfer underway */
		blkacty &= ~(1<<HP0);
		dp = (struct iobuf *)hptab.b_actf;
		bp = dp->b_actf;
		unit = minor(bp->b_dev);
		rp = (struct device *)&mbadev[unit>>3];
		if (mbastat & MBADTABT) {
			if (++dp->b_errcnt>16)
				bp->b_flags |= B_ERROR;
			else if (rp->hper1&WLE) {
				bp->b_flags |= B_ERROR;
				printf("Write lock error RP04/5/6 drive %d\n",
					unit>>3);
			} else {
				hptab.b_active = 0;
			}
			fmtberr(dp,hp_sizes[unit&07].cyloff);
			if (dp->b_errcnt > 2)
				deverr(dp, mbastat, rp->hper1);
			if ((rp->hper1&0xffff) == DCK) {
				if (hpecc(rp, bp))
					return;
			}
			rp->hpcs1 = DCLR|GO;
		}
		unit >>= 3;
		if (hptab.b_active) {
			if (dp->io_erec)
				logberr(dp,bp->b_flags&B_ERROR);
			hptab.b_active = 0;
			dp->b_active = 0;
			dp->b_errcnt = 0;
			dp->b_actf = bp->av_forw;
			bp->b_resid = -(mbactl.mba_bcr) & 0xffff;
			dp->qcnt--;
			if (bp == (struct buf *)dp->acts)
				dp->acts = (int)dp->b_actf;
			iodone(bp);
			rp->hpcs1 = RELEASE|GO;
		}
		hptab.b_actf = dp->b_forw;
		if (dp->b_actf)
			hpustart(unit);
		as &= ~(1<<unit);
	}
	for (unit=0; as; unit++)
		if (as&(1<<unit)) {
			as &= ~(1<<unit);
			hpustart(unit);
		}
	if (hptab.b_actf != NULL)
		hpstart();
}

hpread(dev)
{
	if (physck(hp_sizes[dev&07].nblocks, B_READ))
		physio(hpstrategy, &hpbuf, dev, B_READ);
}

hpwrite(dev)
{
	if (physck(hp_sizes[dev&07].nblocks, B_WRITE))
		physio(hpstrategy, &hpbuf, dev, B_WRITE);
}

hpecc(rp, bp)
register struct device *rp;
register struct buf *bp;
{
	register i;
	register b, n, map, mix;
	register char * cp;
	register mask;
	extern short piget();

	mask = rp->hpec2&0xffff;
	if (mask == 0) {
		rp->hpof = FMT22;
		return(0);
	}
	i = (rp->hpec1&0xffff) - 1;
	n = i&017;
	i = (i&~017)>>3;
	b = (((mbactl.mba_bcr&0xffff) +
		(bp->b_bcount) - 1)>>9)&0177;
	if (bp->b_flags&B_PHYS)
		map = 128 + b;
	else
		map = (paddr(bp) - (paddr_t)buffers)>>9;
	mix = i + ((int)paddr(bp)&0x1ff);
	i += b<<BSHIFT;
	if ( i < bp->b_bcount) {
		cp = (char *)((mbamap[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff);
		piput(cp,piget(cp)^(mask<<n));
	}
	mix += 2;
	i += 2;
	if ( i < bp->b_bcount) {
		cp = (char *)((mbamap[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff);
		piput(cp,piget(cp)^(mask>>(16-n)));
	}
	hptab.b_active++;
	if (mbactl.mba_bcr) {
		i = (int)bp->trksec;
		i = NSECT*(i>>8) + (i&0377) + b + 1;
		if (i >= NSECT*NTRAC) {
			i -= NSECT*NTRAC;
			rp->hpdc = bp->cylin + 1;
		} else
			rp->hpdc = bp->cylin;
		rp->hpda = ((i/NSECT)<<8) + (i%NSECT);
		rp->hpcs1 = DCLR|GO;
		mbactl.mba_sr = -1;
		mbactl.mba_var = ((128+b+1)<<9)|((int)paddr(bp)&0x1ff);
		if (pwr_act >= 0)
			rp->hpcs1 = RCOM|GO;
		return(1);
	} else
		return(0);
}

hptimer()
{
	register unit;
	register struct iobuf *dp;
	register struct buf *bp;

	for (unit=0; unit < 8; unit++) {
		dp = &hputab[unit];
		if (dp->wtime == WOK)
			continue;
		hpustart(unit);
		if (dp->wtime == WOK)
			continue;
		if (dp->wtime == WABORT) {
			if (dp->io_erec)
				logberr(dp, B_ERROR);
			while (bp = dp->b_actf) {
				bp->b_flags |= B_ERROR;
				dp->b_actf = bp->av_forw;
				iodone(bp);
			}
			dp->b_active = 0;
			dp->b_errcnt = 0;
			dp->qcnt = 0;
			printf("RP04/5/6 drive %d not available\n", unit);
		}
		dp->wtime--;
	}
	if (hptab.b_active == 0 && hptab.b_actf != NULL)
		hpstart();
	timeout(hptimer, 0, 15*HZ);
}

hpclr()
{
	register unit;

	hptab.b_active = 0;
	hptab.b_actf = NULL;
	for (unit = 0; unit < 8; unit++)
		hpustart(unit);
	hpstart();
}