Interdata_v6/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);
}