#
/*
 */

/*
 * RP04 disk driver
 *
 * This driver has been tested on a working RP04 for a few hours.
 * It does not attempt ECC error correction and is probably
 * deficient in general in the case of errors and when packs
 * are dismounted.
 */

#include "../param.h"
#include "../buf.h"
#include "../conf.h"
#include "../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	hpca;	/* Desired Cylinder address register*/
	int	hpcc;	/* Current Cylinder */
	int	hper2;	/* Error register 2 */
	int	hper3;	/* Error register 3 */
	int	hppos;	/* Burst error bit position */
	int	hppat;	/* Burst error bit pattern */
	int	hpbae;	/* 11/70 bus extension */
};

#define	HPADDR	0176700
#define	NHP	8

struct {
	char	*nblocks;
	int	cyloff;
} hp_sizes[] {
	9614,	0,		/* cyl 0 thru 23 */
				/* cyl 24 thru 43 available */
	-1,	44,		/* cyl 44 thru 200 */
	-1,	201,		/* cyl 201 thru 357 */
	20900,	358,		/* cyl 358 thru 407 */
				/* cyl 408 thru 410 blank */
	40600,	0,
	40600,	100,
	40600,	200,
	40600,	300,
};


struct	devtab	hptab;
char	hp_openf;

			/* Drive Commands */
#define	GO	01
#define	PRESET	020
#define	RECAL	06
#define RCLR	010
#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

hpopen()
{

	if(!hp_openf){
		hp_openf++;
		HPADDR->hpcs2 = CLR;
		HPADDR->hpcs1 = RCLR|GO;
		HPADDR->hpcs1 = PRESET|GO;
		HPADDR->hpof = FMT22;
	}
}

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

	bp = abp;
	p1 = &hp_sizes[bp->b_dev.d_minor&07];
	if (bp->b_dev.d_minor >= (NHP<<3) ||
	    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();
	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;

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

hpintr()
{
	register struct buf *bp;
	register int ctr;

	if (hptab.d_active == 0)
		return;
	bp = hptab.d_actf;
	hptab.d_active = 0;
	if (HPADDR->hpcs1 & ERR) {		/* error bit */
		if(HPADDR->hper1 & (DU|DTE|OPI)) {
			HPADDR->hpcs2 = CLR;
			HPADDR->hpcs1 = RECAL|GO;
			ctr = 0;
			while ((HPADDR->hpds&PIP) && --ctr);
		}
		HPADDR->hpcs1 = RCLR|GO;
		if (++hptab.d_errcnt <= 10) {
			hpstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	hptab.d_errcnt = 0;
	hptab.d_actf = bp->av_forw;
	bp->b_resid = HPADDR->hpwc;
	iodone(bp);
	hpstart();
}
