📄 if_dmc.c
字号:
printf("dmc%d: dmcrint no command\n", unit); return; } while (addr->bsel0&DMC_RDYI) { addr->sel4 = qp->qp_ubaddr; addr->sel6 = qp->qp_cc; addr->bsel0 &= ~(DMC_IEI|DMC_RQI); /* free command buffer */ QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); while (addr->bsel0 & DMC_RDYI) { /* * Can't check for RDYO here 'cause * this routine isn't reentrant! */ DELAY(5); } /* move on to next command */ if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) break; /* all done */ /* more commands to do, start the next one */ qp = sc->sc_qactive; DEQUEUE(sc->sc_qhead, sc->sc_qtail); addr->bsel0 = qp->qp_cmd; n = RDYSCAN; while (n-- > 0) if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) break; } if (sc->sc_qactive) { addr->bsel0 |= DMC_IEI|DMC_RQI; /* VMS does it twice !*$%@# */ addr->bsel0 |= DMC_IEI|DMC_RQI; }}/* * DMC interface transmitter 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. */dmcxint(unit) int unit;{ register struct dmc_softc *sc; register struct ifnet *ifp; struct uba_device *ui = dmcinfo[unit]; struct dmcdevice *addr; struct mbuf *m; struct ifqueue *inq; int arg, pkaddr, cmd, len, s; register struct ifrw *ifrw; register struct dmcbufs *rp; register struct ifxmt *ifxp; struct dmc_header *dh; int off, resid; addr = (struct dmcdevice *)ui->ui_addr; sc = &dmc_softc[unit]; ifp = &sc->sc_if; while (addr->bsel2 & DMC_RDYO) { cmd = addr->bsel2 & 0xff; arg = addr->sel6 & 0xffff; /* reconstruct UNIBUS address of buffer returned to us */ pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); /* release port */ addr->bsel2 &= ~DMC_RDYO; switch (cmd & 07) { case DMC_OUR: /* * A read has completed. * Pass packet to type specific * higher-level input routine. */ ifp->if_ipackets++; /* find location in dmcuba 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("dmc rcv"); if ((rp->flags & DBUF_DMCS) == 0) printf("dmc%d: done unalloc rbuf\n", unit); len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); if (len < 0 || len > DMCMTU) { ifp->if_ierrors++; printd("dmc%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 dmc_header *)ifrw->ifrw_addr; dh->dmc_type = ntohs((u_short)dh->dmc_type);#define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) if (dh->dmc_type >= DMC_TRAILER && dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { off = (dh->dmc_type - DMC_TRAILER) * 512; if (off >= DMCMTU) goto setup; /* sanity */ dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); resid = ntohs(*(dmcdataaddr(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; dmc_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->dmc_type) {#ifdef INET case DMC_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); dmcload(sc, DMC_READ, rp->ubinfo, ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); break; case DMC_OUX: /* * A write has completed, start another * transfer if there is more data to send. */ ifp->if_opackets++; /* find associated dmcbuf 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]) { printf("dmc%d: bad packet address 0x%x\n", unit, pkaddr); break; } if ((rp->flags & DBUF_DMCS) == 0) printf("dmc%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_DMCS; if (--sc->sc_oused == 0) sc->sc_if.if_timer = 0; else sc->sc_if.if_timer = dmc_timeout; if ((sc->sc_flag & DMC_ONLINE) == 0) { extern int ifqmaxlen; /* * We're on the air. * Open the queue to the usual value. */ sc->sc_flag |= DMC_ONLINE; ifp->if_snd.ifq_maxlen = ifqmaxlen; } break; case DMC_CNTLO: arg &= DMC_CNTMASK; if (arg & DMC_FATAL) { if (arg != DMC_START) log(LOG_ERR, "dmc%d: fatal error, flags=%b\n", unit, arg, CNTLO_BITS); dmcrestart(unit); break; } /* ACCUMULATE STATISTICS */ switch(arg) { case DMC_NOBUFS: ifp->if_ierrors++; if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) goto report; break; case DMC_DISCONN: if ((sc->sc_disc++ % DMC_RPDSC) == 0) goto report; break; case DMC_TIMEOUT: if ((sc->sc_timeo++ % DMC_RPTMO) == 0) goto report; break; case DMC_DATACK: ifp->if_oerrors++; if ((sc->sc_datck++ % DMC_RPDCK) == 0) goto report; break; default: goto report; } break; report: printd("dmc%d: soft error, flags=%b\n", unit, arg, CNTLO_BITS); if ((sc->sc_flag & DMC_RESTART) == 0) { /* * kill off the dmc to get things * going again by generating a * procedure error */ sc->sc_flag |= DMC_RESTART; arg = UBAI_ADDR(sc->sc_ubinfo); dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); } break; default: printf("dmc%d: bad control %o\n", unit, cmd); break; } } dmcstart(unit); return;}/* * DMC output routine. * Encapsulate a packet of type family for the dmc. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */dmcoutput(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 dmc_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 = DMC_TRAILER + (off>>9); m->m_data -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); goto gottrailertype; } type = DMC_IPTYPE; off = 0; goto gottype;#endif case AF_UNSPEC: dh = (struct dmc_header *)dst->sa_data; type = dh->dmc_type; goto gottype; default: printf("dmc%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 dmc_header), M_DONTWAIT); if (m == 0) { error = ENOBUFS; goto bad; } dh = mtod(m, struct dmc_header *); dh->dmc_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); dmcstart(ifp->if_unit); splx(s); return (0);bad: m_freem(m0); return (error);}/* * Process an ioctl request. *//* ARGSUSED */dmcioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ int s = splimp(), error = 0; register struct dmc_softc *sc = &dmc_softc[ifp->if_unit]; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) dmcinit(ifp->if_unit); break; case SIOCSIFDSTADDR: if ((ifp->if_flags & IFF_RUNNING) == 0) dmcinit(ifp->if_unit); break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && sc->sc_flag & DMC_RUNNING) dmcdown(ifp->if_unit); else if (ifp->if_flags & IFF_UP && (sc->sc_flag & DMC_RUNNING) == 0) dmcrestart(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * Restart after a fatal error. * Clear device and reinitialize. */dmcrestart(unit) int unit;{ register struct dmc_softc *sc = &dmc_softc[unit]; register struct dmcdevice *addr; register int i; int s; #ifdef DEBUG /* dump base table */ printf("dmc%d base table:\n", unit); for (i = 0; i < sizeof (struct dmc_base); i++) printf("%o\n" ,dmc_base[unit].d_base[i]);#endif dmcdown(unit); /* * Let the DMR finish the MCLR. At 1 Mbit, it should do so * in about a max of 6.4 milliseconds with diagnostics enabled. */ addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) ; /* Did the timer expire or did the DMR finish? */ if ((addr->bsel1 & DMC_RUN) == 0) { log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); return; } /* restart DMC */ dmcinit(unit); sc->sc_flag &= ~DMC_RESTART; s = spl5(); dmcstart(unit); splx(s); sc->sc_if.if_collisions++; /* why not? */}/* * Reset a device and mark down. * Flush output queue and drop queue limit. */dmcdown(unit) int unit;{ register struct dmc_softc *sc = &dmc_softc[unit]; register struct ifxmt *ifxp; ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR; sc->sc_flag &= ~(DMC_RUNNING | DMC_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; } } if_qflush(&sc->sc_if.if_snd);}/* * Watchdog timeout to see that transmitted packets don't * lose interrupts. The device has to be online (the first * transmission may block until the other side comes up). */dmctimeout(unit) int unit;{ register struct dmc_softc *sc; struct dmcdevice *addr; sc = &dmc_softc[unit]; if (sc->sc_flag & DMC_ONLINE) { addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n", unit, addr->bsel0 & 0xff, DMC0BITS, addr->bsel2 & 0xff, DMC2BITS); dmcrestart(unit); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -