📄 if_dmv.c
字号:
* Have request mapped to UNIBUS for transmission * and start the output. */ rp->cc = dmvput(&sc->sc_ifuba, n, m); rp->cc &= DMV_CCOUNT; sc->sc_oused++; dmv_issue_buf(sc, DMV_CMD_TXBUF, 1, rp->ubinfo, rp->cc); } n++; }}/* * Routine to issue mode command. */dmv_issue_mode( sc, mode )register struct dmv_softc *sc;register u_short mode;{ struct dmv_command cmd; bzero(&cmd, sizeof(cmd)); cmd.qp_cmd = DMV_CMD_MODE; cmd.qp_data = 0; cmd.qp_trib = DMV_TRIB_POINT; cmd.qp_mode = mode; dmvload(sc, &cmd);}/* * Routine to issue control command. */dmv_issue_ctl( sc, trib, data, ctl )register struct dmv_softc *sc;register u_char trib;register u_short data;register u_short ctl;{ struct dmv_command cmd; bzero(&cmd, sizeof(cmd)); cmd.qp_cmd = DMV_CMD_CNTL; cmd.qp_trib = trib; cmd.qp_data = data; cmd.qp_ctl = ctl; dmvload(sc, &cmd);}/* * Routine to issue Tx/Rx buffer command. */dmv_issue_buf( sc, cmd_type, trib, addr, cc )register struct dmv_softc *sc;register u_char cmd_type, trib;register u_int addr;register u_short cc;{ struct dmv_command cmd; bzero(&cmd, sizeof(cmd)); cmd.qp_cmd = cmd_type | DMV_22BIT; cmd.qp_trib = trib; cmd.qp_lowaddr = (u_short) addr; cmd.qp_hiaddr = (u_short) (addr >> 16); cmd.qp_cc = cc; dmvload(sc, &cmd);}/* * Utility routine to load the DMV device registers. */dmvload(sc, cmd) register struct dmv_softc *sc; register struct dmv_command *cmd;{ register struct dmvdevice *addr; register int unit, sps; register struct dmv_command *qp; unit = sc->sc_if.if_unit; addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; sps = splimp(); /* grab a command buffer from the free list */ if((qp = sc->sc_qfreeh) == (struct dmv_command *)0) { printf("dmv%d: no free command buffer\n", unit); splx(sps); return; } DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); /* fill in requested info and pass to device */ *qp = *cmd; if (sc->sc_qactive){ /* command in progress */ if(((cmd->qp_cmd & DMV_CMD_MASK) == DMV_CMD_RXBUF) && ! (sc->sc_dmvcs.if_dstate == IFS_STARTING) ) { 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 |= DMV_IEI|DMV_RQI; } splx(sps);}/* * DMV interface receiver interrupt. * Ready to accept another command, * pull one off the command queue. */dmvrint(unit) int unit;{ register struct dmv_softc *sc; register struct dmvdevice *addr; register struct dmv_command *qp; addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; sc = &dmv_softc[unit]; if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { printd("dmvrint: no command\n"); addr->bsel2 |= DMV_CMD_CNTL; addr->sel6 = DMV_CNTL_NOP; addr->bsel0 &= ~(DMV_RQI | DMV_IEI); addr->bsel2 &= (DMV_CMD_CNTL | DMV_RDYO); return; } addr->bsel3 = qp->qp_trib; addr->bsel2 |= (qp->qp_cmd & 0x0f); switch ( qp->qp_cmd & 0x7 ) { case DMV_CMD_RXBUF: case DMV_CMD_TXBUF: addr->sel4 = qp->qp_lowaddr; addr->sel6 = qp->qp_hiaddr & HIADDR_MASK; addr->sel10 = qp->qp_cc & CC_MASK; break; case DMV_CMD_CNTL: addr->sel4 = qp->qp_data; addr->sel6 = qp->qp_ctl & CTL_MASK; break; case DMV_CMD_MODE: addr->sel6 = qp->qp_mode & MODE_MASK; break; default: printd("dmvrint: bad command = %x\n", qp->qp_cmd); addr->sel6 = DMV_CNTL_NOP; addr->bsel2 |= DMV_CMD_CNTL; break; } /* free command buffer */ QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); /* pre-fetch next command */ if ( (sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0 ) addr->bsel0 &= ~(DMV_RQI | DMV_IEI); else DEQUEUE(sc->sc_qhead, sc->sc_qtail); addr->bsel2 &= ~DMV_RDYI;}/* * DMV 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. */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 len, pkaddr; register struct ifrw *ifrw; register struct dmvbufs *rp; register struct ifxmt *ifxp; struct dmv_header *dh; struct dmv_command response; int off, resid; struct protosw *pr; addr = (struct dmvdevice *)ui->ui_addr; sc = &dmv_softc[unit]; ifp = &sc->sc_if; if ( (response.qp_cmd = addr->bsel2) & DMV_22BIT ) response.qp_cc = addr->sel10; response.qp_lowaddr = addr->sel4; response.qp_hiaddr = addr->sel6; response.qp_trib = addr->bsel3; /* release port */ addr->bsel2 &= ~DMV_RDYO; /* * analyze response */ switch (response.qp_cmd & DMV_CMD_MASK) { case DMV_RSP_RXBUFOK: /* * A read has completed. * Pass packet to type specific * higher-level input routine. */ pkaddr = (response.qp_hiaddr << 16) | response.qp_lowaddr; ifp->if_ipackets++; /* * Accumulate statistics for DECnet */ if ( (sc->sc_errctrs.ctr_ddcmp.dst_bytercvd + (response.qp_cc & CC_MASK)) > sc->sc_errctrs.ctr_ddcmp.dst_bytercvd ) sc->sc_errctrs.ctr_ddcmp.dst_bytercvd += (response.qp_cc & CC_MASK); if (sc->sc_errctrs.ctr_ddcmp.dst_blockrcvd != 0xffffffff) sc->sc_errctrs.ctr_ddcmp.dst_blockrcvd++; /* find location in dmvuba 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("dmv%d rcv", unit); if ((rp->flags & DBUF_DMVS) == 0) printf("dmv%d: done unalloc rbuf\n", unit); if ( sc->sc_dmvcs.if_nomuxhdr ) { len = (response.qp_cc & CC_MASK); } else { len = (response.qp_cc & CC_MASK) - sizeof (struct dmv_header); } if (len < 0 || len > DMVMTU) { ifp->if_ierrors++; printd("dmv%d: bad rcv pkt addr 0x%x len 0x%x\n", unit, pkaddr, len); goto setup; } /* * If using dmv 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_dmvcs.if_nomuxhdr ) { 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; } 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 = dmv_get(&sc->sc_ifuba, ifrw, len, off, ! (sc->sc_dmvcs.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_dmvcs.if_nomuxhdr ) { /* * Multiplexed - find protocol as a * function of packet type */ switch (dh->dmv_type) { #ifdef INET case DMV_IPTYPE: if (nINET) { inq = &ipintrq; smp_lock(&ipintrq.lk_ifqueue, LK_RETRY); schednetisr(NETISR_IP); break; } else { printf("dmv%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("dmv%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("dmv%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; if ( sc->sc_dmvcs.if_dstate != IFS_HALTING ) dmv_issue_buf(sc, DMV_CMD_RXBUF, 1, rp->ubinfo, rp->cc); else { rp->flags &= ~DBUF_DMVS; sc->sc_iused--; } break; case DMV_RSP_RXBUF: /* * An Rx buffer has just been returned unused. */ pkaddr = (response.qp_hiaddr << 16) | response.qp_lowaddr; /* find location in dmvuba 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("dmv%d rcv", unit); if ((rp->flags & DBUF_DMVS) == 0) printf("dmv%d: done unalloc rbuf\n", unit); rp->flags &= ~DBUF_DMVS; sc->sc_iused--; break; case DMV_RSP_TXBUFOK: /* * A write has completed, start another * transfer if there is more data to send. */ ifp->if_opackets++; /* * Accumulate statistics for DECnet */ if ( (sc->sc_errctrs.ctr_ddcmp.dst_bytesent + (response.qp_cc & CC_MASK)) > sc->sc_errctrs.ctr_ddcmp.dst_bytesent ) sc->sc_errctrs.ctr_ddcmp.dst_bytesent += (response.qp_cc & CC_MASK); if (sc->sc_errctrs.ctr_ddcmp.dst_blocksent != 0xffffffff) sc->sc_errctrs.ctr_ddcmp.dst_blocksent++; case DMV_RSP_TXBUF1: case DMV_RSP_TXBUF2: /* find associated dmvbuf structure */ pkaddr = (response.qp_hiaddr << 16) | response.qp_lowaddr; 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("dmv%d: bad packet address 0x%x\n", unit, pkaddr); break; } if ((rp->flags & DBUF_DMVS) == 0) printf("dmv%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_DMVS; sc->sc_oused--; sc->sc_nticks = 0; sc->sc_flag |= DMV_ACTIVE; break; case DMV_RSP_CNTL: dmv_rsp_cntl(sc, &response); break; case DMV_RSP_INFO: if ( response.qp_ctl & (DMV_INFO_READ | DMV_INFO_READZ) ) { dmv_format_tgss(sc, &response); } else if ( (response.qp_ctl & KEY_MASK) == DMV_INFO_BUFRET ) { if ( sc->sc_if.if_addr.sa_family != AF_UNSPEC ) { struct protosw *pr; if ((pr=iffamily_to_proto(sc->sc_if.if_addr.sa_family)) && pr->pr_ifstate ) (*pr->pr_ifstate)(&sc->sc_if, (sc->sc_dmvcs.if_dstate == IFS_ENTEREDMOP) ? IFS_ENTEREDMOP : IFS_HALTED, &sc->sc_dmvcs); dmvstate(&sc->sc_if, sc, ui); } else sc->sc_dmvcs.if_dstate = IFS_STARTING; if ( sc->sc_dmvcs.if_dstate == IFS_STARTING ) dmvinit(unit); } else if ( (response.qp_ctl & KEY_MASK) == DMV_INFO_MODEM ) { printf("dmv%d: information response; modem control = %x\n", unit, response.qp_data); } else { printd("dmv%d: unsolicited information response; ctl = %x, data = %x\n", unit, response.qp_ctl, response.qp_data); } break; default: printd("dmv%d: bad control %o\n", unit, response.qp_cmd); break; } dmvstart(unit); return;}/* * DMV routine to process control responses. */dmv_rsp_cntl(sc, rsp)register struct dmv_softc *sc;register struct dmv_command *rsp;{ register struct protosw *pr; register struct uba_device *ui = dmvinfo[sc->sc_if.if_unit]; switch ( rsp->qp_ctl & EVENT_MASK ) { case DMV_EVT_DISCONN: case DMV_EVT_CARLOSS: printdmverr("dmv%d: modem disconnect\n", sc->sc_if.if_unit); sc->sc_disc++; sc->sc_if.if_flags &= ~IFF_UP; sc->sc_dmvcs.if_dstate = IFS_HALTED; if ( sc->sc_if.if_addr.sa_family != AF_UNSPEC ) { if ((pr=iffamily_to_proto(sc->sc_if.if_addr.sa_family)) && pr->pr_ifstate ) (*pr->pr_ifstate)(&sc->sc_if, sc->sc_dmvcs.if_dstate, &sc->sc_dmvcs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -