Interdata732/usr/sys/dsk.c_old

#

#include "param.h"
#include "buf.h"
#include "conf.h"
#include "selch.h"

/*
 * 10-mb cartridge disk driver
 */

int dskseek(), dskscintr(), dsknrdy();

struct devtab	dsktab;
struct buf	rdskbuf;

struct selchq dskscq {
	&dskseek,
	&dskscintr,
	0
};

int	dskfile;
int	dskcyl;
int	dsksector;
int	dsksad, dskead;
int	dskseekf;
int	dskqlen;		/* current length of i/o queue
				   (for display only */

#define NDSK	4		/* number of disks */
#define NDSKBLK	9792		/* number of blocks on disk */
#define NDSKERR	10		/* number of error retries */

/* device addresses */

#define NSELCH	0	/* connected to first selch */

int	cntladdr	0xb6;		/* disk controller */
char	dskaddr[NDSK] {			/* disk files */
	0xc6,
	0xc7,
	0xd6,
	0xd7
};

/* disk file status & commands */

#define	UNRCV		0156
#define	ADDR_INTLK	0020
#define	WRT_PROT	0200
#define	NOT_READY	0001

#define	SEEK		0102

/* disk controller status & commands */

#define	CNTL_UNRCV	0341
#define	OVERRUN		0200
#define	CYL_OV		0020

#define	READ		0001
#define	WRITE		0002

/*
 *	disk strategy routine
 */
dskstrategy(abp)
{
	register struct buf *bp;

	bp = abp;
	bp->b_resid = bp->b_bcount;

	if (bp->b_dev.d_minor >= NDSK) {
		bp->b_flags =| B_ERROR;
		iodone(bp);
		return;
	}

	/*
	 * Block no. too high -- looks like EOF for raw read, error otherwise
	 */
	if (bp->b_blkno >= NDSKBLK) {
		if ((bp->b_flags&(B_PHYS|B_READ)) != (B_PHYS|B_READ))
			bp->b_flags =| B_ERROR;
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	spl(5);
	dskqlen = (dskqlen<<1) | 01;
	if (dsktab.d_actf == 0)
		dsktab.d_actf = bp;
	else
		dsktab.d_actl->av_forw = bp;
	dsktab.d_actl = bp;
	if (dsktab.d_active == 0)
		dskstart();
	spl(0);
}

/*
 * start next disk i/o operation
 *	- set up file address, cylinder/head/sector address
 *	- set up memory start & end addresses
 *	- check disk status
 *	- initiate seek
 */

dskstart()
{
	register struct buf *bp;
	register stat;

	if (!(bp = dsktab.d_actf))
		return;
	dsktab.d_active++;

	trace(01<<16, "dstart", bp);

	dskfile = dskaddr[bp->b_dev.d_minor];
	dskcyl = bp->b_blkno / 24;
	if ((dsksector = (bp->b_blkno<<1) % 48) > 23)
		dsksector =+ 32-24;

	dsksad = bp->b_addr;
	dskead = bp->b_addr + bp->b_bcount - 1;

	selchreq(NSELCH, &dskscq);
}

dskseek()
{
	register stat;

	trace(010<<16, "seek", dskfile);
	trace(010<<16, "cyl", dskcyl);

	while ((stat = ss(dskfile))&~WRT_PROT) {
		if (stat & ADDR_INTLK)
			continue;
		if (stat & NOT_READY) {
			selchfree(NSELCH);
			timeout(&dsknrdy, 0, 1000);
			return;
		}
		if (stat & UNRCV) {
			dsktab.d_errcnt = NDSKERR;
			dskerror(dsktab.d_actf, stat, dskfile);
			return;
		}
	}
	dskseekf++;
	wh(dskfile, dskcyl);
	oc(dskfile, SEEK);
}

/*
 * disk not ready routine
 *	- retry I/O every 10 seconds until disk starts again
 */
dsknrdy()
{
	selchreq(NSELCH, &dskscq);
}

/*
 * disk interrupt routine
 *	-disk interrupts only after a seek (I hope)
 *	-check status, initiate read/write
 */

dskintr(dev,stat)
{
	register struct buf *bp;
	register scmd, ccmd;

	trace(020<<16, "interrupt", dev);
	trace(020<<16, "status", stat);

	if (!(bp = dsktab.d_actf) || !dskseekf)
		return;
	dskseekf = 0;

	if (stat & ~WRT_PROT) {
		dskerror(bp, stat, dskfile);
		return;
	}

	if (bp->b_flags & B_READ) {
		scmd = READ_GO;
		ccmd = READ;
	} else {
		scmd = GO;
		ccmd = WRITE;
	}

	trace(010<<16, "dcmd", ccmd);
	trace(010<<16, "sector", dsksector);

	oc(selchaddr[NSELCH], STOP);
	trace(010<<16, "bufstart", dsksad);
	trace(010<<16, "bufend", dskead);
	wdh(selchaddr[NSELCH], dsksad);
	wdh(selchaddr[NSELCH], dskead);
	wh(dskfile, dskcyl);
	wd(cntladdr, dsksector);
	oc(cntladdr, ccmd);
	oc(selchaddr[NSELCH], scmd);
}

/*
 * selch interrupt routine
 *	-selch interrupt will be followed by a controller interrupt
 *	 (unless OVERRUN status is set)
 */

dskscintr(dev, stat)
{
	register struct buf *bp;

	if (!(bp = dsktab.d_actf))
		return;

	oc(selchaddr[NSELCH], STOP);
	if ((stat = ss(cntladdr))&OVERRUN)
		dskerror(bp, stat, cntladdr);
}

/*
 * disk controller interrupt routine
 *	-check ending status, signal i/o done
 */

cntlintr(dev, stat)
{
	register struct buf *bp;
	trace(020<<16, "interrupt", dev);
	trace(020<<16, "status", stat);


	if (!(bp = dsktab.d_actf))
		return;
	if (dskseekf)
		return;

	if (stat & CNTL_UNRCV) {
		dskerror(bp, stat, cntladdr);
		return;
	}
	bp->b_resid = 0;

	/*
	 * Cylinder overflow
	 */
	if (stat & CYL_OV) {
		oc(selchaddr[NSELCH], STOP);
		dsksad =+ (rdh(selchaddr[NSELCH])-dsksad+2)&~0377;
		trace(020<<16, "cyl ov", dsksad);
		dsksector = 0;
		bp->b_resid = dskead - dsksad;
		if (++dskcyl < NDSKBLK/24) {
			dskseek();
			return;
		} else
			if ((bp->b_flags&(B_PHYS|B_READ)) != (B_PHYS|B_READ))
				bp->b_flags =| B_ERROR;
	}

	dsktab.d_errcnt = 0;
	dsktab.d_active = 0;
	dsktab.d_actf = bp->av_forw;
	dskqlen =>> 1;
	iodone(bp);
	selchfree(NSELCH);
	dskstart();
}

dskerror(abp, stat, addr)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	deverror(bp, stat, addr);
	if (++dsktab.d_errcnt <= NDSKERR) {
		dskseek();
		return;
	}
	dsktab.d_errcnt = 0;
	bp->b_flags =| B_ERROR;
	dsktab.d_active = 0;
	dsktab.d_actf = bp->av_forw;
	dskqlen =>> 1;
	iodone(bp);
	selchfree(NSELCH);
	dskstart();
}

/*
 * 'Raw' disc interface
 */
dskread(dev)
{
	physio(dskstrategy, &rdskbuf, dev, B_READ);
}

dskwrite(dev)
{
	physio(dskstrategy, &rdskbuf, dev, B_WRITE);
}