SysIII/usr/src/uts/vax/io/dmb.c
#include "sys/param.h"
#include "sys/buf.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/tty.h"
#include "sys/uba.h"
#include "sys/systm.h"
#include "sys/ioctl.h"
struct device *dmb_addr[];
struct device {
union {
char b[8];
short w[4];
} un;
};
#define bsel0 un.b[0]
#define bsel1 un.b[1]
#define bsel2 un.b[2]
#define bsel3 un.b[3]
#define bsel4 un.b[4]
#define bsel5 un.b[5]
#define bsel6 un.b[6]
#define bsel7 un.b[7]
#define sel0 un.w[0]
#define sel2 un.w[1]
#define sel4 un.w[2]
#define sel6 un.w[3]
int dmb_cnt;
#define RWMAX 7
#define MAXBUF 8192
#define RDYSCAN 16 /* loop delay for RDYI after RQI */
#define PRIDMC (PZERO+1)
#define NRD 3 /* number read buffers */
#define NWR 2 /* number write buffers */
/* Defines for bsel0 and bsel2 */
#define BACCI 0
#define CNTLI 1
#define PERR 2
#define BASEI 3
#define INX 0 /* transmit block */
#define INR 4 /* read block */
#define RQI 040 /* port request bit */
#define IEI 0100 /* enable input interrupts */
#define RDYI 0200 /* port ready */
#define BACCO 0
#define CNTLO 1
#define OUX 0 /* transmit block */
#define OUR 4 /* read block */
#define IEO 0100 /* enable output interrupts */
#define RDYO 0200 /* port available */
#define MCLR 0100 /* DMC11 Master Clear */
/* Defines for CNTLI mode */
#define HDPLX 02000 /* half duplex DDCMP operation */
#define SEC 04000 /* half duplex secondary station */
#define MAINT 0400 /* enter maintenance mode */
/* Defines for BACCI/O and BASEI mode */
#define DMXMEM 0140000 /* xmem bit position */
#define CCOUNT 037777 /* character count mask */
#define RESUME 02000 /* resume (BASEI only) */
/* Defines for CNTLO */
#define CNTMASK 01777
#define FATAL 01620
struct dmb {
short d_flag;
struct buf *d_next;
struct buf *d_rdy[2];
struct clist d_que;
char d_rwq[2];
short d_ioc[12];
int d_map[2];
short d_base[128];
};
#define DMCACT 1
#define DMCRUN 2
#define DMCBUF 4
#define NDMC 2
struct dmb dmb_dmb[NDMC];
dmbopen(dev)
{
register struct dmb *mp;
paddr_t base;
if (dev >= dmb_cnt || dev >= NDMC) {
u.u_error = ENXIO;
return;
}
mp = &dmb_dmb[dev];
mp->d_flag |= DMCACT;
if ((mp->d_flag&DMCRUN) == 0) {
mp->d_flag |= DMCRUN;
dmb_addr[dev]->bsel2 |= IEO;
base = ubmdata(mp->d_base);
dmbload(mp, BASEI, loword(base), hiword(base)<<14);
dmbload(mp, CNTLI, 0, 0);
}
if ((mp->d_flag&DMCBUF) == 0) {
register i;
register struct buf *bp;
mp->d_flag |= DMCBUF;
mp->d_rdy[B_READ] = NULL;
mp->d_rdy[B_WRITE] = NULL;
for (i=0; i<NRD; i++) {
bp = geteblk();
bp->b_dev = dev;
bp->b_flags = B_READ;
dmbstrategy(bp);
}
for (i=0; i<NWR; i++) {
bp = geteblk();
bp->b_dev = dev;
bp->b_flags = B_WRITE;
bp->av_forw = mp->d_rdy[B_WRITE];
mp->d_rdy[B_WRITE] = bp;
}
}
}
dmbclose(dev)
{
register struct dmb *mp;
register struct buf *bp;
mp = &dmb_dmb[dev];
mp->d_flag &= ~DMCACT;
if (mp->d_flag&DMCRUN) {
dmbload(mp, PERR, 0, 0);
} else if (mp->d_flag&DMCBUF) {
mp->d_flag &= ~DMCBUF;
while (bp = mp->d_rdy[B_READ]) {
mp->d_rdy[B_READ] = bp->av_forw;
brelse(bp);
}
while (bp = mp->d_rdy[B_WRITE]) {
mp->d_rdy[B_WRITE] = bp->av_forw;
brelse(bp);
}
}
}
dmbstrategy(bp)
register struct buf *bp;
{
register struct dmb *mp;
register struct buf *abp;
int sps;
mp = &dmb_dmb[minor(bp->b_dev)];
bp->b_flags &= ~B_STALE;
bp->av_forw = NULL;
sps = spl5();
if ((abp = mp->d_next) == NULL)
mp->d_next = bp;
else {
while (abp->av_forw)
abp = abp->av_forw;
abp->av_forw = bp;
}
dmbstart(mp, bp->b_flags&B_READ);
splx(sps);
}
dmbstart(mp, flag)
register struct dmb *mp;
{
register struct buf *bp;
register count;
paddr_t addr;
if ((bp = mp->d_next) == NULL)
return;
do {
if ((bp->b_flags&(B_STALE|B_READ))!=flag)
continue;
if (mp->d_rwq[flag] >= RWMAX)
return;
mp->d_rwq[flag]++;
bp->b_flags |= B_STALE;
count = bp->b_bcount;
if (flag == B_WRITE)
count -= bp->b_resid;
addr = ubmaddr(bp, mp->d_map[flag]);
dmbload(mp, flag<<2, loword(addr),
(count&CCOUNT)|((hiword(addr)&03)<<14));
} while (bp = bp->av_forw);
}
dmbload(mp, type, w0, w1)
register struct dmb *mp;
{
register struct device *kp;
register dev;
register sps, n;
dev = mp - dmb_dmb;
kp = dmb_addr[dev];
sps = spl5();
if ((n = mp->d_que.c_cc) == 0)
kp->bsel0 = type | RQI;
else
putc(type | RQI, &mp->d_que);
putc(lobyte(w0), &mp->d_que);
putc(hibyte(w0), &mp->d_que);
putc(lobyte(w1), &mp->d_que);
putc(hibyte(w1), &mp->d_que);
if (n == 0)
dmbrint(dev);
splx(sps);
}
dmbrint(dev)
{
register struct dmb *mp;
register struct device *kp;
register int n;
kp = dmb_addr[dev];
mp = &dmb_dmb[dev];
while (kp->bsel0&RDYI) {
kp->bsel4 = getc(&mp->d_que);
kp->bsel5 = getc(&mp->d_que);
kp->bsel6 = getc(&mp->d_que);
kp->bsel7 = getc(&mp->d_que);
kp->bsel0 &= ~(IEI|RQI);
while (kp->bsel0&RDYI);
if (mp->d_que.c_cc == 0)
return;
kp->bsel0 = getc(&mp->d_que);
n = RDYSCAN;
while (n-- && (kp->bsel0&RDYI) == 0);
}
if (mp->d_que.c_cc)
kp->bsel0 |= IEI;
}
dmbxint(dev)
{
register struct dmb *mp;
int arg, cmd;
{
register struct device *kp;
kp = dmb_addr[dev];
arg = kp->sel6;
cmd = kp->bsel2&7;
kp->bsel2 &= ~RDYO;
}
mp = &dmb_dmb[dev];
switch (cmd) {
case OUR:
case OUX:
{
register struct buf *bp, *abp;
register flag;
flag = (cmd==OUR)?B_READ:B_WRITE;
/*
* Look through the active Q for the buffer
* the DMC11 says is finished. Assume the DMC11
* returns the buffers in FIFO order.
*/
abp = NULL;
if (bp = mp->d_next) do {
if ((bp->b_flags&B_READ)!=flag)
continue;
mp->d_rwq[flag]--;
mp->d_ioc[flag]++;
bp->b_resid = bp->b_bcount - (arg&CCOUNT);
if (abp)
abp->av_forw = bp->av_forw;
else
mp->d_next = bp->av_forw;
bp->av_forw = NULL;
if ((abp = mp->d_rdy[flag]) == NULL)
mp->d_rdy[flag] = bp;
else {
while (abp->av_forw)
abp = abp->av_forw;
abp->av_forw = bp;
}
wakeup(&mp->d_rdy[flag]);
dmbstart(mp, flag);
return;
} while (abp = bp, bp = bp->av_forw);
printf("DMC%d lost block\n", dev);
return;
}
case CNTLO:
{
register short *ip;
register count;
register struct buf *bp;
count = arg&CNTMASK;
if (count&FATAL) {
dmb_addr[dev]->bsel1 = MCLR;
mp->d_flag &= ~DMCRUN;
mp->d_rwq[0] = mp->d_rwq[1] = 0;
bp = mp->d_next;
while (bp) {
bp->b_flags &= ~B_STALE;
if (mp->d_flag&DMCACT) {
bp = bp->av_forw;
} else {
mp->d_next = bp->av_forw;
bp->av_forw = mp->d_rdy[bp->b_flags&B_READ];
mp->d_rdy[bp->b_flags&B_READ] = bp;
bp = mp->d_next;
}
}
if (mp->d_flag&DMCACT) {
dmbopen(dev);
dmbstart(mp, B_READ);
dmbstart(mp, B_WRITE);
} else {
dmbclose(dev);
}
}
ip = &mp->d_ioc[2];
while (count) {
if (count&01)
(*ip)++;
ip++;
count >>= 1;
}
return;
}
default:
printf("DMC%d bad control %o\n", cmd);
}
}
dmbread(dev)
{
register struct dmb *mp;
register struct buf *bp;
register n;
mp = &dmb_dmb[dev];
spl5();
while ((bp = mp->d_rdy[B_READ]) == NULL)
sleep(&mp->d_rdy[B_READ], PRIDMC);
mp->d_rdy[B_READ] = bp->av_forw;
spl0();
n = min(u.u_count, bp->b_bcount - bp->b_resid);
iomove(paddr(bp), n, B_READ);
dmbstrategy(bp);
}
dmbwrite(dev)
{
register struct dmb *mp;
register struct buf *bp;
register n;
mp = &dmb_dmb[dev];
spl5();
while ((bp = mp->d_rdy[B_WRITE]) == NULL)
sleep(&mp->d_rdy[B_WRITE], PRIDMC);
mp->d_rdy[B_WRITE] = bp->av_forw;
spl0();
n = min(u.u_count, bp->b_bcount);
iomove(paddr(bp), n, B_WRITE);
bp->b_resid = bp->b_bcount - n;
dmbstrategy(bp);
}
dmbioctl(dev, cmd, arg, mode)
{
register struct dmb *mp;
mp = &dmb_dmb[dev];
switch (cmd) {
case IOCTYPE:
u.u_rval1 = DIOC;
break;
case DIOCGETC:
if (copyout(mp->d_ioc, arg, sizeof(mp->d_ioc)))
u.u_error = EFAULT;
break;
case DIOCGETB:
if (copyout(mp->d_base, arg, sizeof(mp->d_base)))
u.u_error = EFAULT;
break;
case DIOCSETE:
dmbload(mp, PERR, 0, 0);
break;
}
}