123558Ssklower /*
229361Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
335318Sbostic * All rights reserved.
423558Ssklower *
544558Sbostic * %sccs.include.redist.c%
635318Sbostic *
7*45801Sbostic * @(#)if_ec.c 7.8 (Berkeley) 12/16/90
823558Ssklower */
96520Sfeldman
106520Sfeldman #include "ec.h"
1125271Sbloom #if NEC > 0
126520Sfeldman
136520Sfeldman /*
146520Sfeldman * 3Com Ethernet Controller interface
156520Sfeldman */
16*45801Sbostic #include "../include/pte.h"
176520Sfeldman
18*45801Sbostic #include "sys/param.h"
19*45801Sbostic #include "sys/systm.h"
20*45801Sbostic #include "sys/mbuf.h"
21*45801Sbostic #include "sys/buf.h"
22*45801Sbostic #include "sys/protosw.h"
23*45801Sbostic #include "sys/socket.h"
24*45801Sbostic #include "sys/syslog.h"
25*45801Sbostic #include "sys/vmmac.h"
26*45801Sbostic #include "sys/ioctl.h"
27*45801Sbostic #include "sys/errno.h"
288461Sroot
29*45801Sbostic #include "net/if.h"
30*45801Sbostic #include "net/netisr.h"
31*45801Sbostic #include "net/route.h"
3223558Ssklower
3323558Ssklower #ifdef INET
34*45801Sbostic #include "netinet/in.h"
35*45801Sbostic #include "netinet/in_systm.h"
36*45801Sbostic #include "netinet/in_var.h"
37*45801Sbostic #include "netinet/ip.h"
38*45801Sbostic #include "netinet/if_ether.h"
3923558Ssklower #endif
4023558Ssklower
4123558Ssklower #ifdef NS
42*45801Sbostic #include "netns/ns.h"
43*45801Sbostic #include "netns/ns_if.h"
4419951Sbloom #endif
456520Sfeldman
46*45801Sbostic #include "../include/cpu.h"
47*45801Sbostic #include "../include/mtpr.h"
4817112Sbloom #include "if_ecreg.h"
4917112Sbloom #include "if_uba.h"
50*45801Sbostic #include "../uba/ubareg.h"
51*45801Sbostic #include "../uba/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 */
ecubamem(ui,uban)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 */
ecprobe(reg,ui)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 */
ecreset(unit,uban)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 */
ecinit(unit)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 */
ecxint(unit)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 */
eccollide(unit)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 */
ecrint(unit)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
ecread(unit)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 */
ecput(ecbuf,m)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 *
ecget(ecbuf,totlen,off0,ifp)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 */
ecioctl(ifp,cmd,data)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
ec_setaddr(physaddr,unit)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