📄 if_dmv.c
字号:
} addr->bsel0 = DMV_IEO; } else /* RDO set or DMV still holding CSR */ addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);}/* * DMV interface output interrupt. * A transfer may have completed, check for errors. * If it was a read, notify appropriate protocol. * If it was a write, pull the next one off the queue. */dmvxint(unit) int unit;{ register struct dmv_softc *sc; register struct ifnet *ifp; struct uba_device *ui = dmvinfo[unit]; struct dmvdevice *addr; struct mbuf *m; struct ifqueue *inq; int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; register struct ifrw *ifrw; register struct dmvbufs *rp; register struct ifxmt *ifxp; struct dmv_header *dh; int off, resid; addr = (struct dmvdevice *)ui->ui_addr; sc = &dmv_softc[unit]; splx(sc->sc_ipl); ifp = &sc->sc_if; while (addr->bsel2 & DMV_RDO) { sel2 = addr->bsel2; sel3 = addr->bsel3; sel4 = addr->wsel4; /* release port */ sel6 = addr->wsel6; if(sel2 & DMV_22BIT) sel10 = addr->wsel10; addr->bsel2 &= ~DMV_RDO; pkaddr = sel4 | ((sel6 & 0x3f) << 16); printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", (unsigned) sel2, (unsigned) sel4, (unsigned) sel6, (unsigned) sel10, (unsigned) pkaddr )); if((sc->sc_flag & DMV_RUNNING)==0) { log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); return; } switch (sel2 & 07) { case DMV_BDRUS: /* * A read has completed. * Pass packet to type specific * higher-level input routine. */ ifp->if_ipackets++; /* find location in dmvuba struct */ ifrw= &sc->sc_ifr[0]; for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { if(rp->ubinfo == pkaddr) break; ifrw++; } if (rp >= &sc->sc_rbufs[NRCV]) panic("dmv rcv"); if ((rp->flags & DBUF_DMVS) == 0) log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); len = (sel10&0x3fff) - sizeof (struct dmv_header); if (len < 0 || len > DMVMTU) { ifp->if_ierrors++; log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", unit, pkaddr, len); goto setup; } /* * Deal with trailer protocol: if type is trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ dh = (struct dmv_header *)ifrw->ifrw_addr; dh->dmv_type = ntohs((u_short)dh->dmv_type);#define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) if (dh->dmv_type >= DMV_TRAILER && dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { off = (dh->dmv_type - DMV_TRAILER) * 512; if (off >= DMVMTU) goto setup; /* sanity */ dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); if (off + resid > len) goto setup; /* sanity */ len = off + resid; } else off = 0; if (len == 0) goto setup; /* * Pull packet off interface. Off is nonzero if * packet has trailing header; dmv_get will then * force this header information to be at the front, * but we still have to drop the type and length * which are at the front of any trailer data. */ m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); if (m == 0) goto setup; switch (dh->dmv_type) {#ifdef INET case DMV_IPTYPE: schednetisr(NETISR_IP); inq = &ipintrq; break;#endif default: m_freem(m); goto setup; } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); splx(s); setup: /* is this needed? */ rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); dmvload( sc, DMV_BACCR, QP_SEL4|QP_SEL6|QP_SEL10, 0, (u_short) rp->ubinfo, (rp->ubinfo>>16)&0x3f, rp->cc ); break; case DMV_BDXSA: /* * A write has completed, start another * transfer if there is more data to send. */ ifp->if_opackets++; /* find associated dmvbuf structure */ ifxp = &sc->sc_ifw[0]; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { if(rp->ubinfo == pkaddr) break; ifxp++; } if (rp >= &sc->sc_xbufs[NXMT]) { log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", unit, pkaddr); break; } if ((rp->flags & DBUF_DMVS) == 0) log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", unit, pkaddr); /* mark buffer free */ if (ifxp->ifw_xtofree) { (void)m_freem(ifxp->ifw_xtofree); ifxp->ifw_xtofree = 0; } rp->flags &= ~DBUF_DMVS; if (--sc->sc_oused == 0) sc->sc_if.if_timer = 0; else sc->sc_if.if_timer = dmv_timeout; if ((sc->sc_flag & DMV_ONLINE) == 0) { extern int ifqmaxlen; /* * We're on the air. * Open the queue to the usual value. */ sc->sc_flag |= DMV_ONLINE; ifp->if_snd.ifq_maxlen = ifqmaxlen; } break; case DMV_CNTRLO: /* ACCUMULATE STATISTICS */ switch(sel6&DMV_EEC) { case DMV_ORUN: if(sc->sc_flag & DMV_RESTART) { load_rec_bufs(sc); sc->sc_flag &= ~DMV_RESTART; log(LOG_INFO, "dmv%d: far end on-line\n", unit); } else { log(LOG_WARNING, "dmv%d: far end restart\n", unit); goto restart; } break; case DMV_RTE: ifp->if_ierrors++; if ((sc->sc_rte++ % DMV_RPRTE) == 0) log(LOG_WARNING, "dmv%d: receive threshold error\n", unit); break; case DMV_TTE: ifp->if_oerrors++; if ((sc->sc_xte++ % DMV_RPTTE) == 0) log(LOG_WARNING, "dmv%d: transmit threshold error\n", unit); break; case DMV_STE: if ((sc->sc_ste++ % DMV_RPSTE) == 0) log(LOG_WARNING, "dmv%d: select threshold error\n", unit); break; case DMV_NXM: if ((sc->sc_nxm++ % DMV_RPNXM) == 0) log(LOG_WARNING, "dmv%d: nonexistent memory error\n", unit); break; case DMV_MODD: if ((sc->sc_modd++ % DMV_RPMODD) == 0) { log(LOG_WARNING, "dmv%d: modem disconnected error\n", unit); goto restart; } break; case DMV_CXRL: if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) log(LOG_WARNING, "dmv%d: carrier loss error\n", unit); break; case DMV_QOVF: log(LOG_WARNING, "dmv%d: response queue overflow\n", unit); sc->sc_qovf++; goto restart; default: log(LOG_WARNING, "dmv%d: unknown error %o\n", unit, sel6&DMV_EEC); if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) goto restart; break; } break; case DMV_BDRUNUS: case DMV_BDXSN: case DMV_BDXNS: log(LOG_INFO, "dmv%d: buffer disp for halted trib %o\n", unit, sel2&0x7 ); break; case DMV_MDEFO: if((sel6&0x1f) == 020) { log(LOG_INFO, "dmv%d: buffer return complete sel3=%x\n", unit, sel3); } else { log(LOG_INFO, "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n", unit, sel3, sel4, sel6 ); } break; default: log(LOG_WARNING, "dmv%d: bad control %o\n", unit, sel2&0x7 ); break; } } dmvstart(unit); return;restart: dmvrestart(unit);}load_rec_bufs(sc)register struct dmv_softc *sc;{ register struct dmvbufs *rp; /* queue first NRCV buffers for DMV to fill */ for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { rp->flags |= DBUF_DMVS; dmvload( sc, DMV_BACCR, QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 1, rp->ubinfo, (rp->ubinfo>>16)&0x3f, rp->cc ); sc->sc_iused++; }}/* * DMV output routine. * Encapsulate a packet of type family for the dmv. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */dmvoutput(ifp, m0, dst) register struct ifnet *ifp; register struct mbuf *m0; struct sockaddr *dst;{ int type, error, s; register struct mbuf *m = m0; register struct dmv_header *dh; register int off; if ((ifp->if_flags & IFF_UP) == 0) { error = ENETDOWN; goto bad; } switch (dst->sa_family) {#ifdef INET case AF_INET: off = m->m_pkthdr.len - m->m_len; if ((ifp->if_flags & IFF_NOTRAILERS) == 0) if (off > 0 && (off & 0x1ff) == 0 && (m->m_flags & M_EXT) == 0 && m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { type = DMV_TRAILER + (off>>9); m->m_data -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); goto gottrailertype; } type = DMV_IPTYPE; off = 0; goto gottype;#endif case AF_UNSPEC: dh = (struct dmv_header *)dst->sa_data; type = dh->dmv_type; goto gottype; default: log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; }gottrailertype: /* * Packet to be sent as a trailer; move first packet * (control information) to end of chain. */ while (m->m_next) m = m->m_next; m->m_next = m0; m = m0->m_next; m0->m_next = 0; m0 = m;gottype: /* * Add local network header * (there is space for a uba on a vax to step on) */ M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT); if (m == 0) { error = ENOBUFS; goto bad; } dh = mtod(m, struct dmv_header *); dh->dmv_type = htons((u_short)type); /* * Queue message on interface, and start output if interface * not yet active. */ s = splimp(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); dmvstart(ifp->if_unit); splx(s); return (0);bad: m_freem(m0); return (error);}/* * Process an ioctl request. *//* ARGSUSED */dmvioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ int s = splimp(), error = 0; struct mbuf *m; register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) dmvinit(ifp->if_unit); break; case SIOCSIFDSTADDR: if ((ifp->if_flags & IFF_RUNNING) == 0) dmvinit(ifp->if_unit); break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && sc->sc_flag & DMV_RUNNING) dmvdown(ifp->if_unit); else if (ifp->if_flags & IFF_UP && (sc->sc_flag & DMV_RUNNING) == 0) dmvrestart(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * Restart after a fatal error. * Clear device and reinitialize. */dmvrestart(unit) int unit;{ register struct dmvdevice *addr; register int i; dmvdown(unit); addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); /* * Let the DMV finish the MCLR. */ for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; if ((addr->bsel1 & DMV_RUN) == 0) { log(LOG_ERR, "dmvrestart: can't start device\n" ); return (0); } if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) { log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n", unit, addr->bsel4, addr->bsel6); return (0); } /* restart DMV */ dmvinit(unit); dmv_softc[unit].sc_if.if_collisions++; /* why not? */} /* * Reset a device and mark down. * Flush output queue and drop queue limit. */dmvdown(unit) int unit;{ struct dmv_softc *sc = &dmv_softc[unit]; register struct ifxmt *ifxp; ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR; sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE); for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { if (ifxp->ifw_xtofree) { (void) m_freem(ifxp->ifw_xtofree); ifxp->ifw_xtofree = 0; } } sc->sc_oused = 0; if_qflush(&sc->sc_if.if_snd); /* * Limit packets enqueued until we're back on the air. */ sc->sc_if.if_snd.ifq_maxlen = 3;}/* * Watchdog timeout to see that transmitted packets don't * lose interrupts. The device has to be online. */dmvtimeout(unit) int unit;{ register struct dmv_softc *sc; struct dmvdevice *addr; sc = &dmv_softc[unit]; if (sc->sc_flag & DMV_ONLINE) { addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr); log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n", unit, addr->bsel0 & 0xff, DMV0BITS, addr->bsel2 & 0xff, DMV2BITS); dmvrestart(unit); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -