141003Swilliam /*- 241003Swilliam * Copyright (c) 1990 The Regents of the University of California. 341003Swilliam * All rights reserved. 441003Swilliam * 541003Swilliam * This code is derived from software contributed to Berkeley by 641003Swilliam * Tim L. Tucker 741003Swilliam * 8*49596Swilliam * %sccs.include.redist.c% 941003Swilliam * 10*49596Swilliam * @(#)if_we.c 7.1 (Berkeley) 05/09/91 1141003Swilliam */ 1241003Swilliam 1341003Swilliam /* 1441003Swilliam * Modification history 1541003Swilliam * 1645540Sbill * 8/28/89 - Initial version(if_wd.c), Tim L Tucker 1741003Swilliam */ 1841003Swilliam 1945540Sbill #include "we.h" 2045540Sbill #if NWE > 0 2141003Swilliam /* 2241003Swilliam * Western Digital 8003 ethernet/starlan adapter 2341003Swilliam * 2441003Swilliam * Supports the following interface cards: 2545541Sbill * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT 2641003Swilliam * 2741003Swilliam * The Western Digital card is one of many AT/MCA ethernet interfaces 2845541Sbill * based on the National DS8390 Network Interface chip set. 2941003Swilliam */ 3041003Swilliam #include "param.h" 3141003Swilliam #include "mbuf.h" 3241003Swilliam #include "socket.h" 3341003Swilliam #include "ioctl.h" 3441003Swilliam #include "errno.h" 3541003Swilliam #include "syslog.h" 3641003Swilliam 37*49596Swilliam #include "net/if.h" 38*49596Swilliam #include "net/netisr.h" 3941003Swilliam 4041003Swilliam #ifdef INET 41*49596Swilliam #include "netinet/in.h" 42*49596Swilliam #include "netinet/in_systm.h" 43*49596Swilliam #include "netinet/in_var.h" 44*49596Swilliam #include "netinet/ip.h" 45*49596Swilliam #include "netinet/if_ether.h" 4641003Swilliam #endif 4741003Swilliam 4841003Swilliam #ifdef NS 49*49596Swilliam #include "netns/ns.h" 50*49596Swilliam #include "netns/ns_if.h" 5141003Swilliam #endif 5241003Swilliam 53*49596Swilliam #include "i386/isa/if_wereg.h" 54*49596Swilliam #include "i386/isa/isa_device.h" 5541003Swilliam 5641003Swilliam /* 5745540Sbill * This constant should really be 60 because the we adds 4 bytes of crc. 5841003Swilliam * However when set to 60 our packets are ignored by deuna's , 3coms are 5941003Swilliam * okay ?????????????????????????????????????????? 6041003Swilliam */ 6141003Swilliam #define ETHER_MIN_LEN 64 6241003Swilliam #define ETHER_ADDR_LEN 6 6341003Swilliam #define ETHER_HDR_SIZE 14 6441003Swilliam 6541003Swilliam /* 6641003Swilliam * Ethernet software status per interface. 6741003Swilliam * 6841003Swilliam * Each interface is referenced by a network interface structure, 6941003Swilliam * qe_if, which the routing code uses to locate the interface. 7041003Swilliam * This structure contains the output queue for the interface, its address, ... 7141003Swilliam */ 7245540Sbill struct we_softc { 7345540Sbill struct arpcom we_ac; /* Ethernet common part */ 7445540Sbill #define we_if we_ac.ac_if /* network-visible interface */ 7545540Sbill #define we_addr we_ac.ac_enaddr /* hardware Ethernet address */ 7641003Swilliam 7745540Sbill u_char we_flags; /* software state */ 7841003Swilliam #define WDF_RUNNING 0x01 7941003Swilliam #define WDF_TXBUSY 0x02 8041003Swilliam 8145540Sbill u_char we_type; /* interface type code */ 8245540Sbill u_short we_vector; /* interrupt vector */ 83*49596Swilliam short we_io_ctl_addr; /* i/o bus address, control */ 84*49596Swilliam short we_io_nic_addr; /* i/o bus address, DS8390 */ 8541003Swilliam 8645540Sbill caddr_t we_vmem_addr; /* card RAM virtual memory base */ 8745540Sbill u_long we_vmem_size; /* card RAM bytes */ 8845540Sbill caddr_t we_vmem_ring; /* receive ring RAM vaddress */ 89*49596Swilliam caddr_t we_vmem_end; /* receive ring RAM end */ 9045540Sbill } we_softc[NWE]; 9141003Swilliam 92*49596Swilliam int weprobe(), weattach(), weintr(), westart(); 93*49596Swilliam int weinit(), ether_output(), weioctl(), wereset(), wewatchdog(); 9445540Sbill 9545540Sbill struct isa_driver wedriver = { 9645540Sbill weprobe, weattach, "we", 9745540Sbill }; 9841003Swilliam 9941003Swilliam /* 10041003Swilliam * Probe the WD8003 to see if it's there 10141003Swilliam */ 10245540Sbill weprobe(is) 10341003Swilliam struct isa_device *is; 10441003Swilliam { 10541003Swilliam register int i; 10645540Sbill register struct we_softc *sc = &we_softc[is->id_unit]; 10745540Sbill union we_mem_sel wem; 10841003Swilliam u_char sum; 10941003Swilliam 11041003Swilliam /* 11141003Swilliam * Here we check the card ROM, if the checksum passes, and the 11241003Swilliam * type code and ethernet address check out, then we know we have 11341003Swilliam * a wd8003 card. 11441003Swilliam * 11541003Swilliam * Autoconfiguration: No warning message is printed on error. 11641003Swilliam */ 11741003Swilliam for (sum = 0, i = 0; i < 8; ++i) 11845540Sbill sum += inb(is->id_iobase + WD_ROM_OFFSET + i); 11941003Swilliam if (sum != WD_CHECKSUM) 12041003Swilliam return (0); 12145540Sbill sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6); 12245540Sbill if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN) 12345540Sbill && (sc->we_type != WD_ETHER2)) 12441003Swilliam return (0); 12541003Swilliam 12641003Swilliam /* 12741003Swilliam * Setup card RAM area and i/o addresses 12841003Swilliam * Kernel Virtual to segment C0000-DFFFF????? 12941003Swilliam */ 13045540Sbill sc->we_io_ctl_addr = is->id_iobase; 13145540Sbill sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET; 13245540Sbill sc->we_vector = is->id_irq; 13345540Sbill sc->we_vmem_addr = (caddr_t)is->id_maddr; 13445540Sbill sc->we_vmem_size = is->id_msize; 13545540Sbill sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE); 136*49596Swilliam sc->we_vmem_end = sc->we_vmem_addr + is->id_msize; 13741003Swilliam 13841003Swilliam /* 13941003Swilliam * Save board ROM station address 14041003Swilliam */ 14141003Swilliam for (i = 0; i < ETHER_ADDR_LEN; ++i) 14245540Sbill sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i); 14341003Swilliam 14441003Swilliam /* 14541003Swilliam * Mapin interface memory, setup memory select register 14641003Swilliam */ 147*49596Swilliam /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */ 148*49596Swilliam wem.ms_addr = (u_long)(0xd0000)>> 13; 14945540Sbill wem.ms_enable = 1; 15045540Sbill wem.ms_reset = 0; 15145540Sbill outb(sc->we_io_ctl_addr, wem.ms_byte); 15241003Swilliam 15341003Swilliam /* 15441003Swilliam * clear interface memory, then sum to make sure its valid 15541003Swilliam */ 15645540Sbill for (i = 0; i < sc->we_vmem_size; ++i) 15745540Sbill sc->we_vmem_addr[i] = 0x0; 15845540Sbill for (sum = 0, i = 0; i < sc->we_vmem_size; ++i) 15945540Sbill sum += sc->we_vmem_addr[i]; 16041003Swilliam if (sum != 0x0) { 16145540Sbill printf("we%d: wd8003 dual port RAM address error\n", is->id_unit); 16241003Swilliam return (0); 16341003Swilliam } 16441003Swilliam 16541003Swilliam return (WD_IO_PORTS); 16641003Swilliam } 16741003Swilliam 16841003Swilliam /* 16941003Swilliam * Interface exists: make available by filling in network interface 17041003Swilliam * record. System will initialize the interface when it is ready 17141003Swilliam * to accept packets. 17241003Swilliam */ 17345540Sbill weattach(is) 17441003Swilliam struct isa_device *is; 17541003Swilliam { 17645540Sbill register struct we_softc *sc = &we_softc[is->id_unit]; 17745540Sbill register struct ifnet *ifp = &sc->we_if; 178*49596Swilliam union we_command wecmd; 17941003Swilliam 180*49596Swilliam wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 181*49596Swilliam wecmd.cs_stp = 1; 182*49596Swilliam wecmd.cs_sta = 0; 183*49596Swilliam wecmd.cs_ps = 0; 184*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 18541003Swilliam /* 18641003Swilliam * Initialize ifnet structure 18741003Swilliam */ 18845540Sbill ifp->if_unit = is->id_unit; 189*49596Swilliam ifp->if_name = "we" ; 19041003Swilliam ifp->if_mtu = ETHERMTU; 191*49596Swilliam ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ; 19245540Sbill ifp->if_init = weinit; 193*49596Swilliam ifp->if_output = ether_output; 194*49596Swilliam ifp->if_start = westart; 19545540Sbill ifp->if_ioctl = weioctl; 19645540Sbill ifp->if_reset = wereset; 197*49596Swilliam ifp->if_watchdog = wewatchdog; 19841003Swilliam if_attach(ifp); 19941003Swilliam 20041003Swilliam /* 20141003Swilliam * Banner... 20241003Swilliam */ 20345540Sbill printf(" %s address %s", 20445540Sbill ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"), 20545540Sbill ether_sprintf(sc->we_addr)); 20641003Swilliam } 20741003Swilliam 20841003Swilliam /* 20941003Swilliam * Reset of interface. 21041003Swilliam */ 21145540Sbill wereset(unit, uban) 21241003Swilliam int unit, uban; 21341003Swilliam { 21445540Sbill if (unit >= NWE) 21541003Swilliam return; 21645540Sbill printf("we%d: reset\n", unit); 217*49596Swilliam /* we_softc[unit].we_flags &= ~WDF_RUNNING; */ 21845540Sbill weinit(unit); 21941003Swilliam } 22041003Swilliam 22141003Swilliam /* 22241003Swilliam * Take interface offline. 22341003Swilliam */ 22445540Sbill westop(unit) 22541003Swilliam int unit; 22641003Swilliam { 22745540Sbill register struct we_softc *sc = &we_softc[unit]; 22845540Sbill union we_command wecmd; 22941003Swilliam int s; 23041003Swilliam 23141003Swilliam /* 23245541Sbill * Shutdown DS8390 23341003Swilliam */ 23441003Swilliam s = splimp(); 23545540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 23645540Sbill wecmd.cs_stp = 1; 23745540Sbill wecmd.cs_sta = 0; 23845540Sbill wecmd.cs_ps = 0; 23945540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 24041003Swilliam (void) splx(s); 24141003Swilliam } 24241003Swilliam 243*49596Swilliam wewatchdog(unit) { 244*49596Swilliam 245*49596Swilliam log(LOG_WARNING,"we%d: soft reset\n", unit); 246*49596Swilliam printf("we: reset!\n"); 247*49596Swilliam westop(unit); 248*49596Swilliam DELAY(100000); 249*49596Swilliam weinit(unit); 250*49596Swilliam } 251*49596Swilliam 252*49596Swilliam static Bdry; 25341003Swilliam /* 25445541Sbill * Initialization of interface (really just DS8390). 25541003Swilliam */ 25645540Sbill weinit(unit) 25741003Swilliam int unit; 25841003Swilliam { 25945540Sbill register struct we_softc *sc = &we_softc[unit]; 26045540Sbill register struct ifnet *ifp = &sc->we_if; 26145540Sbill union we_command wecmd; 26241003Swilliam int i, s; 26341003Swilliam 26441003Swilliam /* address not known */ 26541003Swilliam if (ifp->if_addrlist == (struct ifaddr *)0) 26641003Swilliam return; 26741003Swilliam 26841003Swilliam /* already running */ 269*49596Swilliam /* if (sc->we_flags & WDF_RUNNING)*/ 270*49596Swilliam /*if (ifp->if_flags & IFF_RUNNING) return; */ 27141003Swilliam 27241003Swilliam /* 27345541Sbill * Initialize DS8390 in order given in NSC NIC manual. 27441003Swilliam * this is stock code...please see the National manual for details. 27541003Swilliam */ 27645540Sbill s = splhigh(); 277*49596Swilliam Bdry = 0; 27845540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 27945540Sbill wecmd.cs_stp = 1; 28045540Sbill wecmd.cs_sta = 0; 28145540Sbill wecmd.cs_ps = 0; 28245540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 28345540Sbill outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); 28445540Sbill outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0); 28545540Sbill outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0); 28645540Sbill outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON); 28745540Sbill outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); 28845540Sbill outb(sc->we_io_nic_addr + WD_P0_TPSR, 0); 28945540Sbill outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); 29045540Sbill outb(sc->we_io_nic_addr + WD_P0_PSTOP, 29145540Sbill sc->we_vmem_size / WD_PAGE_SIZE); 29245540Sbill outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); 29345540Sbill outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff); 29445540Sbill outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 29545540Sbill wecmd.cs_ps = 1; 29645540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 29741003Swilliam for (i = 0; i < ETHER_ADDR_LEN; ++i) 29845540Sbill outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]); 29941003Swilliam for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ 30045540Sbill outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff); 30145540Sbill outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); 30245540Sbill wecmd.cs_ps = 0; 30345540Sbill wecmd.cs_stp = 0; 30445540Sbill wecmd.cs_sta = 1; 30545540Sbill wecmd.cs_rd = 0x4; 30645540Sbill outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte); 30745540Sbill outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); 30841003Swilliam 30941003Swilliam /* 31041003Swilliam * Take the interface out of reset, program the vector, 31141003Swilliam * enable interrupts, and tell the world we are up. 31241003Swilliam */ 313*49596Swilliam ifp->if_flags |= IFF_RUNNING; 31445540Sbill sc->we_flags &= ~WDF_TXBUSY; 31541003Swilliam (void) splx(s); 316*49596Swilliam westart(ifp); 31741003Swilliam } 31841003Swilliam 31941003Swilliam /* 32041003Swilliam * Start output on interface. 32141003Swilliam */ 322*49596Swilliam westart(ifp) 323*49596Swilliam struct ifnet *ifp; 32441003Swilliam { 325*49596Swilliam register struct we_softc *sc = &we_softc[ifp->if_unit]; 32641003Swilliam struct mbuf *m0, *m; 32741003Swilliam register caddr_t buffer; 328*49596Swilliam int len, s; 32945540Sbill union we_command wecmd; 33041003Swilliam 33141003Swilliam /* 33245541Sbill * The DS8390 has only one transmit buffer, if it is busy we 33341003Swilliam * must wait until the transmit interrupt completes. 33441003Swilliam */ 33545540Sbill s = splhigh(); 33645540Sbill if (sc->we_flags & WDF_TXBUSY) { 33741003Swilliam (void) splx(s); 33841003Swilliam return; 33941003Swilliam } 34045540Sbill IF_DEQUEUE(&sc->we_if.if_snd, m); 34141003Swilliam if (m == 0) { 34241003Swilliam (void) splx(s); 34341003Swilliam return; 34441003Swilliam } 34545540Sbill sc->we_flags |= WDF_TXBUSY; 34641003Swilliam (void) splx(s); 34741003Swilliam 34841003Swilliam /* 34941003Swilliam * Copy the mbuf chain into the transmit buffer 35041003Swilliam */ 35145540Sbill buffer = sc->we_vmem_addr; 352*49596Swilliam len = 0; 353*49596Swilliam /*printf("\nT "); */ 35441003Swilliam for (m0 = m; m != 0; m = m->m_next) { 355*49596Swilliam /*int j;*/ 35641003Swilliam bcopy(mtod(m, caddr_t), buffer, m->m_len); 357*49596Swilliam /*for(j=0; j < m->m_len;j++) { 358*49596Swilliam 359*49596Swilliam puthex(buffer[j]); 360*49596Swilliam if (j == sizeof(struct ether_header)-1) 361*49596Swilliam printf("|"); 362*49596Swilliam }*/ 36341003Swilliam buffer += m->m_len; 36441003Swilliam len += m->m_len; 36541003Swilliam } 366*49596Swilliam /*printf("|%d ", len);*/ 36741003Swilliam 368*49596Swilliam m_freem(m0); 36941003Swilliam 37041003Swilliam /* 37141003Swilliam * Init transmit length registers, and set transmit start flag. 37241003Swilliam */ 37345540Sbill s = splhigh(); 37441003Swilliam len = MAX(len, ETHER_MIN_LEN); 375*49596Swilliam /*printf("L %d ", len); 376*49596Swilliam if (len < 70) len=70;*/ 37745540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 37845540Sbill wecmd.cs_ps = 0; 37945540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 38045540Sbill outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff); 38145540Sbill outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8); 38245540Sbill wecmd.cs_txp = 1; 38345540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 38441003Swilliam (void) splx(s); 38541003Swilliam } 38641003Swilliam 38741003Swilliam /* 38841003Swilliam * Ethernet interface interrupt processor 38941003Swilliam */ 39045540Sbill weintr(unit) 39141003Swilliam int unit; 39241003Swilliam { 393*49596Swilliam register struct we_softc *sc = &we_softc[unit]; 39445540Sbill union we_command wecmd; 39545540Sbill union we_interrupt weisr; 396*49596Swilliam 39745540Sbill unit =0; 39841003Swilliam 39941003Swilliam /* disable onboard interrupts, then get interrupt status */ 40045540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 40145540Sbill wecmd.cs_ps = 0; 40245540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 403*49596Swilliam /*outb(sc->we_io_nic_addr + WD_P0_IMR, 0);*/ 40445540Sbill weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 405*49596Swilliam loop: 406*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte); 40741003Swilliam 40841003Swilliam /* transmit error */ 40945540Sbill if (weisr.is_txe) { 41041003Swilliam /* need to read these registers to clear status */ 41145540Sbill sc->we_if.if_collisions += 41245540Sbill inb(sc->we_io_nic_addr + WD_P0_TBCR0); 41345540Sbill ++sc->we_if.if_oerrors; 41441003Swilliam } 41541003Swilliam 41641003Swilliam /* receiver error */ 41745540Sbill if (weisr.is_rxe) { 41841003Swilliam /* need to read these registers to clear status */ 41945540Sbill (void) inb(sc->we_io_nic_addr + 0xD); 42045540Sbill (void) inb(sc->we_io_nic_addr + 0xE); 42145540Sbill (void) inb(sc->we_io_nic_addr + 0xF); 42245540Sbill ++sc->we_if.if_ierrors; 42341003Swilliam } 42441003Swilliam 42541003Swilliam /* normal transmit complete */ 426*49596Swilliam if (weisr.is_ptx || weisr.is_txe) 42745540Sbill wetint (unit); 42841003Swilliam 42941003Swilliam /* normal receive notification */ 430*49596Swilliam if (weisr.is_prx || weisr.is_rxe) 43145540Sbill werint (unit); 43241003Swilliam 43341003Swilliam /* try to start transmit */ 434*49596Swilliam westart(&sc->we_if); 43541003Swilliam 43641003Swilliam /* re-enable onboard interrupts */ 43745540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 43845540Sbill wecmd.cs_ps = 0; 43945540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 440*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/); 441*49596Swilliam weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 442*49596Swilliam if (weisr.is_byte) goto loop; 44341003Swilliam } 44441003Swilliam 44541003Swilliam /* 44641003Swilliam * Ethernet interface transmit interrupt. 44741003Swilliam */ 44845540Sbill wetint(unit) 44941003Swilliam int unit; 45041003Swilliam { 45145540Sbill register struct we_softc *sc = &we_softc[unit]; 45241003Swilliam 45341003Swilliam /* 45441003Swilliam * Do some statistics (assume page zero of NIC mapped in) 45541003Swilliam */ 45645540Sbill sc->we_flags &= ~WDF_TXBUSY; 45745540Sbill sc->we_if.if_timer = 0; 45845540Sbill ++sc->we_if.if_opackets; 45945540Sbill sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0); 46041003Swilliam } 46141003Swilliam 46241003Swilliam /* 46341003Swilliam * Ethernet interface receiver interrupt. 46441003Swilliam */ 46545540Sbill werint(unit) 46641003Swilliam int unit; 46741003Swilliam { 46845540Sbill register struct we_softc *sc = &we_softc[unit]; 46941003Swilliam u_char bnry, curr; 470*49596Swilliam long len; 47145540Sbill union we_command wecmd; 47245540Sbill struct we_ring *wer; 47341003Swilliam 47441003Swilliam /* 47541003Swilliam * Traverse the receive ring looking for packets to pass back. 47641003Swilliam * The search is complete when we find a descriptor not in use. 47741003Swilliam */ 47845540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 47945540Sbill wecmd.cs_ps = 0; 48045540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 48145540Sbill bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY); 48245540Sbill wecmd.cs_ps = 1; 48345540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 48445540Sbill curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 485*49596Swilliam if(Bdry) 48645540Sbill bnry =Bdry; 487*49596Swilliam 488*49596Swilliam /*printf("B %d c %d ", bnry, curr);*/ 48941003Swilliam while (bnry != curr) 49041003Swilliam { 49141003Swilliam /* get pointer to this buffer header structure */ 49245540Sbill wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8)); 49341003Swilliam 494*49596Swilliam /* count includes CRC */ 495*49596Swilliam len = wer->we_count - 4; 496*49596Swilliam if (len > 30 && len <= ETHERMTU+100 497*49596Swilliam /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/) 498*49596Swilliam weread(sc, (caddr_t)(wer + 1), len); 499*49596Swilliam else printf("reject %d", len); 50041003Swilliam 50141003Swilliam outofbufs: 50245540Sbill wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 50345540Sbill wecmd.cs_ps = 0; 50445540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 50541003Swilliam 506*49596Swilliam /* advance on chip Boundry register */ 507*49596Swilliam if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) { 508*49596Swilliam bnry = WD_TXBUF_SIZE; 509*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_BNRY, 510*49596Swilliam sc->we_vmem_size / WD_PAGE_SIZE-1); 511*49596Swilliam 512*49596Swilliam } else { 513*49596Swilliam if (len > 30 && len <= ETHERMTU+100) 514*49596Swilliam bnry = wer->we_next_packet; 515*49596Swilliam else bnry = curr; 516*49596Swilliam 517*49596Swilliam /* watch out for NIC overflow, reset Boundry if invalid */ 518*49596Swilliam if ((bnry - 1) < WD_TXBUF_SIZE) { 519*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_BNRY, 520*49596Swilliam (sc->we_vmem_size / WD_PAGE_SIZE) - 1); 521*49596Swilliam bnry = WD_TXBUF_SIZE; 522*49596Swilliam } else 523*49596Swilliam outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1); 52441003Swilliam } 52541003Swilliam 52641003Swilliam /* refresh our copy of CURR */ 52745540Sbill wecmd.cs_ps = 1; 52845540Sbill outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 52945540Sbill curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 530*49596Swilliam /*printf("b %d c %d ", bnry, curr); */ 53141003Swilliam } 53245540Sbill Bdry = bnry; 53341003Swilliam } 53441003Swilliam 535*49596Swilliam #ifdef shit 53641003Swilliam /* 537*49596Swilliam * Process an ioctl request. 53841003Swilliam */ 539*49596Swilliam weioctl(ifp, cmd, data) 540*49596Swilliam register struct ifnet *ifp; 541*49596Swilliam int cmd; 542*49596Swilliam caddr_t data; 54341003Swilliam { 544*49596Swilliam struct we_softc *sc = &we_softc[ifp->if_unit]; 545*49596Swilliam struct ifaddr *ifa = (struct ifaddr *)data; 546*49596Swilliam int s = splimp(), error = 0; 54741003Swilliam 548*49596Swilliam switch (cmd) { 54941003Swilliam 550*49596Swilliam case SIOCSIFADDR: 551*49596Swilliam ifp->if_flags |= IFF_UP; 552*49596Swilliam weinit(ifp->if_unit); 553*49596Swilliam switch(ifa->ifa_addr->sa_family) { 55441003Swilliam #ifdef INET 555*49596Swilliam case AF_INET: 556*49596Swilliam ((struct arpcom *)ifp)->ac_ipaddr = 557*49596Swilliam IA_SIN(ifa)->sin_addr; 558*49596Swilliam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 559*49596Swilliam break; 56041003Swilliam #endif 56141003Swilliam #ifdef NS 562*49596Swilliam case AF_NS: 563*49596Swilliam { 564*49596Swilliam register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 565*49596Swilliam 566*49596Swilliam if (ns_nullhost(*ina)) 567*49596Swilliam ina->x_host = *(union ns_host *)(sc->we_addr); 568*49596Swilliam else 569*49596Swilliam wesetaddr(ina->x_host.c_host, ifp->if_unit); 570*49596Swilliam break; 571*49596Swilliam } 572*49596Swilliam #endif 573*49596Swilliam } 57441003Swilliam break; 57541003Swilliam 576*49596Swilliam case SIOCSIFFLAGS: 577*49596Swilliam if (((ifp->if_flags & IFF_UP) == 0) && 578*49596Swilliam (sc->we_flags & WDF_RUNNING)) { 579*49596Swilliam westop(ifp->if_unit); 580*49596Swilliam } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && 581*49596Swilliam ((sc->we_flags & WDF_RUNNING) == 0)) 582*49596Swilliam weinit(ifp->if_unit); 58341003Swilliam break; 584*49596Swilliam 58541003Swilliam default: 586*49596Swilliam error = EINVAL; 58741003Swilliam 58841003Swilliam } 58941003Swilliam (void) splx(s); 59041003Swilliam return (error); 59141003Swilliam } 592*49596Swilliam #endif 59341003Swilliam 59441003Swilliam /* 59541003Swilliam * Process an ioctl request. 59641003Swilliam */ 59745540Sbill weioctl(ifp, cmd, data) 59841003Swilliam register struct ifnet *ifp; 59941003Swilliam int cmd; 60041003Swilliam caddr_t data; 60141003Swilliam { 602*49596Swilliam register struct ifaddr *ifa = (struct ifaddr *)data; 60345540Sbill struct we_softc *sc = &we_softc[ifp->if_unit]; 604*49596Swilliam struct ifreq *ifr = (struct ifreq *)data; 60541003Swilliam int s = splimp(), error = 0; 606*49596Swilliam 607*49596Swilliam 60841003Swilliam switch (cmd) { 609*49596Swilliam 61041003Swilliam case SIOCSIFADDR: 61141003Swilliam ifp->if_flags |= IFF_UP; 612*49596Swilliam 613*49596Swilliam switch (ifa->ifa_addr->sa_family) { 61441003Swilliam #ifdef INET 61541003Swilliam case AF_INET: 616*49596Swilliam weinit(ifp->if_unit); /* before arpwhohas */ 61741003Swilliam ((struct arpcom *)ifp)->ac_ipaddr = 61841003Swilliam IA_SIN(ifa)->sin_addr; 61941003Swilliam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 62041003Swilliam break; 62141003Swilliam #endif 62241003Swilliam #ifdef NS 62341003Swilliam case AF_NS: 62441003Swilliam { 62541003Swilliam register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 626*49596Swilliam 62741003Swilliam if (ns_nullhost(*ina)) 628*49596Swilliam ina->x_host = *(union ns_host *)(sc->ns_addr); 629*49596Swilliam else { 630*49596Swilliam /* 631*49596Swilliam * The manual says we can't change the address 632*49596Swilliam * while the receiver is armed, 633*49596Swilliam * so reset everything 634*49596Swilliam */ 635*49596Swilliam ifp->if_flags &= ~IFF_RUNNING; 636*49596Swilliam bcopy((caddr_t)ina->x_host.c_host, 637*49596Swilliam (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); 638*49596Swilliam } 639*49596Swilliam weinit(ifp->if_unit); /* does ne_setaddr() */ 64041003Swilliam break; 64141003Swilliam } 64241003Swilliam #endif 643*49596Swilliam default: 644*49596Swilliam weinit(ifp->if_unit); 645*49596Swilliam break; 64641003Swilliam } 64741003Swilliam break; 64841003Swilliam 64941003Swilliam case SIOCSIFFLAGS: 650*49596Swilliam if ((ifp->if_flags & IFF_UP) == 0 && 651*49596Swilliam ifp->if_flags & IFF_RUNNING) { 652*49596Swilliam ifp->if_flags &= ~IFF_RUNNING; 65345540Sbill westop(ifp->if_unit); 654*49596Swilliam } else if (ifp->if_flags & IFF_UP && 655*49596Swilliam (ifp->if_flags & IFF_RUNNING) == 0) 65645540Sbill weinit(ifp->if_unit); 65741003Swilliam break; 65841003Swilliam 659*49596Swilliam #ifdef notdef 660*49596Swilliam case SIOCGHWADDR: 661*49596Swilliam bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, 662*49596Swilliam sizeof(sc->sc_addr)); 663*49596Swilliam break; 664*49596Swilliam #endif 665*49596Swilliam 66641003Swilliam default: 66741003Swilliam error = EINVAL; 66841003Swilliam } 669*49596Swilliam splx(s); 67041003Swilliam return (error); 67141003Swilliam } 67241003Swilliam /* 67341003Swilliam * set ethernet address for unit 67441003Swilliam */ 67545540Sbill wesetaddr(physaddr, unit) 67641003Swilliam u_char *physaddr; 67741003Swilliam int unit; 67841003Swilliam { 67945540Sbill register struct we_softc *sc = &we_softc[unit]; 68041003Swilliam register int i; 68141003Swilliam 68241003Swilliam /* 68341003Swilliam * Rewrite ethernet address, and then force restart of NIC 68441003Swilliam */ 68541003Swilliam for (i = 0; i < ETHER_ADDR_LEN; i++) 68645540Sbill sc->we_addr[i] = physaddr[i]; 68745540Sbill sc->we_flags &= ~WDF_RUNNING; 68845540Sbill weinit(unit); 68941003Swilliam } 69041003Swilliam 691*49596Swilliam #define wedataaddr(sc, eh, off, type) \ 692*49596Swilliam ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \ 693*49596Swilliam (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \ 694*49596Swilliam + (sc)->we_vmem_ring: \ 695*49596Swilliam ((caddr_t)((eh)+1)+(off))) 69641003Swilliam /* 69741003Swilliam * Pass a packet to the higher levels. 698*49596Swilliam * We deal with the trailer protocol here. 69941003Swilliam */ 700*49596Swilliam weread(sc, buf, len) 70145540Sbill register struct we_softc *sc; 702*49596Swilliam char *buf; 703*49596Swilliam int len; 70441003Swilliam { 705*49596Swilliam register struct ether_header *eh; 706*49596Swilliam struct mbuf *m, *weget(); 707*49596Swilliam int off, resid; 708*49596Swilliam 70941003Swilliam /* 710*49596Swilliam * Deal with trailer protocol: if type is trailer type 711*49596Swilliam * get true type from first 16-bit word past data. 712*49596Swilliam * Remember that type was trailer by setting off. 71341003Swilliam */ 714*49596Swilliam eh = (struct ether_header *)buf; 715*49596Swilliam eh->ether_type = ntohs((u_short)eh->ether_type); 716*49596Swilliam if (eh->ether_type >= ETHERTYPE_TRAIL && 717*49596Swilliam eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 718*49596Swilliam off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 719*49596Swilliam if (off >= ETHERMTU) return; /* sanity */ 720*49596Swilliam eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *)); 721*49596Swilliam resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *))); 722*49596Swilliam if (off + resid > len) return; /* sanity */ 723*49596Swilliam len = off + resid; 724*49596Swilliam } else off = 0; 72541003Swilliam 726*49596Swilliam len -= sizeof(struct ether_header); 727*49596Swilliam if (len <= 0) return; 728*49596Swilliam 72941003Swilliam /* 730*49596Swilliam * Pull packet off interface. Off is nonzero if packet 731*49596Swilliam * has trailing header; neget will then force this header 732*49596Swilliam * information to be at the front, but we still have to drop 733*49596Swilliam * the type and length which are at the front of any trailer data. 73441003Swilliam */ 735*49596Swilliam m = weget(buf, len, off, &sc->we_if, sc); 736*49596Swilliam if (m == 0) return; 737*49596Swilliam ether_input(&sc->we_if, eh, m); 738*49596Swilliam } 73941003Swilliam 740*49596Swilliam /* 741*49596Swilliam * Supporting routines 742*49596Swilliam */ 74341003Swilliam 744*49596Swilliam /* 745*49596Swilliam * Pull read data off a interface. 746*49596Swilliam * Len is length of data, with local net header stripped. 747*49596Swilliam * Off is non-zero if a trailer protocol was used, and 748*49596Swilliam * gives the offset of the trailer information. 749*49596Swilliam * We copy the trailer information and then all the normal 750*49596Swilliam * data into mbufs. When full cluster sized units are present 751*49596Swilliam * we copy into clusters. 752*49596Swilliam */ 753*49596Swilliam struct mbuf * 754*49596Swilliam weget(buf, totlen, off0, ifp, sc) 755*49596Swilliam caddr_t buf; 756*49596Swilliam int totlen, off0; 757*49596Swilliam struct ifnet *ifp; 758*49596Swilliam struct we_softc *sc; 759*49596Swilliam { 760*49596Swilliam struct mbuf *top, **mp, *m, *p; 761*49596Swilliam int off = off0, len; 762*49596Swilliam register caddr_t cp = buf; 763*49596Swilliam char *epkt; 764*49596Swilliam int tc =totlen; 76541003Swilliam 766*49596Swilliam /* 767*49596Swilliam printf("\nR"); 768*49596Swilliam { int j; 769*49596Swilliam for(j=0; j < sizeof(struct ether_header);j++) puthex(buf[j]); 770*49596Swilliam printf("|"); 771*49596Swilliam }*/ 772*49596Swilliam buf += sizeof(struct ether_header); 773*49596Swilliam cp = buf; 774*49596Swilliam epkt = cp + totlen; 775*49596Swilliam 776*49596Swilliam if (off) { 777*49596Swilliam cp += off + 2 * sizeof(u_short); 778*49596Swilliam totlen -= 2 * sizeof(u_short); 779*49596Swilliam } 780*49596Swilliam 781*49596Swilliam MGETHDR(m, M_DONTWAIT, MT_DATA); 782*49596Swilliam if (m == 0) 783*49596Swilliam return (0); 784*49596Swilliam m->m_pkthdr.rcvif = ifp; 785*49596Swilliam m->m_pkthdr.len = totlen; 786*49596Swilliam m->m_len = MHLEN; 787*49596Swilliam 788*49596Swilliam top = 0; 789*49596Swilliam mp = ⊤ 790*49596Swilliam while (totlen > 0) { 791*49596Swilliam if (top) { 792*49596Swilliam MGET(m, M_DONTWAIT, MT_DATA); 793*49596Swilliam if (m == 0) { 794*49596Swilliam m_freem(top); 795*49596Swilliam return (0); 796*49596Swilliam } 797*49596Swilliam m->m_len = MLEN; 798*49596Swilliam } 799*49596Swilliam len = min(totlen, epkt - cp); 800*49596Swilliam #ifdef nope 801*49596Swilliam /* only do up to end of buffer */ 802*49596Swilliam if (epkt > sc->we_vmem_end) 803*49596Swilliam len = min(len, sc->we_vmem_end - cp); 80441003Swilliam #endif 805*49596Swilliam if (len >= MINCLSIZE) { 806*49596Swilliam MCLGET(m, M_DONTWAIT); 807*49596Swilliam if (m->m_flags & M_EXT) 808*49596Swilliam m->m_len = len = min(len, MCLBYTES); 809*49596Swilliam else 810*49596Swilliam len = m->m_len; 811*49596Swilliam } else { 812*49596Swilliam /* 813*49596Swilliam * Place initial small packet/header at end of mbuf. 814*49596Swilliam */ 815*49596Swilliam if (len < m->m_len) { 816*49596Swilliam if (top == 0 && len + max_linkhdr <= m->m_len) 817*49596Swilliam m->m_data += max_linkhdr; 818*49596Swilliam m->m_len = len; 819*49596Swilliam } else 820*49596Swilliam len = m->m_len; 821*49596Swilliam } 82241003Swilliam 823*49596Swilliam totlen -= len; 824*49596Swilliam /* only do up to end of buffer */ 825*49596Swilliam if (cp+len > sc->we_vmem_end) { 826*49596Swilliam unsigned toend = sc->we_vmem_end - cp; 827*49596Swilliam 828*49596Swilliam bcopy(cp, mtod(m, caddr_t), toend); 829*49596Swilliam cp = sc->we_vmem_ring; 830*49596Swilliam bcopy(cp, mtod(m, caddr_t)+toend, len - toend); 831*49596Swilliam cp += len - toend; 832*49596Swilliam epkt = cp + totlen; 833*49596Swilliam } else { 834*49596Swilliam bcopy(cp, mtod(m, caddr_t), (unsigned)len); 835*49596Swilliam cp += len; 836*49596Swilliam } 837*49596Swilliam /*{ int j; 838*49596Swilliam for(j=0; j < m->m_len;j++) puthex(mtod(m, char *)[j]); 839*49596Swilliam printf("|"); 840*49596Swilliam }*/ 841*49596Swilliam *mp = m; 842*49596Swilliam mp = &m->m_next; 843*49596Swilliam if (cp == epkt) { 844*49596Swilliam cp = buf; 845*49596Swilliam epkt = cp + tc; 846*49596Swilliam } 84741003Swilliam } 848*49596Swilliam /*printf("%d ",tc); */ 849*49596Swilliam return (top); 85041003Swilliam } 85141003Swilliam 852*49596Swilliam puthex(c){ 853*49596Swilliam printf("%x",(c>>4)&0xf); 854*49596Swilliam printf("%x",c&0xf); 855*49596Swilliam } 85641003Swilliam #endif 857