V8/usr/sys/dev/cmcld.c
/*
* Raw line discipline and listener stuff for talking to controller
*/
#include "cm.h"
#if NCM
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/ioctl.h"
#include "../h/pte.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/ubavar.h"
#include "../h/conf.h"
#include "../h/dkstat.h"
#include "../h/dkmod.h"
#include "sparam.h"
#include "dk.h"
#include "kdi.h"
#include "kmc.h"
/* channel states */
#define CLOSED 0
#define RCLOSE 1
#define LCLOSE 2
#define OPEN 3
/*
* CMC/Listener message structure
*/
struct dialin {
char type;
char srv;
short param0;
short param1;
short param2;
short param3;
short param4;
short param5;
};
struct dialout {
short chan;
struct dialin d;
};
/*
* Message codes
*/
#define T_LSTNR 4
#define T_CHG 3
#define T_REPLY 10
#define D_CLOSE 1
#define D_ISCLOSED 2
/*
* Raw-mode line discipline for DK (only)
*/
int nulldev(), rdkopen(), rdkclose(), rdkiput(), rdkoput(), rdkosrv();
static struct qinit rdkrinit = { rdkiput, NULL, rdkopen, rdkclose, 72, 36};
static struct qinit rdkwinit = { rdkoput, rdkosrv, rdkopen, nulldev, 72, 36};
struct streamtab rdkinfo = { &rdkrinit, &rdkwinit };
extern struct dkstat dkstat;
#define NDKMOD (NDK+NKMC) /* number of different DK devices */
struct dkmodule dkmod[NDKMOD];
#define NDKRAW 32
struct rdk {
struct queue *q;
struct dkmodule *module;
short chan;
} rdk[NDKRAW];
rdkopen(q, dev)
register struct queue *q;
{
static timer_on = 0;
register struct rdk *dkp, *edkp;
register struct dkmodule *dkm;
edkp = NULL;
for (dkp=rdk; ; dkp++) {
if (dkp >= &rdk[NDKRAW])
break;
if (dkp->q == q) {
if (dkp->chan != minor(dev) || WR(q)->ptr==NULL) {
printf("q %x dkp %x\n", q, dkp);
panic("rdkopen botch");
}
return(1);
}
if (dkp->q == NULL && edkp==NULL)
edkp = dkp;
}
if (edkp==NULL)
return(0);
for (dkm=dkmod; ; dkm++) {
if (dkm >= &dkmod[NDKMOD])
return(0);
if (major(dev) == dkm->dev)
break;
}
edkp->q = q;
edkp->chan = minor(dev);
edkp->module = dkm;
q->flag |= QDELIM;
q->ptr = 0;
WR(q)->ptr = (caddr_t)edkp;
if (timer_on==0) {
dktimer();
timer_on = 1;
}
return(1);
}
rdkclose(q)
register struct queue *q;
{
register i;
register struct block *bp;
register struct rdk *dkp = (struct rdk *)WR(q)->ptr;
if (dkp==NULL) printf("null ptr; q %x wq %x\n", q, WR(q));
if (WR(q)==dkp->module->listnrq)
dkp->module->listnrq = NULL;
while (bp = getq(q))
(*q->next->qinfo->putp)(q->next, bp);
dkp->q = NULL;
dkp->module = NULL;
}
/*
* output put procedure.
*/
rdkoput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct block *bp1;
register struct ioctl1 {
int com;
int stuff;
} *iop;
register struct rdk *dkp = (struct rdk *)q->ptr;
register struct dkmodule *modp = dkp->module;
register i;
switch (bp->type) {
case M_IOCTL:
switch (((struct ioctl1 *)bp->rptr)->com) {
/* hang everybody up */
case DIOCHUP:
/* must be on channel 1 or 0 */
if (dkp->chan <= 1) {
dkmesg(modp, T_LSTNR, 0, 0, 0, 1);
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
}
break;
/* announce listener channel */
case DIOCLHN:
if (modp->listnrq == NULL) {
modp->listnrq = q;
dkmesg(modp, T_LSTNR, 0, 0, 0, 0);
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
}
break;
/* delay input */
case DIOCSTOP:
RD(q)->ptr = (caddr_t)1;
bp->type = M_IOCACK;
bp->rptr = bp->wptr;
qreply(q, bp);
return;
/* suggest a free outgoing channel */
case DIOCCHAN:
for (i=3; i<modp->nchan; i+=2) {
if (modp->dkstate[i]==CLOSED) {
((struct ioctl1 *)bp->rptr)->stuff = i;
bp->wptr =
bp->rptr+sizeof(struct ioctl1);
bp->type = M_IOCACK;
break;
}
}
qreply(q, bp);
return;
default:
(*q->next->qinfo->putp)(q->next, bp);
return;
}
bp->type = M_IOCNAK;
bp->wptr = bp->rptr;
qreply(q, bp);
return;
}
putq(q, bp);
}
rdkosrv(q)
register struct queue *q;
{
register struct block *bp;
while ((q->next->flag&QFULL)==0 && (bp = getq(q)))
(*q->next->qinfo->putp)(q->next, bp);
}
/*
* input put procedure
* -- ignores all control bytes
*/
rdkiput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct rdk *dkp = (struct rdk *)WR(q)->ptr;
switch (bp->type) {
case M_DATA:
if (WR(q)==dkp->module->listnrq && dklstnr(dkp->module, bp))
return;
if (q->next->flag&QFULL) { /* sorry, you lose */
freeb(bp);
return;
}
if (q->ptr) { /* input delayed */
putq(q, bp);
qpctl(q, M_DELIM);
return;
}
(*q->next->qinfo->putp)(q->next, bp);
putctl(q->next, M_DELIM);
return;
case M_IOCACK:
case M_IOCNAK:
case M_HANGUP:
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_CLOSE:
if (dkp->module->dkstate[*bp->rptr] == RCLOSE)
dkmesg(dkp->module, T_CHG, D_ISCLOSED, 0, *bp->rptr, 0);
else
dkmesg(dkp->module, T_CHG, D_CLOSE, 0, *bp->rptr, 0);
freeb(bp);
return;
default:
freeb(bp);
}
}
/*
* listener sends a message to CMC
*/
dkmesg(modp, type, srv, p0, p1, p2)
register struct dkmodule *modp;
{
register struct dialout *dp;
register struct block *bp;
if (modp->listnrq==NULL || modp->listnrq->next->flag&QFULL)
return;
if ((bp = allocb(sizeof(struct dialout))) == NULL)
return; /* hope it will be retried later */
dp = (struct dialout *)bp->wptr;
dp->chan = 1; /* channel 1 builtin */
dp->d.type = type;
dp->d.srv = srv;
dp->d.param0 = p0;
dp->d.param1 = p1;
dp->d.param2 = p2;
bp->wptr += sizeof(struct dialout);
(*modp->listnrq->next->qinfo->putp)(modp->listnrq->next, bp);
putctl(modp->listnrq->next, M_DELIM);
}
/*
* Receive message for listener
*/
dklstnr(modp, bp)
register struct block *bp;
struct dkmodule *modp;
{
register struct dialin *dialp;
register i;
register struct queue *listnrq = modp->listnrq;
register struct rdk *dkp;
dialp = (struct dialin *)bp->rptr;
switch (dialp->type) {
case T_CHG:
i = dialp->param1;
if (i <= 0 || i >= modp->nchan) {
dkstat.chgstrange++;
if (dialp->srv)
dkmesg(modp, T_CHG, D_ISCLOSED, 0, i, 0);
freeb(bp);
return(1);
}
switch (dialp->srv) {
case D_CLOSE: /* remote shutdown */
switch (modp->dkstate[i]) {
case RCLOSE:
dkstat.notclosed++;
case OPEN:
putctl1(listnrq->next, M_CLOSE, i);
break;
case LCLOSE:
case CLOSED:
dkmesg(modp, T_CHG, D_ISCLOSED, 0, i, 0);
putctl1(listnrq->next, M_CLOSE, i);
break;
}
break;
case D_ISCLOSED:
switch (modp->dkstate[i]) {
case LCLOSE:
case CLOSED:
putctl1(listnrq->next, M_CLOSE, i);
break;
case OPEN:
case RCLOSE:
dkstat.isclosed++;
break;
}
break;
}
freeb(bp);
return(1);
case T_REPLY: /* CMC sends reply; find, and hand to process */
i = dialp->param0;
if (i < 0 || i >= modp->nchan)
return(0);
for (dkp=rdk; dkp<&rdk[NDKRAW]; dkp++) {
if (dkp->module==modp && dkp->chan==i) {
(*dkp->q->next->qinfo->putp)(dkp->q->next, bp);
putctl(dkp->q->next, M_DELIM);
return(1);
}
}
return(0);
default:
return(0);
}
}
/*
* 15-second timer
*/
dktimer()
{
register i;
register struct dkmodule *dkp;
for (dkp = dkmod; dkp < &dkmod[NDKMOD]; dkp++) {
if (dkp->listnrq) {
dkmesg(dkp, T_LSTNR, 0, 0, 0, 0);
for (i=0; i< dkp->nchan; i++)
if (dkp->dkstate[i] == LCLOSE)
dkmesg(dkp, T_CHG, D_CLOSE, 0, i, 0);
}
}
timeout(dktimer, (caddr_t)NULL, 15*hz);
}
#endif