BBN-V6/dmr/hp.c

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

#
/*
 * RWP06 driver
 * PRELIMINARY *
 *  modified by A. G. Nemeth - BBN - 18 May 1978 *
 */


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

struct {
	int	hpcs1;	/* Control and Status register 1 */
	int	hpwc;	/* Word count register */
	int	hpba;	/* UNIBUS address register */
	int	hpda;	/* Desired address register */
	int	hpcs2;	/* Control and Status register 2*/
	int	hpds;	/* Drive Status */
	int	hper1;	/* Error register 1 */
	int	hpas;	/* Attention Summary */
	int	hpla;	/* Look ahead */
	int	hpdb;	/* Data buffer */
	int	hpmr;	/* Maintenance register */
	int	hpdt;	/* Drive type */
	int	hpsn;	/* Serial number */
	int	hpof;	/* Offset register */
	int	hpdc;	/* Desired Cylinder address register*/
	int	hpcc;	/* Current Cylinder */
	int	hper2;	/* Error register 2 */
	int	hper3;	/* Error register 3 */
	int	hpec1;	/* Burst error bit position */
	int	hpec2;	/* Burst error bit pattern */
	int	hpbae;	/* Bus address extension */
	int	hpcs3;	/* Control and status register 3 */
};

#define	HPADDR	0176700
#define	NHP	2	/*number of HP drives */
#define NMDLOG2 4	/* number of meta disks log 2 */
#define MASK	((1<<NMDLOG2)-1)	/* mask for meta disk ID */

struct {
	char	*nblocks;
	int	cyloff;
} hp_sizes[] {
	9614,	0,	/* 0 - hpsx8 */
	9614,  23,	/* 1 - hpsx7 */
	9614,  46,	/* 2 - hpsx6 */
	9614,  69,	/* 3 - hpsx5 */
       63536,  92,	/* 4 - hplx2 */
	9614, 244,	/* 5 - hpsx4 */
	9614, 267,	/* 6 - hpsx3 */
	9614, 290,	/* 7 - hpsx2 */
	9614, 313, 	/* 8 - hpsx1 */
	9614, 336,	/* 9 - hpsx0 */
       63536, 359,	/*10 - hplx0 */
       63536, 511,	/*11 - hplx1 */
       63536, 663,	/*12 - hplx3 */
};


struct	devtab	hptab;
struct	devtab	hputab[NHP];
struct	buf	hpbuf;
char	hpstatus[NHP];
int	hpsioc[NHP];
int	hpsios[NHP];

int	ghper1, ghper2, ghper3, ghpds, ghpcs2;

			/* Drive Commands */
#define	GO	01
#define	UNLOAD	02
#define	SEEK	04
#define DCLR	010
#define	RELEASE	012
#define	PRESET	020
#define	SEARCH	030

#define	ERR	040000	/* hpds - Error */
#define	MOL	010000	/* hpds - Medium online */
#define	DRY	0200	/* hpds - drive ready */
#define VV	0100	/* hpds - volume valid */
#define SC	0100000	/* hpcs1 - Special condition */
#define	TRE	040000	/* hpcs1 - transfer error */
#define DVA	04000	/* hpcs1 - drive available */
#define	IE	0100	/* hpcs1 - interrupt enable */
#define RDY     0200    /* hpcs1 - controller ready */
#define	NED	010000	/* hpcs2 - Nonexistent drive */
#define	WLE	04000	/* hper1 - Write lock error */
#define FMT22	010000	/* hpof - 16 bit /word format */
#define	ECI	04000	/* hpof - ecc inhibit */
/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */

#define	trksec	av_back
#define	cylin	b_resid

hpstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char *p1, *p2;
	struct devtab *dp;
	int	unit;

	bp = abp;
	p1 = &hp_sizes[bp->b_dev.d_minor&MASK];
	unit = bp->b_dev.d_minor>>NMDLOG2;
	if (unit >= NHP || hpstatus[unit] ||
	    bp->b_blkno >= p1->nblocks) {
		bp->b_flags =| B_ERROR;
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	bp->cylin = p1->cyloff;
	p1 = bp->b_blkno;
	p2 = lrem(p1, 22);
	p1 = ldiv(p1, 22);
	bp->trksec = (p1%19)<<8 | p2;
	bp->cylin =+ p1/19;
	spl5();
	dp = &hputab[unit];
	hpsioc[unit]++;
	if ((p1 = dp->d_actf)==0)
		dp->d_actf = bp;
	else {
		for (; p2 = p1->av_forw; p1 = p2) {
			if (p1->cylin <= bp->cylin
			 && bp->cylin <  p2->cylin
			 || p1->cylin >= bp->cylin
			 && bp->cylin >  p2->cylin) 
				break;
		}
		bp->av_forw = p2;
		p1->av_forw = bp;
	}
	if (dp->d_active==0)
		hpustart(unit);
	spl0();
}

hpustart(dev)
{
	register struct buf *bp;
	register struct devtab *dp;
	register unit;
	int	search;
	int     i;

	unit = dev;
	dp = &hputab[unit];
	HPADDR->hpcs2.lobyte = unit;
	HPADDR->hpas = 1<<unit;
	/* hpstatus[unit] = 0 was here, moved lower */
	if ((HPADDR->hpcs1&DVA)==0) {
	/* either NED or dual-port not avail */
		printf("NED ");
		goto abort;
	}
	if ((HPADDR->hpds&MOL)==0) {
		if(hpstatus[unit] == 0)   /* check added to prevent */
			printf("MOL ");   /* multiple printfs: 9/25/77:mob */
		goto abort;
	}
	/* check on dp->d_actf was here: moved for error handling 9/23/77:mob */
	hpstatus[unit] = 0;     /* moved from above 9/25/77:mob */
	if (HPADDR->hpds&ERR) {
		printf("SE %d %o\n",unit,HPADDR->hper1);
		HPADDR->hpcs1.lobyte = IE|DCLR|GO;
		if (++dp->d_errcnt > 16) {
			printf("Unit %d unloaded\n",unit);
			HPADDR->hpcs1.lobyte = IE|UNLOAD|GO;
			goto abort;
		}
		if (dp->d_actf)         /* error handling 9/23/77:mob */
			dp->d_active--;
	}
	if ((HPADDR->hpds&VV) == 0) {
		HPADDR->hpcs1.lobyte = IE|PRESET|GO;
		HPADDR->hpof = FMT22|ECI;
	}
	if ((bp = dp->d_actf)==0)       /* error handling (moved) 9/23/77:mob */
		return;                 /*              "               */
	dp->d_active++;
	i = bp->cylin - HPADDR->hpcc;
/*      systm[11] =+ (i > 0 ? i : -i);  /* monitoring 9/22/77:rsk */
	HPADDR->hpdc = bp->cylin;
	search = bp->trksec.lobyte-(HPADDR->hpla>>6)-1;
	if (search<0) search =+ 22;
	if ((bp->cylin!=HPADDR->hpcc || search>6) &&
	    dp->d_active<3) {
		search = bp->trksec;
		search.lobyte =- 4;
		if (search.lobyte<0) search.lobyte =+ 22;
		hpsios[unit]++;
		HPADDR->hpda = search;
		HPADDR->hpcs1.lobyte = IE|SEARCH|GO;
	} else {
		dp->b_forw = 0;
		if (hptab.d_actf == 0)
			hptab.d_actf = dp; else
			hptab.d_actl->b_forw = dp;
		hptab.d_actl = dp;
		if (hptab.d_active == 0)
			hpstart();
	}
	return;
abort:
	if (hpstatus[unit] == 0) {      /* check must be here since we want,
					 * in all, cases, to free pending blocks */
		printf("er1 %o, er2 %o, er3 %o, ds %o, cs1 %o, cs2 %o\n",
		    HPADDR->hper1, HPADDR->hper2, HPADDR->hper3, HPADDR->hpds,
		    HPADDR->hpcs1, HPADDR->hpcs2);      /* helpful debugging info: 9/21/77:mob */
		HPADDR->hpcs1.lobyte = IE|DCLR|GO;      /* error handling: 9/23/77:mob */
	}
	hpstatus[unit]++;
	while(bp = dp->d_actf) {
		bp->b_flags =| B_ERROR;
		dp->d_actf = bp->av_forw;
		iodone(bp);
	}
	dp->d_active = 0;
	dp->d_errcnt = 0;
	printf("RP06 drive %d offline\n",unit);
}

hpstart()
{
	register struct buf *bp;
	register struct devtab *dp;

	if ((dp = hptab.d_actf) == 0)
		return;
	bp = dp->d_actf;
	HPADDR->hpcs2.lobyte = bp->b_dev.d_minor >> NMDLOG2;
	hptab.d_active++;
	HPADDR->hpdc = bp->cylin;
	rhstart(bp, &HPADDR->hpda, bp->trksec, &HPADDR->hpbae);
}

hpintr()
{
	register struct buf *bp;
	register struct devtab *dp;
	register unit;

	if (hptab.d_active) {	/* data transfer underway */
	dp = hptab.d_actf;
	bp = dp->d_actf;
	unit = bp->b_dev.d_minor>>NMDLOG2;
	HPADDR->hpcs2.lobyte = unit;
	if (HPADDR->hpcs1 & TRE) {                        /* error bit */
		deverror(bp, HPADDR->hper1, HPADDR->hpcs2);
		ghper1 = HPADDR->hper1;
		ghper2 = HPADDR->hper2;
		ghper3 = HPADDR->hper3;
		ghpds = HPADDR->hpds;
		ghpcs2 = HPADDR->hpcs2;
		HPADDR->hpcs1 = TRE|IE|DCLR|GO;
		if (++hptab.d_errcnt > 16 ||
		  ghper1&WLE ) {
			bp->b_flags =| B_ERROR;
		} else
			hptab.d_active = 0;
	}

	/* check not only for data transfer but also be sure this is
	 * really the interrupt for it and not some seek interrupt.
	 */

	if (hptab.d_active && (HPADDR->hpcs1&RDY)) {    /* mob:10/07/77 */
		hptab.d_active = 0;
		hptab.d_errcnt = 0;
		hptab.d_actf = dp->b_forw;
		dp->d_active = 0;
		dp->d_errcnt = 0;
		dp->d_actf = bp->av_forw;
		bp->b_resid = HPADDR->hpwc;
		iodone(bp);
		HPADDR->hpcs1 = IE|RELEASE|GO;
		hpustart(unit);
	}
	if (hptab.d_active==0)
		hpstart();
	} else
		HPADDR->hpcs1.hibyte = TRE>>8;
	for (unit=0; unit<NHP; unit++) {
		if (HPADDR->hpas&(1<<unit))
			hpustart(unit);
	}
	if ((HPADDR->hpcs1&IE)==0) {
		HPADDR->hpcs1 = IE;
		if (HPADDR->hpcs1&TRE)
			HPADDR->hpcs1.hibyte = TRE>>8;
	}
}

hpread(dev)
{

	if(hpphys(dev))
	physio(hpstrategy, &hpbuf, dev, B_READ);
}

hpwrite(dev)
{

	if(hpphys(dev))
	physio(hpstrategy, &hpbuf, dev, B_WRITE);
}

hpphys(dev)
{
	register c;

	c = lshift(u.u_offset, -9);
	c =+ ldiv(u.u_count+511, 512);
	if(c > hp_sizes[dev.d_minor & MASK].nblocks) {
		u.u_error = ENXIO;
		return(0);
	}
	return(1);
}