|
|
researchv10 Norman
/*
* Raw line discipline and communications with unixp datakit controller
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/dkio.h"
#include "sys/conf.h"
#include "sys/dkstat.h"
#include "sys/dkmod.h"
/*
* Unixp message structure
*/
struct dialin {
char type;
char srv;
short param0;
short param1;
short param2;
short param3;
short param4;
};
/*
* Message codes
*/
#define T_SRV 1
#define T_REPLY 2
#define T_CHG 3
#define T_ALIVE 4
#define T_RESTART 8
#define D_CLOSE 1
#define D_ISCLOSED 2
#define D_CLOSEALL 3
#define D_OK 1
#define D_OPEN 2
#define D_FAIL 3
#define D_RESTART 1
#define D_XINIT 7
/*
* Raw-mode line discipline for DK (only)
*/
long xpopen();
int xpclose(), xpiput(), xpoput(), xposrv();
static struct qinit xprinit = { xpiput, NULL, xpopen, xpclose, 72, 36};
static struct qinit xpwinit = { xpoput, xposrv, xpopen, nulldev, 72, 36};
struct streamtab xpstream = { &xprinit, &xpwinit };
extern struct dkstat dkstat;
extern struct dkmodule dkmod[];
extern int dkmodcnt;
#define NDKRAW 32
struct xp {
struct queue *q;
struct dkmodule *module;
short chan;
} xp[NDKRAW];
long
xpopen(q, dev)
register struct queue *q;
{
static timer_on = 0;
register struct xp *dkp, *edkp;
register struct dkmodule *dkm;
if ((dkm = getdkmod(dev)) == NULL)
return (0);
edkp = NULL;
for (dkp=xp; dkp < &xp[NDKRAW]; dkp++) {
if (dkp->q == q) {
if (dkp->chan != minor(dev) - dkm->lo || WR(q)->ptr==NULL) {
printf("q %x dkp %x\n", q, dkp);
panic("xpopen");
}
return(1);
}
if (dkp->q == NULL && edkp==NULL)
edkp = dkp;
}
if (edkp==NULL)
return(0);
edkp->q = q;
edkp->chan = minor(dev) - dkm->lo;
edkp->module = dkm;
q->flag |= QDELIM;
q->ptr = 0;
WR(q)->ptr = (caddr_t)edkp;
if (timer_on==0) {
xptimer();
timer_on = 1;
}
return(1);
}
xpclose(q)
register struct queue *q;
{
register struct block *bp;
register struct xp *dkp = (struct xp *)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;
dkp->module->type = 0;
}
while (bp = getq(q))
(*q->next->qinfo->putp)(q->next, bp);
dkp->q = NULL;
dkp->module = NULL;
}
/*
* output put procedure.
*/
xpoput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct xp *dkp = (struct xp *)q->ptr;
register struct dkmodule *modp = dkp->module;
register i;
switch (bp->type) {
case M_IOCTL:
switch (stiocom(bp)) {
/* hang everybody up */
case DIOCHUP:
/* must be on low channels */
if (dkp->chan < 5) {
xpmesg(modp, T_ALIVE, D_RESTART, 0);
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;
modp->type = UNIXPLD;
xpmesg(modp, T_ALIVE, 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=modp->lo + 2; i<modp->hi; i++) {
if (modp->dkstate[i]==DKCLOSED) {
*(int *)stiodata(bp) = i;
bp->wptr = bp->rptr+sizeof(int)+STIOCHDR;
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);
}
xposrv(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 almost all control bytes
*/
xpiput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct xp *dkp = (struct xp *)WR(q)->ptr;
switch (bp->type) {
case M_DATA:
if (WR(q)==dkp->module->listnrq && xplstnr(dkp->module, bp))
return;
if (q->next->flag&QFULL) { /* sorry, you lose */
freeb(bp);
return;
}
bp->class |= S_DELIM;
if (q->ptr) { /* input delayed */
putq(q, bp);
return;
}
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_IOCACK:
case M_IOCNAK:
case M_HANGUP:
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_PRICTL:
switch (*bp->rptr) {
case DKMCLOSE:
dkp->module->dkstate[bp->rptr[1]] = DKLCLOSE;
xpmesg(dkp->module, T_CHG, D_CLOSE, bp->rptr[1]);
freeb(bp);
return;
default:
freeb(bp);
return;
}
default:
freeb(bp);
}
}
/*
* listener sends a message to CMC
*/
xpmesg(modp, type, srv, p0)
register struct dkmodule *modp;
{
register struct dialin *dp;
register struct block *bp;
if (modp->listnrq==NULL || modp->listnrq->next->flag&QFULL)
return;
if ((bp = allocb(sizeof(struct dialin))) == NULL)
return; /* hope it will be retried later */
dp = (struct dialin *)bp->wptr;
dp->type = type;
dp->srv = srv;
dp->param0 = p0;
dp->param1 = 0;
dp->param2 = 0;
dp->param3 = 0;
dp->param4 = 0;
bp->wptr += sizeof(struct dialin);
bp->class |= S_DELIM;
(*modp->listnrq->next->qinfo->putp)(modp->listnrq->next, bp);
}
/*
* Receive message for listener
*/
xplstnr(modp, bp)
register struct block *bp;
struct dkmodule *modp;
{
register struct dialin *dialp;
register i;
register struct queue *listnrq = modp->listnrq;
register struct xp *dkp;
int t;
dialp = (struct dialin *)bp->rptr;
i = dialp->param0;
t = dialp->param1;
switch (dialp->type) {
case T_CHG:
if (dialp->srv == D_CLOSEALL) {
printf("datakit closing all chans\n");
for(i=modp->hi-modp->lo-1; i > 0; i--) {
if(((struct xp *)listnrq->ptr)->chan == i)
continue;
switch (modp->dkstate[i]) {
case DKRCLOSE:
dkstat.notclosed++;
case DKOPEN:
printf("closing %d\n", i);
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
case DKLCLOSE:
printf("closed %d\n", i);
case DKCLOSED:
modp->dkstate[i] = DKCLOSED;
break;
}
}
freeb(bp);
return(1);
}
if (i <= 0 || i >= modp->hi - modp->lo) {
dkstat.chgstrange++;
if (dialp->srv)
xpmesg(modp, T_CHG, D_CLOSE, i);
freeb(bp);
return(1);
}
switch (dialp->srv) {
case D_CLOSE: /* remote shutdown */
switch (modp->dkstate[i]) {
case DKRCLOSE:
dkstat.notclosed++;
case DKOPEN:
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
case DKLCLOSE:
case DKCLOSED:
xpmesg(modp, T_CHG, D_CLOSE, i);
break;
}
break;
case D_ISCLOSED:
switch (modp->dkstate[i]) {
case DKLCLOSE:
case DKCLOSED:
putctl2(listnrq->next, M_PRICTL, DKMCLOSE, i);
break;
case DKOPEN:
case DKRCLOSE:
dkstat.isclosed++;
break;
}
break;
}
freeb(bp);
return(1);
case T_REPLY: /* CMC sends reply; find, and hand to process */
if (i < 0 || i >= modp->hi - modp->lo)
return(0);
for (dkp=xp; dkp<&xp[NDKRAW]; dkp++) {
if (dkp->module==modp && dkp->chan==i) {
(*dkp->q->next->qinfo->putp)(dkp->q->next, bp);
return(1);
}
}
return(0);
case T_SRV:
/* see if we've been spliced */
if (dialp->srv == D_XINIT) {
if (i < 0 || i >= modp->hi - modp->lo)
return(0);
freeb(bp);
if((bp = allocb(4))==0)
return(0);
*bp->wptr++ = DKMXINIT;
*bp->wptr++ = i;
*bp->wptr++ = t>>8;
*bp->wptr++ = t;
bp->type = M_PRICTL;
(*listnrq->next->qinfo->putp)(listnrq->next, bp);
return(1);
}
return(0);
case T_RESTART:
/* datakit has rebooted, tell it what we think is closed */
printf("datakit restart\n");
for(i = modp->hi - modp->lo - 1; i > 0; --i) {
switch (modp->dkstate[i]) {
case DKLCLOSE:
xpmesg(modp, T_CHG, D_CLOSE, i);
break;
}
}
freeb(bp);
return(1);
default:
return(0);
}
}
/*
* 15-second timer
*/
xptimer()
{
register i;
register struct dkmodule *dkp;
for (dkp = dkmod; dkp < &dkmod[dkmodcnt]; dkp++) {
if (dkp->listnrq && dkp->type == UNIXPLD) {
xpmesg(dkp, T_ALIVE, 0, 0);
for (i=dkp->hi - dkp->lo - 1; i >= 0; --i)
if (dkp->dkstate[i] == DKLCLOSE)
xpmesg(dkp, T_CHG, D_CLOSE, i);
}
}
timeout(xptimer, (caddr_t)NULL, 15*HZ);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.