#
/*
 * RK 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"

#define	NRK	4
#define	NRKBLK	4872
#define	RKADDR	0177400

#define	RESET	0
#define	GO	01
#define	DRESET	014
#define	IENABLE	0100
#define	DRY	0200
#define	ARDY	0100
#define	WLO	020000
#define	CTLRDY	0200

/*
 * Monitoring device bit
 */
#define	DK_N	1

struct rkregs {
	int rkds;
	int rker;
	int rkcs;
	int rkwc;
	int rkba;
	int rkda;
};

struct	devtab	rktab;
struct	buf	rrkbuf;

struct	iostat	rkstat[NRK];
struct	errtab	rketab { etabinit(E_BLK,NRK,RK,rkstat) };

rkopen(dev, flag)
{
	if((dev.d_minor&07) >= NRK)		/* even in interleaved, max */
		u.u_error = ENXIO;	/* unit num must be < NRK */
}

rkstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register int d;

	bp = abp;
	if(bp->b_flags&B_PHYS)
		mapalloc(bp);
	d = bp->b_dev.d_minor-7;
	if(d <= 0)
		d = 1;
	if (bp->b_blkno >= NRKBLK*d) {
		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 (rktab.d_actf==0)
		rktab.d_actf = bp;
	else
		rktab.d_actl->av_forw = bp;
	rktab.d_actl = bp;
	if (rktab.d_active==0)
		rkstart();
	spl0();
}

rkaddr(bp)
struct buf *bp;
{
	register int b, d, m;

	b = bp->b_blkno;
	m = bp->b_dev.d_minor - 7;
	if(m <= 0)
		d = bp->b_dev.d_minor;
	else {
		d = lrem(b, m);
		b = ldiv(b, m);
	}
	rketab.e_aunit = &rkstat[d];
	return(d<<13 | (b/12)<<4 | b%12);
}

rkstart()
{
	register struct buf *bp;
	register a;

	if ((bp = rktab.d_actf) == 0)
		return;
	rktab.d_active++;
	a = rkaddr(bp);		/* also sets e_aunit */
	rketab.e_aunit->io_ops++;
	blkacty =| (1<<RK);
	devstart(bp, &RKADDR->rkda, a, 0);
	dk_busy =| 1<<DK_N;
	dk_numb[DK_N] =+ 1;
	dk_wds[DK_N] =+ (-bp->b_wcount>>5) & 03777;
}

rkintr()
{
	register struct buf *bp;
	struct rkregs rkregs[0];

	if (rktab.d_active == 0)
		return;
	blkacty =& ~(1<<RK);
	dk_busy =& ~(1<<DK_N);
	bp = rktab.d_actf;
	rktab.d_active = 0;
	if (RKADDR->rkcs < 0) {		/* error bit */
/*		deverror(bp, RKADDR->rker, RKADDR->rkds); /**/
		fmtblk(&rketab,RKADDR,sizeof(rkregs[0])/2,bp);
		RKADDR->rkcs = RESET|GO;
		rketab.e_aunit->io_misc++;
		while((RKADDR->rkcs&CTLRDY) == 0) ;
		if (rktab.d_errcnt < 10) {
			if(rktab.d_errcnt++ == 0)
				logerr(&rketab,E_FIRST);
			rkstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	if(rketab.e_emsg != NULL)
		logerr(&rketab,E_RETRY);
	rktab.d_errcnt = 0;
	rktab.d_actf = bp->av_forw;
	bp->b_resid = RKADDR->rkwc;
	iodone(bp);
	rkstart();
}

rkread(dev)
{
	register nblks;

	nblks = dev.d_minor - 7;
	if (nblks <= 0)
		nblks = 1;


	physio(rkstrategy, &rrkbuf, dev, B_READ, NRKBLK*nblks);
}

rkwrite(dev)
{
	register nblks;

	nblks = dev.d_minor - 7;
	if (nblks <= 0)
		nblks = 1;

	physio(rkstrategy, &rrkbuf, dev, B_WRITE, NRKBLK*nblks);
}
