123558Ssklower /* 229361Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335318Sbostic * All rights reserved. 423558Ssklower * 5*44558Sbostic * %sccs.include.redist.c% 635318Sbostic * 7*44558Sbostic * @(#)if_ec.c 7.7 (Berkeley) 06/28/90 823558Ssklower */ 96520Sfeldman 106520Sfeldman #include "ec.h" 1125271Sbloom #if NEC > 0 126520Sfeldman 136520Sfeldman /* 146520Sfeldman * 3Com Ethernet Controller interface 156520Sfeldman */ 1637508Smckusick #include "machine/pte.h" 176520Sfeldman 1817112Sbloom #include "param.h" 1917112Sbloom #include "systm.h" 2017112Sbloom #include "mbuf.h" 2117112Sbloom #include "buf.h" 2217112Sbloom #include "protosw.h" 2317112Sbloom #include "socket.h" 2425445Skarels #include "syslog.h" 2517112Sbloom #include "vmmac.h" 2617112Sbloom #include "ioctl.h" 2717112Sbloom #include "errno.h" 288461Sroot 298461Sroot #include "../net/if.h" 308461Sroot #include "../net/netisr.h" 318461Sroot #include "../net/route.h" 3223558Ssklower 3323558Ssklower #ifdef INET 348417Swnj #include "../netinet/in.h" 358417Swnj #include "../netinet/in_systm.h" 3619863Skarels #include "../netinet/in_var.h" 378417Swnj #include "../netinet/ip.h" 3811574Ssam #include "../netinet/if_ether.h" 3923558Ssklower #endif 4023558Ssklower 4123558Ssklower #ifdef NS 4223558Ssklower #include "../netns/ns.h" 4323558Ssklower #include "../netns/ns_if.h" 4419951Sbloom #endif 456520Sfeldman 468461Sroot #include "../vax/cpu.h" 478461Sroot #include "../vax/mtpr.h" 4817112Sbloom #include "if_ecreg.h" 4917112Sbloom #include "if_uba.h" 508461Sroot #include "../vaxuba/ubareg.h" 518461Sroot #include "../vaxuba/ubavar.h" 528461Sroot 5317995Skarels #if CLSIZE == 2 5417995Skarels #define ECBUFSIZE 32 /* on-board memory, clusters */ 5516749Sbloom #endif 5616749Sbloom 5717995Skarels int ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide(); 586520Sfeldman struct uba_device *ecinfo[NEC]; 596520Sfeldman u_short ecstd[] = { 0 }; 606520Sfeldman struct uba_driver ecdriver = 6132520Sbostic { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, 0, ecubamem }; 626520Sfeldman 6337475Ssklower int ecinit(),ecioctl(),ecstart(),ecreset(),ether_output(); 648773Sroot struct mbuf *ecget(); 656520Sfeldman 666545Sfeldman extern struct ifnet loif; 676545Sfeldman 686520Sfeldman /* 696520Sfeldman * Ethernet software status per interface. 706520Sfeldman * 716520Sfeldman * Each interface is referenced by a network interface structure, 726520Sfeldman * es_if, which the routing code uses to locate the interface. 736520Sfeldman * This structure contains the output queue for the interface, its address, ... 746520Sfeldman * We also have, for each interface, a UBA interface structure, which 756520Sfeldman * contains information about the UNIBUS resources held by the interface: 766520Sfeldman * map registers, buffered data paths, etc. Information is cached in this 776520Sfeldman * structure for use by the if_uba.c routines in running the interface 786520Sfeldman * efficiently. 796520Sfeldman */ 806520Sfeldman struct ec_softc { 8111574Ssam struct arpcom es_ac; /* common Ethernet structures */ 8211574Ssam #define es_if es_ac.ac_if /* network-visible interface */ 8311574Ssam #define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ 846520Sfeldman struct ifuba es_ifuba; /* UNIBUS resources */ 856520Sfeldman short es_mask; /* mask for current output delay */ 868773Sroot u_char *es_buf[16]; /* virtual addresses of buffers */ 876520Sfeldman } ec_softc[NEC]; 886520Sfeldman 896520Sfeldman /* 9017995Skarels * Configure on-board memory for an interface. 9117995Skarels * Called from autoconfig and after a uba reset. 9217995Skarels * The address of the memory on the uba is supplied in the device flags. 936520Sfeldman */ 9417995Skarels ecubamem(ui, uban) 9517995Skarels register struct uba_device *ui; 966520Sfeldman { 9717995Skarels register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags]; 9817995Skarels register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 996520Sfeldman 10017995Skarels /* 10117995Skarels * Make sure csr is there (we run before ecprobe). 10217995Skarels */ 10317995Skarels if (badaddr((caddr_t)addr, 2)) 10417995Skarels return (-1); 10517995Skarels #if VAX780 10617995Skarels if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { 10717995Skarels uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; 10817995Skarels return (-1); 10917995Skarels } 1106520Sfeldman #endif 1116520Sfeldman /* 1126637Sfeldman * Make sure memory is turned on 1136637Sfeldman */ 1146637Sfeldman addr->ec_rcr = EC_AROM; 1156637Sfeldman /* 11617995Skarels * Tell the system that the board has memory here, so it won't 11717995Skarels * attempt to allocate the addresses later. 1187470Sfeldman */ 11917995Skarels if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) { 12017995Skarels printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit); 12117995Skarels addr->ec_rcr = EC_MDISAB; /* disable memory */ 12217995Skarels return (-1); 12317995Skarels } 1247470Sfeldman /* 1256520Sfeldman * Check for existence of buffers on Unibus. 1266520Sfeldman */ 1278773Sroot if (badaddr((caddr_t)ecbuf, 2)) { 12817995Skarels bad: 12917995Skarels printf("ec%d: buffer mem not found\n", ui->ui_unit); 13017995Skarels (void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0); 1317470Sfeldman addr->ec_rcr = EC_MDISAB; /* disable memory */ 13217995Skarels return (-1); 1336520Sfeldman } 1347470Sfeldman #if VAX780 13517995Skarels if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { 13617995Skarels uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; 13717995Skarels goto bad; 1387470Sfeldman } 1397470Sfeldman #endif 14017995Skarels if (ui->ui_alive == 0) /* Only printf from autoconfig */ 14117995Skarels printf("ec%d: mem %x-%x\n", ui->ui_unit, 14217995Skarels ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1); 14317995Skarels ui->ui_type = 1; /* Memory on, allocated */ 14417995Skarels return (0); 14517995Skarels } 1466520Sfeldman 14717995Skarels /* 14817995Skarels * Do output DMA to determine interface presence and 14917995Skarels * interrupt vector. DMA is too short to disturb other hosts. 15017995Skarels */ 15117995Skarels ecprobe(reg, ui) 15217995Skarels caddr_t reg; 15317995Skarels struct uba_device *ui; 15417995Skarels { 15517995Skarels register int br, cvec; /* r11, r10 value-result */ 15617995Skarels register struct ecdevice *addr = (struct ecdevice *)reg; 15717995Skarels register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags]; 15817995Skarels 15917995Skarels #ifdef lint 16017995Skarels br = 0; cvec = br; br = cvec; 16117995Skarels ecrint(0); ecxint(0); eccollide(0); 16217995Skarels #endif 16317995Skarels 1646520Sfeldman /* 16517995Skarels * Check that buffer memory was found and enabled. 1666520Sfeldman */ 16717995Skarels if (ui->ui_type == 0) 16817995Skarels return(0); 1696520Sfeldman /* 1706520Sfeldman * Make a one byte packet in what should be buffer #0. 17117995Skarels * Submit it for sending. This should cause an xmit interrupt. 1726520Sfeldman * The xmit interrupt vector is 8 bytes after the receive vector, 1736520Sfeldman * so adjust for this before returning. 1746520Sfeldman */ 1756520Sfeldman *(u_short *)ecbuf = (u_short) 03777; 1766520Sfeldman ecbuf[03777] = '\0'; 1776520Sfeldman addr->ec_xcr = EC_XINTEN|EC_XWBN; 1786520Sfeldman DELAY(100000); 1796520Sfeldman addr->ec_xcr = EC_XCLR; 1807216Ssam if (cvec > 0 && cvec != 0x200) { 1817470Sfeldman if (cvec & 04) { /* collision interrupt */ 1827470Sfeldman cvec -= 04; 1837470Sfeldman br += 1; /* rcv is collision + 1 */ 1847470Sfeldman } else { /* xmit interrupt */ 1857470Sfeldman cvec -= 010; 1867470Sfeldman br += 2; /* rcv is xmit + 2 */ 1877470Sfeldman } 1887216Ssam } 1896520Sfeldman return (1); 1906520Sfeldman } 1916520Sfeldman 1926520Sfeldman /* 1936520Sfeldman * Interface exists: make available by filling in network interface 1946520Sfeldman * record. System will initialize the interface when it is ready 1956520Sfeldman * to accept packets. 1966520Sfeldman */ 1976520Sfeldman ecattach(ui) 1986520Sfeldman struct uba_device *ui; 1996520Sfeldman { 2007216Ssam struct ec_softc *es = &ec_softc[ui->ui_unit]; 2017216Ssam register struct ifnet *ifp = &es->es_if; 2026520Sfeldman register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 2037216Ssam int i, j; 2047216Ssam u_char *cp; 2056520Sfeldman 2067216Ssam ifp->if_unit = ui->ui_unit; 2077216Ssam ifp->if_name = "ec"; 2089745Ssam ifp->if_mtu = ETHERMTU; 2096520Sfeldman 2106520Sfeldman /* 2117216Ssam * Read the ethernet address off the board, one nibble at a time. 2126520Sfeldman */ 21324227Ssklower addr->ec_xcr = EC_UECLR; /* zero address pointer */ 2146520Sfeldman addr->ec_rcr = EC_AROM; 21519863Skarels cp = es->es_addr; 2167216Ssam #define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM 21716217Skarels for (i=0; i < sizeof (es->es_addr); i++) { 2186520Sfeldman *cp = 0; 2196520Sfeldman for (j=0; j<=4; j+=4) { 2206520Sfeldman *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 2217216Ssam NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 2226520Sfeldman } 2236520Sfeldman cp++; 2246520Sfeldman } 22525973Skarels printf("ec%d: hardware address %s\n", ui->ui_unit, 22625973Skarels ether_sprintf(es->es_addr)); 2277216Ssam ifp->if_init = ecinit; 22813055Ssam ifp->if_ioctl = ecioctl; 22937475Ssklower ifp->if_output = ether_output; 23037475Ssklower ifp->if_start = ecstart; 2318977Sroot ifp->if_reset = ecreset; 23237475Ssklower ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 2336520Sfeldman for (i=0; i<16; i++) 23416749Sbloom es->es_buf[i] 23517995Skarels = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i]; 2367216Ssam if_attach(ifp); 2376520Sfeldman } 2386520Sfeldman 2396520Sfeldman /* 2406520Sfeldman * Reset of interface after UNIBUS reset. 2416520Sfeldman * If interface is on specified uba, reset its state. 2426520Sfeldman */ 2436520Sfeldman ecreset(unit, uban) 2446520Sfeldman int unit, uban; 2456520Sfeldman { 2466520Sfeldman register struct uba_device *ui; 2476520Sfeldman 2486520Sfeldman if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || 2496520Sfeldman ui->ui_ubanum != uban) 2506520Sfeldman return; 2516520Sfeldman printf(" ec%d", unit); 25216207Skarels ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING; 2536520Sfeldman ecinit(unit); 2546520Sfeldman } 2556520Sfeldman 2566520Sfeldman /* 2576520Sfeldman * Initialization of interface; clear recorded pending 2586520Sfeldman * operations, and reinitialize UNIBUS usage. 2596520Sfeldman */ 2606520Sfeldman ecinit(unit) 2616520Sfeldman int unit; 2626520Sfeldman { 2637216Ssam struct ec_softc *es = &ec_softc[unit]; 2647216Ssam struct ecdevice *addr; 26511574Ssam register struct ifnet *ifp = &es->es_if; 26613055Ssam int i, s; 2676520Sfeldman 26819863Skarels /* not yet, if address still unknown */ 26919863Skarels if (ifp->if_addrlist == (struct ifaddr *)0) 27011574Ssam return; 27111574Ssam 2726520Sfeldman /* 2737217Sfeldman * Hang receive buffers and start any pending writes. 2746637Sfeldman * Writing into the rcr also makes sure the memory 2756637Sfeldman * is turned on. 2766520Sfeldman */ 27719863Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 27837475Ssklower u_short start_read; 27913055Ssam addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 28013055Ssam s = splimp(); 28124227Ssklower /* 28224227Ssklower * write our ethernet address into the address recognition ROM 28324227Ssklower * so we can always use the same EC_READ bits (referencing ROM), 28424227Ssklower * in case we change the address sometime. 28525445Skarels * Note that this is safe here as the receiver is NOT armed. 28624227Ssklower */ 28724227Ssklower ec_setaddr(es->es_addr, unit); 28824227Ssklower /* 28925445Skarels * Arm the receiver 29037475Ssklower #ifdef MULTI 29137475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 29237475Ssklower start_read = EC_PROMISC; 29337475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 29437475Ssklower start_read = EC_MULTI; 29537475Ssklower else 29637475Ssklower #endif MULTI 29737475Ssklower start_read = EC_READ; 29824227Ssklower */ 29913055Ssam for (i = ECRHBF; i >= ECRLBF; i--) 30013055Ssam addr->ec_rcr = EC_READ | i; 30137475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 30213055Ssam es->es_mask = ~0; 30319863Skarels es->es_if.if_flags |= IFF_RUNNING; 30413055Ssam if (es->es_if.if_snd.ifq_head) 30537475Ssklower (void) ecstart(&es->es_if); 30613055Ssam splx(s); 30713055Ssam } 3086520Sfeldman } 3096520Sfeldman 3106520Sfeldman /* 31125445Skarels * Start output on interface. Get another datagram to send 31225445Skarels * off of the interface queue, and copy it to the interface 3136520Sfeldman * before starting the output. 3146520Sfeldman */ 31537475Ssklower ecstart(ifp) 31637475Ssklower struct ifnet *ifp; 3176520Sfeldman { 31837475Ssklower int unit = ifp->if_unit; 31925445Skarels register struct ec_softc *es = &ec_softc[unit]; 3207216Ssam struct ecdevice *addr; 3216520Sfeldman struct mbuf *m; 3226520Sfeldman 32325445Skarels if ((es->es_if.if_flags & IFF_RUNNING) == 0) 32437475Ssklower return (0); 3256520Sfeldman IF_DEQUEUE(&es->es_if.if_snd, m); 32625445Skarels if (m == 0) 32737475Ssklower return (0); 3286520Sfeldman ecput(es->es_buf[ECTBF], m); 3297216Ssam addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 3306520Sfeldman addr->ec_xcr = EC_WRITE|ECTBF; 33137475Ssklower es->es_if.if_flags |= IFF_OACTIVE; 33237475Ssklower return (0); 3336520Sfeldman } 3346520Sfeldman 3356520Sfeldman /* 3366520Sfeldman * Ethernet interface transmitter interrupt. 3376520Sfeldman * Start another output if more data to send. 3386520Sfeldman */ 3396520Sfeldman ecxint(unit) 3406520Sfeldman int unit; 3416520Sfeldman { 3426520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 3437216Ssam register struct ecdevice *addr = 3447216Ssam (struct ecdevice *)ecinfo[unit]->ui_addr; 3456520Sfeldman 34637475Ssklower if ((es->es_if.if_flags & IFF_OACTIVE) == 0) 3476520Sfeldman return; 3487216Ssam if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) { 3497216Ssam printf("ec%d: stray xmit interrupt, xcr=%b\n", unit, 3507216Ssam addr->ec_xcr, EC_XBITS); 35137475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 3527216Ssam addr->ec_xcr = EC_XCLR; 3537216Ssam return; 3547216Ssam } 3556520Sfeldman es->es_if.if_opackets++; 35637475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 3576520Sfeldman es->es_mask = ~0; 3586520Sfeldman addr->ec_xcr = EC_XCLR; 3597216Ssam if (es->es_if.if_snd.ifq_head) 36037475Ssklower (void) ecstart(&es->es_if); 3616520Sfeldman } 3626520Sfeldman 3636520Sfeldman /* 3646520Sfeldman * Collision on ethernet interface. Do exponential 3656520Sfeldman * backoff, and retransmit. If have backed off all 3666520Sfeldman * the way print warning diagnostic, and drop packet. 3676520Sfeldman */ 3686520Sfeldman eccollide(unit) 3696520Sfeldman int unit; 3706520Sfeldman { 3716520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 3726545Sfeldman register struct ecdevice *addr = 3736545Sfeldman (struct ecdevice *)ecinfo[unit]->ui_addr; 3746545Sfeldman register i; 3756545Sfeldman int delay; 3766520Sfeldman 37725445Skarels es->es_if.if_collisions++; 37837475Ssklower if ((es->es_if.if_flags & IFF_OACTIVE) == 0) 37925445Skarels return; 38025445Skarels 3816520Sfeldman /* 3826520Sfeldman * Es_mask is a 16 bit number with n low zero bits, with 3836520Sfeldman * n the number of backoffs. When es_mask is 0 we have 3846520Sfeldman * backed off 16 times, and give up. 3856520Sfeldman */ 3866520Sfeldman if (es->es_mask == 0) { 38737475Ssklower u_short start_read; 3886545Sfeldman es->es_if.if_oerrors++; 38925445Skarels log(LOG_ERR, "ec%d: send error\n", unit); 3906520Sfeldman /* 3916545Sfeldman * Reset interface, then requeue rcv buffers. 3926545Sfeldman * Some incoming packets may be lost, but that 3936545Sfeldman * can't be helped. 3946520Sfeldman */ 3956545Sfeldman addr->ec_xcr = EC_UECLR; 39637475Ssklower #ifdef MULTI 39737475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 39837475Ssklower start_read = EC_PROMISC; 39937475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 40037475Ssklower start_read = EC_MULTI; 40137475Ssklower else 40237475Ssklower #endif MULTI 40337475Ssklower start_read = EC_READ; 4046545Sfeldman for (i=ECRHBF; i>=ECRLBF; i--) 40537475Ssklower addr->ec_rcr = start_read|i; 4066545Sfeldman /* 4076545Sfeldman * Reset and transmit next packet (if any). 4086545Sfeldman */ 40937475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 4106545Sfeldman es->es_mask = ~0; 4116545Sfeldman if (es->es_if.if_snd.ifq_head) 41237475Ssklower (void) ecstart(&es->es_if); 4136520Sfeldman return; 4146520Sfeldman } 4156520Sfeldman /* 4166545Sfeldman * Do exponential backoff. Compute delay based on low bits 41725445Skarels * of the interval timer (1 bit for each transmission attempt, 41825445Skarels * but at most 5 bits). Then delay for that number of 4196545Sfeldman * slot times. A slot time is 51.2 microseconds (rounded to 51). 4206545Sfeldman * This does not take into account the time already used to 4216545Sfeldman * process the interrupt. 4226520Sfeldman */ 4236520Sfeldman es->es_mask <<= 1; 42425445Skarels delay = mfpr(ICR) & 0x1f &~ es->es_mask; 4256545Sfeldman DELAY(delay * 51); 4266520Sfeldman /* 4276545Sfeldman * Clear the controller's collision flag, thus enabling retransmit. 4286520Sfeldman */ 4297470Sfeldman addr->ec_xcr = EC_CLEAR; 4306520Sfeldman } 4316520Sfeldman 4326520Sfeldman /* 4336520Sfeldman * Ethernet interface receiver interrupt. 4346520Sfeldman * If input error just drop packet. 43524227Ssklower * Otherwise examine 4366520Sfeldman * packet to determine type. If can't determine length 4376520Sfeldman * from type, then have to drop packet. Othewise decapsulate 4386520Sfeldman * packet based on type and pass to type specific higher-level 4396520Sfeldman * input routine. 4406520Sfeldman */ 4416520Sfeldman ecrint(unit) 4426520Sfeldman int unit; 4436520Sfeldman { 4446520Sfeldman struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 4456520Sfeldman 4466520Sfeldman while (addr->ec_rcr & EC_RDONE) 4476520Sfeldman ecread(unit); 4486520Sfeldman } 4496520Sfeldman 4506520Sfeldman ecread(unit) 4516520Sfeldman int unit; 4526520Sfeldman { 4536520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 4546520Sfeldman struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 4559745Ssam register struct ether_header *ec; 4566520Sfeldman struct mbuf *m; 4578773Sroot int len, off, resid, ecoff, rbuf; 4586520Sfeldman register struct ifqueue *inq; 45937475Ssklower u_short start_read; 4608773Sroot u_char *ecbuf; 4616520Sfeldman 4626520Sfeldman es->es_if.if_ipackets++; 4638773Sroot rbuf = addr->ec_rcr & EC_RBN; 4648773Sroot if (rbuf < ECRLBF || rbuf > ECRHBF) 4656520Sfeldman panic("ecrint"); 4668773Sroot ecbuf = es->es_buf[rbuf]; 4676520Sfeldman ecoff = *(short *)ecbuf; 4686545Sfeldman if (ecoff <= ECRDOFF || ecoff > 2046) { 4696520Sfeldman es->es_if.if_ierrors++; 4706520Sfeldman #ifdef notdef 4716520Sfeldman if (es->es_if.if_ierrors % 100 == 0) 4726520Sfeldman printf("ec%d: += 100 input errors\n", unit); 4736520Sfeldman #endif 4746520Sfeldman goto setup; 4756520Sfeldman } 4766520Sfeldman 4776520Sfeldman /* 4786520Sfeldman * Get input data length. 4796520Sfeldman * Get pointer to ethernet header (in input buffer). 48019863Skarels * Deal with trailer protocol: if type is trailer type 4816520Sfeldman * get true type from first 16-bit word past data. 4826520Sfeldman * Remember that type was trailer by setting off. 4836520Sfeldman */ 4849745Ssam len = ecoff - ECRDOFF - sizeof (struct ether_header); 4859745Ssam ec = (struct ether_header *)(ecbuf + ECRDOFF); 4869745Ssam ec->ether_type = ntohs((u_short)ec->ether_type); 4876520Sfeldman #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) 48819863Skarels if (ec->ether_type >= ETHERTYPE_TRAIL && 48919863Skarels ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 49019863Skarels off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; 4919745Ssam if (off >= ETHERMTU) 4926520Sfeldman goto setup; /* sanity */ 4939745Ssam ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); 4949745Ssam resid = ntohs(*(ecdataaddr(ec, off+2, u_short *))); 4956520Sfeldman if (off + resid > len) 4966520Sfeldman goto setup; /* sanity */ 4976520Sfeldman len = off + resid; 4986520Sfeldman } else 4996520Sfeldman off = 0; 5006520Sfeldman if (len == 0) 5016520Sfeldman goto setup; 5026520Sfeldman 5036520Sfeldman /* 5046520Sfeldman * Pull packet off interface. Off is nonzero if packet 5056520Sfeldman * has trailing header; ecget will then force this header 5066520Sfeldman * information to be at the front, but we still have to drop 5076520Sfeldman * the type and length which are at the front of any trailer data. 5086520Sfeldman */ 50924789Skarels m = ecget(ecbuf, len, off, &es->es_if); 51037475Ssklower if (m) 51137475Ssklower ether_input(&es->es_if, ec, m); 5126520Sfeldman /* 5136520Sfeldman * Reset for next packet. 5146520Sfeldman */ 51537475Ssklower setup: 51637475Ssklower #ifdef MULTI 51737475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 51837475Ssklower start_read = EC_PROMISC; 51937475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 52037475Ssklower start_read = EC_MULTI; 52137475Ssklower else 52237475Ssklower #endif MULTI 52337475Ssklower start_read = EC_READ; 52437475Ssklower addr->ec_rcr = start_read|EC_RCLR|rbuf; 5256520Sfeldman } 5266520Sfeldman 5276520Sfeldman /* 5289177Ssam * Routine to copy from mbuf chain to transmit 5297216Ssam * buffer in UNIBUS memory. 5309177Ssam * If packet size is less than the minimum legal size, 5319177Ssam * the buffer is expanded. We probably should zero out the extra 5329177Ssam * bytes for security, but that would slow things down. 5336520Sfeldman */ 5346520Sfeldman ecput(ecbuf, m) 5357216Ssam u_char *ecbuf; 5366520Sfeldman struct mbuf *m; 5376520Sfeldman { 5386520Sfeldman register struct mbuf *mp; 5397216Ssam register int off; 5407263Ssam u_char *bp; 5416520Sfeldman 5427216Ssam for (off = 2048, mp = m; mp; mp = mp->m_next) 5437216Ssam off -= mp->m_len; 5449745Ssam if (2048 - off < ETHERMIN + sizeof (struct ether_header)) 5459745Ssam off = 2048 - ETHERMIN - sizeof (struct ether_header); 5467216Ssam *(u_short *)ecbuf = off; 5477216Ssam bp = (u_char *)(ecbuf + off); 5487263Ssam for (mp = m; mp; mp = mp->m_next) { 5497263Ssam register unsigned len = mp->m_len; 5507263Ssam u_char *mcp; 5517216Ssam 5527216Ssam if (len == 0) 5537216Ssam continue; 5547216Ssam mcp = mtod(mp, u_char *); 5557216Ssam if ((unsigned)bp & 01) { 5567032Swnj *bp++ = *mcp++; 5577216Ssam len--; 5587032Swnj } 5597263Ssam if (off = (len >> 1)) { 5607263Ssam register u_short *to, *from; 5617263Ssam 5627263Ssam to = (u_short *)bp; 5637263Ssam from = (u_short *)mcp; 5647263Ssam do 5657263Ssam *to++ = *from++; 5667263Ssam while (--off > 0); 5677263Ssam bp = (u_char *)to, 5687263Ssam mcp = (u_char *)from; 5697032Swnj } 5707263Ssam if (len & 01) 5716520Sfeldman *bp++ = *mcp++; 5726520Sfeldman } 5737263Ssam m_freem(m); 5746520Sfeldman } 5756520Sfeldman 5766520Sfeldman /* 5776520Sfeldman * Routine to copy from UNIBUS memory into mbufs. 5786520Sfeldman * Similar in spirit to if_rubaget. 5797032Swnj * 5807032Swnj * Warning: This makes the fairly safe assumption that 5817032Swnj * mbufs have even lengths. 5826520Sfeldman */ 5836520Sfeldman struct mbuf * 58424789Skarels ecget(ecbuf, totlen, off0, ifp) 5857263Ssam u_char *ecbuf; 5866520Sfeldman int totlen, off0; 58724789Skarels struct ifnet *ifp; 5886520Sfeldman { 5897263Ssam register struct mbuf *m; 5907263Ssam struct mbuf *top = 0, **mp = ⊤ 5917263Ssam register int off = off0, len; 59237475Ssklower u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header)); 59337475Ssklower u_char *packet_end = cp + totlen; 5946520Sfeldman 59537475Ssklower if (off) { 59637475Ssklower off += 2 * sizeof(u_short); 59737475Ssklower totlen -= 2 *sizeof(u_short); 59837475Ssklower cp += off; 59937475Ssklower } 60037475Ssklower 60137475Ssklower MGETHDR(m, M_DONTWAIT, MT_DATA); 60237475Ssklower if (m == 0) 60337475Ssklower return (0); 60437475Ssklower m->m_pkthdr.rcvif = ifp; 60537475Ssklower m->m_pkthdr.len = totlen; 60637475Ssklower m->m_len = MHLEN; 60737475Ssklower 6086520Sfeldman while (totlen > 0) { 6097263Ssam register int words; 6107263Ssam u_char *mcp; 6117263Ssam 61237475Ssklower if (top) { 61337475Ssklower MGET(m, M_DONTWAIT, MT_DATA); 61437475Ssklower if (m == 0) { 61537475Ssklower m_freem(top); 61637475Ssklower return (0); 61737475Ssklower } 61837475Ssklower m->m_len = MLEN; 61937475Ssklower } 62037475Ssklower len = min(totlen, (packet_end - cp)); 62137475Ssklower if (len >= MINCLSIZE) { 62237475Ssklower MCLGET(m, M_DONTWAIT); 62337475Ssklower if (m->m_flags & M_EXT) 62437475Ssklower m->m_len = len = min(len, MCLBYTES); 62526230Skarels else 62637475Ssklower len = m->m_len; 6276520Sfeldman } else { 62824789Skarels /* 62937475Ssklower * Place initial small packet/header at end of mbuf. 63024789Skarels */ 63137475Ssklower if (len < m->m_len) { 63237475Ssklower if (top == 0 && len + max_linkhdr <= m->m_len) 63337475Ssklower m->m_data += max_linkhdr; 63437475Ssklower m->m_len = len; 63537475Ssklower } else 63637475Ssklower len = m->m_len; 63724789Skarels } 63839690Ssklower mcp = mtod(m, u_char *); 6397263Ssam if (words = (len >> 1)) { 6407263Ssam register u_short *to, *from; 6417263Ssam 6427263Ssam to = (u_short *)mcp; 6437263Ssam from = (u_short *)cp; 6447263Ssam do 6457263Ssam *to++ = *from++; 6467263Ssam while (--words > 0); 6477263Ssam mcp = (u_char *)to; 6487263Ssam cp = (u_char *)from; 6497032Swnj } 6507216Ssam if (len & 01) 6516520Sfeldman *mcp++ = *cp++; 6526520Sfeldman *mp = m; 6536520Sfeldman mp = &m->m_next; 65437475Ssklower totlen -= len; 65537475Ssklower if (cp == packet_end) 65637475Ssklower cp = ecbuf; 6576520Sfeldman } 6586520Sfeldman return (top); 6596520Sfeldman bad: 6606520Sfeldman m_freem(top); 6616520Sfeldman return (0); 6626520Sfeldman } 66313055Ssam 66413055Ssam /* 66513055Ssam * Process an ioctl request. 66613055Ssam */ 66713055Ssam ecioctl(ifp, cmd, data) 66813055Ssam register struct ifnet *ifp; 66913055Ssam int cmd; 67013055Ssam caddr_t data; 67113055Ssam { 67219863Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 67325445Skarels struct ec_softc *es = &ec_softc[ifp->if_unit]; 67425445Skarels struct ecdevice *addr; 67513055Ssam int s = splimp(), error = 0; 67613055Ssam 67725445Skarels addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr); 67825445Skarels 67913055Ssam switch (cmd) { 68013055Ssam 68113055Ssam case SIOCSIFADDR: 68219863Skarels ifp->if_flags |= IFF_UP; 68319863Skarels 68437475Ssklower switch (ifa->ifa_addr->sa_family) { 68523558Ssklower #ifdef INET 68619863Skarels case AF_INET: 68725445Skarels ecinit(ifp->if_unit); /* before arpwhohas */ 68819863Skarels ((struct arpcom *)ifp)->ac_ipaddr = 68919863Skarels IA_SIN(ifa)->sin_addr; 69019863Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 69119863Skarels break; 69223558Ssklower #endif 69323558Ssklower #ifdef NS 69423558Ssklower case AF_NS: 69523558Ssklower { 69623558Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 69723558Ssklower 69825445Skarels if (ns_nullhost(*ina)) 69925445Skarels ina->x_host = *(union ns_host *)(es->es_addr); 70025445Skarels else { 70124227Ssklower /* 70224227Ssklower * The manual says we can't change the address 70325445Skarels * while the receiver is armed, 70425445Skarels * so reset everything 70524227Ssklower */ 70625445Skarels ifp->if_flags &= ~IFF_RUNNING; 70726390Skarels bcopy((caddr_t)ina->x_host.c_host, 70826390Skarels (caddr_t)es->es_addr, sizeof(es->es_addr)); 70923558Ssklower } 71024227Ssklower ecinit(ifp->if_unit); /* does ec_setaddr() */ 71123558Ssklower break; 71223558Ssklower } 71323558Ssklower #endif 71425445Skarels default: 71525445Skarels ecinit(ifp->if_unit); 71625445Skarels break; 71719863Skarels } 71813055Ssam break; 71913055Ssam 72025445Skarels case SIOCSIFFLAGS: 72125445Skarels if ((ifp->if_flags & IFF_UP) == 0 && 72225445Skarels ifp->if_flags & IFF_RUNNING) { 72325445Skarels addr->ec_xcr = EC_UECLR; 72425445Skarels ifp->if_flags &= ~IFF_RUNNING; 72525445Skarels } else if (ifp->if_flags & IFF_UP && 72625445Skarels (ifp->if_flags & IFF_RUNNING) == 0) 72725445Skarels ecinit(ifp->if_unit); 72825445Skarels break; 72925445Skarels 73013055Ssam default: 73113055Ssam error = EINVAL; 73213055Ssam } 73313055Ssam splx(s); 73413055Ssam return (error); 73513055Ssam } 73623558Ssklower 73723558Ssklower ec_setaddr(physaddr,unit) 73825445Skarels u_char *physaddr; 73925445Skarels int unit; 74023558Ssklower { 74123558Ssklower struct ec_softc *es = &ec_softc[unit]; 74223558Ssklower struct uba_device *ui = ecinfo[unit]; 74323558Ssklower register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 74423558Ssklower register char nibble; 74523558Ssklower register int i, j; 74624789Skarels 74723558Ssklower /* 74823558Ssklower * Use the ethernet address supplied 74925445Skarels * Note that we do a UECLR here, so the receive buffers 75024227Ssklower * must be requeued. 75123558Ssklower */ 75223558Ssklower 75324227Ssklower #ifdef DEBUG 75425973Skarels printf("ec_setaddr: setting address for unit %d = %s", 75525973Skarels unit, ether_sprintf(physaddr)); 75624227Ssklower #endif 75724227Ssklower addr->ec_xcr = EC_UECLR; 75823558Ssklower addr->ec_rcr = 0; 75924227Ssklower /* load requested address */ 76023558Ssklower for (i = 0; i < 6; i++) { /* 6 bytes of address */ 76123558Ssklower es->es_addr[i] = physaddr[i]; 76223558Ssklower nibble = physaddr[i] & 0xf; /* lower nibble */ 76323558Ssklower addr->ec_rcr = (nibble << 8); 76424227Ssklower addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 76523558Ssklower addr->ec_rcr = (nibble << 8); 76623558Ssklower for (j=0; j < 4; j++) { 76723558Ssklower addr->ec_rcr = 0; 76823558Ssklower addr->ec_rcr = EC_ASTEP; /* step counter */ 76923558Ssklower addr->ec_rcr = 0; 77023558Ssklower } 77123558Ssklower nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ 77223558Ssklower addr->ec_rcr = (nibble << 8); 77324227Ssklower addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 77423558Ssklower addr->ec_rcr = (nibble << 8); 77523558Ssklower for (j=0; j < 4; j++) { 77623558Ssklower addr->ec_rcr = 0; 77723558Ssklower addr->ec_rcr = EC_ASTEP; /* step counter */ 77823558Ssklower addr->ec_rcr = 0; 77923558Ssklower } 78023558Ssklower } 78124227Ssklower #ifdef DEBUG 78224227Ssklower /* 78324227Ssklower * Read the ethernet address off the board, one nibble at a time. 78424227Ssklower */ 78524227Ssklower addr->ec_xcr = EC_UECLR; 78624227Ssklower addr->ec_rcr = 0; /* read RAM */ 78724227Ssklower cp = es->es_addr; 78824227Ssklower #undef NEXTBIT 78924227Ssklower #define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 79024227Ssklower for (i=0; i < sizeof (es->es_addr); i++) { 79124227Ssklower *cp = 0; 79224227Ssklower for (j=0; j<=4; j+=4) { 79324227Ssklower *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 79424227Ssklower NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 79524227Ssklower } 79624227Ssklower cp++; 79724227Ssklower } 79825973Skarels printf("ec_setaddr: RAM address for unit %d = %s", 79925973Skarels unit, ether_sprintf(physaddr)); 80024227Ssklower #endif 80123558Ssklower } 80225271Sbloom #endif 803