153897Smckusick /* 253897Smckusick * Copyright (c) 1992 The Regents of the University of California. 353897Smckusick * All rights reserved. 453897Smckusick * 553897Smckusick * This code is derived from software contributed to Berkeley by 653897Smckusick * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 753897Smckusick * 853897Smckusick * %sccs.include.redist.c% 953897Smckusick * 1053897Smckusick * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY 1153897Smckusick * 12*54473Sutashiro * @(#)if_en.c 7.2 (Berkeley) 06/25/92 1353897Smckusick */ 1453897Smckusick 1553897Smckusick #include "en.h" 1653897Smckusick #include "rawether.h" 1753897Smckusick #include "bpfilter.h" 1853897Smckusick 1953897Smckusick #if NEN > 0 2053897Smckusick 2153897Smckusick /* 2253897Smckusick * Interlan Ethernet Communications Controller interface 2353897Smckusick */ 2453897Smckusick #include "types.h" 2553897Smckusick #include "../include/fix_machine_type.h" 2653897Smckusick #include "../include/pte.h" 2753897Smckusick 2853897Smckusick #include "param.h" 2953897Smckusick #include "systm.h" 3053897Smckusick #include "mbuf.h" 3153897Smckusick #include "buf.h" 3253897Smckusick #include "protosw.h" 3353897Smckusick #include "socket.h" 3453897Smckusick #include "ioctl.h" 3553897Smckusick #include "errno.h" 3653897Smckusick #include "time.h" 3753897Smckusick #include "cdefs.h" 3853897Smckusick 3953897Smckusick #include "net/if.h" 4053897Smckusick #include "net/netisr.h" 4153897Smckusick #include "net/route.h" 4253897Smckusick 4353897Smckusick #ifdef INET 4453897Smckusick #include "netinet/in.h" 4553897Smckusick #include "netinet/in_systm.h" 4653897Smckusick #include "netinet/in_var.h" 4753897Smckusick #include "netinet/ip.h" 4853897Smckusick #include "netinet/if_ether.h" 4953897Smckusick #endif 5053897Smckusick 5153897Smckusick #include "../if/if_news.h" 5253897Smckusick #include "../if/if_en.h" 5353897Smckusick 5453897Smckusick #ifdef CPU_SINGLE 5553897Smckusick #include "../hbdev/hbvar.h" 5653897Smckusick #define iop_device hb_device 5753897Smckusick #define iop_driver hb_driver 5853897Smckusick #define ii_unit hi_unit 5953897Smckusick #define ii_intr hi_intr 6053897Smckusick #define ii_alive hi_alive 6153897Smckusick #else 6253897Smckusick #include "../iop/iopvar.h" 6353897Smckusick #endif 6453897Smckusick 6553897Smckusick int enprobe(), enattach(), enrint(), enxint(); 6653897Smckusick struct mbuf *m_devget(); 6753897Smckusick 6853897Smckusick #ifdef CPU_SINGLE 6953897Smckusick struct hb_device *eninfo[NEN]; 7053897Smckusick struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo }; 7153897Smckusick #else 7253897Smckusick struct iop_device *eninfo[NEN]; 7353897Smckusick struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo }; 7453897Smckusick #endif 7553897Smckusick 7653897Smckusick #define ENUNIT(x) minor(x) 7753897Smckusick 78*54473Sutashiro int eninit(),enioctl(),enreset(),enwatch(),enstart(); 7953897Smckusick int endebug = 0; 8053897Smckusick 8153897Smckusick struct ether_addr { 8253897Smckusick u_char addr[6]; 8353897Smckusick }; 8453897Smckusick 8553897Smckusick extern struct ifnet loif; 8653897Smckusick 8753897Smckusick struct en_softc en_softc[NEN]; 8853897Smckusick struct ether_addr myether[NEN]; 8953897Smckusick 9053897Smckusick #if NBPFILTER > 0 9153897Smckusick #include "../net/bpf.h" 9253897Smckusick caddr_t en_bpf[NEN]; 9353897Smckusick #endif 9453897Smckusick 9553897Smckusick enprobe(ii) 9653897Smckusick struct iop_device *ii; 9753897Smckusick { 9853897Smckusick 9953897Smckusick return (en_probe(ii)); 10053897Smckusick } 10153897Smckusick 10253897Smckusick /* 10353897Smckusick * Interface exists: make available by filling in network interface 10453897Smckusick * record. System will initialize the interface when it is ready 10553897Smckusick * to accept packets. A STATUS command is done to get the ethernet 10653897Smckusick * address and other interesting data. 10753897Smckusick */ 10853897Smckusick enattach(ii) 10953897Smckusick register struct iop_device *ii; 11053897Smckusick { 11153897Smckusick register struct en_softc *es = &en_softc[ii->ii_unit]; 11253897Smckusick register struct ifnet *ifp = &es->es_if; 11353897Smckusick extern char *ether_sprintf(); 11453897Smckusick 11553897Smckusick en_attach(ii->ii_unit); 11653897Smckusick bcopy((caddr_t)es->es_addr, &myether[ii->ii_unit], 11753897Smckusick sizeof(struct ether_addr)); 11853897Smckusick printf("en%d: hardware address %s\n", 11953897Smckusick ii->ii_unit, ether_sprintf((u_char *)es->es_addr)); 12053897Smckusick ifp->if_unit = ii->ii_unit; 12153897Smckusick ifp->if_name = "en"; 12253897Smckusick ifp->if_mtu = ETHERMTU; 12353897Smckusick ifp->if_init = eninit; 12453897Smckusick ifp->if_ioctl = enioctl; 12553897Smckusick ifp->if_output = ether_output; 12653897Smckusick #ifdef NOTDEF /* KU:XXX if_reset is obsolete */ 12753897Smckusick ifp->if_reset = enreset; 12853897Smckusick #endif 12953897Smckusick ifp->if_start = enstart; 13053897Smckusick ifp->if_flags = IFF_BROADCAST; 13153897Smckusick #if NBPFILTER > 0 13253897Smckusick { 13353897Smckusick static struct bpf_devp dev = 13453897Smckusick { DLT_EN10MB, sizeof(struct ether_header) }; 13553897Smckusick 13653897Smckusick bpfattach(&en_bpf[ii->ii_unit], ifp, &dev); 13753897Smckusick } 13853897Smckusick #endif 13953897Smckusick if_attach(ifp); 14053897Smckusick } 14153897Smckusick 14253897Smckusick /* 14353897Smckusick * Reset of interface after IOP reset. 14453897Smckusick */ 14553897Smckusick enreset(unit) 14653897Smckusick int unit; 14753897Smckusick { 14853897Smckusick register struct iop_device *ii; 14953897Smckusick 15053897Smckusick if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0) 15153897Smckusick return; 15253897Smckusick printf(" en%d", unit); 15353897Smckusick en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 15453897Smckusick en_softc[unit].es_flags &= ~ENF_RUNNING; 15553897Smckusick eninit(unit); 15653897Smckusick } 15753897Smckusick 15853897Smckusick /* 15953897Smckusick * Initialization of interface; clear recorded pending 16053897Smckusick * operations, and reinitialize IOP usage. 16153897Smckusick */ 16253897Smckusick eninit(unit) 16353897Smckusick int unit; 16453897Smckusick { 16553897Smckusick register struct en_softc *es = &en_softc[unit]; 16653897Smckusick register struct ifnet *ifp = &es->es_if; 16753897Smckusick int s; 16853897Smckusick 16953897Smckusick /* not yet, if address still unknown */ 17053897Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 17153897Smckusick return; 17253897Smckusick if (es->es_flags & ENF_RUNNING) 17353897Smckusick return; 17453897Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 17553897Smckusick if (if_newsinit(&es->es_ifnews, 17653897Smckusick sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) { 17753897Smckusick printf("en%d: can't initialize\n", unit); 17853897Smckusick es->es_if.if_flags &= ~IFF_UP; 17953897Smckusick return; 18053897Smckusick } 18153897Smckusick ifp->if_watchdog = enwatch; 18253897Smckusick es->es_interval = ENWATCHINTERVAL; 18353897Smckusick ifp->if_timer = es->es_interval; 18453897Smckusick s = splimp(); 18553897Smckusick en_init(unit); 18653897Smckusick splx(s); 18753897Smckusick } 18853897Smckusick es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS; 18953897Smckusick es->es_flags |= ENF_RUNNING; 19053897Smckusick } 19153897Smckusick 19253897Smckusick /* 19353897Smckusick * Start output on interface. 19453897Smckusick * Get another datagram to send off of the interface queue, 19553897Smckusick * and map it to the interface before starting the output. 19653897Smckusick */ 19753897Smckusick enstart(ifp) 19853897Smckusick register struct ifnet *ifp; 19953897Smckusick { 20053897Smckusick int unit = ifp->if_unit, len; 20153897Smckusick register struct en_softc *es = &en_softc[unit]; 20253897Smckusick register struct mbuf *m; 20353897Smckusick 20453897Smckusick IF_DEQUEUE(&es->es_if.if_snd, m); 20553897Smckusick if (m == 0) 20653897Smckusick return(0); 20753897Smckusick #ifdef CPU_SINGLE 20853897Smckusick es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit); 20953897Smckusick #endif 21053897Smckusick len = if_wnewsput(&es->es_ifnews, m); 21153897Smckusick /* 21253897Smckusick * Ensure minimum packet length. 21353897Smckusick * This makes the safe assumtion that there are no virtual holes 21453897Smckusick * after the data. 21553897Smckusick * For security, it might be wise to zero out the added bytes, 21653897Smckusick * but we're mainly interested in speed at the moment. 21753897Smckusick */ 21853897Smckusick if (len - sizeof(struct ether_header) < ETHERMIN) 21953897Smckusick len = ETHERMIN + sizeof(struct ether_header); 22053897Smckusick en_start(unit, len); 22153897Smckusick #if NBPFILTER > 0 22253897Smckusick /* 22353897Smckusick * If bpf is listening on this interface, let it 22453897Smckusick * see the packet before we commit it to the wire. 22553897Smckusick */ 22653897Smckusick if (en_bpf[unit]) { 22753897Smckusick #ifdef CPU_SINGLE 22853897Smckusick bpf_tap(en_bpf[unit], es->es_ifnews.ifn_waddr, len); 22953897Smckusick #else 23053897Smckusick bpf_mtap(en_bpf[unit], m); 23153897Smckusick #endif 23253897Smckusick } 23353897Smckusick #endif /* NBPFILTER > 0 */ 23453897Smckusick es->es_if.if_flags |= IFF_OACTIVE; 23553897Smckusick return(0); 23653897Smckusick } 23753897Smckusick 23853897Smckusick /* 23953897Smckusick * Transmit done interrupt. 24053897Smckusick */ 24153897Smckusick _enxint(unit, error, collision) 24253897Smckusick int unit; 24353897Smckusick int error, collision; 24453897Smckusick { 24553897Smckusick register struct en_softc *es = &en_softc[unit]; 24653897Smckusick 24753897Smckusick #ifdef notyet /* KU:XXX */ 24853897Smckusick intrcnt[INTR_ETHER0 + unit]++; 24953897Smckusick #endif 25053897Smckusick if ((es->es_if.if_flags & IFF_OACTIVE) == 0) { 25153897Smckusick printf("en%d: stray xmit interrupt\n", unit); 25253897Smckusick return; 25353897Smckusick } else { 25453897Smckusick es->es_if.if_flags &= ~IFF_OACTIVE; 25553897Smckusick es->es_if.if_opackets++; 25653897Smckusick } 25753897Smckusick if (error) 25853897Smckusick es->es_if.if_oerrors++; 25953897Smckusick if (collision) 26053897Smckusick es->es_if.if_collisions++; 26153897Smckusick enstart(&es->es_if); 26253897Smckusick } 26353897Smckusick 26453897Smckusick /* 26553897Smckusick * Ethernet interface receiver interrupt. 26653897Smckusick * If input error just drop packet. 26753897Smckusick * Otherwise purge input buffered data path and examine 26853897Smckusick * packet to determine type. If can't determine length 26953897Smckusick * from type, then have to drop packet. Othewise decapsulate 27053897Smckusick * packet based on type and pass to type specific higher-level 27153897Smckusick * input routine. 27253897Smckusick */ 27353897Smckusick _enrint(unit, len) 27453897Smckusick int unit; 27553897Smckusick register int len; 27653897Smckusick { 27753897Smckusick register struct en_softc *es = &en_softc[unit]; 27853897Smckusick register struct en_rheader *en; 27953897Smckusick struct mbuf *m; 28053897Smckusick int off, resid, s; 28153897Smckusick int type; 28253897Smckusick register struct ensw *esp; 28353897Smckusick extern struct mbuf *if_rnewsget(); 28453897Smckusick 28553897Smckusick #ifdef notyet /* KU:XXX */ 28653897Smckusick intrcnt[INTR_ETHER0 + unit]++; 28753897Smckusick #endif 28853897Smckusick es->es_if.if_ipackets++; 28953897Smckusick if ((es->es_flags & ENF_RUNNING) == 0) 29053897Smckusick return; 29153897Smckusick en = (struct en_rheader *)(es->es_ifnews.ifn_raddr); 29253897Smckusick if (len < ETHERMIN || len > ETHERMTU) { 29353897Smckusick es->es_if.if_ierrors++; 29453897Smckusick return; 29553897Smckusick } 29653897Smckusick #if NBPFILTER > 0 29753897Smckusick #if NRAWETHER > 0 29853897Smckusick etherinput(unit, en, len + sizeof(struct en_rheader)); 29953897Smckusick #endif 30053897Smckusick /* 30153897Smckusick * Check if there's a bpf filter listening on this interface. 30253897Smckusick * If so, hand off the raw packet to enet. 30353897Smckusick */ 30453897Smckusick if (en_bpf[unit]) { 30553897Smckusick bpf_tap(en_bpf[unit], es->es_ifnews.ifn_raddr, 30653897Smckusick len + sizeof(struct en_rheader)); 30753897Smckusick /* 30853897Smckusick * Note that the interface cannot be in promiscuous mode if 30953897Smckusick * there are no bpf listeners. And if we are in promiscuous 31053897Smckusick * mode, we have to check if this packet is really ours. 31153897Smckusick * 31253897Smckusick * XXX This test does not support multicasts. 31353897Smckusick */ 31453897Smckusick if ((es->es_if.if_flags & IFF_PROMISC) 31553897Smckusick && bcmp(en->enr_dhost, es->es_addr, 31653897Smckusick sizeof(en->enr_dhost)) != 0 31753897Smckusick && bcmp(en->enr_dhost, etherbroadcastaddr, 31853897Smckusick sizeof(en->enr_dhost)) != 0) 31953897Smckusick return; 32053897Smckusick } 32153897Smckusick #else /* NBPFILTER > 0 */ 32253897Smckusick #if NRAWETHER > 0 32353897Smckusick if (etherinput(unit, en, len + sizeof(struct en_rheader))) 32453897Smckusick return; 32553897Smckusick #endif 32653897Smckusick #endif /* NBPFILTER > 0 */ 32753897Smckusick /* 32853897Smckusick * Deal with trailer protocol: if type is trailer type 32953897Smckusick * get true type from first 16-bit word past data. 33053897Smckusick * Remember that type was trailer by setting off. 33153897Smckusick */ 33253897Smckusick en->enr_type = ntohs((u_short)en->enr_type); 33353897Smckusick #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 33453897Smckusick if (en->enr_type >= ETHERTYPE_TRAIL && 33553897Smckusick en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 33653897Smckusick off = (en->enr_type - ETHERTYPE_TRAIL) * 512; 33753897Smckusick if (off >= ETHERMTU) 33853897Smckusick return; 33953897Smckusick en->enr_type = ntohs(*endataaddr(en, off, u_short *)); 34053897Smckusick resid = ntohs(*(endataaddr(en, off+2, u_short *))); 34153897Smckusick if (off + resid > len) 34253897Smckusick return; 34353897Smckusick len = off + resid; 34453897Smckusick } else 34553897Smckusick off = 0; 34653897Smckusick /* 34753897Smckusick * Pull packet off interface. Off is nonzero if packet 34853897Smckusick * has trailing header; m_devget will then force this header 34953897Smckusick * information to be at the front, but we still have to drop 35053897Smckusick * the type and length which are at the front of any trailer data. 35153897Smckusick * KU:XXX really? 35253897Smckusick */ 35353897Smckusick type = en->enr_type; 35453897Smckusick m = m_devget((char *)(en + 1), len, off, &es->es_if, 0); 35553897Smckusick if (m == 0) 35653897Smckusick return; 35753897Smckusick ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m); 35853897Smckusick } 35953897Smckusick 36053897Smckusick /* 36153897Smckusick * Watchdog routine, request statistics from board. 36253897Smckusick */ 36353897Smckusick enwatch(unit) 36453897Smckusick int unit; 36553897Smckusick { 36653897Smckusick register struct en_softc *es = &en_softc[unit]; 36753897Smckusick register struct ifnet *ifp = &es->es_if; 36853897Smckusick 36953897Smckusick ifp->if_timer = es->es_interval; 37053897Smckusick } 37153897Smckusick 37253897Smckusick /* 37353897Smckusick * Process an ioctl request. 37453897Smckusick */ 37553897Smckusick enioctl(ifp, cmd, data) 37653897Smckusick register struct ifnet *ifp; 37753897Smckusick int cmd; 37853897Smckusick caddr_t data; 37953897Smckusick { 38053897Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 38153897Smckusick register struct en_softc *es = &en_softc[ifp->if_unit]; 38253897Smckusick register struct ensw *esp; 38353897Smckusick register int family; 38453897Smckusick int s = splimp(), error = 0; 38553897Smckusick 38653897Smckusick switch (cmd) { 38753897Smckusick 38853897Smckusick case SIOCSIFADDR: 38953897Smckusick ifp->if_flags |= IFF_UP; 39053897Smckusick eninit(ifp->if_unit); 39153897Smckusick switch (ifa->ifa_addr->sa_family) { 39253897Smckusick #ifdef INET 39353897Smckusick case AF_INET: 39453897Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 39553897Smckusick IA_SIN(ifa)->sin_addr; 39653897Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 39753897Smckusick break; 39853897Smckusick #endif 39953897Smckusick } 40053897Smckusick break; 40153897Smckusick 40253897Smckusick case SIOCSIFFLAGS: 40353897Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 40453897Smckusick es->es_flags & ENF_RUNNING) { 40553897Smckusick es->es_flags &= ~ENF_RUNNING; 40653897Smckusick } else if (ifp->if_flags & IFF_UP && 40753897Smckusick (es->es_flags & ENF_RUNNING) == 0) 40853897Smckusick eninit(ifp->if_unit); 40953897Smckusick #if NBPFILTER > 0 41053897Smckusick else if (ifp->if_flags & IFF_UP && 41153897Smckusick (ifp->if_flags & IFF_RUNNING) == 0) { 41253897Smckusick en_prom_mode(ifp->if_unit, 41353897Smckusick ifp->if_flags & IFF_PROMISC); 41453897Smckusick ifp->if_flags |= IFF_RUNNING; 41553897Smckusick } 41653897Smckusick #endif 41753897Smckusick break; 41853897Smckusick 41953897Smckusick default: 42053897Smckusick error = EINVAL; 42153897Smckusick } 42253897Smckusick splx(s); 42353897Smckusick return (error); 42453897Smckusick } 42553897Smckusick 42653897Smckusick /* 42753897Smckusick * set ethernet address for unit 42853897Smckusick */ 42953897Smckusick ensetaddr(physaddr, unit) 43053897Smckusick u_char *physaddr; 43153897Smckusick int unit; 43253897Smckusick { 43353897Smckusick register struct en_softc *es = &en_softc[unit]; 43453897Smckusick 43553897Smckusick if (!(es->es_flags & ENF_RUNNING)) 43653897Smckusick return; 43753897Smckusick 43853897Smckusick bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr); 43953897Smckusick es->es_flags &= ~ENF_RUNNING; 44053897Smckusick es->es_flags |= ENF_SETADDR; 44153897Smckusick eninit(unit); 44253897Smckusick } 44353897Smckusick 44453897Smckusick /* 44553897Smckusick * Machine dependent functions 44653897Smckusick * 44753897Smckusick * en_probe(); 44853897Smckusick * en_attach(); 44953897Smckusick * en_init(); 45053897Smckusick * enxint(); 45153897Smckusick * enrint(); 45253897Smckusick * en_prom_mode() 45353897Smckusick */ 45453897Smckusick #ifdef CPU_SINGLE 45553897Smckusick #include "../include/cpu.h" 45653897Smckusick 45753897Smckusick en_probe(hi) 45853897Smckusick struct hb_device *hi; 45953897Smckusick { 46053897Smckusick 46153897Smckusick return (lance_probe(hi->hi_unit)); 46253897Smckusick } 46353897Smckusick 46453897Smckusick en_attach(unit) 46553897Smckusick int unit; 46653897Smckusick { 46753897Smckusick register struct en_softc *es = &en_softc[unit]; 46853897Smckusick register u_char *p; 46953897Smckusick register int i; 47053897Smckusick extern lance_intr(); 47153897Smckusick 47253897Smckusick #if !defined(news700) && !defined(mips) 47353897Smckusick register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr); 47453897Smckusick #endif 47553897Smckusick if (lance_open(unit) < 0) 47653897Smckusick printf("lance initialize error\n"); 47753897Smckusick lance_get_addr(unit, (caddr_t)es->es_addr); 47853897Smckusick } 47953897Smckusick 48053897Smckusick en_init(unit) 48153897Smckusick int unit; 48253897Smckusick { 48353897Smckusick 48453897Smckusick } 48553897Smckusick 48653897Smckusick en_start(unit, len) 48753897Smckusick int unit; 48853897Smckusick int len; 48953897Smckusick { 49053897Smckusick 49153897Smckusick lance_transmit(unit, len); 49253897Smckusick } 49353897Smckusick 49453897Smckusick enxint(unit) 49553897Smckusick register int unit; 49653897Smckusick { 49753897Smckusick 49853897Smckusick _enxint(unit, lance_xmit_error(unit), lance_collision(unit)); 49953897Smckusick } 50053897Smckusick 50153897Smckusick enrint(unit) 50253897Smckusick register int unit; 50353897Smckusick { 50453897Smckusick register struct en_softc *es = &en_softc[unit]; 50553897Smckusick caddr_t get_recv_buffer(); 50653897Smckusick 50753897Smckusick while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) { 50853897Smckusick _enrint(unit, 50953897Smckusick get_recv_length(unit) - sizeof(struct en_rheader)); 51053897Smckusick free_recv_buffer(unit); 51153897Smckusick } 51253897Smckusick } 51353897Smckusick 51453897Smckusick en_prom_mode(unit, mode) 51553897Smckusick int unit, mode; 51653897Smckusick { 51753897Smckusick 51853897Smckusick lance_prom_mode(unit, mode); 51953897Smckusick } 52053897Smckusick #endif /* CPU_SINGLE */ 52153897Smckusick 52253897Smckusick #ifdef IPC_MRX 52353897Smckusick #include "../ipc/newsipc.h" 52453897Smckusick #include "../mrx/h/lancereg.h" 52553897Smckusick #include "../mrx/h/lance.h" 52653897Smckusick 52753897Smckusick int port_enxmit[NEN]; 52853897Smckusick int port_enrecv[NEN]; 52953897Smckusick int port_enctrl[NEN]; 53053897Smckusick int port_enxmit_iop[NEN]; 53153897Smckusick int port_enrecv_iop[NEN]; 53253897Smckusick int port_enctrl_iop[NEN]; 53353897Smckusick 53453897Smckusick en_probe(ii) 53553897Smckusick register struct iop_device *ii; 53653897Smckusick { 53753897Smckusick int unit = ii->ii_unit; 53853897Smckusick int lance_func, *reply; 53953897Smckusick char name[32]; 54053897Smckusick extern char *make_name(); 54153897Smckusick 54253897Smckusick if (port_enrecv[unit] == 0) { 54353897Smckusick 54453897Smckusick #define PT_CREATE(buf, name, unit, func) \ 54553897Smckusick port_create(make_name(buf, name, unit), func, unit) 54653897Smckusick #define OB_QUERY(buf, name, unit) \ 54753897Smckusick object_query(make_name(buf, name, unit)) 54853897Smckusick 54953897Smckusick make_name(name, "@enrecvX", unit); 55053897Smckusick port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint); 55153897Smckusick port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint); 55253897Smckusick port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL); 55353897Smckusick /* use NULL action port */ 55453897Smckusick port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit); 55553897Smckusick port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit); 55653897Smckusick port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit); 55753897Smckusick } 55853897Smckusick if (port_enctrl_iop[unit] < 0) 55953897Smckusick goto bad; 56053897Smckusick lance_func = EN_START; 56153897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 56253897Smckusick sizeof(lance_func), 0); 56353897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 56453897Smckusick if (*reply < 0) 56553897Smckusick goto bad; 56653897Smckusick lance_func = EN_STOP; 56753897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 56853897Smckusick sizeof(lance_func), 0); 56953897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 57053897Smckusick return (1); 57153897Smckusick bad: 57253897Smckusick return (0); 57353897Smckusick } 57453897Smckusick 57553897Smckusick en_attach(unit) 57653897Smckusick int unit; 57753897Smckusick { 57853897Smckusick register struct en_softc *es = &en_softc[unit]; 57953897Smckusick int lance_func; 58053897Smckusick struct ether_addr *ether_addr; 58153897Smckusick 58253897Smckusick lance_func = EN_GETADDR; 58353897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 58453897Smckusick sizeof(lance_func), 0); 58553897Smckusick msg_recv(port_enctrl[unit], NULL, ðer_addr, NULL, 0); 58653897Smckusick bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr)); 58753897Smckusick msg_free(port_enctrl[unit]); 58853897Smckusick } 58953897Smckusick 59053897Smckusick en_init(unit) 59153897Smckusick int unit; 59253897Smckusick { 59353897Smckusick register struct en_softc *es = &en_softc[unit]; 59453897Smckusick register int port; 59553897Smckusick struct lance_ctrl_req req; 59653897Smckusick int *reply; 59753897Smckusick 59853897Smckusick req.lance_func = EN_SETXMITBUF; 59953897Smckusick mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr, 60053897Smckusick ETHERMTU + sizeof(struct en_rheader)); 60153897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 60253897Smckusick &req, sizeof(req), 0); 60353897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 60453897Smckusick 60553897Smckusick req.lance_func = EN_START; 60653897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 60753897Smckusick &req, sizeof(req), 0); 60853897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 60953897Smckusick msg_free(port_enctrl[unit]); 61053897Smckusick 61153897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 61253897Smckusick es->es_ifnews.ifn_raddr, 61353897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 61453897Smckusick } 61553897Smckusick 61653897Smckusick en_start(unit, len) 61753897Smckusick int unit; 61853897Smckusick int len; 61953897Smckusick { 62053897Smckusick 62153897Smckusick msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0); 62253897Smckusick } 62353897Smckusick 62453897Smckusick enxint(unit) 62553897Smckusick register int unit; 62653897Smckusick { 62753897Smckusick int *len; 62853897Smckusick struct en_softc *es = &en_softc[unit]; 62953897Smckusick 63053897Smckusick if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) { 63153897Smckusick printf("stray enxint\n"); 63253897Smckusick return; 63353897Smckusick } 63453897Smckusick if (es->es_ifnews.ifn_mbuf) 63553897Smckusick m_freem(es->es_ifnews.ifn_mbuf); 63653897Smckusick _enxint(unit, *len < 0, *len & 0x10000); 63753897Smckusick } 63853897Smckusick 63953897Smckusick enrint(unit) 64053897Smckusick int unit; 64153897Smckusick { 64253897Smckusick int len; 64353897Smckusick int *reply; 64453897Smckusick 64553897Smckusick if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) { 64653897Smckusick printf("stray enrint\n"); 64753897Smckusick return; 64853897Smckusick } 64953897Smckusick len = *reply - sizeof(struct en_rheader); 65053897Smckusick msg_free(port_enrecv[unit]); 65153897Smckusick #ifdef mips 65253897Smckusick /* 65353897Smckusick * cache flush address must aligned long word boundary. 65453897Smckusick * so, add 3 for sanity. 65553897Smckusick */ 65653897Smckusick clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03, 65753897Smckusick len + sizeof (struct en_rheader) + 3); 65853897Smckusick #endif 65953897Smckusick _enrint(unit, len); 66053897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 66153897Smckusick en_softc[unit].es_ifnews.ifn_raddr, 66253897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 66353897Smckusick } 66453897Smckusick 66553897Smckusick en_prom_mode(unit, mode) 66653897Smckusick int unit, mode; 66753897Smckusick { 66853897Smckusick static int port; 66953897Smckusick struct lance_ctrl_req req; 67053897Smckusick extern int port_enctrl_iop[]; 67153897Smckusick 67253897Smckusick req.lance_func = EN_PROMMODE; 67353897Smckusick req.lance_mode = mode; 67453897Smckusick msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0); 67553897Smckusick } 67653897Smckusick #endif /* IPC_MRX */ 67753897Smckusick #endif /* NEN > 0 */ 678