#
/*
 * RP04 disk driver
 */

#include "../head/param.h"
#include "../head/systm.h"
#include "../head/buf.h"
#include "../head/conf.h"
#include "../head/user.h"
#include "../head/userx.h"
#include "../head/elog.h"

#define NSECT	22	/* 22 sectors per track */
#define NTRACK	19
#define NCYL	NSECT*NTRACK	/* 418 sectors per cylinder */

struct hpregs {
	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

struct {
	char	*nblocks;
	int	cyloff;
} hp_sizes[] {
	23*NCYL,	0,		/*  0: cyl   0 thru  22 incl.  */
					/*     cyl  23 thru  43 incl. unused */
	65535l,		44,		/*  1: cyl  44 thru 200 incl. (158) */
	65535l,		201,		/*  2: cyl 201 thru 357 incl.  */
	50*NCYL,	358,		/*  3: cyl 358 thru 407 incl.  */
					/*     cyl 408 thru 410 incl. unused */
	100*NCYL,	0,		/*  4: cyl   0 thru  99 incl. */
	100*NCYL,	100,		/*  5: cyl 100 thru 199 incl.  */
	99*NCYL,	201,		/*  6: cyl 201 thru 299 incl.  */
	100*NCYL,	300,		/*  7: cyl 300 thru 399 incl. */
	44*NCYL,	0,		/*  8: cyl   0 thru  43 incl. */
	65535l,		44,		/*  9: cyl  44 thru 201 incl.(158) */
	65535l,		202,		/* 10: cyl 202 thru 359 incl.(158) */
	48*NCYL,	360,		/* 11: cyl 360 thru 407 incl. */
	65535l,		408,		/* 12: cyl 408 thru 565 incl.(158) */
	65535l,		566,		/* 13: cyl 566 thru 723 incl.(158) */
	89*NCYL,	724,		/* 14: cyl 724 thru 812 incl. */
					/*     cyl 813 thru 814 spare */
	79*NCYL,	44,		/* 15: cyl  44 thru 122 incl. */
	79*NCYL,	123,		/* 16: cyl 123 thru 201 incl. */
	79*NCYL,	202,		/* 17: cyl 202 thru 280 incl. */
	79*NCYL,	281,		/* 18: cyl 281 thru 359 incl. */
					/*     cyl 360 thru 379 spare */
	28*NCYL,	380,		/* 19: cyl 380 thru 407 incl. */
	79*NCYL,	408,		/* 20: cyl 408 thru 486 incl. */
	79*NCYL,	487,		/* 21: cyl 487 thru 565 incl. */
	79*NCYL,	566,		/* 22: cyl 566 thru 644 incl. */
	79*NCYL,	645,		/* 23: cyl 645 thru 723 incl. */
					/* Negative Filesystems */
					/* Backward version of first 8 filsys */
	NCYL*23,	-22,		/* 24: cyl   0 thru  23 incl. rev.  */
					/*     cyl  24 thru  43 incl. unused */
	65535l,		-200,		/* 25: cyl  44 thru 200 incl. (158) */
	65535l,		-357,		/* 26: cyl 201 thru 357 incl. (158) */
	50*NCYL,	-407,		/* 27: cyl 358 thru 407 incl. rev.  */
					/*     cyl 408 thru 410 incl. unused */
	100*NCYL,	-99,		/* 28: cyl   0 thru  99 incl. rev.  */
	100*NCYL,	-199,		/* 29: cyl 100 thru 199 incl. rev.  */
	99*NCYL,	-299,		/* 30: cyl 201 thru 299 incl. rev.  */
	100*NCYL,	-399,		/* 31: cyl 300 thru 399 incl. rev.  */
};
/*
 * NOTE: THE SWAP AREA MAY NOT BE ON AN INVERTED DISK AREA
 */


struct	devtab	hptab;
struct	buf	rhpbuf;

struct	iostat	hpstat[NHP];
struct	errtab	hpetab { etabinit(E_BLK|E_RH70,NHP,HP,hpstat) };

			/* Drive Commands */
#define	GO	01
#define	PRESET	020
#define	RECAL	06
#define RCLR	010
#define VV	0100
#define OFFSET	014

#define	READY	0200	/* hpds - drive ready */
#define	PIP	020000	/* hpds - Positioning Operation in Progress */
#define	ERR	040000	/* hpcs1 - composite error */

#define	DU	040000	/* hper1 - Drive Unsafe	*/
#define	DTE	010000  /* hper1 - Drive Timing Error	*/
#define	OPI	020000  /* hper1 - Operation Incomplete	*/
		/* Error Correction Code errors */
#define DCK	0100000	/* hper1 - Data Check error */
#define ECH	0100    /* hper1 - ECC hard error */

#define CLR	040	/* hpcs2 - Controller Clear */

#define FMT22	010000	/* hpof - 16 bit /word format */
/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */

#define	trksec	av_back
#define	cylin	b_resid

#define	DK_N	2

hpopen(dev, flag)
{
	if(dev.d_minor >= (NHP<<5))
		u.u_error = ENXIO;
}

hpstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char *p1, *p2;
	char	*p3;

	bp = abp;
	p3 = p1 = &hp_sizes[bp->b_dev.d_minor&037];
	if(bp->b_blkno >= p1->nblocks){
		if (bp->b_flags&B_READ)
			bp->b_resid = bp->b_wcount;
		else{
			bp->b_flags =| B_ERROR;
			bp->b_error = ENXIO;
		}
		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;
	if(p3->cyloff < 0){
		bp->cylin = -bp->cylin;
	}
	spl5();
	if ((p1 = hptab.d_actf)==0)
		hptab.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 (hptab.d_active==0)
		hpstart();
	spl0();
}

hpstart()
{
	register struct buf *bp;
	register unit;

	if ((bp = hptab.d_actf) == 0)
		return;
	hptab.d_active++;
	unit = (bp->b_dev.d_minor>>5)&07;
	HPADDR->hpcs2 = unit;
	hpetab.e_aunit = &hpstat[unit];
	if((HPADDR->hpds&VV) == 0) {
		HPADDR -> hpcs1 = PRESET | GO;
		HPADDR -> hpof = FMT22;
		hpetab.e_aunit->io_misc++;
	}
	hpetab.e_aunit->io_ops++;
	blkacty =| (1<<HP);
	HPADDR->hpdc = bp->cylin;
	rhstart(bp, &HPADDR->hpda, bp->trksec, &HPADDR->hpbae);
	dk_busy =| 1<<DK_N;
	dk_numb[DK_N] =+ 1;
	dk_wds[DK_N] =+ (-bp->b_wcount>>5) & 03777;
}

hpintr()
{
	register struct buf *bp;
	struct hpregs hpregs[0];
	int ctr;

	if (hptab.d_active == 0)
		return;
	bp = hptab.d_actf;
	hptab.d_active = 0;
	blkacty =& ~(1<<HP);
	dk_busy =& ~(1<<DK_N);
	if (HPADDR->hpcs1 & ERR) {		/* error bit */
/*		deverror(bp, HPADDR->hpcs2);/**/
		fmtblk(&hpetab,HPADDR,sizeof(hpregs[0])/2,bp);
		if(HPADDR->hper1 & (DU|DTE|OPI)) {
			HPADDR->hpcs2 = CLR;
			HPADDR->hpcs1 = RECAL|GO;
			hpetab.e_aunit->io_misc++;
			ctr = 0;
			while ((HPADDR->hpds&PIP) && --ctr);
		}
		HPADDR->hpcs1 = RCLR|GO;
		if (hptab.d_errcnt < 10) {
			if(hptab.d_errcnt++ == 0)
				logerr(&hpetab,E_FIRST);
			hpstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	if(hpetab.e_emsg != NULL)
		logerr(&hpetab,E_RETRY);
	hptab.d_errcnt = 0;
	hptab.d_actf = bp->av_forw;
	bp->b_resid = HPADDR->hpwc;
	iodone(bp);
	hpstart();
}

hpread(dev)
{
	register nblks;
	register char *p1;

	p1 = &hp_sizes[dev.d_minor&037];
	nblks = p1->nblocks;
	if(p1->cyloff<0){
		if(negcyl(hpstrategy, &rhpbuf, dev, B_READ, nblks, NCYL))
			return;
		if(u.u_error)
			return;
	}
	physio(hpstrategy, &rhpbuf, dev, B_READ, nblks);
}

hpwrite(dev)
{
	register nblks;
	register char *p1;

	p1 = &hp_sizes[dev.d_minor&037];
	nblks = p1->nblocks;
	if(p1->cyloff<0){
		if(negcyl(hpstrategy, &rhpbuf, dev, B_WRITE, nblks, NCYL))
			return;
		if(u.u_error)
			return;
	}
	physio(hpstrategy, &rhpbuf, dev, B_WRITE, nblks);
}
