SysIII/usr/src/uts/pdp11/io/rl.c

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

/*
 *  RL disk driver
 */

#include "sys/param.h"
#include "sys/buf.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/systm.h"
#include "sys/elog.h"
#include "sys/iobuf.h"

#define NBLK1 10240
#define NBLK2 20480
#define RL02 0200	/* bit 7 indicates an rl02 present if set */
#define RLCYLSZ 10240
#define RLSECSZ 256

#define RESET 013
#define STAT 03
#define GETSTAT 04
#define WCOM 012
#define RCOM 014
#define SEEK 06
#define SEEKHI 5
#define SEEKLO 1
#define RDHDR 010
#define IENABLE 0100
#define CRDY 0200
#define OPI 02000
#define CRCERR 04000
#define TIMOUT 010000
#define NXM 020000
#define DE  040000

struct device
{
	short rlcs, rlba, rlda, rlmp;
};

struct	device	*rl_addr[];
short	rl_cnt;

struct 
{
	short	cn[8];		/* location of heads for each drive */
	short	dn;		/* drive number */
	short	com;		/* read or write command word */
	short	chn;		/* cylinder and head number */
	unsigned bleft;		/* bytes left to be transferred */
	unsigned bpart;		/* number of bytes transferred */
	short	sn;		/* sector number */
	paddr_t	addr;		/* address of memory for transfer */

}	rl = {-1,-1,-1,-1,-1,-1,-1,-1};

int nblk[4] = {-1, -1, -1, -1} ;
struct	iostat	rlstat[4];
struct	iobuf	rltab =	tabinit(RL0,rlstat);
struct	buf	rrlbuf;

rlopen(dev)
{
	struct device *dp;
	int dnum = minor(dev)&03;

	if(dev>=rl_cnt) {
		u.u_error = ENXIO;
		return;
	}
	spl5();
	dp = rl_addr[dev>>2];
	if( nblk[dnum] == -1) {
		dp->rlda = STAT;
		dp->rlcs = (dnum<<8) | GETSTAT ;
		while ( (dp->rlcs & CRDY) == 0)
			;
		nblk[dnum]=(dp->rlmp & RL02) ? NBLK2 : NBLK1 ;
	}
	spl0();
	rltab.io_addr = (physadr)rl_addr[dev>>2];
	rltab.io_nreg = NDEVREG;
	if ((rltab.b_flags&B_ONCE)==0) {
		rltab.b_flags |= B_ONCE;
		rltab.io_s1 = ubmalloc(0-1);
	}
}

rlclose(dev)
{
}

rlstrategy(bp)
register struct buf *bp;
{
	if(bp->b_blkno >= nblk[minor(bp->b_dev)&03]) {
		if(bp->b_blkno == nblk[minor(bp->b_dev)&03] && bp->b_flags&B_READ)
			bp->b_resid = bp->b_bcount;
		else {
			bp->b_flags |= B_ERROR;
			bp->b_error = ENXIO;
		}
		iodone(bp);
		return;
	}
	bp->av_forw = NULL;
	spl5();
	if(rltab.b_actf == NULL)
		rltab.b_actf = bp;
	else
		rltab.b_actl->av_forw = bp;
	rltab.b_actl = bp;
	if(rltab.b_active == 0)
		rlstart();
	spl0();
}

rlstart()
{

	register struct device *rp;
	register struct buf *bp;

	if ((bp = rltab.b_actf) == NULL)
		return;
	rltab.b_active++;
	rl.dn = minor(bp->b_dev)&3;
	rl.chn = bp->b_blkno/20;
	rl.sn = (bp->b_blkno%20) << 1;
	rl.bleft = bp->b_bcount;
	rl.addr = ubmaddr(bp,rltab.io_s1);
	rl.com = (rl.dn << 8) | IENABLE;
	if (bp->b_flags & B_READ)
		rl.com |= RCOM;
	else
		rl.com |= WCOM;
	rp = rl_addr[minor(bp->b_dev)>>2];
	rlio(rp);
}

rlintr()
{

	register struct buf *bp;
	register struct device *rp;
	register short status;

	bp = rltab.b_actf;
	rp = rl_addr[minor(bp->b_dev)>>2];
	if (rltab.b_active == 0) {
		logstray(rp);
		return;
	}
	blkacty &= ~(1<<RL0);
	bp = rltab.b_actf;
	if (rp->rlcs < 0) {		/* error bit */
		if (rp->rlcs & 036000) {
			rltab.io_stp = &rlstat[minor(bp->b_dev)];
			fmtberr(&rltab,0);
			if(rltab.b_errcnt > 2)
				deverr(&rltab, rp->rlcs, rp->rlda);
		}
		if (rp->rlcs & 040000) {
			rp->rlda = STAT;
			rlstat[minor(bp->b_dev)].io_misc++;
			rp->rlcs = (rl.dn << 8) | GETSTAT;
			while ((rp->rlcs & CRDY) == 0)
				;
			status = rp->rlmp;
			if(!status&01000 || rl.cn[rl.dn] != -1) {
				rltab.io_stp = &rlstat[minor(bp->b_dev)];
				fmtberr(&rltab,0);
				if(rltab.b_errcnt > 2)
					deverr(&rltab, status, rp->rlda);
			}
			rp->rlda = RESET;
			rp->rlcs = (rl.dn << 8) | GETSTAT;
			while ((rp->rlcs & CRDY) == 0)
				;
			if(status & 01000) {
				rlstart();
				return;
			}
		}
		if (++rltab.b_errcnt <= 10) {
			rl.cn[rl.dn] = -1;
			rlstart();
			return;
		}
		bp->b_flags |= B_ERROR;
		rl.bpart = rl.bleft;
	}

	if ((rl.bleft -= rl.bpart) > 0) {
		rl.addr += rl.bpart;
		rl.sn=0;
		rl.chn++;
		rlio(rp);
		return;
	}
	if(rltab.io_erec)
		logberr(&rltab,bp->b_flags&B_ERROR);
	rltab.b_active = 0;
	rltab.b_errcnt = 0;
	rltab.b_actf = bp->av_forw;
	bp->b_resid = 0;
	iodone(bp);
	rlstart();
}

rlio(rp)
register struct device *rp;
{

	register dif,head;
	
	if (rl.cn[rl.dn] < 0) {
		rlstat[rl.dn].io_misc++;
		blkacty |= (1<<RL0);
		rp->rlcs = (rl.dn << 8) | RDHDR;
		while ((rp->rlcs&CRDY) == 0)
			;
		blkacty &= ~(1<<RL0);
		rl.cn[rl.dn] = (rp->rlmp&077700) >> 6;
	}
	dif =(rl.cn[rl.dn] >> 1) - (rl.chn >>1);
	head = (rl.chn & 1) << 4;
	if (dif < 0)
		rp->rlda = (-dif <<7) | SEEKHI | head;
	else
		rp->rlda = (dif << 7) | SEEKLO | head;
	rlstat[rl.dn].io_misc++;
	blkacty |= (1<<RL0);
	rp->rlcs = (rl.dn << 8) | SEEK;
	while ((rp->rlcs&CRDY) == 0)
		;
	blkacty &= ~(1<<RL0);
	rl.cn[rl.dn] = rl.chn;
	if (rl.bleft < (rl.bpart = RLCYLSZ - (rl.sn * RLSECSZ)))
		rl.bpart = rl.bleft;
	rp->rlda = (rl.chn << 6) | rl.sn;
	rp->rlba = loword(rl.addr);
	rp->rlmp = -(rl.bpart >> 1);
	rlstat[rl.dn].io_ops++;
	blkacty |= (1<<RL0);
	rp->rlcs = rl.com | hiword(rl.addr) << 4;
}

rlread(dev)
{

	if (physck((daddr_t) nblk[minor(dev)&03], B_READ))
		physio(rlstrategy, &rrlbuf, dev, B_READ);
}

rlwrite(dev)
{

	if (physck((daddr_t)nblk[minor(dev)&03],B_WRITE))
		physio(rlstrategy, &rrlbuf, dev, B_WRITE);
}

rlclr()
{
	rltab.b_active = 0;
	rlstart();
}