123558Ssklower /* 229361Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335318Sbostic * All rights reserved. 423558Ssklower * 535318Sbostic * Redistribution and use in source and binary forms are permitted 635318Sbostic * provided that the above copyright notice and this paragraph are 735318Sbostic * duplicated in all such forms and that any documentation, 835318Sbostic * advertising materials, and other materials related to such 935318Sbostic * distribution and use acknowledge that the software was developed 1035318Sbostic * by the University of California, Berkeley. The name of the 1135318Sbostic * University may not be used to endorse or promote products derived 1235318Sbostic * from this software without specific prior written permission. 1335318Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435318Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535318Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635318Sbostic * 17*39690Ssklower * @(#)if_ec.c 7.6 (Berkeley) 12/07/89 1823558Ssklower */ 196520Sfeldman 206520Sfeldman #include "ec.h" 2125271Sbloom #if NEC > 0 226520Sfeldman 236520Sfeldman /* 246520Sfeldman * 3Com Ethernet Controller interface 256520Sfeldman */ 2637508Smckusick #include "machine/pte.h" 276520Sfeldman 2817112Sbloom #include "param.h" 2917112Sbloom #include "systm.h" 3017112Sbloom #include "mbuf.h" 3117112Sbloom #include "buf.h" 3217112Sbloom #include "protosw.h" 3317112Sbloom #include "socket.h" 3425445Skarels #include "syslog.h" 3517112Sbloom #include "vmmac.h" 3617112Sbloom #include "ioctl.h" 3717112Sbloom #include "errno.h" 388461Sroot 398461Sroot #include "../net/if.h" 408461Sroot #include "../net/netisr.h" 418461Sroot #include "../net/route.h" 4223558Ssklower 4323558Ssklower #ifdef INET 448417Swnj #include "../netinet/in.h" 458417Swnj #include "../netinet/in_systm.h" 4619863Skarels #include "../netinet/in_var.h" 478417Swnj #include "../netinet/ip.h" 4811574Ssam #include "../netinet/if_ether.h" 4923558Ssklower #endif 5023558Ssklower 5123558Ssklower #ifdef NS 5223558Ssklower #include "../netns/ns.h" 5323558Ssklower #include "../netns/ns_if.h" 5419951Sbloom #endif 556520Sfeldman 568461Sroot #include "../vax/cpu.h" 578461Sroot #include "../vax/mtpr.h" 5817112Sbloom #include "if_ecreg.h" 5917112Sbloom #include "if_uba.h" 608461Sroot #include "../vaxuba/ubareg.h" 618461Sroot #include "../vaxuba/ubavar.h" 628461Sroot 6317995Skarels #if CLSIZE == 2 6417995Skarels #define ECBUFSIZE 32 /* on-board memory, clusters */ 6516749Sbloom #endif 6616749Sbloom 6717995Skarels int ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide(); 686520Sfeldman struct uba_device *ecinfo[NEC]; 696520Sfeldman u_short ecstd[] = { 0 }; 706520Sfeldman struct uba_driver ecdriver = 7132520Sbostic { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, 0, ecubamem }; 726520Sfeldman 7337475Ssklower int ecinit(),ecioctl(),ecstart(),ecreset(),ether_output(); 748773Sroot struct mbuf *ecget(); 756520Sfeldman 766545Sfeldman extern struct ifnet loif; 776545Sfeldman 786520Sfeldman /* 796520Sfeldman * Ethernet software status per interface. 806520Sfeldman * 816520Sfeldman * Each interface is referenced by a network interface structure, 826520Sfeldman * es_if, which the routing code uses to locate the interface. 836520Sfeldman * This structure contains the output queue for the interface, its address, ... 846520Sfeldman * We also have, for each interface, a UBA interface structure, which 856520Sfeldman * contains information about the UNIBUS resources held by the interface: 866520Sfeldman * map registers, buffered data paths, etc. Information is cached in this 876520Sfeldman * structure for use by the if_uba.c routines in running the interface 886520Sfeldman * efficiently. 896520Sfeldman */ 906520Sfeldman struct ec_softc { 9111574Ssam struct arpcom es_ac; /* common Ethernet structures */ 9211574Ssam #define es_if es_ac.ac_if /* network-visible interface */ 9311574Ssam #define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ 946520Sfeldman struct ifuba es_ifuba; /* UNIBUS resources */ 956520Sfeldman short es_mask; /* mask for current output delay */ 968773Sroot u_char *es_buf[16]; /* virtual addresses of buffers */ 976520Sfeldman } ec_softc[NEC]; 986520Sfeldman 996520Sfeldman /* 10017995Skarels * Configure on-board memory for an interface. 10117995Skarels * Called from autoconfig and after a uba reset. 10217995Skarels * The address of the memory on the uba is supplied in the device flags. 1036520Sfeldman */ 10417995Skarels ecubamem(ui, uban) 10517995Skarels register struct uba_device *ui; 1066520Sfeldman { 10717995Skarels register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags]; 10817995Skarels register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 1096520Sfeldman 11017995Skarels /* 11117995Skarels * Make sure csr is there (we run before ecprobe). 11217995Skarels */ 11317995Skarels if (badaddr((caddr_t)addr, 2)) 11417995Skarels return (-1); 11517995Skarels #if VAX780 11617995Skarels if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { 11717995Skarels uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; 11817995Skarels return (-1); 11917995Skarels } 1206520Sfeldman #endif 1216520Sfeldman /* 1226637Sfeldman * Make sure memory is turned on 1236637Sfeldman */ 1246637Sfeldman addr->ec_rcr = EC_AROM; 1256637Sfeldman /* 12617995Skarels * Tell the system that the board has memory here, so it won't 12717995Skarels * attempt to allocate the addresses later. 1287470Sfeldman */ 12917995Skarels if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) { 13017995Skarels printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit); 13117995Skarels addr->ec_rcr = EC_MDISAB; /* disable memory */ 13217995Skarels return (-1); 13317995Skarels } 1347470Sfeldman /* 1356520Sfeldman * Check for existence of buffers on Unibus. 1366520Sfeldman */ 1378773Sroot if (badaddr((caddr_t)ecbuf, 2)) { 13817995Skarels bad: 13917995Skarels printf("ec%d: buffer mem not found\n", ui->ui_unit); 14017995Skarels (void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0); 1417470Sfeldman addr->ec_rcr = EC_MDISAB; /* disable memory */ 14217995Skarels return (-1); 1436520Sfeldman } 1447470Sfeldman #if VAX780 14517995Skarels if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { 14617995Skarels uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; 14717995Skarels goto bad; 1487470Sfeldman } 1497470Sfeldman #endif 15017995Skarels if (ui->ui_alive == 0) /* Only printf from autoconfig */ 15117995Skarels printf("ec%d: mem %x-%x\n", ui->ui_unit, 15217995Skarels ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1); 15317995Skarels ui->ui_type = 1; /* Memory on, allocated */ 15417995Skarels return (0); 15517995Skarels } 1566520Sfeldman 15717995Skarels /* 15817995Skarels * Do output DMA to determine interface presence and 15917995Skarels * interrupt vector. DMA is too short to disturb other hosts. 16017995Skarels */ 16117995Skarels ecprobe(reg, ui) 16217995Skarels caddr_t reg; 16317995Skarels struct uba_device *ui; 16417995Skarels { 16517995Skarels register int br, cvec; /* r11, r10 value-result */ 16617995Skarels register struct ecdevice *addr = (struct ecdevice *)reg; 16717995Skarels register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags]; 16817995Skarels 16917995Skarels #ifdef lint 17017995Skarels br = 0; cvec = br; br = cvec; 17117995Skarels ecrint(0); ecxint(0); eccollide(0); 17217995Skarels #endif 17317995Skarels 1746520Sfeldman /* 17517995Skarels * Check that buffer memory was found and enabled. 1766520Sfeldman */ 17717995Skarels if (ui->ui_type == 0) 17817995Skarels return(0); 1796520Sfeldman /* 1806520Sfeldman * Make a one byte packet in what should be buffer #0. 18117995Skarels * Submit it for sending. This should cause an xmit interrupt. 1826520Sfeldman * The xmit interrupt vector is 8 bytes after the receive vector, 1836520Sfeldman * so adjust for this before returning. 1846520Sfeldman */ 1856520Sfeldman *(u_short *)ecbuf = (u_short) 03777; 1866520Sfeldman ecbuf[03777] = '\0'; 1876520Sfeldman addr->ec_xcr = EC_XINTEN|EC_XWBN; 1886520Sfeldman DELAY(100000); 1896520Sfeldman addr->ec_xcr = EC_XCLR; 1907216Ssam if (cvec > 0 && cvec != 0x200) { 1917470Sfeldman if (cvec & 04) { /* collision interrupt */ 1927470Sfeldman cvec -= 04; 1937470Sfeldman br += 1; /* rcv is collision + 1 */ 1947470Sfeldman } else { /* xmit interrupt */ 1957470Sfeldman cvec -= 010; 1967470Sfeldman br += 2; /* rcv is xmit + 2 */ 1977470Sfeldman } 1987216Ssam } 1996520Sfeldman return (1); 2006520Sfeldman } 2016520Sfeldman 2026520Sfeldman /* 2036520Sfeldman * Interface exists: make available by filling in network interface 2046520Sfeldman * record. System will initialize the interface when it is ready 2056520Sfeldman * to accept packets. 2066520Sfeldman */ 2076520Sfeldman ecattach(ui) 2086520Sfeldman struct uba_device *ui; 2096520Sfeldman { 2107216Ssam struct ec_softc *es = &ec_softc[ui->ui_unit]; 2117216Ssam register struct ifnet *ifp = &es->es_if; 2126520Sfeldman register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 2137216Ssam int i, j; 2147216Ssam u_char *cp; 2156520Sfeldman 2167216Ssam ifp->if_unit = ui->ui_unit; 2177216Ssam ifp->if_name = "ec"; 2189745Ssam ifp->if_mtu = ETHERMTU; 2196520Sfeldman 2206520Sfeldman /* 2217216Ssam * Read the ethernet address off the board, one nibble at a time. 2226520Sfeldman */ 22324227Ssklower addr->ec_xcr = EC_UECLR; /* zero address pointer */ 2246520Sfeldman addr->ec_rcr = EC_AROM; 22519863Skarels cp = es->es_addr; 2267216Ssam #define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM 22716217Skarels for (i=0; i < sizeof (es->es_addr); i++) { 2286520Sfeldman *cp = 0; 2296520Sfeldman for (j=0; j<=4; j+=4) { 2306520Sfeldman *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 2317216Ssam NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 2326520Sfeldman } 2336520Sfeldman cp++; 2346520Sfeldman } 23525973Skarels printf("ec%d: hardware address %s\n", ui->ui_unit, 23625973Skarels ether_sprintf(es->es_addr)); 2377216Ssam ifp->if_init = ecinit; 23813055Ssam ifp->if_ioctl = ecioctl; 23937475Ssklower ifp->if_output = ether_output; 24037475Ssklower ifp->if_start = ecstart; 2418977Sroot ifp->if_reset = ecreset; 24237475Ssklower ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 2436520Sfeldman for (i=0; i<16; i++) 24416749Sbloom es->es_buf[i] 24517995Skarels = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i]; 2467216Ssam if_attach(ifp); 2476520Sfeldman } 2486520Sfeldman 2496520Sfeldman /* 2506520Sfeldman * Reset of interface after UNIBUS reset. 2516520Sfeldman * If interface is on specified uba, reset its state. 2526520Sfeldman */ 2536520Sfeldman ecreset(unit, uban) 2546520Sfeldman int unit, uban; 2556520Sfeldman { 2566520Sfeldman register struct uba_device *ui; 2576520Sfeldman 2586520Sfeldman if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || 2596520Sfeldman ui->ui_ubanum != uban) 2606520Sfeldman return; 2616520Sfeldman printf(" ec%d", unit); 26216207Skarels ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING; 2636520Sfeldman ecinit(unit); 2646520Sfeldman } 2656520Sfeldman 2666520Sfeldman /* 2676520Sfeldman * Initialization of interface; clear recorded pending 2686520Sfeldman * operations, and reinitialize UNIBUS usage. 2696520Sfeldman */ 2706520Sfeldman ecinit(unit) 2716520Sfeldman int unit; 2726520Sfeldman { 2737216Ssam struct ec_softc *es = &ec_softc[unit]; 2747216Ssam struct ecdevice *addr; 27511574Ssam register struct ifnet *ifp = &es->es_if; 27613055Ssam int i, s; 2776520Sfeldman 27819863Skarels /* not yet, if address still unknown */ 27919863Skarels if (ifp->if_addrlist == (struct ifaddr *)0) 28011574Ssam return; 28111574Ssam 2826520Sfeldman /* 2837217Sfeldman * Hang receive buffers and start any pending writes. 2846637Sfeldman * Writing into the rcr also makes sure the memory 2856637Sfeldman * is turned on. 2866520Sfeldman */ 28719863Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 28837475Ssklower u_short start_read; 28913055Ssam addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 29013055Ssam s = splimp(); 29124227Ssklower /* 29224227Ssklower * write our ethernet address into the address recognition ROM 29324227Ssklower * so we can always use the same EC_READ bits (referencing ROM), 29424227Ssklower * in case we change the address sometime. 29525445Skarels * Note that this is safe here as the receiver is NOT armed. 29624227Ssklower */ 29724227Ssklower ec_setaddr(es->es_addr, unit); 29824227Ssklower /* 29925445Skarels * Arm the receiver 30037475Ssklower #ifdef MULTI 30137475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 30237475Ssklower start_read = EC_PROMISC; 30337475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 30437475Ssklower start_read = EC_MULTI; 30537475Ssklower else 30637475Ssklower #endif MULTI 30737475Ssklower start_read = EC_READ; 30824227Ssklower */ 30913055Ssam for (i = ECRHBF; i >= ECRLBF; i--) 31013055Ssam addr->ec_rcr = EC_READ | i; 31137475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 31213055Ssam es->es_mask = ~0; 31319863Skarels es->es_if.if_flags |= IFF_RUNNING; 31413055Ssam if (es->es_if.if_snd.ifq_head) 31537475Ssklower (void) ecstart(&es->es_if); 31613055Ssam splx(s); 31713055Ssam } 3186520Sfeldman } 3196520Sfeldman 3206520Sfeldman /* 32125445Skarels * Start output on interface. Get another datagram to send 32225445Skarels * off of the interface queue, and copy it to the interface 3236520Sfeldman * before starting the output. 3246520Sfeldman */ 32537475Ssklower ecstart(ifp) 32637475Ssklower struct ifnet *ifp; 3276520Sfeldman { 32837475Ssklower int unit = ifp->if_unit; 32925445Skarels register struct ec_softc *es = &ec_softc[unit]; 3307216Ssam struct ecdevice *addr; 3316520Sfeldman struct mbuf *m; 3326520Sfeldman 33325445Skarels if ((es->es_if.if_flags & IFF_RUNNING) == 0) 33437475Ssklower return (0); 3356520Sfeldman IF_DEQUEUE(&es->es_if.if_snd, m); 33625445Skarels if (m == 0) 33737475Ssklower return (0); 3386520Sfeldman ecput(es->es_buf[ECTBF], m); 3397216Ssam addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 3406520Sfeldman addr->ec_xcr = EC_WRITE|ECTBF; 34137475Ssklower es->es_if.if_flags |= IFF_OACTIVE; 34237475Ssklower return (0); 3436520Sfeldman } 3446520Sfeldman 3456520Sfeldman /* 3466520Sfeldman * Ethernet interface transmitter interrupt. 3476520Sfeldman * Start another output if more data to send. 3486520Sfeldman */ 3496520Sfeldman ecxint(unit) 3506520Sfeldman int unit; 3516520Sfeldman { 3526520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 3537216Ssam register struct ecdevice *addr = 3547216Ssam (struct ecdevice *)ecinfo[unit]->ui_addr; 3556520Sfeldman 35637475Ssklower if ((es->es_if.if_flags & IFF_OACTIVE) == 0) 3576520Sfeldman return; 3587216Ssam if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) { 3597216Ssam printf("ec%d: stray xmit interrupt, xcr=%b\n", unit, 3607216Ssam addr->ec_xcr, EC_XBITS); 36137475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 3627216Ssam addr->ec_xcr = EC_XCLR; 3637216Ssam return; 3647216Ssam } 3656520Sfeldman es->es_if.if_opackets++; 36637475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 3676520Sfeldman es->es_mask = ~0; 3686520Sfeldman addr->ec_xcr = EC_XCLR; 3697216Ssam if (es->es_if.if_snd.ifq_head) 37037475Ssklower (void) ecstart(&es->es_if); 3716520Sfeldman } 3726520Sfeldman 3736520Sfeldman /* 3746520Sfeldman * Collision on ethernet interface. Do exponential 3756520Sfeldman * backoff, and retransmit. If have backed off all 3766520Sfeldman * the way print warning diagnostic, and drop packet. 3776520Sfeldman */ 3786520Sfeldman eccollide(unit) 3796520Sfeldman int unit; 3806520Sfeldman { 3816520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 3826545Sfeldman register struct ecdevice *addr = 3836545Sfeldman (struct ecdevice *)ecinfo[unit]->ui_addr; 3846545Sfeldman register i; 3856545Sfeldman int delay; 3866520Sfeldman 38725445Skarels es->es_if.if_collisions++; 38837475Ssklower if ((es->es_if.if_flags & IFF_OACTIVE) == 0) 38925445Skarels return; 39025445Skarels 3916520Sfeldman /* 3926520Sfeldman * Es_mask is a 16 bit number with n low zero bits, with 3936520Sfeldman * n the number of backoffs. When es_mask is 0 we have 3946520Sfeldman * backed off 16 times, and give up. 3956520Sfeldman */ 3966520Sfeldman if (es->es_mask == 0) { 39737475Ssklower u_short start_read; 3986545Sfeldman es->es_if.if_oerrors++; 39925445Skarels log(LOG_ERR, "ec%d: send error\n", unit); 4006520Sfeldman /* 4016545Sfeldman * Reset interface, then requeue rcv buffers. 4026545Sfeldman * Some incoming packets may be lost, but that 4036545Sfeldman * can't be helped. 4046520Sfeldman */ 4056545Sfeldman addr->ec_xcr = EC_UECLR; 40637475Ssklower #ifdef MULTI 40737475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 40837475Ssklower start_read = EC_PROMISC; 40937475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 41037475Ssklower start_read = EC_MULTI; 41137475Ssklower else 41237475Ssklower #endif MULTI 41337475Ssklower start_read = EC_READ; 4146545Sfeldman for (i=ECRHBF; i>=ECRLBF; i--) 41537475Ssklower addr->ec_rcr = start_read|i; 4166545Sfeldman /* 4176545Sfeldman * Reset and transmit next packet (if any). 4186545Sfeldman */ 41937475Ssklower es->es_if.if_flags &= ~IFF_OACTIVE; 4206545Sfeldman es->es_mask = ~0; 4216545Sfeldman if (es->es_if.if_snd.ifq_head) 42237475Ssklower (void) ecstart(&es->es_if); 4236520Sfeldman return; 4246520Sfeldman } 4256520Sfeldman /* 4266545Sfeldman * Do exponential backoff. Compute delay based on low bits 42725445Skarels * of the interval timer (1 bit for each transmission attempt, 42825445Skarels * but at most 5 bits). Then delay for that number of 4296545Sfeldman * slot times. A slot time is 51.2 microseconds (rounded to 51). 4306545Sfeldman * This does not take into account the time already used to 4316545Sfeldman * process the interrupt. 4326520Sfeldman */ 4336520Sfeldman es->es_mask <<= 1; 43425445Skarels delay = mfpr(ICR) & 0x1f &~ es->es_mask; 4356545Sfeldman DELAY(delay * 51); 4366520Sfeldman /* 4376545Sfeldman * Clear the controller's collision flag, thus enabling retransmit. 4386520Sfeldman */ 4397470Sfeldman addr->ec_xcr = EC_CLEAR; 4406520Sfeldman } 4416520Sfeldman 4426520Sfeldman /* 4436520Sfeldman * Ethernet interface receiver interrupt. 4446520Sfeldman * If input error just drop packet. 44524227Ssklower * Otherwise examine 4466520Sfeldman * packet to determine type. If can't determine length 4476520Sfeldman * from type, then have to drop packet. Othewise decapsulate 4486520Sfeldman * packet based on type and pass to type specific higher-level 4496520Sfeldman * input routine. 4506520Sfeldman */ 4516520Sfeldman ecrint(unit) 4526520Sfeldman int unit; 4536520Sfeldman { 4546520Sfeldman struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 4556520Sfeldman 4566520Sfeldman while (addr->ec_rcr & EC_RDONE) 4576520Sfeldman ecread(unit); 4586520Sfeldman } 4596520Sfeldman 4606520Sfeldman ecread(unit) 4616520Sfeldman int unit; 4626520Sfeldman { 4636520Sfeldman register struct ec_softc *es = &ec_softc[unit]; 4646520Sfeldman struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 4659745Ssam register struct ether_header *ec; 4666520Sfeldman struct mbuf *m; 4678773Sroot int len, off, resid, ecoff, rbuf; 4686520Sfeldman register struct ifqueue *inq; 46937475Ssklower u_short start_read; 4708773Sroot u_char *ecbuf; 4716520Sfeldman 4726520Sfeldman es->es_if.if_ipackets++; 4738773Sroot rbuf = addr->ec_rcr & EC_RBN; 4748773Sroot if (rbuf < ECRLBF || rbuf > ECRHBF) 4756520Sfeldman panic("ecrint"); 4768773Sroot ecbuf = es->es_buf[rbuf]; 4776520Sfeldman ecoff = *(short *)ecbuf; 4786545Sfeldman if (ecoff <= ECRDOFF || ecoff > 2046) { 4796520Sfeldman es->es_if.if_ierrors++; 4806520Sfeldman #ifdef notdef 4816520Sfeldman if (es->es_if.if_ierrors % 100 == 0) 4826520Sfeldman printf("ec%d: += 100 input errors\n", unit); 4836520Sfeldman #endif 4846520Sfeldman goto setup; 4856520Sfeldman } 4866520Sfeldman 4876520Sfeldman /* 4886520Sfeldman * Get input data length. 4896520Sfeldman * Get pointer to ethernet header (in input buffer). 49019863Skarels * Deal with trailer protocol: if type is trailer type 4916520Sfeldman * get true type from first 16-bit word past data. 4926520Sfeldman * Remember that type was trailer by setting off. 4936520Sfeldman */ 4949745Ssam len = ecoff - ECRDOFF - sizeof (struct ether_header); 4959745Ssam ec = (struct ether_header *)(ecbuf + ECRDOFF); 4969745Ssam ec->ether_type = ntohs((u_short)ec->ether_type); 4976520Sfeldman #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) 49819863Skarels if (ec->ether_type >= ETHERTYPE_TRAIL && 49919863Skarels ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 50019863Skarels off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; 5019745Ssam if (off >= ETHERMTU) 5026520Sfeldman goto setup; /* sanity */ 5039745Ssam ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); 5049745Ssam resid = ntohs(*(ecdataaddr(ec, off+2, u_short *))); 5056520Sfeldman if (off + resid > len) 5066520Sfeldman goto setup; /* sanity */ 5076520Sfeldman len = off + resid; 5086520Sfeldman } else 5096520Sfeldman off = 0; 5106520Sfeldman if (len == 0) 5116520Sfeldman goto setup; 5126520Sfeldman 5136520Sfeldman /* 5146520Sfeldman * Pull packet off interface. Off is nonzero if packet 5156520Sfeldman * has trailing header; ecget will then force this header 5166520Sfeldman * information to be at the front, but we still have to drop 5176520Sfeldman * the type and length which are at the front of any trailer data. 5186520Sfeldman */ 51924789Skarels m = ecget(ecbuf, len, off, &es->es_if); 52037475Ssklower if (m) 52137475Ssklower ether_input(&es->es_if, ec, m); 5226520Sfeldman /* 5236520Sfeldman * Reset for next packet. 5246520Sfeldman */ 52537475Ssklower setup: 52637475Ssklower #ifdef MULTI 52737475Ssklower if (es->es_if.if_flags & IFF_PROMISC) 52837475Ssklower start_read = EC_PROMISC; 52937475Ssklower else if (es->es_if.if_flags & IFF_MULTI) 53037475Ssklower start_read = EC_MULTI; 53137475Ssklower else 53237475Ssklower #endif MULTI 53337475Ssklower start_read = EC_READ; 53437475Ssklower addr->ec_rcr = start_read|EC_RCLR|rbuf; 5356520Sfeldman } 5366520Sfeldman 5376520Sfeldman /* 5389177Ssam * Routine to copy from mbuf chain to transmit 5397216Ssam * buffer in UNIBUS memory. 5409177Ssam * If packet size is less than the minimum legal size, 5419177Ssam * the buffer is expanded. We probably should zero out the extra 5429177Ssam * bytes for security, but that would slow things down. 5436520Sfeldman */ 5446520Sfeldman ecput(ecbuf, m) 5457216Ssam u_char *ecbuf; 5466520Sfeldman struct mbuf *m; 5476520Sfeldman { 5486520Sfeldman register struct mbuf *mp; 5497216Ssam register int off; 5507263Ssam u_char *bp; 5516520Sfeldman 5527216Ssam for (off = 2048, mp = m; mp; mp = mp->m_next) 5537216Ssam off -= mp->m_len; 5549745Ssam if (2048 - off < ETHERMIN + sizeof (struct ether_header)) 5559745Ssam off = 2048 - ETHERMIN - sizeof (struct ether_header); 5567216Ssam *(u_short *)ecbuf = off; 5577216Ssam bp = (u_char *)(ecbuf + off); 5587263Ssam for (mp = m; mp; mp = mp->m_next) { 5597263Ssam register unsigned len = mp->m_len; 5607263Ssam u_char *mcp; 5617216Ssam 5627216Ssam if (len == 0) 5637216Ssam continue; 5647216Ssam mcp = mtod(mp, u_char *); 5657216Ssam if ((unsigned)bp & 01) { 5667032Swnj *bp++ = *mcp++; 5677216Ssam len--; 5687032Swnj } 5697263Ssam if (off = (len >> 1)) { 5707263Ssam register u_short *to, *from; 5717263Ssam 5727263Ssam to = (u_short *)bp; 5737263Ssam from = (u_short *)mcp; 5747263Ssam do 5757263Ssam *to++ = *from++; 5767263Ssam while (--off > 0); 5777263Ssam bp = (u_char *)to, 5787263Ssam mcp = (u_char *)from; 5797032Swnj } 5807263Ssam if (len & 01) 5816520Sfeldman *bp++ = *mcp++; 5826520Sfeldman } 5837263Ssam m_freem(m); 5846520Sfeldman } 5856520Sfeldman 5866520Sfeldman /* 5876520Sfeldman * Routine to copy from UNIBUS memory into mbufs. 5886520Sfeldman * Similar in spirit to if_rubaget. 5897032Swnj * 5907032Swnj * Warning: This makes the fairly safe assumption that 5917032Swnj * mbufs have even lengths. 5926520Sfeldman */ 5936520Sfeldman struct mbuf * 59424789Skarels ecget(ecbuf, totlen, off0, ifp) 5957263Ssam u_char *ecbuf; 5966520Sfeldman int totlen, off0; 59724789Skarels struct ifnet *ifp; 5986520Sfeldman { 5997263Ssam register struct mbuf *m; 6007263Ssam struct mbuf *top = 0, **mp = ⊤ 6017263Ssam register int off = off0, len; 60237475Ssklower u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header)); 60337475Ssklower u_char *packet_end = cp + totlen; 6046520Sfeldman 60537475Ssklower if (off) { 60637475Ssklower off += 2 * sizeof(u_short); 60737475Ssklower totlen -= 2 *sizeof(u_short); 60837475Ssklower cp += off; 60937475Ssklower } 61037475Ssklower 61137475Ssklower MGETHDR(m, M_DONTWAIT, MT_DATA); 61237475Ssklower if (m == 0) 61337475Ssklower return (0); 61437475Ssklower m->m_pkthdr.rcvif = ifp; 61537475Ssklower m->m_pkthdr.len = totlen; 61637475Ssklower m->m_len = MHLEN; 61737475Ssklower 6186520Sfeldman while (totlen > 0) { 6197263Ssam register int words; 6207263Ssam u_char *mcp; 6217263Ssam 62237475Ssklower if (top) { 62337475Ssklower MGET(m, M_DONTWAIT, MT_DATA); 62437475Ssklower if (m == 0) { 62537475Ssklower m_freem(top); 62637475Ssklower return (0); 62737475Ssklower } 62837475Ssklower m->m_len = MLEN; 62937475Ssklower } 63037475Ssklower len = min(totlen, (packet_end - cp)); 63137475Ssklower if (len >= MINCLSIZE) { 63237475Ssklower MCLGET(m, M_DONTWAIT); 63337475Ssklower if (m->m_flags & M_EXT) 63437475Ssklower m->m_len = len = min(len, MCLBYTES); 63526230Skarels else 63637475Ssklower len = m->m_len; 6376520Sfeldman } else { 63824789Skarels /* 63937475Ssklower * Place initial small packet/header at end of mbuf. 64024789Skarels */ 64137475Ssklower if (len < m->m_len) { 64237475Ssklower if (top == 0 && len + max_linkhdr <= m->m_len) 64337475Ssklower m->m_data += max_linkhdr; 64437475Ssklower m->m_len = len; 64537475Ssklower } else 64637475Ssklower len = m->m_len; 64724789Skarels } 648*39690Ssklower mcp = mtod(m, u_char *); 6497263Ssam if (words = (len >> 1)) { 6507263Ssam register u_short *to, *from; 6517263Ssam 6527263Ssam to = (u_short *)mcp; 6537263Ssam from = (u_short *)cp; 6547263Ssam do 6557263Ssam *to++ = *from++; 6567263Ssam while (--words > 0); 6577263Ssam mcp = (u_char *)to; 6587263Ssam cp = (u_char *)from; 6597032Swnj } 6607216Ssam if (len & 01) 6616520Sfeldman *mcp++ = *cp++; 6626520Sfeldman *mp = m; 6636520Sfeldman mp = &m->m_next; 66437475Ssklower totlen -= len; 66537475Ssklower if (cp == packet_end) 66637475Ssklower cp = ecbuf; 6676520Sfeldman } 6686520Sfeldman return (top); 6696520Sfeldman bad: 6706520Sfeldman m_freem(top); 6716520Sfeldman return (0); 6726520Sfeldman } 67313055Ssam 67413055Ssam /* 67513055Ssam * Process an ioctl request. 67613055Ssam */ 67713055Ssam ecioctl(ifp, cmd, data) 67813055Ssam register struct ifnet *ifp; 67913055Ssam int cmd; 68013055Ssam caddr_t data; 68113055Ssam { 68219863Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 68325445Skarels struct ec_softc *es = &ec_softc[ifp->if_unit]; 68425445Skarels struct ecdevice *addr; 68513055Ssam int s = splimp(), error = 0; 68613055Ssam 68725445Skarels addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr); 68825445Skarels 68913055Ssam switch (cmd) { 69013055Ssam 69113055Ssam case SIOCSIFADDR: 69219863Skarels ifp->if_flags |= IFF_UP; 69319863Skarels 69437475Ssklower switch (ifa->ifa_addr->sa_family) { 69523558Ssklower #ifdef INET 69619863Skarels case AF_INET: 69725445Skarels ecinit(ifp->if_unit); /* before arpwhohas */ 69819863Skarels ((struct arpcom *)ifp)->ac_ipaddr = 69919863Skarels IA_SIN(ifa)->sin_addr; 70019863Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 70119863Skarels break; 70223558Ssklower #endif 70323558Ssklower #ifdef NS 70423558Ssklower case AF_NS: 70523558Ssklower { 70623558Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 70723558Ssklower 70825445Skarels if (ns_nullhost(*ina)) 70925445Skarels ina->x_host = *(union ns_host *)(es->es_addr); 71025445Skarels else { 71124227Ssklower /* 71224227Ssklower * The manual says we can't change the address 71325445Skarels * while the receiver is armed, 71425445Skarels * so reset everything 71524227Ssklower */ 71625445Skarels ifp->if_flags &= ~IFF_RUNNING; 71726390Skarels bcopy((caddr_t)ina->x_host.c_host, 71826390Skarels (caddr_t)es->es_addr, sizeof(es->es_addr)); 71923558Ssklower } 72024227Ssklower ecinit(ifp->if_unit); /* does ec_setaddr() */ 72123558Ssklower break; 72223558Ssklower } 72323558Ssklower #endif 72425445Skarels default: 72525445Skarels ecinit(ifp->if_unit); 72625445Skarels break; 72719863Skarels } 72813055Ssam break; 72913055Ssam 73025445Skarels case SIOCSIFFLAGS: 73125445Skarels if ((ifp->if_flags & IFF_UP) == 0 && 73225445Skarels ifp->if_flags & IFF_RUNNING) { 73325445Skarels addr->ec_xcr = EC_UECLR; 73425445Skarels ifp->if_flags &= ~IFF_RUNNING; 73525445Skarels } else if (ifp->if_flags & IFF_UP && 73625445Skarels (ifp->if_flags & IFF_RUNNING) == 0) 73725445Skarels ecinit(ifp->if_unit); 73825445Skarels break; 73925445Skarels 74013055Ssam default: 74113055Ssam error = EINVAL; 74213055Ssam } 74313055Ssam splx(s); 74413055Ssam return (error); 74513055Ssam } 74623558Ssklower 74723558Ssklower ec_setaddr(physaddr,unit) 74825445Skarels u_char *physaddr; 74925445Skarels int unit; 75023558Ssklower { 75123558Ssklower struct ec_softc *es = &ec_softc[unit]; 75223558Ssklower struct uba_device *ui = ecinfo[unit]; 75323558Ssklower register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 75423558Ssklower register char nibble; 75523558Ssklower register int i, j; 75624789Skarels 75723558Ssklower /* 75823558Ssklower * Use the ethernet address supplied 75925445Skarels * Note that we do a UECLR here, so the receive buffers 76024227Ssklower * must be requeued. 76123558Ssklower */ 76223558Ssklower 76324227Ssklower #ifdef DEBUG 76425973Skarels printf("ec_setaddr: setting address for unit %d = %s", 76525973Skarels unit, ether_sprintf(physaddr)); 76624227Ssklower #endif 76724227Ssklower addr->ec_xcr = EC_UECLR; 76823558Ssklower addr->ec_rcr = 0; 76924227Ssklower /* load requested address */ 77023558Ssklower for (i = 0; i < 6; i++) { /* 6 bytes of address */ 77123558Ssklower es->es_addr[i] = physaddr[i]; 77223558Ssklower nibble = physaddr[i] & 0xf; /* lower nibble */ 77323558Ssklower addr->ec_rcr = (nibble << 8); 77424227Ssklower addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 77523558Ssklower addr->ec_rcr = (nibble << 8); 77623558Ssklower for (j=0; j < 4; j++) { 77723558Ssklower addr->ec_rcr = 0; 77823558Ssklower addr->ec_rcr = EC_ASTEP; /* step counter */ 77923558Ssklower addr->ec_rcr = 0; 78023558Ssklower } 78123558Ssklower nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ 78223558Ssklower addr->ec_rcr = (nibble << 8); 78324227Ssklower addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 78423558Ssklower addr->ec_rcr = (nibble << 8); 78523558Ssklower for (j=0; j < 4; j++) { 78623558Ssklower addr->ec_rcr = 0; 78723558Ssklower addr->ec_rcr = EC_ASTEP; /* step counter */ 78823558Ssklower addr->ec_rcr = 0; 78923558Ssklower } 79023558Ssklower } 79124227Ssklower #ifdef DEBUG 79224227Ssklower /* 79324227Ssklower * Read the ethernet address off the board, one nibble at a time. 79424227Ssklower */ 79524227Ssklower addr->ec_xcr = EC_UECLR; 79624227Ssklower addr->ec_rcr = 0; /* read RAM */ 79724227Ssklower cp = es->es_addr; 79824227Ssklower #undef NEXTBIT 79924227Ssklower #define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 80024227Ssklower for (i=0; i < sizeof (es->es_addr); i++) { 80124227Ssklower *cp = 0; 80224227Ssklower for (j=0; j<=4; j+=4) { 80324227Ssklower *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 80424227Ssklower NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 80524227Ssklower } 80624227Ssklower cp++; 80724227Ssklower } 80825973Skarels printf("ec_setaddr: RAM address for unit %d = %s", 80925973Skarels unit, ether_sprintf(physaddr)); 81024227Ssklower #endif 81123558Ssklower } 81225271Sbloom #endif 813