📄 if_dmc.c
字号:
/* * Inform owner that device is up. */ if ( ifp->if_addr.sa_family != AF_UNSPEC ) { struct protosw *pr; sc->sc_dmccs.if_dstate = IFS_RUNNING; if ((pr=iffamily_to_proto(ifp->if_addr.sa_family)) && pr->pr_ifstate) (*pr->pr_ifstate)(ifp, IFS_RUNNING, &sc->sc_dmccs); }}/* * Start output on interface. Get another datagram * to send from the interface queue and map it to * the interface before starting output. * * Must be called at pri 5 */dmcstart(dev) dev_t dev;{ int unit = minor(dev); register struct dmc_softc *sc = &dmc_softc[unit]; struct mbuf *m; register struct dmcbufs *rp; register int n; /* * Dequeue up to NXMT requests and map them to the UNIBUS. * If no more requests, or no dmc buffers available, just return. */ n = 0; for(rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[sc->sc_bufres.nxmt]; rp++ ) { /* find an available buffer */ if ((rp->flags & DBUF_DMCS) == 0) { IF_DEQUEUE(&sc->sc_if.if_snd, m); if (m == 0) return; /* mark it dmcs */ rp->flags |= (DBUF_DMCS); /* * Have request mapped to UNIBUS for transmission * and start the output. */ rp->cc = dmcput(&sc->sc_ifuba, n, m); rp->cc &= DMC_CCOUNT; sc->sc_oused++; dmcload(sc, DMC_WRITE, rp->ubinfo, rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); } n++; }}/* * Utility routine to load the DMC device registers. */dmcload(sc, type, w0, w1) register struct dmc_softc *sc; int type, w0, w1;{ register struct dmcdevice *addr; register int unit, sps; register struct dmc_command *qp; unit = sc->sc_if.if_unit; addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; sps = splimp(); /* grab a command buffer from the free list */ if((qp = sc->sc_qfreeh) == (struct dmc_command *)0) { printf("dmc%d: no free command buffer\n", unit); splx(sps); return; } DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); /* fill in requested info */ qp->qp_cmd = (type | DMC_RQI); qp->qp_ubaddr = w0; qp->qp_cc = w1; if (sc->sc_qactive){ /* command in progress */ if(type == DMC_READ) { QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); } else { QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); } } else { /* command port free */ sc->sc_qactive = qp; addr->bsel0 = qp->qp_cmd; dmcrint(unit); } splx(sps);}/* * DMC interface receiver interrupt. * Ready to accept another command, * pull one off the command queue. */dmcrint(unit) int unit;{ register struct dmc_softc *sc; register struct dmcdevice *addr; register struct dmc_command *qp; register int n; addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; sc = &dmc_softc[unit]; if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { printf("dmcrint: no command for dmc%d\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! */ ; /* 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; register struct ifrw *ifrw; register struct dmcbufs *rp; register struct ifxmt *ifxp; struct dmc_header *dh; int off, resid; struct protosw *pr; 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++; /* * Accumulate statistics for DECnet */ if ( (sc->sc_rxtxctrs[DMCZ_RXBYTE] + (arg & DMC_CCOUNT)) > sc->sc_rxtxctrs[DMCZ_RXBYTE] ) sc->sc_rxtxctrs[DMCZ_RXBYTE] += (arg & DMC_CCOUNT); if ( sc->sc_rxtxctrs[DMCZ_RXBLOK] != 0xffffffff ) sc->sc_rxtxctrs[DMCZ_RXBLOK]++; /* find location in dmcuba struct */ ifrw= &sc->sc_ifuba.ifu_r[0]; for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[sc->sc_bufres.nrcv]; rp++) { if(rp->ubinfo == pkaddr) break; ifrw++; } if (rp >= &sc->sc_rbufs[sc->sc_bufres.nrcv]) panic("dmc rcv"); if ((rp->flags & DBUF_DMCS) == 0) printf("dmc%d: done unalloc rbuf\n", unit); if ( sc->sc_dmccs.if_nomuxhdr ) { len = (arg & DMC_CCOUNT); } else { 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; } /* * If using dmc header, then * 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. */ if ( ! sc->sc_dmccs.if_nomuxhdr ) { 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; } 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 = dmc_get(&sc->sc_ifuba, ifrw, len, off, ! (sc->sc_dmccs.if_nomuxhdr)); if (m == 0) goto setup; if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } /* * Find protocol to which packet is destined */ if ( ! sc->sc_dmccs.if_nomuxhdr ) { /* * Multiplexed - find protocol as a * function of packet type */ switch (dh->dmc_type) { #ifdef INET case DMC_IPTYPE: if (nINET) { inq = &ipintrq; smp_lock(&ipintrq.lk_ifqueue, LK_RETRY); schednetisr(NETISR_IP); break; } else { printf("dmc%d: unknown address type %d\n", unit, ifp->if_addr.sa_family); goto setup; }#endif default: /* * see if other protocol families defined * and call protocol specific routines. * If no other protocols defined then dump message. */ if ((pr=iffamily_to_proto(ifp->if_addr.sa_family)) && pr->pr_ifinput) { if (( m = (struct mbuf *)(*pr->pr_ifinput)(m, ifp, &inq, NULL)) == 0) goto setup; } else { printf("dmc%d: unknown address type %d\n", unit, ifp->if_addr.sa_family); m_freem(m); goto setup; } } } else { /* * Not multiplexed - find protocol as a * function of family */ if ((pr=iffamily_to_proto(ifp->if_addr.sa_family)) && pr->pr_ifinput) { if (( m = (struct mbuf *)(*pr->pr_ifinput)(m, ifp, &inq, NULL)) == 0) goto setup; } else { printf("dmc%d: unknown address type %d\n", unit, ifp->if_addr.sa_family); m_freem(m); goto setup; } } if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUEIF(inq, m, ifp); smp_unlock(&inq->lk_ifqueue); setup: /* is this needed? */ rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 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++; /* * Accumulate statistics for DECnet */ if ( (sc->sc_rxtxctrs[DMCZ_TXBYTE] + (arg & DMC_CCOUNT)) > sc->sc_rxtxctrs[DMCZ_TXBYTE] ) sc->sc_rxtxctrs[DMCZ_TXBYTE] += (arg & DMC_CCOUNT); if ( sc->sc_rxtxctrs[DMCZ_TXBLOK] != 0xffffffff ) sc->sc_rxtxctrs[DMCZ_TXBLOK]++; /* find associated dmcbuf structure */ ifxp = &sc->sc_ifuba.ifu_w[0]; for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[sc->sc_bufres.nxmt]; rp++) { if(rp->ubinfo == pkaddr) break; ifxp++; } if (rp >= &sc->sc_xbufs[sc->sc_bufres.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->x_xtofree) { (void)m_freem(ifxp->x_xtofree); ifxp->x_xtofree = 0; } rp->flags &= ~DBUF_DMCS; sc->sc_oused--; sc->sc_nticks = 0; sc->sc_flag |= DMC_ACTIVE; break; case DMC_CNTLO: arg &= DMC_CNTMASK; if (arg & DMC_FATAL) { sc->sc_dmccs.if_dstate = ( arg & DMC_MAINTREC ) ? IFS_ENTEREDMOP : IFS_HALTED; if (pr=iffamily_to_proto(ifp->if_addr.sa_family)) if (pr->pr_ifstate && (*pr->pr_ifstate)(ifp, sc->sc_dmccs.if_dstate, &sc->sc_dmccs)) dmcstate(ifp, sc, ui); else printd("dmc%d: fatal error, flags=%b\n", unit, arg, CNTLO_BITS); else printd("dmc%d: fatal error, flags=%b\n", unit, arg, CNTLO_BITS); ifp->if_flags &= ~IFF_UP; if ( ifp->if_addr.sa_family == AF_UNSPEC || sc->sc_dmccs.if_dstate == IFS_STARTING ) { 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -