📄 if_de.c
字号:
/* * if_de.c */#ifndef lintstatic char *sccsid = "@(#)if_de.c 4.3 (ULTRIX) 2/26/91";#endif lint/************************************************************************ * * * Copyright (c) 1985-89 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 * * * * 24-Feb-91 - jsd * Allow loopback packets if COPYALL mode is set * * 10-Nov-89 - jaw * replace references to maxcpu with smp. * * 28-Oct-89 - Uttam Shikarpur * * Added: * * 1) Reporting counters for multicast packs. and bytes * * 2) Added "if_version" support. * * * * 3-Mar-89 - Uttam S.N * * Add support for Ethernet packet filter * * Moved common read code to ../net/ether_read.c * * * * 3-Mar-89 - U. Sinkewicz * * Added smp support. * * * * 29-Jun-88 - Fred L. Templin * * Added code to the "deoutput" routine to verify that the * * interface has been marked as "IFF_UP" and "IFF_RUNNING" * * * * 05-Feb-88 - lp * * Fix deget to switch only 1 cluster as unibus mapping had not * * changed. * * * * 15-Jan-88 - Larry Palmer * * Added changes for 43BSD. Also added changes for malloced mbufs. * * 12-Aug-87 -- Fred L. Templin * * Removed the "de0: buffer unavailable" printf. This has been * * around since the beginning of time, and this information is * * already maintained by the deuna counter block. Also, added check * * in deintr for USCI and SERI error interrupts. No error recovery * * is attempted; only print diagnostic messages. Fix suggested by * * Bill Dallas. * * * * 26-Feb-87 -- jsd * * Check return of iftype_to_proto so that we don't jump to 0. * * * * 13-Jun-86 -- jaw fix to uba reset and drivers. * * * * 18-mar-86 -- jaw br/cvec changed to NOT use registers. * * * * Chet Juszczak - 03/12/86 * * Modify MCLGET macro call to match new definition * * * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * * 10-Sep-85 -- pjt * * Delua support * * * * 19-Jun-85 -- jaw * * VAX8200 name change. * * * * 13 Mar 85 - Jaw * * add support for VAX8200 and bua * * * * LSC001 - Larry Cohen, 3/6/85: add internal loopback * * * * LSC002 - Larry cohen, 3/685: poke deuna when transmit ring * * is full and more data to send. Prevents system from * * dropping off the network and hanging occasionally * ***********************************************************************/#include "de.h"#if NDE > 0 || defined(BINARY)/* * DEC DEUNA interface * * Lou Salkind * New York University * * TODO: * timeout routine (get statistics) */#include "packetfilter.h" /* NPACKETFILTER */#include "../data/if_de_data.c"int dedebug = 0;u_char unused_multi[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};extern struct protosw *iftype_to_proto(), *iffamily_to_proto();extern struct timeval time;extern int net_output();int deprobe(), deattach(), deintr();struct uba_device ;u_short destd[] = { 0 };struct uba_driver dedriver = { deprobe, 0, deattach, 0, destd, "de", deinfo };#define DEUNIT(x) minor(x)int deinit(),destart(),deioctl(),dereset();struct mbuf *deget();#define DELUA_LOOP_LEN 32-sizeof(struct ether_header)deprobe(reg) caddr_t reg;{ register struct dedevice *addr = (struct dedevice *)reg; register i;#ifdef lint i = 0; derint(i); deintr(i);#endif /* * Make sure self-test is finished * Self-test on a DELUA can take 15 seconds. */ for (i = 0; i < 160 && (addr->pcsr0 & PCSR0_FATI) == 0 && (addr->pcsr1 & PCSR1_STMASK) == STAT_RESET; ++i) DELAY(100000); if ((addr->pcsr0 & PCSR0_FATI) != 0 || (addr->pcsr1 & PCSR1_STMASK) != STAT_READY) return(0); addr->pcsr0 = 0; addr->pcsr0 = PCSR0_RSET; /* * just in case this is not a deuna or delua * dont wait for more than 30 secs */ for (i = 0; i < 300 && (addr->pcsr0 & PCSR0_INTR) == 0; i++) DELAY(100000); if ((addr->pcsr0 & PCSR0_INTR) == 0) return(0); /* make board interrupt by executing a GETPCBB command */ addr->pcsr0 = PCSR0_INTE; addr->pcsr2 = 0; addr->pcsr3 = 0; addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB; DELAY(100000); return(1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. We get the ethernet address here. */deattach(ui) struct uba_device *ui;{ register struct de_softc *ds = &de_softc[ui->ui_unit]; register struct ifnet *ifp = &ds->ds_if; register struct dedevice *addr = (struct dedevice *)ui->ui_addr; struct sockaddr_in *sin; int csr0,i; u_short csr1 = addr->pcsr1; /* Initialize SMP lock */ lockinit(&ds->lk_de_softc, &lock_device15_d); /* * Is it a DEUNA or a DELUA? Save the device id. */ ds->ds_devid = (csr1 & PCSR1_DEVID) >> 4; /* check status of board */ if (csr1 & 0xff80) printf("de%d: hardware error, pcsr1=%x\n", csr1); ifp->if_unit = ui->ui_unit; ifp->if_name = "de"; ifp->lk_softc = &ds->lk_de_softc; ifp->if_mtu = ETHERMTU; ifp->if_type = IFT_ETHER; ifp->if_flags |= IFF_BROADCAST|IFF_DYNPROTO; /* * Fill the multicast address table with unused entries (broadcast * address) so that we can always give the full table to the device * and we don't have to worry about gaps. */ for (i=0; i < NMULTI; i++) bcopy(unused_multi,&ds->ds_multicast[i],MULTISIZE); /* * Reset the board and map the pcbb buffer onto the Unibus. */ addr->pcsr0 = PCSR0_RSET; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if ((csr0 & PCSR0_PCEI) || (csr0 & PCSR0_DNI)==0) { if (ds->ds_devid == DEUNA) printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); else printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS_DELUA); } ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE, 0); addr->pcsr2 = ds->ds_ubaddr & 0xffff; addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3; addr->pclow = CMD_GETPCBB; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if ((csr0 & PCSR0_PCEI) || (csr0 & PCSR0_DNI)==0) { if (ds->ds_devid == DEUNA) printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); else printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS_DELUA); } ds->ds_pcbb.pcbb0 = FC_RDPHYAD; addr->pclow = CMD_GETCMD; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if ((csr0 & PCSR0_PCEI) || (csr0 & PCSR0_DNI)==0) { if (ds->ds_devid == DEUNA) printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); else printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS_DELUA); } if (dedebug) printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit, ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff, ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff, ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff); bcopy((caddr_t)&ds->ds_pcbb.pcbb2,(caddr_t)ds->ds_addr, sizeof (ds->ds_addr)); ifp->if_init = deinit; ifp->if_output = net_output; ifp->if_start = destart; ifp->if_ioctl = deioctl; ifp->if_reset = dereset; ifp->d_affinity = ALLCPU; /* 10.18.88.us */ ds->ds_deuba.ifu_flags = UBA_CANTWAIT;#ifdef notdef /* CAN WE USE BDP's ??? */ ds->ds_deuba.ifu_flags |= UBA_NEEDBDP;#endif if (ds->ds_devid == DEUNA) { ifp->if_sysid_type = 1; bcopy("DEC DEUNA Ethernet Interface", ifp->if_version, 28); } else { ifp->if_sysid_type = 11; bcopy("DEC DELUA Ethernet Interface", ifp->if_version, 28); } ifp->if_version[28] = '\0'; printf ("de%d: %s, hardware address %s\n", ifp->if_unit, ifp->if_version, ether_sprintf(ds->ds_addr));#if NPACKETFILTER > 0 /* Tell the packet filter we are here */ attachpfilter(&(ds->ds_ed));#endif NPACKETFILTER if_attach(ifp);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */dereset(unit, uban) int unit, uban;{ register struct uba_device *ui; register struct de_softc *ds = &de_softc[unit]; if (unit >= nNDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" de%d", unit); ds->ds_ubaddr = uballoc(uban, INCORE_BASE(ds), INCORE_SIZE, 0); deinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */deinit(unit) int unit;{ register struct de_softc *ds = &de_softc[unit]; register struct uba_device *ui = deinfo[unit]; register struct dedevice *addr; register struct ifrw *ifrw; register struct ifxmt *ifxp; struct ifnet *ifp = &ds->ds_if; int s; struct de_ring *rp; int incaddr; int csr0; /* not yet, if address still unknown */ /* DECnet must set this somewhere to make device happy */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (ifp->if_flags & IFF_RUNNING) return; if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum, sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) { printf("de%d: can't initialize\n", unit); ds->ds_if.if_flags &= ~IFF_UP; return; } addr = (struct dedevice *)ui->ui_addr; /* set the transmit and receive ring header addresses */ incaddr = ds->ds_ubaddr + UDBBUF_OFFSET; ds->ds_pcbb.pcbb0 = FC_WTRING; ds->ds_pcbb.pcbb2 = incaddr & 0xffff; ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3; incaddr = ds->ds_ubaddr + XRENT_OFFSET; ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff; ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3; ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short); ds->ds_udbbuf.b_trlen = NXMT; incaddr = ds->ds_ubaddr + RRENT_OFFSET; ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff; ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3; ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short); ds->ds_udbbuf.b_rrlen = NRCV; addr->pclow = CMD_GETCMD; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if (csr0 & PCSR0_PCEI) if (ds->ds_devid == DEUNA) printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); else printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS_DELUA); /* initialize the mode - enable hardware padding */ ds->ds_pcbb.pcbb0 = FC_WTMODE; /* let hardware do padding - set MTCH bit on broadcast */ ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;#ifdef IFF_PROMISC if (ifp->if_flags & IFF_PROMISC) /* set promiscuous if wanted */ ds->ds_pcbb.pcbb2 |= MOD_PROM;#endif IFF_PROMISC addr->pclow = CMD_GETCMD; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if (csr0 & PCSR0_PCEI) if (ds->ds_devid == DEUNA) printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); else printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS_DELUA); /* set up the receive and transmit ring entries */ ifxp = &ds->ds_deuba.ifu_w[0]; for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) { rp->r_segbl = ifxp->x_ifrw.ifrw_info & 0xffff; rp->r_segbh = (ifxp->x_ifrw.ifrw_info >> 16) & 0x3; rp->r_flags = 0; ifxp++; } ifrw = &ds->ds_deuba.ifu_r[0]; for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) { rp->r_slen = sizeof (struct de_buf); rp->r_segbl = ifrw->ifrw_info & 0xffff; rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; rp->r_flags = RFLG_OWN; /* hang receive */ ifrw++; } /* start up the board (rah rah) */ s = splimp(); ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = ds->ds_nxmit = 0; ds->ds_if.if_flags |= IFF_UP|IFF_RUNNING; ds->ds_if.if_flags &= ~IFF_OACTIVE; addr->pclow = PCSR0_INTE; /* avoid interlock */ smp_lock(&ds->lk_de_softc, LK_RETRY); destart(unit); /* queue output packets */ smp_unlock(&ds->lk_de_softc); addr->pclow = CMD_START | PCSR0_INTE; ds->ds_flags |= DSF_RUNNING; ds->ds_ztime = time.tv_sec; splx(s);}/* * Setup output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. */destart(unit) int unit;{ int len; struct uba_device *ui = deinfo[unit]; struct dedevice *addr = (struct dedevice *)ui->ui_addr; register struct de_softc *ds = &de_softc[unit]; register struct de_ring *rp; struct mbuf *m; register int nxmit; for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) { IF_DEQUEUE(&ds->ds_if.if_snd, m); if (m == 0) break; rp = &ds->ds_xrent[ds->ds_xfree]; if (rp->r_flags & XFLG_OWN) panic("deuna xmit in progress"); len = deput(&ds->ds_deuba, ds->ds_xfree, m); if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(ds->ds_deuba.ifu_uba, ds->ds_deuba.ifu_w[ds->ds_xfree].x_ifrw.ifrw_bdp, ds->ds_deuba.ifu_uban); rp->r_slen = len; rp->r_tdrerr = 0; rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN; ds->ds_xfree++; if (ds->ds_xfree == NXMT) ds->ds_xfree = 0; } if (ds->ds_nxmit != nxmit) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -