/* * Datakit driver * DR11C version without KMC * * uses mbufs for transmission * * SCCSID[] = "@(#)dkit_dr.c 1.5 Garage 84/04/11" */ #include "dkitdr.h" #if NDKITDR>0 #include "datakit.h" #include "../machine/pte.h" #include "param.h" #include "time.h" #include "kernel.h" #include "buf.h" #include "mbuf.h" #include "errno.h" #include "socket.h" #include "syslog.h" #include "../net/if.h" #include "../vaxuba/ubareg.h" #include "../vaxuba/ubavar.h" #include "dk.h" #include "dkit.h" #include "dkdr.h" #define PKBHOG 64 /* max temp buffers per channel */ #define DKNPKB (200+4*NDATAKIT) #define DKNSTB 10 struct dkchan dkit[NDATAKIT]; extern int dk_nchan; int dkdr_npk = DKNPKB; struct dkpkbufr dk_pkbuf[DKNPKB]; int dkdr_nstat = DKNSTB; struct dkstat dkdr_stat[DKNSTB]; int dkattached = 0; /* Is it really there? */ #ifdef KALYPSO #define URPDEBUG 5000 #else #define URPDEBUG 500 #endif #ifdef URPDEBUG int dkurpdebug = 0; #define URPTRACE(chan, chr, Dkp) if (dkurpdebug == (chan)) \ dkurptrace(chr, Dkp); #endif /* * structure of data in first mbuf on chain (type DKM_HDR) * */ struct mpacket { short mp_len; /* Total length left */ char mp_ctl; /* Control character */ int mp_eob; /* Send end-of-block indicator */ int (*mp_endfcn)(); /* End-action function */ caddr_t mp_endparm; /* Parameter to above function */ }; /* * dr11-c bit definitions */ #define DKTENAB 0100 /* transmit interrupt enable */ #define DKRENAB 040 /* receiver interrupt enable */ #define ENABS 0140 /* both enables */ #define DKCOM 03 /* dr11-c command bits */ #define DKTDONE 0200 /* transmit done bit */ #define DKRDONE 0100000 /* receiver done bit */ #define DKMARK 01000 /* start of packet bit */ #define DKOVF 040000 /* receiver overflow bit (in drin) */ #define DKDATA 0400 /* bit 9 ... indicates non-control */ #define DKCHUNK 16 /* packet size */ /* * dr11c commands */ #define D_OSEQ 0 #define D_READ 1 #define D_WRITE 2 #define D_XPACK 3 /* * error control protocol definitions */ #define SEQ 0010 /* 8 sequence numbers to end trailers */ #define ECHO 0020 /* 8 echoes, data given to host */ #define REJ 0030 /* 8 rejections, transmission error */ #define ACK 0040 /* first of 8 acks, correct reception */ #define BOT 0050 /* normal beginning of trailer */ #define BOTM 0051 /* trailer with more data to follow */ #define BOTS 0052 /* seq update algorithm on this trailer */ #define SOI 0053 /* start of interrupt trailer */ #define EOI 0054 /* end of interrupt trailer */ #define ENQ 0055 /* xmitter request flow/error status */ #define CHECK 0056 /* xmitter request error status */ #define INITREQ 0057 /* request initialization */ #define INIT0 0060 /* disable trailer processing */ #define INIT1 0061 /* enable trailer processing */ #define AINIT 0062 /* response to INIT0/INIT1 */ #define DKBMASK 03 /* this xmitter has window size of 4, */ /* #define DKBLOCK 60 /* each message is 60 bytes */ #define DKBLOCK 28 /* each message is 60 bytes */ /* * some commonly used macros */ struct dkpkbufr *dk_Sfree; extern int dkdr_npk; extern struct dkpkbufr dk_pkbuf[]; int dknopkb = 1 ; /* Counter for 'no dkpkbufr' condition. */ int dkstray; /* number of stray interrupts since last timeout */ int dkdrlostint; /* Number of lost receiver interrupts */ int dkdisabled; /* flag to indicate that DK interface has been disabled due to stray interrupts, etc. */ #define MAX_STRAY 10 /* maximum number of stray interrupts before temporarily disabling DK interrupts */ /* * dr11c device registers */ struct rdevice { short dkcsr; short dko; short dki; }; extern int dkdr_nstat; extern struct dkstat dkdr_stat[]; static char Hstat, Tstat; #define DKADDR ((struct rdevice *) dkitdrdinfo[0]->ui_addr) /* * Intermediate level command codes */ #define KS_SEND 20 #define KS_RDB 21 #define KS_EOI 22 #define KS_CNTL 23 #define KS_ERR 24 int dkdebug = 512 ; int dkactive ; static int timeron; int dkitdrprobe(), dkitdrattach(); struct uba_device *dkitdrdinfo[1]; u_short dkitdrstd[] = { 0 }; struct uba_driver dkitdrdriver = { dkitdrprobe, 0, dkitdrattach, 0, dkitdrstd, "dkitdr", dkitdrdinfo }; dkitdrprobe(reg) caddr_t reg; { register int br, cvec; /* value-result */ register struct rdevice *draddr = (struct rdevice *) reg; register int i, c; #ifdef lint br = 0; cvec = br; br = cvec; dkdrrint(0); dkdrxint(0); #endif draddr->dkcsr = D_READ; for (i = 0; i < 1024; i++) if (draddr->dkcsr & DKRDONE) c = draddr->dki; else break; #ifdef lint c = c; #endif draddr->dkcsr = D_WRITE; draddr->dko = DKMARK | (dk_nchan-1); /* pack on 511 */ draddr->dkcsr = D_XPACK + DKTENAB; draddr->dko = 0; DELAY(10000); draddr->dkcsr = 0; return(sizeof(struct rdevice)); } /*ARGSUSED*/ dkitdrattach(ui) struct uba_device *ui; { dkattached = 1; #if defined(INET) && NDKI>0 dkiattach(); #endif } static dk_init() { register struct rdevice *raddr = DKADDR; register s ; /* * At attach time for the hardware device * initialize and check things out to the * (grumble) limited extent that is possible. */ s = spl5() ; Hstat = Tstat = 0 ; dkdisabled = 0; dkstray = 0; { register struct dkchan *dkp ; for (dkp = &dkit[0]; dkp < &dkit[dk_nchan]; dkp++) { dkp->dk_rlen = 0 ; dkp->dk_xlen = 0 ; dkp->dk_X = XM_OFF; dkp->dk_rq = NULL ; dkp->dk_outq.ifq_len = 0; dkp->dk_outq.ifq_maxlen = 20; dkp->dk_outq.ifq_drops = 0; dkp->dk_outq.ifq_head = NULL; dkp->dk_outq.ifq_tail = NULL; } } { register struct dkpkbufr *pkb ; for (pkb = &dk_pkbuf[1]; pkb < &dk_pkbuf[dkdr_npk-1]; pkb++) { pkb->Pnext = pkb + 1 ; } dk_pkbuf[dkdr_npk-1].Pnext = NULL ; dk_Sfree = &dk_pkbuf[1] ; dk_pkbuf[0].Pnext = NULL ; } { register int seq, i, c ; raddr->dkcsr = D_OSEQ ; raddr->dko = 0 ; /* clears all FIFO's */ seq = 0 ; while (raddr->dkcsr & DKTDONE) { seq += (((raddr->dki)>>10) & 017) + 2 ; if (seq > 100) { dkreport(KS_ERR, 0, 1, 0, 1) ; splx(s) ; return -EIO ; } } raddr->dkcsr = D_READ; for (i = 0; i < 1024; i++) if (raddr->dkcsr & DKRDONE) c = raddr->dki; else break; #ifdef lint c = c; #endif } raddr->dkcsr = ENABS ; if(!timeron){ dk_timeout(); timeron++; } splx(s) ; dkactive = 1 ; return 0 ; } /*ARGSUSED*/ dkitreset(uban) int uban; { register struct rdevice *raddr ; raddr = DKADDR; raddr->dkcsr = ENABS; log(LOG_ERR, " dkit_dr%d", 0); } dk_open(chan, supfcn) register chan ; int (*supfcn)() ; { register struct dkchan *dkp; register s ; extern dkkint() ; static firsttime = 1; static init; extern int commchan; if (chan >= dk_nchan || !dkattached) return -ENXIO ; if (firsttime) { if ((init = dk_init()) < 0) return init; firsttime = 0; } dkp = &dkit[chan] ; s = spl5() ; /* * Channel 0 (0-3 in ISN) is reserved for maintenance. * An open on channel 0 is interpreted as a request * for an unused channel. Channel 1 (4 in ISN or RADIAN) * is the common supervisory channel. */ if (chan == 0) { chan = commchan+1 ; /* Start above commchan */ while (1) { dkp = &dkit[chan] ; if (dkp->dk_state == 0) break ; chan++ ; if (chan >= dk_nchan) { splx(s) ; return -EADDRNOTAVAIL ; } } } /* * Finish setting up dkp struct. */ if ((dkp->dk_state & DK_OPEN) ==0) { if (chan > dkdebug) log(LOG_ERR, "dkopen %d: %x\n", chan, supfcn) ; dkp->dk_S = 1 ; dkp->dk_R = 0 ; dkp->dk_X = 0 ; dkp->dk_A = 0 ; dkp->dk_rejcnt = 0; dkp->dk_srejcnt = 0; dkp->dk_ackrejcnt = 0; dkp->dk_enqcnt = 0; dksend(chan, INIT1) ; flushall(dkp, 0); dkp->dk_state &= ~DK_LINGR ; dkp->dk_state |= DK_OPEN; } dkp->dk_supfcn = supfcn ; splx(s) ; return chan ; } /* * Close a channel: */ dk_close(chan) { register struct dkchan *dkp; register s ; s = spl5() ; if (chan > dkdebug) log(LOG_ERR, "dkclose %d\n", chan) ; dkp = &dkit[chan] ; if (chan == 0) { if (!dkattached) return -ENXIO; for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) { if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV)) { dkp->dk_state |= DK_RESET ; flushall(dkp, 0) ; } } dkactive = 0 ; splx(s); return dk_init() ; } else { dkp->dk_state |= DK_OPEN ; flushall(dkp, 0) ; dkp->dk_state = DK_LINGR ; dkp->dk_X = XM_OFF; dkp->dk_trmode = 0 ; } splx(s) ; return 0; } /* * Close phase 2 - mark available for reassignment */ dk_free(chan) { if (chan > dkdebug) log(LOG_ERR, "dkfree %d\n", chan) ; dkit[chan].dk_state &= ~DK_LINGR ; } /* * Reset a channel * prevents further I/O until close */ dk_reset(chan) { register struct dkchan *dkp ; register s ; if (chan > dkdebug) log(LOG_ERR, "dkreset %d\n", chan) ; s = spl5() ; dkp = &dkit[chan] ; dkp->dk_state |= DK_RESET ; flushall(dkp, 0) ; splx(s) ; } /* * Xmit a short control (interrupt) packet */ dk_xint(chan, intr) { register struct rdevice *raddr ; register s ; register struct dkchan *dkp ; dkp = &dkit[chan] ; if (chan == 0 || dkp->dk_X < XM_INIT) return -1 ; s = spl5() ; if (chan > dkdebug) log(LOG_ERR, "dkxint %d: %o %o\n", chan, (intr & 0377), ((intr >>8)&0377)) ; raddr = DKADDR ; raddr->dkcsr = D_WRITE ; raddr->dko = chan | DKMARK ; raddr->dko = SOI ; raddr->dko = (intr & 0377) | DKDATA ; raddr->dko = ((intr >> 8) & 0377) | DKDATA ; raddr->dko = EOI ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; if(dkdisabled) raddr->dko = 0; else raddr->dko = ENABS; splx(s) ; return 0 ; } /* * Adjust window size */ dk_winsize(chan, win) struct diocxwin win; { return EINVAL; /* For now... */ } /* * Xmit data on a channel * NOTE * * * * * * Although it is never checked here, buffer addresses * in this version of the driver must be kernel addressable. */ dk_xmit(chan, m, eob, ctlchar, endfcn, endparm) struct mbuf *m ; int (*endfcn)() ; caddr_t endparm ; { register struct dkchan *dkp ; register struct mpacket *mbp ; register struct mbuf *mb; int s ; s = spl5() ; dkp = &dkit[chan] ; if ((dkp->dk_state & DK_RESET) || (mb = m_get(M_DONTWAIT,DKMT_HDR)) == NULL) { m_freem(m); splx(s) ; return 0 ; } if (ctlchar == '\001') eob = 0; mb->m_len = 0; mbp = mtod(mb, struct mpacket *); mbp->mp_endfcn = endfcn ; mbp->mp_endparm = endparm ; mbp->mp_eob = eob; mb->m_next = m; mbp->mp_len = 0; while (m) { #ifdef notdef if (m->m_type != DKMT_DATA && m->m_type != DKMT_CTL) { log(LOG_ERR, "dk_xmit %d: got type %x\n", chan, m->m_type); m_freem(mb); return 0; } #endif mbp->mp_len += m->m_len; m = m->m_next; } if ((ctlchar & 0300) == 0100) { register struct mbuf *n = mb, *mc; mc = m_get(M_DONTWAIT, DKMT_CTL); if (mc == NULL) { m_freem(mb); splx(s); return 0; } *mtod(mc, char *) = ctlchar; mc->m_len = 1; /* Append it -- can't use m_cat because type field counts */ while (n->m_next) n = n->m_next; n->m_next = mc; mbp->mp_len++; ctlchar = 0; } mbp->mp_ctl = ctlchar; if ((dkp->dk_state & DK_BUSY) == 0) { dkp->dk_state |= DK_BUSY ; dkp->dk_curout = mb; dkp->dk_xlen = mbp->mp_len ; if (chan > dkdebug) log(LOG_ERR, "xmit %d: %x len %d\n", chan, mb->m_next, mbp->mp_len) ; dkxmit(dkp, chan, 2) ; splx(s) ; return dkp->dk_state ; } if (IF_QFULL(&dkp->dk_outq)) { IF_DROP(&dkp->dk_outq); m_freem(mb); } else IF_ENQUEUE(&dkp->dk_outq, mb); splx(s) ; return dkp->dk_state ; } /* * Receive into a block buffer */ dk_recv(chan, addr, len, mode, endfcn, endparm) caddr_t addr ; int (*endfcn)() ; caddr_t endparm ; { register struct dkchan *dkp ; register s ; if (addr == 0) { log(LOG_ERR, "dk_recv: channel %d endfcn %x: invalid address specification\n", chan, endfcn); return 0; } s = spl5() ; dkp = &dkit[chan] ; if (dkp->dk_state & (DK_RCV | DK_RESET)) { splx(s) ; return 0 ; } dkp->dk_state |= DK_RCV ; dkp->dk_endfcn = endfcn ; dkp->dk_endparm = endparm ; dkp->dk_rmode = mode ; dkp->dk_rlen = len ; dkp->dk_raddr = (caddr_t)addr ; if (chan > dkdebug) log(LOG_ERR, "dkrecv %d: %x len %d mode %o\n", chan, (caddr_t)addr, len, mode) ; dkrcv(dkp, chan, 2) ; splx(s) ; return dkp->dk_state ; } dk_rabort(chan, nendfcn, nendparm) int (*nendfcn)() ; caddr_t nendparm ; { register struct dkchan *dkp ; register s ; dkp = &dkit[chan] ; s = spl5() ; if (dkp->dk_state & DK_RCV) { dkp->dk_state &= ~DK_RCV ; if (dkp->dk_rlen) { if (chan > dkdebug) log(LOG_ERR, "rcvabo %d: rlen %d\n", chan, dkp->dk_rlen) ; (*nendfcn)(nendparm, chan, dkp->dk_rlen, DKR_ABORT, 0) ; } dkp->dk_rlen = 0 ; } splx(s) ; return dkp->dk_state ; } dk_status(chan) { if (chan >= dk_nchan) return 0 ; return dkit[chan].dk_state ; } dk_timeout() { register struct rdevice *raddr; register struct dkchan *dkp; register chan ; int s = spl5(); chan = 0 ; for (dkp = &dkit[0]; dkp < &dkit[dk_nchan]; dkp++) { if (dkp->dk_X != XM_OFF) { if (dkp->dk_X == 0) dksend(chan, INIT1) ; else if (dkp->dk_S != ((dkp->dk_R + 1) & 07)) { if (dkp->dk_X & XM_ENQ) { dksend(chan, ENQ) ; dkp->dk_X &= ~XM_REJ ; dkp->dk_enqcnt++; URPTRACE(chan, ENQ, dkp); } else dkp->dk_X |= XM_ENQ; } } chan++ ; } dkstray = 0; if(dkdisabled){ if(dkdisabled++ > 10){ /* try re-enabling interrupts */ dkdisabled = 0; log(LOG_ERR, "re-enabling DK interface\n"); raddr = DKADDR; raddr->dkcsr = ENABS; } } else { /* Look for lost interrupts */ if (raddr->dkcsr < 0) { dkdrlostint++; dkdrxint(0); } } timeout(dk_timeout, (caddr_t) 0, 1*hz); splx(s); } dk_cmd(chan, cmd) { register struct dkchan *dkp ; int s = spl5(); if (chan > dkdebug) log(LOG_ERR, "dkcmd %d: %o\n", chan, cmd) ; dkp = &dkit[chan] ; if (cmd & DKC_XINIT) { dkp->dk_X = dkp->dk_R = dkp->dk_A = 0 ; dkp->dk_S = 1 ; dksend(chan, INIT1) ; } if (cmd & DKC_FLUSH) { flushall(dkp, -1) ; } if (cmd & DKC_SPND) dkp->dk_state |= DK_SPND ; if (cmd & DKC_RSME) { dkp->dk_state &= ~DK_SPND ; dkxmit(dkp, chan, 2) ; } splx(s); } static flushall(dkp, rwflag) register struct dkchan *dkp ; { register s ; struct mpacket *mbp; s = spl5() ; if ((dkp->dk_state & DK_RCV) && (rwflag >= 0)) { dkp->dk_state &= ~DK_RCV ; if (dkp->dk_endfcn) (*dkp->dk_endfcn)(dkp->dk_endparm, dkp-dkit, dkp->dk_rlen, DKR_ABORT, 0) ; dkp->dk_rlen = 0 ; } if ((dkp->dk_state & DK_BUSY) && (rwflag <= 0)) { register struct mbuf *m ; dkp->dk_xlen = 0; if (dkp->dk_curout) { mbp = mtod(dkp->dk_curout, struct mpacket *); if (mbp->mp_endfcn) (mbp->mp_endfcn)(mbp->mp_endparm, dkp-dkit); m_freem(dkp->dk_curout); dkp->dk_curout = NULL; } while (1) { IF_DEQUEUE(&dkp->dk_outq, m); if (!m) break; mbp = mtod(m, struct mpacket *); if (mbp->mp_endfcn) (mbp->mp_endfcn)(mbp->mp_endparm, dkp-dkit); m_freem(m); } dkp->dk_state &= ~DK_BUSY ; } if ((dkp->dk_state & DK_OPEN) && (rwflag >= 0)) { register struct dkpkbufr *dbp ; dkp->dk_rlen = 0 ; dkp->dk_xlen = 0 ; dkp->dk_C = 0 ; while (dbp = dkp->dk_rq) { dkp->dk_rq = dbp->Pnext ; dbp->Pnext = dk_Sfree ; dk_Sfree = dbp ; } while (dbp = dkp->dk_rb) { dkp->dk_rb = dbp->Pnext ; dbp->Pnext = dk_Sfree ; dk_Sfree = dbp ; } } splx(s) ; } /* * Routine to handle completion status */ static dkkint() { register struct dkchan *dkp; register struct dkstat *sp; register chan; struct mbuf *m ,*om; struct mpacket *mbp; static char *cmpltype[] = {"send", "rdb", "eoi", "cntl", "err"}; while (Tstat != Hstat) { sp = &dkdr_stat[Hstat]; chan = sp->k_chan; dkp = &dkit[chan]; if (sp->k_chan > dkdebug) { if (sp->k_type >= KS_SEND && sp->k_type <= KS_ERR) log(LOG_ERR, "dkdone: type %s chan %d info %o-%o\n", cmpltype[sp->k_type-KS_SEND], sp->k_chan, sp->k_info1, sp->k_info2) ; else log(LOG_ERR, "dkdone: type %d chan %d info %o-%o\n", sp->k_type, sp->k_chan, sp->k_info1, sp->k_info2) ; } if (Hstat==dkdr_nstat-1) Hstat=0; else Hstat++; switch(sp->k_type) { case KS_CNTL: if (dkp->dk_supfcn) (*dkp->dk_supfcn)(chan, sp->k_info1) ; break ; case KS_EOI: break ; case KS_SEND: om = dkp->dk_curout ; if (om == NULL) { log(LOG_ERR, "dkk: xbufout\n"); break; } IF_DEQUEUE(&dkp->dk_outq, m); if (m == NULL) { dkp->dk_state &= ~DK_BUSY; dkp->dk_curout = NULL; } else { dkp->dk_curout = m; mbp = mtod(m, struct mpacket *); dkp->dk_xlen = mbp->mp_len ; if (chan > dkdebug) log(LOG_ERR, "xmiti %d: %x len %d\n", chan, m->m_next, mbp->mp_len) ; dkxmit(dkp, chan, 0) ; } mbp = mtod(om, struct mpacket *); if (mbp->mp_endfcn != NULL) (mbp->mp_endfcn)(mbp->mp_endparm, chan) ; m_freem(om); break; case KS_RDB: dkp->dk_state &= ~(DK_RCV|DK_RCVQ) ; if (sp->k_info2 == DKR_TIME && dkp->dk_rlen == 0) break ; /* another coming later */ if (dkp->dk_rlen) { sp->k_info1 = dkp->dk_rlen ; dkp->dk_rlen = 0 ; } if (dkp->dk_endfcn != NULL) (*dkp->dk_endfcn)(dkp->dk_endparm, dkp-dkit, sp->k_info1, sp->k_info2&0377, (sp->k_info2>>8)&0377) ; break; case KS_ERR: log(LOG_ERR, "err in dkit.c: chan - %d, code - %o\n", chan, sp->k_info1); break; } /* end switch */ } /* end while */ } /* static */ int dkxmitpanic = 0; dkxmit(dkp, stechan, intrpt) struct dkchan *dkp ; { register struct rdevice *raddr ; register char *ptr ; register struct mbuf *m; register int wtype; short pklen ; short mlen, unacked ; short blklen ; unsigned short totlen ; struct mpacket *mbp ; #ifdef notdef short scheck ; #endif if( dkp->dk_curout == NULL || stechan ==0 ) return ; mbp = mtod(dkp->dk_curout, struct mpacket *); raddr = DKADDR ; if ((dkp->dk_S & DKBMASK) == (dkp->dk_R & DKBMASK) || (dkp->dk_state & DK_SPND)) goto ctlchk ; if ((dkp->dk_xlen || ((mbp->mp_ctl & 0200) == 0)) && dkp->dk_X < XM_INIT) goto ctlchk ; #ifdef notdef if ((dkp->dk_S & DKBMASK) == ((dkp->dk_R + 1) & DKBMASK)) scheck = 0 ; else scheck = 1 ; #endif unacked = ((dkp->dk_S - dkp->dk_A - 1) & 07) * DKBLOCK ; mlen = MIN(unacked, dkp->dk_xlen) ; totlen = dkp->dk_xlen - mlen; if (totlen == 0) goto ctlchk ; /* Skip over stuff sent but not acked */ for (m = dkp->dk_curout->m_next; m && (mlen > 0); m = m->m_next) if (mlen > m->m_len) mlen -= m->m_len; else break; while (totlen && ((dkp->dk_S ^ dkp->dk_R) & DKBMASK)) { if (dkxmitpanic) panic("dkxmit -- panic 1"); blklen = MIN (totlen, DKBLOCK) ; pklen = 0 ; raddr->dkcsr = D_WRITE ; raddr->dko = stechan | DKMARK ; while (blklen) { if (dkxmitpanic) panic("dkxmit -- panic 2"); if (m == NULL) panic("dkxmit mlen"); ptr = mtod(m, char *) + mlen; mlen = MIN(blklen, m->m_len - mlen); blklen -= mlen; wtype = (m->m_type == DKMT_CTL ? 0 : DKDATA); while (mlen--) { if (dkxmitpanic) panic("dkxmit -- panic 3"); raddr->dko = (*ptr++ & 0377) | wtype ; pklen++ ; if ((pklen & (DKCHUNK-1)) == 0) { raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; raddr->dkcsr = D_WRITE ; raddr->dko = stechan|DKMARK ; } } if (ptr == (mtod(m, char *) + m->m_len)) { m = m->m_next; mlen = 0; } else mlen = ptr - mtod(m, char *); } blklen = MIN (totlen, DKBLOCK) ; if ((pklen & (DKCHUNK-1)) > (DKCHUNK-4)) { raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; raddr->dkcsr = D_WRITE ; raddr->dko = stechan|DKMARK ; } if (blklen == totlen && mbp->mp_eob) raddr->dko = BOT ; else raddr->dko = BOTM ; raddr->dko = (blklen & 0377) | DKDATA ; raddr->dko = ((blklen>>8) & 0377) | DKDATA ; raddr->dko = SEQ + dkp->dk_S ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; URPTRACE(stechan, SEQ + dkp->dk_S, dkp); dkp->dk_S++ ; dkp->dk_S &= 07 ; totlen -= blklen ; } #ifdef notdef if (totlen == 0 && dkp->dk_xlen && scheck) { raddr->dkcsr = D_WRITE ; raddr->dko = stechan|DKMARK ; raddr->dko = CHECK ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; URPTRACE(stechan, CHECK, dkp); } #endif ctlchk: if (mbp->mp_ctl & 0200) { raddr->dkcsr = D_WRITE ; raddr->dko = stechan|DKMARK ; raddr->dko = mbp->mp_ctl & 0377 ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; mbp->mp_ctl = 0 ; if (dkp->dk_xlen == 0) dkreport(KS_SEND, stechan, 0, 0, intrpt) ; } if(dkdisabled) raddr->dkcsr = 0; else raddr->dkcsr = ENABS ; } static dkrcv(dkp, stechan, intrpt) struct dkchan *dkp ; { register char *ptr1 ; register char *ptr2 ; register len ; short final ; short hibits ; struct dkpkbufr *pkb ; short tlen ; if ((dkp->dk_rlen == 0) || (dkp->dk_rq == NULL)) return ; final = 0 ; tlen = 0 ; while (final == 0 && (pkb = dkp->dk_rq)) { if (dkp->dk_rlen == 0) final |= DKR_FULL ; ptr1 = &pkb->Pdata[0] ; ptr2 = dkp->dk_raddr ; len = MIN(pkb->Plen, dkp->dk_rlen) ; hibits = pkb->Phibits ; while (len--) { if (hibits < 0) break ; hibits <<= 1 ; *ptr2++ = *ptr1++ ; } len = ptr2 - dkp->dk_raddr ; tlen += len ; dkp->dk_rlen -= len ; dkp->dk_raddr = ptr2 ; if ((pkb->Plen -= len) && hibits < 0) { final |= ((*ptr1++ & 0377) << 8) | DKR_CNTL ; hibits <<= 1 ; pkb->Plen-- ; } if (len = pkb->Plen) { ptr2 = &pkb->Pdata[0] ; while (len--) *ptr2++ = *ptr1++ ; pkb->Phibits = hibits ; } while (pkb && (pkb->Plen == 0)) { if ((pkb->Pseq & 0370) == ACK) { pkb->Pseq += ECHO - ACK ; final |= dkp->dk_rmode & DKR_BLOCK ; } if (pkb->Pseq) { dksend(stechan, pkb->Pseq) ; dkp->dk_C = pkb->Pseq ; } dkp->dk_rq = pkb->Pnext ; pkb->Pnext = dk_Sfree ; dk_Sfree = pkb ; pkb = dkp->dk_rq ; } } if (tlen && (dkp->dk_rmode & DKR_TIME)) final |= DKR_TIME ; if (dkp->dk_rlen == 0) final |= DKR_FULL ; if (final && (final != DKR_TIME || ((dkp->dk_state & DK_RCVQ) == 0))) { dkp->dk_state |= DK_RCVQ ; len = dkp->dk_rlen ; if (final != DKR_TIME) dkp->dk_rlen = 0 ; dkreport(KS_RDB, stechan, len, final, (final == DKR_TIME)?2:intrpt) ; } } static dksend(stechan, val) { register struct rdevice *raddr ; register savcsr ; if(stechan == 0) return; raddr = DKADDR ; savcsr = raddr->dkcsr ; raddr->dkcsr = D_WRITE ; raddr->dko = stechan| DKMARK ; raddr->dko = val ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; raddr->dkcsr = savcsr ; } /*ARGSUSED*/ dkdrrint(dev) /* ?? */ /* needed for UNIX OS */ { register struct rdevice *raddr ; register c ; register cnt; #ifdef lint c = 0; cnt = c; #endif cnt = 0; raddr = DKADDR ; raddr->dkcsr = D_OSEQ ; if((raddr->dkcsr & DKTDONE) == 0){ if(dkstray++ >= MAX_STRAY){ log(LOG_ERR, "DK err 1 (Cabling?)\n"); raddr->dkcsr = 0; dkdisabled = 1; return; } } while (raddr->dkcsr & DKTDONE){ c = raddr->dki ; if(cnt++ > 65){ log(LOG_ERR, "DK err 2 (Cabling?)\n"); raddr->dkcsr = 0; dkdisabled = 1; return; } } raddr->dkcsr = ENABS ; if (Hstat != Tstat) dkkint() ; } /*ARGSUSED*/ dkdrxint(dev) /* ?? */ { register struct rdevice *raddr ; register char *ptr ; struct dkchan *dkp ; register c ; short badpacks ; struct dkpkbufr *pkb ; short stechan ; short len, xlen ; unsigned short bitloc ; badpacks = 0 ; raddr = DKADDR ; pkb = NULL ; if(raddr->dkcsr >= 0){ if(dkstray++ > MAX_STRAY){ log(LOG_ERR, "DK err 3 (Cabling?)\n"); goto disable; } } while (raddr->dkcsr < 0) { raddr->dkcsr = D_READ ; c = raddr->dki ; while (raddr->dkcsr < 0 && (c & DKMARK)) { c &= 0777 ; if (c >= dk_nchan) { if (++badpacks > 20) { log(LOG_ERR, "DK err 4 (Cabling?)\n"); dkreport(KS_ERR, 0, 2, 0, 1) ; goto disable ; } break ; } /* discard all chl 0 packets; * the LDI version of the CPM-DR and CPM-422 * puts out packets on chl 0 occasionally. */ if(c == 0) break; dkp = &dkit[c] ; stechan = c ; qpkb: if (pkb && pkb->Plen) { dkrcvq(stechan, dkp, pkb, 0) ; pkb = NULL ; } if (pkb == NULL) { if ((pkb = dk_Sfree) != NULL) { dk_Sfree = pkb->Pnext ; pkb->Pseq = 0 ; pkb->Plen = 0 ; pkb->Pnext = NULL ; pkb->Phibits = 0 ; } else { /* ** Oops, no more dkpkbufr's. ** Let outer loop gobble up ** the entire packet. ** Report to the console ** every 100th occurrence. */ if ( dknopkb++ >= 100 ) { dknopkb = 1 ; dkreport(KS_ERR, 0, 3, 0, 1) ; } break ; } } raddr->dkcsr = D_READ ; ptr = &pkb->Pdata[0] ; bitloc = 0100000 ; while (raddr->dkcsr < 0 && ((c = raddr->dki) & DKMARK) == 0) switch (c = c & 0777) { case NULL: break ; case AINIT: dkp->dk_X = XM_INIT ; dkp->dk_R = 0 ; dkp->dk_S = 1 ; dkp->dk_A = 0 ; dkxmit(dkp, stechan, 1) ; raddr->dkcsr = D_READ ; break ; case INIT0: dksend(stechan, AINIT) ; dkp->dk_trmode = 0 ; dkp->dk_C = dkp->dk_rseq = 0 ; break ; case INIT1: dksend(stechan, AINIT) ; dkp->dk_trmode = 1 ; dkp->dk_C = dkp->dk_tail1 = dkp->dk_tail2 = dkp->dk_rseq = 0 ; while (pkb) { pkb->Pnext = dk_Sfree ; dk_Sfree = pkb ; if (pkb = dkp->dk_rq) dkp->dk_rq = pkb->Pnext ; if (pkb == NULL) if (pkb = dkp->dk_rb) dkp->dk_rb = pkb->Pnext ; } goto qpkb ; case INITREQ: dksend(stechan, INIT1) ; dkp->dk_X = 0 ; break ; case ENQ: dksend(stechan, dkp->dk_C) ; case CHECK: dksend(stechan, ACK+dkp->dk_rseq) ; while (pkb) { pkb->Pnext = dk_Sfree ; dk_Sfree = pkb ; if (pkb = dkp->dk_rb) dkp->dk_rb = pkb->Pnext ; } dkp->dk_rblen = 0 ; goto qpkb ; case EOI: if (dkp->dk_tail1 == ((SOI<<8)|2)) dkreport(KS_EOI, stechan, dkp->dk_tail2, 0, 1) ; dkp->dk_tail1 = 0 ; break ; default: if (c & DKDATA) { if (dkp->dk_tail1) { dkp->dk_tail2 = ((dkp->dk_tail2 >> 8) & 0377) | (c<<8) ; dkp->dk_tail1++ ; if ((dkp->dk_tail1 & 0377) > 3) dkp->dk_tail1 = 0 ; } else { *ptr++ = c & 0377 ; pkb->Plen++ ; bitloc >>= 1 ; } break ; } if (((c & 0770) == ECHO) || ((c & 0770) == REJ)) { URPTRACE(stechan, c, dkp); dkp->dk_R = c & 07 ; if (((dkp->dk_S - dkp->dk_R - 1) & 07) < ((dkp->dk_S - dkp->dk_A - 1) & 07)) { gotack: dkp->dk_X &= ~(XM_REJ | XM_ENQ); xlen = dkp->dk_xlen ; len = ((c - dkp->dk_A) & 07) * DKBLOCK ; len = MIN(len, xlen); dkp->dk_xlen -= len; if (dkp->dk_curout) m_adj(dkp->dk_curout->m_next, len) ; dkp->dk_A = c & 07 ; if (len || xlen) if ((dkp->dk_xlen) == 0) dkreport(KS_SEND, stechan, 0, 0, 1) ; } dkxmit(dkp, stechan, 1) ; raddr->dkcsr = D_READ ; if ((c & 0770) == REJ && ((dkp->dk_X & XM_REJ) == 0)) { dkp->dk_rejcnt++; gotrej: dkp->dk_S = (c+1) & 07 ; dkxmit(dkp, stechan, 1) ; raddr->dkcsr = D_READ ; dkp->dk_X |= XM_REJ ; } break ; } if ((c & 0770) == ACK) { URPTRACE(stechan, c, dkp); if (dkp->dk_A != (c & 07)) goto gotack ; if ((dkp->dk_X & XM_REJ) == 0) { dkp->dk_ackrejcnt++; goto gotrej ; } break ; } if ((c & 0774) == BOT) { dkp->dk_tail1 = c << 8 ; break ; } if ((c & 0770) == SEQ) { pkb->Pseq = c - SEQ + ECHO ; dkrcvq(stechan, dkp, pkb, 0) ; if (dkp->dk_trmode) { if (dkp->dk_rblen == dkp->dk_tail2 && (dkp->dk_tail1 & 0377) == 2 && ((dkp->dk_tail1 >> 8) & 0377) != SOI && ((dkp->dk_rseq+1) & 07) == (c & 07)) { dkp->dk_rseq = c & 07 ; if (((dkp->dk_tail1>>8) & 0377) != BOTM) pkb->Pseq += ACK - ECHO ; dkrcvq(stechan, dkp, dkp->dk_rb, 1) ; } else { while (pkb = dkp->dk_rb) { dkp->dk_rb = pkb->Pnext ; pkb->Pnext = dk_Sfree ; dk_Sfree = pkb ; } pkb = dk_Sfree ; dk_Sfree = pkb->Pnext ; pkb->Plen = 0 ; pkb->Pnext = NULL ; pkb->Pseq = REJ + dkp->dk_rseq ; dkp->dk_srejcnt++; if (((dkp->dk_tail1>>8) & 0377) == BOTS) { dkp->dk_rseq = c & 07 ; pkb->Pseq = ECHO + dkp->dk_rseq ; } dkrcvq(stechan, dkp, pkb, 1) ; } dkp->dk_rb = NULL ; dkp->dk_rblen = 0 ; dkp->dk_tail1 = 0 ; } else /* always keep seq no up to date */ dkp->dk_rseq = c & 07; pkb = NULL ; goto qpkb ; } if (c & 0200) { dkreport(KS_CNTL, stechan, c, 0, 1) ; raddr->dkcsr = D_READ ; } else { *ptr++ = c & 0377 ; pkb->Plen++ ; pkb->Phibits |= bitloc ; bitloc >>= 1 ; } } if (pkb && pkb->Plen) { dkrcvq(stechan, dkp, pkb, 0) ; pkb = NULL ; } } } if (pkb) { if (pkb->Plen) dkrcvq(stechan, dkp, pkb, 0) ; else { pkb->Pnext = dk_Sfree ; dk_Sfree = pkb ; } } raddr->dkcsr = ENABS ; return; disable: if(pkb){ pkb->Pnext = dk_Sfree; dk_Sfree = pkb; } raddr->dkcsr = 0; dkdisabled = 1; } dkrcvq(stechan, dkp, npkb, where) register struct dkchan *dkp ; struct dkpkbufr *npkb ; { register struct dkpkbufr *pkb ; int i ; i = 0 ; if (dkp->dk_trmode && where == 0) pkb = (struct dkpkbufr *)&dkp->dk_rb ; else pkb = (struct dkpkbufr *)&dkp->dk_rq ; while (pkb->Pnext) { pkb = pkb->Pnext ; i++ ; } if ( i >= PKBHOG ) { /* ** This channel has too many buffers. ** Do not queue any more. ** Return the new buffer to the free list. */ npkb->Pnext = dk_Sfree ; dk_Sfree = npkb ; return ; } pkb->Pnext = npkb ; if (dkp->dk_trmode && where == 0) dkp->dk_rblen += npkb->Plen ; else dkrcv(dkp, stechan, 1) ; } dkreport(type, chan, info1, info2, intrpt) /* intrpt parameter controlls whether the pdp-11 interrupt is called. * Value 0 says no (means dkxint queued already) * Value 1 says call it immediately (like from dr11c interrupt) * Value 2 says to queue a call as soon as processor priority lowers * (by sending a dummy packet on a channel and getting dkxint) */ { register struct dkstat *sp; if ((Tstat + 1) % dkdr_nstat == Hstat) { /* room in queue? */ log(LOG_ERR, "dkit_dr: No room in status queue, Channel %d\n", chan); return; } sp = &dkdr_stat[Tstat] ; sp->k_chan = chan ; sp->k_type = type ; sp->k_info1 = info1 ; sp->k_info2 = info2 ; if (Tstat == dkdr_nstat-1) Tstat = 0 ; else Tstat++ ; if (intrpt==1) { dkkint() ; } else if (intrpt==2) { register struct rdevice *raddr ; raddr = DKADDR ; raddr->dkcsr = D_WRITE ; /* Chl (dk_nchan-1) is used instead of 511 because * the LDI switch module will complain if we use * a chl outside the range set up in its route tables. */ raddr->dko = (dk_nchan-1) | DKMARK ; /* * A null is used here because it should always * be ignored by the far end of the circuit. */ raddr->dko = 0 ; raddr->dkcsr = D_XPACK ; raddr->dko = 0 ; raddr->dkcsr = ENABS ; } } #ifdef URPDEBUG struct dkurps { char dku_ctl; char dku_S; char dku_R; char dku_A; } dkurps[URPDEBUG]; int dkurpsize = URPDEBUG; struct dkurps *dkurpsp = dkurps; int dkurpreset; dkurptrace(ctl, dkp) char ctl; register struct dkchan *dkp; { #ifdef lint dkurpsize = dkurpsize; #endif if (dkurpreset) { dkurpsp = dkurps; dkurpreset = 0; } dkurpsp->dku_ctl = ctl; dkurpsp->dku_S = dkp->dk_S; dkurpsp->dku_R = dkp->dk_R; dkurpsp->dku_A = dkp->dk_A; if (++dkurpsp == dkurps+URPDEBUG) dkurpsp = dkurps; } #endif URPDEBUG #endif