2.11BSD/sys/OTHERS/rx01/rx.c

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

/*
 * Rx disk driver
 */

#ifdef	never
static	char	SCCS_ID[]	= "@(#)rx.c	Ver. 1.2 6/83";
#endif

/*	This was taken and adapted from V7 unix
 *	The baroque ifdefs were to identify changes
 *	I made to handle UCB's Unibus Mapping routines
 *	They can be removed as soon as you're
 *	sure it works.
 */

#include "rx.h"
#if	NRX > 0
#include "param.h"
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/rxreg.h>
#include <sys/uba.h>

#define DK_N	0	/* Monitoring device number */

#define HZ	60	/* line frequency */
#define	NRXDR	4	/* Nbr logical drives per controller */
#define	RXSIZE	2002	/* Size of rx disk in sectors */
#define RXBLK	BSIZE/NRXBYTE	/* Size of block (512 bytes) in rx sectors */
#define	RXBLKTR	26	/* Nbr blocks per track */
#define	NRXBYTE	128	/* Nbr bytes in rx block */
#define	MAXERR	10	/* Nbr retries after error */
#define RXHANG	300	/* Maximum hang on a TR or DONE bit */

#define RXBUSY	1	/* Busy flag */
#define RXERROR	2	/* Error flag */
#define RXINIT	4	/* Initialize flag */

#define rxsa rxdb	/* Sector Address Register */
#define rxta rxdb	/* Track Address Register */
#define rxes rxdb	/* Error Status Register */

#define trwait() { register int n; \
    for (n = RXHANG; (rp->rxcs & TR) == 0; n -= 1) \
        if (n == 0) { dp->b_active |= RXERROR; break; } }
#define donewait() { register int n; \
    for (n = RXHANG; (rp->rxcs & DONE) == 0; n -= 1) \
        if (n == 0) { dp->b_active |= RXERROR; break; } }
#define getdb(n) { trwait (); n = rp->rxdb; }
#define putdb(n) { trwait (); rp->rxdb = n; }
#define errtst (((rp->rxcs & (ERROR|DONE)) != DONE) \
    || ((rp->rxdb & (CRC|PARITY|IDONE)) != 0) \
    || ((dp->b_active & RXERROR) != 0))
#define	exadr(x, y)	(((long) x << 16) | (unsigned) (y))

/*
 * Minor device field coding constants
 */
#define RXLDR	 03	/* Logical drive mask */
#define RXILEAVE 04	/* Interleave mask */
#define RXCTLR	 03	/* Controller shift */

extern struct rxdevice *rx_addr[];
/*
 * Rx handler work areas
 */
struct buf rxtab, rxutab[NRX];	/* rxdevice tables */

/*
 * Rx strategy
 */
rxstrategy (bp)
register struct buf *bp;
{
	register struct buf *dp;
	register int ctlr;

	ctlr = minor (bp->b_dev) >> RXCTLR;
	dp = &rxutab[ctlr];

	if(bp->b_flags & B_PHYS)
		mapalloc(bp);
	/* link buffer into i/o queue and start i/o */
	bp->b_resid = bp->b_bcount;
	bp->b_error = 0;
	spl4 ();
	bp->av_forw = NULL;
	if (dp->b_actf == NULL)
		dp->b_actf = bp;
	else
		dp->b_actl->av_forw = bp;
	dp->b_actl = bp;
	if (!dp->b_active)
		rxstart (ctlr);
	spl0 ();
}

/*
 * Do something
 */
rxstart (ctlr)
int ctlr;
{
	register struct buf *dp, *bp;
	register struct rxdevice *rp;
	unsigned int bx;
	char *ptr;
	long blk, lptr;
	int trk, sct, wd;
	struct	ubmap *ubp;

	dp = &rxutab[ctlr];
	rp = rx_addr[ctlr];
retry:
	if ((bp = dp->b_actf) == NULL)
		return;

	dp->b_active = RXBUSY;
	if ((bp->b_flags & B_READ) == 0) {
		/* output characters to buffer */
		rp->rxcs = FILL|GO;
		lptr = exadr(bp->b_xmem, bp->b_un.b_addr);
		if(bp->b_flags & (B_MAP|B_UBAREMAP)) {
			/*
			 * Simulate UNIBUS map if UNIBUS transfer
			 * This is untested.
			 */
			ubp = UBMAP + ((lptr >> 13) & 037);
			lptr = exadr(ubp->ub_hi, ubp->ub_lo) + (lptr & 017777);
		}
		lptr += (long) (bp->b_bcount - bp->b_resid);
		for (bx = 0; bx < NRXBYTE; bx += 1) {
			wd = (bp->b_resid > bx) ? getmemc(lptr) : 0;
			putdb(wd);
			lptr++;
		}
		donewait ();
		if (errtst) {
			if (rxerror (ctlr)) goto retry;
			return;
		}
	}
/* calculate drive, block, track and sector number for i/o */
	blk = (bp->b_blkno << 2)
	    + (bp->b_bcount - bp->b_resid) / NRXBYTE;
	if ((blk >= RXSIZE) || (blk < 0)) {
		if ((blk > ((RXSIZE+RXBLK-1)/RXBLK*RXBLK))
		    || (blk < 0)
		    || ((bp->b_flags & B_READ) == 0)) {
			/* errors on writes don't actually do any good;
			*  nobody listens to them */
			bp->b_flags |= B_ERROR;
			bp->b_error = ENXIO;
		}
		rxdone (ctlr);
		goto retry;
	}
	trk = blk / RXBLKTR;
	sct = blk % RXBLKTR;

/* if indicated, interleave sectors using DEC's RT-11 algorithm */
	if (minor (bp->b_dev) & RXILEAVE) {
		if ((sct <<= 1) >= RXBLKTR){
			sct++;
		}
		sct = (sct + 6 * trk) % RXBLKTR;
		if (++trk >= (RXSIZE / RXBLKTR)){
			trk = 0;
		}
	}
	sct += 1;

/* perform read/write */
	rp->rxcs = IENABLE
		| GO
		| (bp->b_flags & B_READ ? READ : WRITE)
		| ((minor (bp->b_dev) & RXLDR) << 4);
	putdb (sct);
	putdb (trk);
}

/*
 * Initialize a controller
 */
rxinit (ctlr)
int ctlr;
{
	register struct buf *dp;
	int rxwaker ();


	dp = &rxutab[ctlr];
	if ((dp->b_active & RXINIT) == 0) {
		rx_addr[ctlr]->rxcs = INIT;
		dp->b_active |= RXINIT;
		timeout (rxwaker, ctlr, HZ*3/2);
	}
}

/*
 * Wake up after initialize operation
 */
rxwaker (ctlr)
int ctlr;
{
	register struct buf *dp;
	register struct rxdevice *rp;


	dp = &rxutab[ctlr];
	rp = rx_addr[ctlr];
	dp->b_active &= ~RXINIT;
	if (((rp->rxcs & (DONE|ERROR)) != DONE)
	    || ((rp->rxes & IDONE) == 0)) {
		if (rxerror (ctlr)) rxstart (ctlr);
		return;
	}
	rxstart (ctlr);
}

/*
 * Restart after power fail
 */
rxrstrt (flg)
int flg;
{
	register struct buf *dp;
	register int ctlr;

	if (flg == 0) {
		for (ctlr = 0; ctlr < NRX; ctlr += 1) {
			dp = &rxutab[ctlr];
			if ((dp->b_active & RXBUSY) != 0)
				dp->b_active |= RXERROR;
		}
	}
	else {
		for (ctlr = 0; ctlr < NRX; ctlr += 1) {
			dp = &rxutab[ctlr];
			if ((dp->b_active & RXBUSY) != 0)
				if (rxerror (ctlr)) rxstart (ctlr);
		}
	}
}

/*
 * Interrupt-time stuff
 */
rxintr (ctlr)
int ctlr;
{
	register struct buf *dp, *bp;
	register struct rxdevice *rp;
	unsigned int bx;
	char *ptr, byte;
	long lptr;
	int wd;
	struct	ubmap *ubp;

	dp = &rxutab[ctlr];
	if (!dp->b_active) {
		return;
	}
	rp = rx_addr[ctlr];
	bp = dp->b_actf;
	if (errtst) {
		if (rxerror (ctlr)) rxstart (ctlr);
		return;
	}
	if (bp->b_flags & B_READ) {
		/* input data from buffer */
		rp->rxcs = EMPTY|GO;
		lptr = exadr(bp->b_xmem, bp->b_un.b_addr);
		if(bp->b_flags & (B_MAP|B_UBAREMAP)) {
			/*
			 * Simulate UNIBUS map if UNIBUS transfer
			 * This is untested.
			 */
			ubp = UBMAP + ((lptr >> 13) & 037);
			lptr = exadr(ubp->ub_hi, ubp->ub_lo) + (lptr & 017777);
		}
		lptr += (long) (bp->b_bcount - bp->b_resid);
		for (bx = 0; bx < NRXBYTE; bx += 1) {
			getdb(byte);
			putmemc(lptr, ((bp->b_resid > bx) ? byte : 0));
			lptr++;
		}
		donewait ();
		if (errtst) {
			if (rxerror (ctlr)) rxstart (ctlr);
			return;
		}
	}
	if (bp->b_resid <= NRXBYTE) {
		bp->b_resid = 0;
		rxdone (ctlr);
	}
	else {
		bp->b_resid -= NRXBYTE;
		dp->b_errcnt = 0;
	}
	rxstart (ctlr);
}

rxdone (ctlr)
int ctlr;
{
	register struct buf *dp, *bp;


	dp = &rxutab[ctlr];
	bp = dp->b_actf;
	dp->b_active = 0;
	dp->b_errcnt = 0;
	dp->b_actf = bp->av_forw;
	iodone (bp);
}

rxerror (ctlr)
int ctlr;
{
	register struct buf *dp, *bp;
	register struct rxdevice *rp;


	dp = &rxutab[ctlr];
	bp = dp->b_actf;
	rp = rx_addr[ctlr];
	dp->b_active &= ~RXERROR;
	/* quit if too many errors */
	dp->b_errcnt += 1;
	if (dp->b_errcnt > MAXERR) {
#ifdef UCB_DEVERR
		harderr (bp, "rx");
		printf("active=%d, cs=0%o", dp->b_active, rp->rxcs);
#else
		deverror (bp, dp->b_active, rp->rxcs);
#endif
		bp->b_flags |= B_ERROR;
		rxdone (ctlr);
	}
	else if (!(rp->rxcs & DONE) || !(rp->rxes & (CRC|PARITY))) {
		rxinit (ctlr);
		return (0);
	}
	return (1);
}
#endif	NRX