V7M/sys/dev/hm.c

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

/*
 * UNIX/v7m - RM02/3, RP04/5/6, & ML11 disk driver.
 * Disks on second RH controller (176300)
 * Fred Canter 9/4/81
 *
 * This is a combination driver, it supports any mix
 * of RM02/3, RP04/5/6, & ML11 disks, up to eight
 * drives on the same controller.
 * If support for the ML11 drive type is not
 * required, it may be removed by redefining the control
 * parameter for the ML11 (ML) to zero.
 */

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/seg.h"

/*
 * The following parameter controls the inclusion
 * of code to support the ML11 disk drive.
 */

#define	ML	1	/* ML11 */

struct	device
{
	union {
		int	w;
		char	c[2];
	} hmcs1;		/* Control and Status register 1 */
	int	hmwc;		/* Word count register */
	caddr_t	hmba;		/* UNIBUS address register */
	int	hmda;		/* Desired address register */
	union {
		int	w;
		char	c[2];
	} hmcs2;		/* Control and Status register 2 */
	int	hmds;		/* Drive Status */
	int	hmer1;		/* Error register 1 */
/*		mler	*/	/* Error register */
	int	hmas;		/* Attention Summary */
	int	hmla;		/* Look ahead */
/*		mlpa	*/	/* Prom address register */
	int	hmdb;		/* Data buffer */
	int	hmmr;		/* Maintenance register */
/*		rmmr1	*/	/* Maintenance register 1 */
	int	hmdt;		/* Drive type */
	int	hmsn;		/* Serial number */
	int	hmof;		/* Offset register */
/*		mle1	*/	/* ECC CRC word 1 */
	int	hmdc;		/* Desired Cylinder address register */
/*		mle2	*/	/* ECC CRC word 2 */
	int	hmcc;		/* Current Cylinder */
/*		mld1	*/	/* Data diagnostic 1 register */
/*		rmhr	*/	/* Holding register */
	int	hmer2;		/* Error register 2 */
/*		mld2	*/	/* Data diagnostic 2 register */
/*		rmmr2	*/	/* Maintenance register 2 */
	int	hmer3;		/* Error register 3 */
/*		mlee	*/	/* ECC error register */
/*		rmer2	*/	/* Error register 2 */
	int	hmec1;		/* Burst error bit position */
/*		mlel	*/	/* ECC error location register */
	int	hmec2;		/* Burst error bit pattern */
/*		mlpd	*/	/* Prom data register */
	int	hmbae;		/* 11/70 bus extension */
	int	hmcs3;		/* 11/70 control & status 3 */
};

#define	HMADDR	((struct device *)0176300)
#define	NUNIT	2
/*
 * Instrumentation (iostat) structures
 */
struct	ios	hm_ios[NUNIT];
#define	DK_N	1

/*
 * Drive type definitions
 */
#define	RP04	020
#define	RP05	021
#define	RP06	022
#define	RM03	024
#define	RM02	025
#define	ML11	0110
/*
 * Disk geometry definitions
 */
#define NRMSEC	32
#define NRMTRK	5
#define NRPSEC	22
#define NRPTRK	19
#define	SDIST	2
#define	RDIST	6

/*
 * The number of elements in the hm_sizes[]
 * array has been changed from 8 to 24.
 * The first 8 elements describe the disk partitions
 * for the RP04/5/6 and the second 8 elements
 * specify the RM02/3 disk partitions,
 * the last 8 elements are the size of each ML11
 * unit in blocks.
 * The size of the ML11 unit is determined by reading
 * the ML maintenance register the first time the drive
 * is accessed.
 * The last cylinder of the disk pack is not used, 
 * so that a bad block replacement strategy may be
 * implemented later.
 */

struct	size
{
	daddr_t	nblocks;
	int	cyloff;
} hm_sizes[24] =
{
	9614,	0,	/* cyl   0- 22, root file system on rp04/5/6	*/
	8778,	23,	/* cyl  23- 43, swap area on rp04/5/6		*/
	8778,	44,	/* cyl  44- 64, /sys (system sources) rp04/5/6	*/
	144210,	65,	/* cyl  65-409, /usr (user + sources) rp04/5	*/
	313082,	65,	/* cyl  65-813, /usr (user + sources) rp06	*/
	168454,	411,	/* cyl 411-813, user file system on rp06	*/
	171380,	0,	/* cyl   0-409, user - all of rp04/5 pack	*/
	340252,	0,	/* cyl   0-813, user - all of rp06 pack		*/
	9600,	0,	/* cyl   0- 59, root file system on rm02/3	*/
	8800,	60,	/* cyl  60-114, swap area on rm02/3		*/
	8000,	115,	/* cyl 115-164, /sys (system sources) rm02/3	*/
	105120,	165,	/* cyl 165-821, /usr (user + sources) rm02/3	*/
	0,	0,	/* spare for avoiding bad blocks		*/
	0,	0,	/* spare for avoiding bad blocks		*/
	0,	0,	/* spare for avoiding bad blocks		*/
	131520,	0,	/* cyl   0-821, user - all of rm02/3 pack	*/
	0,	0,	/* ML11  unit	0	*/
	0,	0,	/*		1	*/
	0,	0,	/*		2	*/
	0,	0,	/*		3	*/
	0,	0,	/*		4	*/
	0,	0,	/*		5	*/
	0,	0,	/*		6	*/
	0,	0,	/*		7	*/
};

#define	P400	020
#define	M400	0220
#define	P800	040
#define	M800	0240
#define	P1200	060
#define	M1200	0260
int	hm_offset[16] =
{
	P400, M400, P400, M400,
	P800, M800, P800, M800,
	P1200, M1200, P1200, M1200,
	0, 0, 0, 0,
};

struct	buf	hmtab;
struct	buf	rhmbuf;
struct	buf	hmutab[NUNIT];
char	hm_dt[NUNIT];	/* drive type */

#define	GO	01
#define	PRESET	020
#define	RTC	016
#define	OFFSET	014
#define	SEARCH	030
#define	RECAL	06
#define DCLR	010
#define	WCOM	060
#define	RCOM	070

#define	IE	0100
#define	PIP	020000
#define	DRY	0200
#define	ERR	040000
#define	TRE	040000
#define	DCK	0100000
#define	WLE	04000
#define	ECH	0100
#define VV	0100
#define	DPR	0400
#define	MOL	010000
#define FMT22	010000

#define	b_cylin	b_resid

daddr_t dkblock();

hmstrategy(bp)
register struct buf *bp;
{
	register struct buf *dp;
	register unit;
	long sz, bn;
	int nbpc, dn, dt, fs, pri;

	if((bp->b_flags&B_PHYS) && !rh70hm)
		mapalloc(bp);
	unit = minor(bp->b_dev) & 077;
	dn = (unit >> 3) & 07;	/* get drive number */
	if(hm_dt[dn] == 0) {	/* get drive type, if not known */
		spl5();
		HMADDR->hmcs2.c[0] = dn;
		hm_dt[dn] = HMADDR->hmdt & 0377;
#if ML
/*
 * Find the size of the ML11 unit by reading the
 * number of array modules from the ML maintenance register.
 * There are 512 blocks per array unless the array type
 * bit is set, in which case there are 2048 blocks per array.
 */
		if(hm_dt[dn] == ML11) {
			hm_sizes[dn+16].nblocks = (HMADDR->hmmr >> 2) & 037000;
			if(HMADDR->hmmr & 02000)
				hm_sizes[dn+16].nblocks <<= 2;
/*
 * Check the ML11 transfer rate.
 * 2mb is too fast for any pdp11
 * 1mb allowed on pdp11/70 only
 * .5mb & .25mb ok on any processor.
 */
			fs = HMADDR->hmmr & 01400;
			if((fs == 0) || ((fs == 0400) && !rh70hm)) {
				printf("\nML11 xfer rate error\n");
				goto bad;
				}
			hm_ios[dn].dk_tr = ((fs >> 8) & 3) + 4;
			}
		spl0();
#endif
		if(hm_dt[dn] != ML11) {
			hm_ios[dn].dk_tr = 1;
			if(hm_dt[dn] == RM03)
				hm_ios[dn].dk_tr = 2;
			}
		pri = spl6();
		dk_iop[DK_N] = &hm_ios[0];
		dk_nd[DK_N] = NUNIT;
		splx(pri);
		}
/*
 * Set up the index into the sizes table (dt)
 * and the number of blocks per cylinder (nbpc).
 */
#if ML
	if(hm_dt[dn] == ML11)
		dt = 16;
	else
#endif
	if((hm_dt[dn] == RM02) || (hm_dt[dn] == RM03)) {
		nbpc = NRMSEC*NRMTRK;
		dt = 8;
		}
	else
	if(hm_dt[dn] <= RP06) {
		nbpc = NRPSEC*NRPTRK;
		dt = 0;
		}
	else
	goto bad;
	sz = bp->b_bcount;
	sz = (sz+511) >> 9;
	fs = unit & 07;		/* For RP & RM, fs is partition */
	if(dt == 16)		/* For ML, fs is unit number */
		fs = dn;
#if ML
	if((hm_dt[dn] == ML11) && (unit&7))
		goto bad;	/* ML11 is not partitioned */
#endif
	if (unit >= (NUNIT<<3) ||
	    bp->b_blkno < 0 ||
	    (bn = dkblock(bp))+sz > hm_sizes[fs+dt].nblocks) {
	bad:
		u.u_error = ENXIO;
		bp->b_flags |= B_ERROR;
		iodone(bp);
		return;
	}
#if ML
	if(dt == 16)
		bp->b_cylin = 0;	/* fake out dsort for ML11 */
	else
#endif
	bp->b_cylin = bn/nbpc + hm_sizes[fs+dt].cyloff;
	unit = dkunit(bp);
	dp = &hmutab[unit];
	spl5();
	disksort(dp, bp);
	if (dp->b_active == 0) {
		hmustart(unit);
		if(hmtab.b_active == 0)
			hmstart();
	}
	spl0();
}

hmustart(unit)
register unit;
{
	register struct buf *bp, *dp;
	daddr_t bn;
	int sn, cn, csn;
	int nsect, ntrac;

	HMADDR->hmcs2.w = unit;
	HMADDR->hmcs1.c[0] = IE;
	HMADDR->hmas = 1<<unit;

	if(unit >= NUNIT)
		return;
	if(hm_dt[unit] <= RP06) {
		nsect = NRPSEC;
		ntrac = NRPTRK;
	} else {
		nsect = NRMTRK;
		ntrac = NRMTRK;
		}
	hm_ios[unit].dk_busy = 0;
	dp = &hmutab[unit];
	if((bp=dp->b_actf) == NULL)
		return;
	if((HMADDR->hmds & VV) == 0) {
		HMADDR->hmcs1.c[0] = IE|PRESET|GO;
#if ML
		if(hm_dt[unit] != ML11)
#endif
			HMADDR->hmof = FMT22;
	}
	if(dp->b_active)
		goto done;
#if ML
	if(hm_dt[unit] == ML11) {
		sn = dkblock(bp);
		dp->b_active++;
		goto mlsrch;
		}
#endif
	dp->b_active++;
	if ((HMADDR->hmds & (DPR|MOL)) != (DPR|MOL))
		goto done;

	bn = dkblock(bp);
	cn = bp->b_cylin;
	sn = bn%(nsect*ntrac);
	sn = (sn+nsect-SDIST)%nsect;

	if(HMADDR->hmcc != cn)
		goto search;
	csn = (HMADDR->hmla>>6) - sn + SDIST - 1;
	if(csn < 0)
		csn += nsect;
	if(csn > nsect-RDIST)
		goto done;

search:
	HMADDR->hmdc = cn;
mlsrch:
	HMADDR->hmda = sn;
	hm_ios[unit].dk_busy++;
	HMADDR->hmcs1.c[0] = IE|SEARCH|GO;
	return;

done:
	dp->b_forw = NULL;
	if(hmtab.b_actf == NULL)
		hmtab.b_actf = dp; else
		hmtab.b_actl->b_forw = dp;
	hmtab.b_actl = dp;
}

hmstart()
{
	register struct buf *bp, *dp;
	register unit;
	daddr_t bn;
	int dn, sn, tn, cn, dt;
	int nsect, ntrac;

loop:
	if ((dp = hmtab.b_actf) == NULL)
		return;
	if ((bp = dp->b_actf) == NULL) {
		hmtab.b_actf = dp->b_forw;
		goto loop;
	}
	hmtab.b_active++;
	unit = minor(bp->b_dev) & 077;
	dn = dkunit(bp);
	spl5();
	HMADDR->hmcs2.w = dn;
	if(hm_dt[dn] <= RP06) {
		dt = 0;
		nsect = NRPSEC;
		ntrac = NRPTRK;
	} else {
		dt = 8;
		nsect = NRMSEC;
		ntrac = NRMTRK;
		}
	bn = dkblock(bp);
	if(hm_dt[dn] != ML11) {
		cn = bn/(nsect*ntrac) + hm_sizes[(unit&07)+dt].cyloff;
		sn = bn%(nsect*ntrac);
		tn = sn/nsect;
		sn = sn%nsect;
		}

	if ((HMADDR->hmds & (DPR|MOL)) != (DPR|MOL)) {
		hmtab.b_active = 0;
		hmtab.b_errcnt = 0;
		dp->b_actf = bp->av_forw;
		bp->b_flags |= B_ERROR;
		iodone(bp);
		spl0();
		goto loop;
	}
	if((hmtab.b_errcnt >= 16) && (hm_dt[dn] != ML11)) {
		HMADDR->hmof = hm_offset[hmtab.b_errcnt & 017] | FMT22;
		HMADDR->hmcs1.w = OFFSET|GO;
		while(HMADDR->hmds & PIP)
			;
	}
	if(hm_dt[dn] == ML11)
		HMADDR->hmda = bn;
	else {
		HMADDR->hmdc = cn;
		HMADDR->hmda = (tn << 8) + sn;
	}
	HMADDR->hmba = bp->b_un.b_addr;
	if(rh70hm)
		HMADDR->hmbae = bp->b_xmem;
	HMADDR->hmwc = -(bp->b_bcount>>1);
	unit = ((bp->b_xmem&3) << 8) | IE | GO;
	if(bp->b_flags & B_READ)
		unit |= RCOM; else
		unit |= WCOM;
	HMADDR->hmcs1.w = unit;

	hm_ios[dn].dk_busy++;		/* Instrumentation - disk active, */
	hm_ios[dn].dk_numb++;		/* count number of transfers, */
	unit = bp->b_bcount >> 6;	/* transfer size in 32 word chunks, */
	hm_ios[dn].dk_wds += unit;	/* count total words transferred */
	spl0();
}

hmintr()
{
	register struct buf *bp, *dp;
	register unit;
	register seg, uba;
	int as;
	int tpuis[2], tpbad[2], tppos, tpofst;
	int bsp;
	int pri, ctr, dt

	as = HMADDR->hmas & 0377;
	if(hmtab.b_active) {
		dp = hmtab.b_actf;
		bp = dp->b_actf;
		unit = dkunit(bp);
		HMADDR->hmcs2.c[0] = unit;
		hm_ios[unit].dk_busy = 0;
		if (HMADDR->hmcs1.w & TRE) {		/* error bit */
			while((HMADDR->hmds & DRY) == 0)
				;
#if ML
			if((hm_dt[unit] == ML11) && (hmtab.b_errcnt == 0))
				hmtab.b_errcnt = 18;
#endif
			if(++hmtab.b_errcnt > 28 || HMADDR->hmer1&WLE)
				bp->b_flags |= B_ERROR; else
				hmtab.b_active = 0;
			if(hmtab.b_errcnt > 27)
				deverror(bp, HMADDR->hmcs2.w, HMADDR->hmer1);
/* Start of ECC code, please excuse the improper indentation */
	if(((HMADDR->hmer1&(DCK|ECH)) == DCK) && (hm_dt[unit] != ML11))
	{
		pri = spl7();
		tpuis[0] = UISA->r[0];	/* save User I space PAR */
		tpuis[1] = UISD->r[0];	/* save User I space PDR */
		if(rh70hm)
			uba = (HMADDR->hmbae << 10) & 0176000;
		else
			uba = (HMADDR->hmcs1.w & 01400) << 2;
		uba += (((HMADDR->hmba >> 1) & ~0100000) >> 5);
		uba -= 8;
		if(bp->b_flags & B_MAP) {
			ctr = ((uba >> 6) & 076);
			seg = UBMAP->r[ctr+1] << 10;
			seg |= (UBMAP->r[ctr] >> 6) & 01777;
			UISA->r[0] = seg + (uba & 0177);
		} else
			UISA->r[0] = uba;
		UISD->r[0] = 077406;	/* Set User I space PDR */
		tppos = (HMADDR->hmec1 - 1)/16;	/* word addr of error burst */
		tpofst = (HMADDR->hmec1 - 1)%16;	/* bit in word */
		bsp = HMADDR->hmba & 077;
		bsp += (tppos*2);
		tpbad[0] = fuiword(bsp);
		tpbad[1] = fuiword(bsp+2);
		tpbad[0] ^= (HMADDR->hmec2 << tpofst); /* xor first word */
		if(tpofst > 5) {	/* must fix second word */
			ctr = (HMADDR->hmec2 >> 1) & ~0100000;
			if(tpofst < 15)
				ctr = ctr >> (15 - tpofst);
			tpbad[1] ^= ctr;	/* xor second word */
			}
		suiword(bsp,tpbad[0]);
		suiword((bsp+2),tpbad[1]);
		UISD->r[0] = tpuis[1];	/* restore User PDR */
		UISA->r[0] = tpuis[0];	/* restore User PAR */
		splx(pri);
		/* now see if transfer finished. */
		/* If not then reset;track,sector,etc. */
		if(HMADDR->hmwc != 0)
			{
			tpbad[0] = bp->b_bcount >> 1;
			tpbad[1] = -(HMADDR->hmwc);
			bp->b_blkno =+ (tpbad[0] - tpbad[1]) / 256;
			bp->b_bcount = -(HMADDR->hmwc) << 1;
			bp->b_un.b_addr = HMADDR->hmba;
			if(rh70hm)
				bp->b_xmem = HMADDR->hmbae & 077;
			else
				bp->b_xmem = (HMADDR->hmcs1.w & 01400) >> 8;
			printf("%D ", (bp->b_blkno - 1));
			prdev("ECC", bp->b_dev);
			HMADDR->hmcs1.w = TRE|DCLR|GO;
			hmstart();	/* Continue transfer */
			return;
			}
		hmtab.b_active++;
		printf("%D ", bp->b_blkno);
		prdev("ECC", bp->b_dev);
	}
/* End of ECC code					*/
			HMADDR->hmcs1.w = TRE|IE|DCLR|GO;
			if(((hmtab.b_errcnt&07) == 4) && (hm_dt[unit] != ML11)) {
				HMADDR->hmcs1.w = RECAL|IE|GO;
				while(HMADDR->hmds & PIP)
					;
			}
		}
		if(hmtab.b_active) {
			if((hmtab.b_errcnt) && (hm_dt[unit] != ML11)) {
				HMADDR->hmcs1.w = RTC|GO;
				while(HMADDR->hmds & PIP)
					;
			}
			hmtab.b_active = 0;
			hmtab.b_errcnt = 0;
			hmtab.b_actf = dp->b_forw;
			dp->b_active = 0;
			dp->b_errcnt = 0;
			dp->b_actf = bp->av_forw;
			bp->b_resid = -(HMADDR->hmwc<<1);
			iodone(bp);
			HMADDR->hmcs1.w = IE;
			if(dp->b_actf)
				hmustart(unit);
		}
		as &= ~(1<<unit);
	} else {
		if(as == 0)
			HMADDR->hmcs1.w = IE;
		HMADDR->hmcs1.c[1] = TRE>>8;
	}
	for(unit=0; unit<NUNIT; unit++)
		if(as & (1<<unit))
			hmustart(unit);
	hmstart();
}

hmread(dev)
{

	physio(hmstrategy, &rhmbuf, dev, B_READ);
}

hmwrite(dev)
{

	physio(hmstrategy, &rhmbuf, dev, B_WRITE);
}