📄 if_dmv.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_dmv.c 4.2 (ULTRIX) 9/4/90";#endif lint/************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* ------------------------------------------------------------------------ * Modification History: /sys/vaxif/if_dmv.c * * 11/29/88 -- jaw - remove cursysproc stuff. * * 12/28/86 -- ejf - report threshold error only once. * * 12/16/86 -- ejf - fixed problem where IPL could be lowered below device ipl. * * 03/06/86 -- ejf - cloned from dmc driver * * ----------------------------------------------------------------------- */#include "dmv.h"#if NDMV > 0 || defined(BINARY)/* * DMV11 device driver */#include "../data/if_dmv_data.c"int dmvtimer; /* timer started? */int dmv_timeout = 25; /* timeout value */int dmvwatch();#define printd if(dmvdebug)printf#define printdmverr if(sc->sc_dmvcs.if_dstate == IFS_RUNNING || ! sc->sc_dmverrmsg++ || dmvdebug)printfint dmvdebug = 0;/* error reporting intervals */#define DMV_RPNBFS 50#define DMV_RPDSC 50#define DMV_RPTMO 10#define DMV_RPDCK 10struct mbuf *dmv_get();extern struct protosw *iftype_to_proto(), *iffamily_to_proto();extern struct timeval time;extern int boot_cpu_mask;/* * DMV software status per interface. * * Each interface is referenced by a network interface structure, * sc_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... * We also have, for each interface, a set of 7 UBA interface structures * for each, which * contain information about the UNIBUS resources held by the interface: * map registers, buffered data paths, etc. Information is cached in this * structure for use by the if_uba.c routines in running the interface * efficiently. *//* flags */#define DMV_ALLOC 01 /* unibus resources allocated */#define DMV_BMAPPED 02 /* base table mapped */#define DMV_RESTART 04 /* software restart in progress */#define DMV_ACTIVE 08 /* device active *//* * Driver information for auto-configuration stuff. */int dmvprobe(), dmvattach(), dmvinit(), dmvioctl();int dmvoutput(), dmvreset();u_short dmvstd[] = { 0 };struct uba_driver dmvdriver = { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo };/* * dmv software packet encapsulation. This allows the dmv * link to be multiplexed among several protocols. * The first eight bytes of the dmv header are garbage; they * exist for historical reasons only since this structure is * the same one used for the DMC driver. * The next two bytes encapsulate packet type. */struct dmv_header { char dmv_buf[8]; /* space for uba on vax */ short dmv_type; /* encapsulate packet type */};/* queue manipulation macros */#define QUEUE_AT_HEAD(qp, head, tail) \ (qp)->qp_next = (head); \ (head) = (qp); \ if((tail) == (struct dmv_command *) 0) \ (tail) = (head) #define QUEUE_AT_TAIL(qp, head, tail) \ if((tail)) \ (tail)->qp_next = (qp); \ else \ (head) = (qp); \ (qp)->qp_next = (struct dmv_command *) 0; \ (tail) = (qp)#define DEQUEUE(head, tail) \ (head) = (head)->qp_next;\ if((head) == (struct dmv_command *) 0)\ (tail) = (head)dmvprobe(reg) caddr_t reg;{ register struct dmvdevice *addr = (struct dmvdevice *)reg; register int i;#ifdef lint dmvrint(0); dmvxint(0);#endif addr->bsel1 = DMV_MCLR; for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; if ((addr->bsel1 & DMV_RUN) == 0) { printf("dmvprobe: can't start device\n" ); return (0); } if ( (addr->sel4 & DMV_LBSEL_MASK) != 033 || (addr->sel6 & DMV_LBSEL_MASK) != 0305 ) { printf("dmvprobe: device failed diagnostics, octal failure code = %o\n", (addr->sel6 & DMV_LBSEL_MASK) ); return (0); } addr->bsel0 = DMV_RQI|DMV_IEI; DELAY(1000000); addr->bsel1 = DMV_MCLR; for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; return (sizeof(struct dmvdevice));}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */dmvattach(ui) register struct uba_device *ui;{ register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; struct dmvdevice *addr = (struct dmvdevice *)dmvinfo[ui->ui_unit]->ui_addr; int ncl; sc->sc_if.if_unit = ui->ui_unit; sc->sc_if.if_name = "dmv"; sc->sc_if.if_mtu = DMVMTU; sc->sc_if.if_init = dmvinit; sc->sc_if.if_output = dmvoutput; sc->sc_if.if_ioctl = dmvioctl; sc->sc_if.if_reset = dmvreset; sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_DYNPROTO; sc->sc_if.d_affinity = boot_cpu_mask; sc->sc_ifuba.ifu_flags = UBA_CANTWAIT; bzero(&sc->sc_dmvcs, sizeof(sc->sc_dmvcs)); bzero(&sc->sc_errctrs, sizeof(sc->sc_errctrs)); sc->sc_dmvcs.if_family = AF_UNSPEC; sc->sc_dmvcs.if_next_family = AF_UNSPEC; sc->sc_dmvcs.if_mode = ui->ui_flags; if ((sc->sc_bufres.nxmt = ((NXMT_MASK & ui->ui_flags) >> NXMT_SHIFT)) > NXMT_MIN ) { if (sc->sc_bufres.nxmt > NXMT_MAX) sc->sc_bufres.nxmt = NXMT_MAX; } else sc->sc_bufres.nxmt = NXMT_MIN; sc->sc_bufres.nrcv = NRCV; sc->sc_bufres.ntot = sc->sc_bufres.nrcv + sc->sc_bufres.nxmt; sc->sc_bufres.ncmds = sc->sc_bufres.ntot + 4; /* * Allocate page size buffers now. If we wait until the network * is setup they have already fragmented. By doing it here in * conjunction with always coping on uVAX-I processors we obtain * physically contigous buffers for dma transfers. */ ncl = clrnd((int)btoc(DMVMTU) + CLSIZE) / CLSIZE; sc->sc_bufres.buffers = m_clalloc(sc->sc_bufres.ntot * ncl, MPG_SPACE); if_attach(&sc->sc_if); if (dmvtimer == 0) { dmvtimer = 1; timeout(dmvwatch, (caddr_t) 0, hz); }}/* * Reset of interface after UNIBUS reset. * If interface is on specified UBA, reset it's state. */dmvreset(unit, uban) int unit, uban;{ register struct uba_device *ui; register struct dmv_softc *sc = &dmv_softc[unit]; if (unit >= nNDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf("resetting dmv%d", unit); sc->sc_flag = 0; dmvinit(unit);}/* * Initialization of interface; reinitialize UNIBUS usage. */dmvinit(unit) int unit;{ register struct dmv_softc *sc = &dmv_softc[unit]; register struct uba_device *ui = dmvinfo[unit]; register struct dmvdevice *addr; register struct ifnet *ifp = &sc->sc_if; register struct ifrw *ifrw; register struct ifxmt *ifxp; register struct dmvbufs *rp; register struct dmv_command *qp; register struct ifaddr *ifa; struct dmv_command cmd; int base; int s; u_short dev_strt = 0; addr = (struct dmvdevice *)ui->ui_addr; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if ((ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) || ifa->ifa_addr.sa_family == AF_OSI) break; if (ifa == (struct ifaddr *) 0) return; if((addr->bsel1&DMV_RUN) == 0) { printf("dmvinit: DMV%d not running\n", unit); ifp->if_flags &= ~(IFF_RUNNING|IFF_UP); return; } /* map base table */ if ((sc->sc_flag & DMV_BMAPPED) == 0) { sc->sc_ubinfo = uballoc(ui->ui_ubanum, (caddr_t)&dmv_base[unit], sizeof (struct dmv_base), 0); sc->sc_flag |= DMV_BMAPPED; } /* initialize UNIBUS resources */ sc->sc_iused = sc->sc_oused = 0; if ((sc->sc_flag & DMV_ALLOC) == 0) { if (dmv_ubainit(&sc->sc_ifuba, ui->ui_ubanum, sizeof(struct dmv_header), (int)btoc(DMVMTU), &sc->sc_bufres) == 0) { printf("dmv%d: can't initialize\n", unit); ifp->if_flags &= ~IFF_UP; return; } sc->sc_flag |= DMV_ALLOC; } /* initialize buffer pool */ /* recieves */ ifrw= &sc->sc_ifuba.ifu_r[0]; for(rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[sc->sc_bufres.nrcv]; rp++) { rp->ubinfo = ifrw->ifrw_info & 0x3ffff; rp->cc = DMVMTU + sizeof (struct dmv_header); rp->flags = DBUF_OURS|DBUF_RCV; ifrw++; } /* transmits */ ifxp= &sc->sc_ifuba.ifu_w[0]; for(rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[sc->sc_bufres.nxmt]; rp++) { rp->ubinfo = ifxp->x_ifrw.ifrw_info & 0x3ffff; rp->cc = 0; rp->flags = DBUF_OURS|DBUF_XMIT; ifxp++; } /* set up command queues */ sc->sc_qfreeh = sc->sc_qfreet = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = (struct dmv_command *)0; /* set up free command buffer list */ for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[sc->sc_bufres.ncmds]; qp++) { QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); } /* if first time through, zero out counters */ if ( ! (ifp->if_flags & IFF_RUNNING) ) { sc->sc_ztime = time.tv_sec; bzero(&sc->sc_errctrs, sizeof(sc->sc_errctrs)); } /* set up internal loopback if requested */ if ( ifp->if_flags & IFF_LOOPBACK ) { int i; addr->bsel1 |= (DMV_ILOOP | DMV_MCLR); for ( i = 10000; i && ! (addr->bsel2 & DMV_RDYO); i-- ) ; if ( ! (addr->bsel2 & DMV_RDYO) ) printf("dmvinit: can't place dmv%d into internal loopback\n", unit); else addr->bsel2 = DMV_MAINT_ILOOP; } /* enable operation done interrupts */ sc->sc_flag &= ~DMV_ACTIVE; while ((addr->bsel0 & DMV_IEO) == 0) addr->bsel0 |= DMV_IEO; s = splimp(); /* Issue mode command, establish trib and start device */ switch ( (ifp->if_flags & IFF_LOOPBACK) ? DMV_MFLAGS_FDPLX_DMC : (sc->sc_dmvcs.if_mode & DMV_MFLAGS_MASK) ) { /* use DDCMP point to point full duplex mode */ case DMV_MFLAGS_FDPLX_DMC: dev_strt = DMV_CNTL_RQSTRT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) && ! (ifp->if_flags & IFF_LOOPBACK) ) break; printd("dmv%d: starting device in full duplex, dmc compatible mode\n", unit); dmv_issue_mode(sc, DMV_MODE_FDPLX_DMC); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; case DMV_MFLAGS_FDPLX: dev_strt = DMV_CNTL_RQSTRT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) ) break; printf("dmv%d: starting device in full duplex mode\n", unit); dmv_issue_mode(sc, DMV_MODE_FDPLX); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; /* use DDCMP half duplex as primary station */ case DMV_MFLAGS_HDPLX_DMC: dev_strt = DMV_CNTL_RQSTRT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) ) break; printd("dmv%d: starting device in half duplex, dmc compatible mode\n", unit); dmv_issue_mode(sc, DMV_MODE_HDPLX_DMC); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; case DMV_MFLAGS_HDPLX: dev_strt = DMV_CNTL_RQSTRT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) ) break; printd("dmv%d: starting device in half duplex mode\n", unit); dmv_issue_mode(sc, DMV_MODE_HDPLX); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; /* use MAINTENANCE full duplex mode */ case DMV_MFLAGS_MAINT_FDPLX: dev_strt = DMV_CNTL_RQMAINT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) ) break; printf("dmv%d: starting device in full duplex maintenance mode\n", unit); dmv_issue_mode(sc, DMV_MODE_FDPLX_DMC); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; /* use MAINTENANCE half duplex mode */ case DMV_MFLAGS_MAINT_HDPLX: default: dev_strt = DMV_CNTL_RQMAINT; if ( (ifp->if_flags & IFF_RUNNING) && ! (sc->sc_flag & DMV_RESTART) ) break; printd("dmv%d: starting device in half duplex maintenance mode\n", unit); dmv_issue_mode(sc, DMV_MODE_HDPLX_DMC); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, DMV_CNTL_ESTRIB ); break; } /* override device default values for select and babble timers */ dmv_issue_ctl( sc, DMV_TRIB_POINT, DMV_TIMER_SEL, (DMV_CNTL_WRITE | DMV_KEY_SELECT) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, DMV_TIMER_BAB, (DMV_CNTL_WRITE | DMV_KEY_BABBLE) ); /* tell device to start protocol */ sc->sc_dmvcs.if_dstate = IFS_STARTING; dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, dev_strt ); /* queue first NRCV buffers for DMV to fill */ for(rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[sc->sc_bufres.nrcv]; rp++) { printd("dmv%d: assigning receive buffer\n", unit); rp->flags |= DBUF_DMVS; dmv_issue_buf(sc, DMV_CMD_RXBUF, 1, rp->ubinfo, rp->cc); sc->sc_iused++; } /* * If in Maintenance, inform owner that device is up. */ if ( dev_strt == DMV_CNTL_RQMAINT) { sc->sc_if.if_flags |= IFF_UP; sc->sc_dmvcs.if_dstate = IFS_RUNNING; 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, &sc->sc_dmvcs); } } splx(s); ifp->if_flags |= IFF_RUNNING; if ( sc->sc_dmvcs.if_mode == IFS_MOP ) ifp->if_flags |= IFF_MOP; else ifp->if_flags &= ~IFF_MOP;}/* * 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. */dmvstart(dev) dev_t dev;{ int unit = minor(dev); register struct dmv_softc *sc = &dmv_softc[unit]; struct mbuf *m; register struct dmvbufs *rp; register int n; /* * Dequeue up to NXMT requests and map them to the UNIBUS. * If no more requests, or no dmv 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_DMVS) == 0) { IF_DEQUEUE(&sc->sc_if.if_snd, m); if (m == 0) return; /* mark it dmvs */ rp->flags |= DBUF_DMVS; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -