#
/*
 * RS03/04 disk driver
 */

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

struct hsregs {
	int	hscs1;	/* Control and Status register 1 */
	int	hswc;	/* Word count register */
	int	hsba;	/* UNIBUS address register */
	int	hsda;	/* Desired address register */
	int	hscs2;	/* Control and Status register 2 */
	int	hsds;	/* Drive Status */
	int	hser;	/* Error register */
	int	hsas;	/* not used */
	int	hsla;	/* not used */
	int	hsdb;	/* not used */
	int	hsmr;	/* not used */
	int	hsdt;	/* not used */
	int	hsbae;	/* 11/70 bus extension */
	int	hscs3;	/* 11/70 Control and status register 3 */
};

#define NHS	1
#define	HSADDR	0172040

struct	devtab	hstab;
struct	buf	rhsbuf;

struct	iostat	hsstat[NHS];
struct	errtab	hsetab { etabinit(E_BLK|E_RH70,NHS,HS,hsstat) };

#define ERR	040000	/* hscs1 - composite error */

#define GO	01
#define RCLR	010
#define	DRY	0200	/* hsds - Drive Ready */

#define	DK_N	0

hsopen(dev, flag)
{
	if((dev.d_minor&07) >= NHS)
		u.u_error = ENXIO;
}

hsstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register mblks;

	bp = abp;
	mblks = 1024; /* RJS03 */
	if(bp->b_dev.d_minor >= 8)
		mblks = 2048; /* RJS04 */
	if(bp->b_blkno >= mblks) {
		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;
	spl5();
	if (hstab.d_actf==0)
		hstab.d_actf = bp; else
		hstab.d_actl->av_forw = bp;
	hstab.d_actl = bp;
	if (hstab.d_active==0)
		hsstart();
	spl0();
}

hsstart()
{
	register struct buf *bp;
	register addr, minor;

	if ((bp = hstab.d_actf) == 0)
		return;
	hstab.d_active++;
	addr = bp->b_blkno;
	if((minor = bp->b_dev.d_minor) < 8)
		addr =<< 1; /* RJS03 */
	minor =& 07;
	hsetab.e_aunit = &hsstat[minor];
	hsetab.e_aunit->io_ops++;
	blkacty =| (1<<HS);
	HSADDR->hscs2 = minor;
	rhstart(bp, &HSADDR->hsda, addr<<1, &HSADDR->hsbae);
	dk_busy =| 1<<DK_N;
	dk_numb[DK_N] =+ 1;
	dk_wds[DK_N] =+ (-bp->b_wcount>>5) & 03777;
}

hsintr()
{
	register struct buf *bp;
	struct hsregs hsregs[0];

	if (hstab.d_active == 0)
		return;
	bp = hstab.d_actf;
	blkacty =& ~(1<<HS);
	dk_busy =& ~(1<<DK_N);
	hstab.d_active = 0;
	if(HSADDR->hscs1 & ERR){	/* error bit */
/*		deverror(bp, HSADDR->hscs2, 0);/**/
		fmtblk(&hsetab,HSADDR,sizeof(hsregs[0])/2,bp);
		HSADDR->hscs1 = RCLR|GO;
		hsetab.e_aunit->io_misc++;
		if (hstab.d_errcnt < 10) {
			if(hstab.d_errcnt++ == 0)
				logerr(&hsetab,E_FIRST);
			hsstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	if(hsetab.e_emsg != NULL)
		logerr(&hsetab,E_RETRY);
	hstab.d_errcnt = 0;
	hstab.d_actf = bp->av_forw;
	bp->b_resid = HSADDR->hswc;
	iodone(bp);
	hsstart();
}

hsread(dev)
{

	physio(hsstrategy, &rhsbuf, dev, B_READ,
		dev.d_minor >= 8 ? 2048 : 1024);
}

hswrite(dev)
{

	physio(hsstrategy, &rhsbuf, dev, B_WRITE,
		dev.d_minor >= 8 ? 2048 : 1024);
}
