1*25927Ssam /* if_ace.c 1.4 86/01/20 */ 224007Ssam 324007Ssam /* 424007Ssam * ACC VERSAbus Ethernet controller 524007Ssam */ 624007Ssam #include "ace.h" 724007Ssam #if NACE > 0 824007Ssam 924007Ssam #include "../machine/pte.h" 1024007Ssam 1125694Ssam #include "param.h" 1225694Ssam #include "systm.h" 1325694Ssam #include "mbuf.h" 1425694Ssam #include "buf.h" 1525694Ssam #include "protosw.h" 1625694Ssam #include "socket.h" 1725694Ssam #include "vmmac.h" 1825694Ssam #include "ioctl.h" 1925694Ssam #include "errno.h" 2025694Ssam #include "vmparam.h" 2125855Ssam #include "syslog.h" 2224007Ssam 2324007Ssam #include "../net/if.h" 2424007Ssam #include "../net/netisr.h" 2524007Ssam #include "../net/route.h" 2625855Ssam #ifdef INET 2724007Ssam #include "../netinet/in.h" 2824007Ssam #include "../netinet/in_systm.h" 2925694Ssam #include "../netinet/in_var.h" 3024007Ssam #include "../netinet/ip.h" 3124007Ssam #include "../netinet/ip_var.h" 3224007Ssam #include "../netinet/if_ether.h" 3325855Ssam #endif 3425855Ssam #ifdef NS 3525855Ssam #include "../netns/ns.h" 3625855Ssam #include "../netns/ns_if.h" 3725855Ssam #endif 3824007Ssam 3924007Ssam #include "../tahoe/mtpr.h" 4024007Ssam #include "../tahoeif/if_acereg.h" 4125694Ssam #include "../tahoevba/vbavar.h" 4224007Ssam 4324007Ssam /* station address */ 4424007Ssam char ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 }; 4524007Ssam /* multicast hash table initializer */ 4624007Ssam char ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF }; 4724007Ssam /* backoff table masks */ 4824007Ssam short random_mask_tbl[16] = { 4924007Ssam 0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0, 5024007Ssam 0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0 5124007Ssam }; 5224007Ssam 5324007Ssam int aceprobe(), aceattach(), acerint(), acecint(); 5424007Ssam struct vba_device *aceinfo[NACE]; 5525855Ssam long acestd[] = { 0x0ff0000, 0xff0100, 0 }; 5624007Ssam struct vba_driver acedriver = 57*25927Ssam { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 }; 5824007Ssam 5924007Ssam int aceinit(), aceoutput(), aceioctl(), acereset(); 6024007Ssam struct mbuf *aceget(); 6124007Ssam 6224007Ssam /* 6324007Ssam * Ethernet software status per interface. 6424007Ssam * 6524007Ssam * Each interface is referenced by a network interface structure, 6624007Ssam * is_if, which the routing code uses to locate the interface. 6724007Ssam * This structure contains the output queue for the interface, its address, ... 6824007Ssam */ 6924007Ssam struct ace_softc { 7024007Ssam struct arpcom is_ac; /* Ethernet common part */ 7124007Ssam #define is_if is_ac.ac_if /* network-visible interface */ 7224007Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 7324007Ssam short is_flags; 7424007Ssam #define ACEF_OACTIVE 0x1 /* output is active */ 7524007Ssam #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 7624007Ssam short is_promiscuous; /* true is enabled */ 7724007Ssam short is_segboundry; /* first TX Seg in dpm */ 7824007Ssam short is_eictr; /* Rx segment tracking ctr */ 7924007Ssam short is_eoctr; /* Tx segment tracking ctr */ 8024007Ssam short is_txnext; /* Next available Tx segment */ 8124007Ssam short is_currnd; /* current random backoff */ 8224007Ssam struct ace_stats is_stats; /* holds board statistics */ 8324007Ssam short is_xcnt; /* count xmitted segments to be acked 8424007Ssam by the controller */ 8525855Ssam long is_ivec; /* autoconfig interrupt vector base */ 86*25927Ssam struct pte *is_map; /* pte map for dual ported memory */ 87*25927Ssam caddr_t is_dpm; /* address of mapped memory */ 8824007Ssam } ace_softc[NACE]; 8924007Ssam extern struct ifnet loif; 9024007Ssam 9125855Ssam aceprobe(reg, vi) 9224007Ssam caddr_t reg; 9325855Ssam struct vba_device *vi; 9424007Ssam { 9525855Ssam register br, cvec; /* must be r12, r11 */ 9625855Ssam struct acedevice *ap = (struct acedevice *)reg; 9725855Ssam struct ace_softc *is = &ace_softc[vi->ui_unit]; 9824007Ssam 9924007Ssam #ifdef lint 10024007Ssam acerint(0); acecint(0); 10124007Ssam #endif 10224007Ssam if (badaddr(reg, 2)) 10325855Ssam return (0); 10425855Ssam movow(&ap->csr, CSR_RESET); 10524007Ssam DELAY(10000); 10625855Ssam #ifdef notdef 10725855Ssam /* 10825855Ssam * Select two spaces for the interrupts aligned to an 10925855Ssam * eight vector boundary and fitting in 8 bits (as 11025855Ssam * required by the controller) -- YECH. The controller 11125855Ssam * will be notified later at initialization time. 11225855Ssam */ 11325855Ssam if ((vi->ui_hd->vh_lastiv -= 2) > 0xff) 11425855Ssam vi->ui_hd->vh_lastiv = 0x200; 11525855Ssam is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7; 11625855Ssam #else 11725855Ssam is->is_ivec = 0x90+vi->ui_unit*8; 11825855Ssam #endif 11925855Ssam br = 0x14, cvec = is->is_ivec; /* XXX */ 12025855Ssam return (sizeof (*ap)); 12124007Ssam } 12224007Ssam 12324007Ssam /* 12424007Ssam * Interface exists: make available by filling in network interface 12524007Ssam * record. System will initialize the interface when it is ready 12624007Ssam * to accept packets. 12724007Ssam */ 12824007Ssam aceattach(ui) 12924007Ssam struct vba_device *ui; 13024007Ssam { 13124007Ssam register short unit = ui->ui_unit; 13224007Ssam register struct ace_softc *is = &ace_softc[unit]; 13324007Ssam register struct ifnet *ifp = &is->is_if; 13424007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 13524007Ssam register short *wp, i; 13624007Ssam 13724007Ssam ifp->if_unit = unit; 13824007Ssam ifp->if_name = "ace"; 13924007Ssam ifp->if_mtu = ETHERMTU; 14024007Ssam /* 141*25927Ssam * Set station's addresses and multicast hash table. 14224007Ssam */ 14324007Ssam ace_station[5] = ~(unit + 1); 14424007Ssam acesetetaddr(unit, addr, ace_station); 14524007Ssam is->is_promiscuous = 0; 14624007Ssam wp = (short *)addr->hash; 14724007Ssam for (i = 0; i < 8; i++) 14825694Ssam movow(wp++, ace_hash[i]); 14925694Ssam movow(&addr->bcastena[0], ~0xffff); 15025694Ssam movow(&addr->bcastena[1], ~0xffff); 151*25927Ssam /* 152*25927Ssam * Allocate and map dual ported VERSAbus memory. 153*25927Ssam */ 154*25927Ssam vbmemalloc(32, (caddr_t)ui->ui_flags, &is->is_map, &is->is_dpm); 155*25927Ssam 15624007Ssam ifp->if_init = aceinit; 15724007Ssam ifp->if_output = aceoutput; 15824007Ssam ifp->if_ioctl = aceioctl; 15924007Ssam ifp->if_reset = acereset; 16025694Ssam ifp->if_flags = IFF_BROADCAST; 16124007Ssam if_attach(ifp); 16224007Ssam } 16324007Ssam 16424007Ssam acesetetaddr(unit, addr, station_addr) 16524007Ssam short unit; 16624007Ssam struct acedevice *addr; 16724007Ssam char *station_addr; 16824007Ssam { 16924007Ssam register short *wp, i; 17024007Ssam register char *cp; 17124007Ssam struct ace_softc *is = &ace_softc[unit]; 17224007Ssam 17324007Ssam wp = (short *)addr->station; 17424007Ssam cp = station_addr; 17524007Ssam for (i = 0; i < 6; i++) 17625694Ssam movow(wp++, *cp++); 17724007Ssam wp = (short *)addr->station; 17825694Ssam cp = (char *)is->is_addr; 17924007Ssam for (i = 0; i < 6; i++) 18024007Ssam *cp++ = ~(*wp++); 18124007Ssam } 18224007Ssam 18324007Ssam /* 18424007Ssam * Reset of interface after "system" reset. 18524007Ssam */ 18624007Ssam acereset(unit, vban) 18724007Ssam int unit, vban; 18824007Ssam { 18924007Ssam register struct vba_device *ui; 19024007Ssam 19124007Ssam if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 19224007Ssam ui->ui_vbanum != vban) 19324007Ssam return; 19424007Ssam printf(" ace%d", unit); 19524007Ssam aceinit(unit); 19624007Ssam } 19724007Ssam 19824007Ssam /* 19924007Ssam * Initialization of interface; clear recorded pending operations 20024007Ssam */ 20124007Ssam aceinit(unit) 20224007Ssam int unit; 20324007Ssam { 20424007Ssam register struct ace_softc *is = &ace_softc[unit]; 20524007Ssam register struct vba_device *ui = aceinfo[unit]; 20624007Ssam register struct acedevice *addr; 20724007Ssam register struct ifnet *ifp = &is->is_if; 20824007Ssam register short Csr; 20925694Ssam register int s; 21024007Ssam 21125694Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 21224007Ssam return; 21324007Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 21424007Ssam /* 21524007Ssam * Reset the controller, initialize the recieve buffers, 21624007Ssam * and turn the controller on again and set board online. 21724007Ssam */ 21824007Ssam addr = (struct acedevice *)ui->ui_addr; 21924007Ssam s = splimp(); 22025694Ssam movow(&addr->csr, CSR_RESET); 22124007Ssam DELAY(10000); 22224007Ssam 22324007Ssam /* 224*25927Ssam * Clean up dpm since the controller might 225*25927Ssam * jumble dpm after reset. 22624007Ssam */ 227*25927Ssam acesetup(unit); 22825694Ssam movow(&addr->csr, CSR_GO); 22924007Ssam Csr = addr->csr; 23024007Ssam if (Csr & CSR_ACTIVE) { 23125855Ssam movow(&addr->ivct, is->is_ivec); 23224007Ssam Csr |= CSR_IENA | is->is_promiscuous; 23325694Ssam movow(&addr->csr, Csr); 23424007Ssam is->is_flags = 0; 23524007Ssam is->is_xcnt = 0; 23625694Ssam is->is_if.if_flags |= IFF_RUNNING; 23724007Ssam } 23824007Ssam splx(s); 23924007Ssam } 24025694Ssam if (is->is_if.if_snd.ifq_head) 241*25927Ssam acestart(unit); 24224007Ssam } 24324007Ssam 24424007Ssam /* 24524007Ssam * Start output on interface. 24624007Ssam * Get another datagram to send off of the interface queue, 24724007Ssam * and map it to the interface before starting the output. 24824007Ssam * 24924007Ssam */ 250*25927Ssam acestart(unit) 251*25927Ssam int unit; 25224007Ssam { 25324007Ssam register struct tx_segment *txs; 25425694Ssam register long len; 25525694Ssam register int s; 25624007Ssam register struct ace_softc *is = &ace_softc[unit]; 25724007Ssam struct mbuf *m; 25825694Ssam short retries; 25924007Ssam 260*25927Ssam if (is->is_flags & ACEF_OACTIVE) 261*25927Ssam return; 262*25927Ssam is->is_flags |= ACEF_OACTIVE; 26324007Ssam again: 26424007Ssam txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 26524007Ssam if (txs->tx_csr & TCS_TBFULL) { 26624007Ssam is->is_stats.tx_busy++; 267*25927Ssam is->is_flags &= ~ACEF_OACTIVE; 26824007Ssam return; 26924007Ssam } 27025694Ssam s = splimp(); 27124007Ssam IF_DEQUEUE(&is->is_if.if_snd, m); 27225694Ssam splx(s); 273*25927Ssam if (m == 0) { 274*25927Ssam is->is_flags &= ~ACEF_OACTIVE; 27524007Ssam return; 276*25927Ssam } 27724007Ssam len = aceput(unit, txs->tx_data, m); 27824007Ssam retries = txs->tx_csr & TCS_RTC; 27924007Ssam if (retries > 0) 28024007Ssam acebakoff(is, txs, retries); 28124007Ssam 28224007Ssam /* 28324007Ssam * Ensure minimum packet length. 28424007Ssam * This makes the safe assumtion that there are no virtual holes 28524007Ssam * after the data. 28624007Ssam * For security, it might be wise to zero out the added bytes, 28724007Ssam * but we're mainly interested in speed at the moment. 28824007Ssam */ 28924007Ssam #ifdef notdef 29024007Ssam if (len - sizeof (struct ether_header) < ETHERMIN) 29124007Ssam len = ETHERMIN + sizeof (struct ether_header); 29224007Ssam #else 29324007Ssam if (len - 14 < ETHERMIN) 29424007Ssam len = ETHERMIN + 14; 29524007Ssam #endif 29624007Ssam if (++is->is_txnext > SEG_MAX) 29724007Ssam is->is_txnext = is->is_segboundry; 29824007Ssam is->is_if.if_opackets++; 29924007Ssam is->is_xcnt++; 30024007Ssam len = (len & 0x7fff) | TCS_TBFULL; 30125694Ssam movow(txs, len); 30224007Ssam goto again; 30324007Ssam } 30424007Ssam 30524007Ssam /* 30624007Ssam * Transmit done interrupt. 30724007Ssam */ 30824007Ssam acecint(unit) 30924007Ssam int unit; 31024007Ssam { 31124007Ssam register struct ace_softc *is = &ace_softc[unit]; 31224007Ssam register struct tx_segment *txseg; 31325694Ssam short eostat; 31424007Ssam 31524007Ssam if (is->is_xcnt <= 0) { 31625855Ssam log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n", 31724007Ssam unit, is->is_xcnt); 31824007Ssam is->is_xcnt = 0; 31925694Ssam if (is->is_if.if_snd.ifq_head) 320*25927Ssam acestart(unit); 32124007Ssam return; 32224007Ssam } 32324007Ssam is->is_xcnt--; 32424007Ssam txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 32524007Ssam eostat = txseg->tx_csr; 32624007Ssam if ((eostat & TCS_TBFULL) == 0) { 32724007Ssam is->is_stats.tx_retries += eostat & TCS_RTC; 32824007Ssam if (eostat & TCS_RTFAIL) { 32924007Ssam is->is_stats.tx_discarded++; 33024007Ssam is->is_if.if_oerrors++; 33124007Ssam } else 33224007Ssam is->is_stats.tx_datagrams++; 33324007Ssam if (++is->is_eoctr >= 16) 33424007Ssam is->is_eoctr = is->is_segboundry; 33524007Ssam } 33625694Ssam if (is->is_if.if_snd.ifq_head) 337*25927Ssam acestart(unit); 33824007Ssam } 33924007Ssam 34024007Ssam /* 34124007Ssam * Ethernet interface receiver interrupt. 34224007Ssam * If input error just drop packet. 34324007Ssam * Otherwise purge input buffered data path and examine 34424007Ssam * packet to determine type. If can't determine length 34524007Ssam * from type, then have to drop packet. Othewise decapsulate 34624007Ssam * packet based on type and pass to type specific higher-level 34724007Ssam * input routine. 34824007Ssam */ 34924007Ssam acerint(unit) 35024007Ssam int unit; 35124007Ssam { 35224007Ssam register struct ace_softc *is = &ace_softc[unit]; 35324007Ssam register struct ifqueue *inq; 35424007Ssam register struct ether_header *ace; 35524007Ssam register struct rx_segment *rxseg; 35624007Ssam int len, s, off, resid; 35724007Ssam struct mbuf *m; 35824007Ssam short eistat; 35924007Ssam 36025694Ssam if ((is->is_if.if_flags&IFF_RUNNING) == 0) 36125694Ssam return; 36224007Ssam again: 36324007Ssam rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 36424007Ssam eistat = rxseg->rx_csr; 36524007Ssam if ((eistat & RCS_RBFULL) == 0) 36624007Ssam return; 36724007Ssam is->is_if.if_ipackets++; 36824007Ssam if (++is->is_eictr >= is->is_segboundry) 36924007Ssam is->is_eictr = 0; 37024007Ssam len = eistat & RCS_RBC; 37124007Ssam if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 37224007Ssam len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 37324007Ssam if (eistat & RCS_ROVRN) 37424007Ssam is->is_stats.rx_overruns++; 37524007Ssam if (eistat & RCS_RCRC) 37624007Ssam is->is_stats.rx_crc_errors++; 37724007Ssam if (eistat & RCS_RODD) 37824007Ssam is->is_stats.rx_align_errors++; 37924007Ssam if (len < ET_MINLEN) 38024007Ssam is->is_stats.rx_underruns++; 38124007Ssam if (len > ET_MAXLEN+CRC_SIZE) 38224007Ssam is->is_stats.rx_overruns++; 38324007Ssam is->is_if.if_ierrors++; 38424007Ssam rxseg->rx_csr = 0; 38524007Ssam return; 38624007Ssam } else 38724007Ssam is->is_stats.rx_datagrams++; 38824007Ssam ace = (struct ether_header *)rxseg->rx_data; 38924007Ssam #ifdef notdef 39024007Ssam len -= sizeof (struct ether_header); 39124007Ssam #else 39224007Ssam len -= 14; 39324007Ssam #endif 39424007Ssam /* 39525694Ssam * Deal with trailer protocol: if type is trailer 39624007Ssam * get true type from first 16-bit word past data. 39724007Ssam * Remember that type was trailer by setting off. 39824007Ssam */ 39924007Ssam ace->ether_type = ntohs((u_short)ace->ether_type); 40024007Ssam #ifdef notdef 40124007Ssam #define acedataaddr(ace, off, type) \ 40224007Ssam ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 40324007Ssam #else 40424007Ssam #define acedataaddr(ace, off, type) \ 40524007Ssam ((type)(((caddr_t)(((char *)ace)+14)+(off)))) 40624007Ssam #endif 40725694Ssam if (ace->ether_type >= ETHERTYPE_TRAIL && 40825694Ssam ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 40925694Ssam off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; 41024007Ssam if (off >= ETHERMTU) 41124007Ssam goto setup; /* sanity */ 41224007Ssam ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 41324007Ssam resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 41424007Ssam if (off + resid > len) 41524007Ssam goto setup; /* sanity */ 41624007Ssam len = off + resid; 41724007Ssam } else 41824007Ssam off = 0; 41924007Ssam if (len == 0) 42024007Ssam goto setup; 42124007Ssam 42224007Ssam /* 42324007Ssam * Pull packet off interface. Off is nonzero if packet 42424007Ssam * has trailing header; aceget will then force this header 42524007Ssam * information to be at the front, but we still have to drop 42624007Ssam * the type and length which are at the front of any trailer data. 42724007Ssam */ 42825855Ssam m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if); 42924007Ssam if (m == 0) 43024007Ssam goto setup; 43124007Ssam if (off) { 43225855Ssam struct ifnet *ifp; 43325855Ssam 43425855Ssam ifp = *(mtod(m, struct ifnet **)); 43524007Ssam m->m_off += 2 * sizeof (u_short); 43624007Ssam m->m_len -= 2 * sizeof (u_short); 43725855Ssam *(mtod(m, struct ifnet **)) = ifp; 43824007Ssam } 43924007Ssam switch (ace->ether_type) { 44024007Ssam 44124007Ssam #ifdef INET 44225694Ssam case ETHERTYPE_IP: 44324007Ssam schednetisr(NETISR_IP); 44424007Ssam inq = &ipintrq; 44524007Ssam break; 44625855Ssam #endif 44724007Ssam 44825694Ssam case ETHERTYPE_ARP: 44924007Ssam arpinput(&is->is_ac, m); 45024007Ssam goto setup; 45125694Ssam #ifdef NS 45225694Ssam case ETHERTYPE_NS: 45325694Ssam schednetisr(NETISR_NS); 45425694Ssam inq = &nsintrq; 45525694Ssam break; 45625694Ssam 45725694Ssam #endif 45824007Ssam default: 45924007Ssam m_freem(m); 46024007Ssam goto setup; 46124007Ssam } 46224007Ssam if (IF_QFULL(inq)) { 46324007Ssam IF_DROP(inq); 46424007Ssam m_freem(m); 46524007Ssam goto setup; 46624007Ssam } 46724007Ssam s = splimp(); 46824007Ssam IF_ENQUEUE(inq, m); 46924007Ssam splx(s); 47024007Ssam setup: 47124007Ssam rxseg->rx_csr = 0; 47224007Ssam goto again; 47324007Ssam } 47424007Ssam 47524007Ssam /* 47624007Ssam * Ethernet output routine. 47724007Ssam * Encapsulate a packet of type family for the local net. 47824007Ssam * Use trailer local net encapsulation if enough data in first 47924007Ssam * packet leaves a multiple of 512 bytes of data in remainder. 48024007Ssam */ 48124007Ssam aceoutput(ifp, m0, dst) 48224007Ssam struct ifnet *ifp; 48324007Ssam struct mbuf *m0; 48424007Ssam struct sockaddr *dst; 48524007Ssam { 48624007Ssam register struct ace_softc *is = &ace_softc[ifp->if_unit]; 48724007Ssam register struct mbuf *m = m0; 48824007Ssam register struct ether_header *ace; 48924007Ssam register int off; 49024007Ssam struct mbuf *mcopy = (struct mbuf *)0; 49124007Ssam int type, s, error; 49225694Ssam u_char edst[6]; 49324007Ssam struct in_addr idst; 49424007Ssam 49525855Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 49625855Ssam error = ENETDOWN; 49725855Ssam goto bad; 49825855Ssam } 49924007Ssam switch (dst->sa_family) { 50024007Ssam 50124007Ssam #ifdef INET 50224007Ssam case AF_INET: 50324007Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 50425694Ssam if (!arpresolve(&is->is_ac, m, &idst, edst)) 50524007Ssam return (0); /* if not yet resolved */ 50625694Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 50725694Ssam sizeof(edst))) 50824007Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 50924007Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 51024007Ssam /* need per host negotiation */ 51124007Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 && 51224007Ssam (off & 0x1ff) == 0 && 51324007Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 51425694Ssam type = ETHERTYPE_TRAIL + (off>>9); 51524007Ssam m->m_off -= 2 * sizeof (u_short); 51624007Ssam m->m_len += 2 * sizeof (u_short); 51725694Ssam *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 51824007Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 51924007Ssam goto gottrailertype; 52024007Ssam } 52125694Ssam type = ETHERTYPE_IP; 52224007Ssam off = 0; 52324007Ssam goto gottype; 52424007Ssam #endif 52525694Ssam #ifdef NS 52625694Ssam case AF_NS: 52725694Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 52825694Ssam (caddr_t)edst, sizeof (edst)); 52925694Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst))) 53025694Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 53125694Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 53225694Ssam sizeof(edst))) 53325694Ssam return(looutput(&loif, m, dst)); 53425694Ssam type = ETHERTYPE_NS; 53525694Ssam off = 0; 53625694Ssam goto gottype; 53725694Ssam #endif 53824007Ssam case AF_UNSPEC: 53924007Ssam ace = (struct ether_header *)dst->sa_data; 54025694Ssam bcopy((caddr_t)ace->ether_dhost, (caddr_t)edst, sizeof (edst)); 54124007Ssam type = ace->ether_type; 54224007Ssam goto gottype; 54324007Ssam 54424007Ssam default: 54525855Ssam log(LOG_ERR, "ace%d: can't handle af%d\n", 54624007Ssam ifp->if_unit, dst->sa_family); 54724007Ssam error = EAFNOSUPPORT; 54824007Ssam goto bad; 54924007Ssam } 55024007Ssam 55124007Ssam gottrailertype: 55224007Ssam /* 55324007Ssam * Packet to be sent as trailer: move first packet 55424007Ssam * (control information) to end of chain. 55524007Ssam */ 55624007Ssam while (m->m_next) 55724007Ssam m = m->m_next; 55824007Ssam m->m_next = m0; 55924007Ssam m = m0->m_next; 56024007Ssam m0->m_next = 0; 56124007Ssam m0 = m; 56224007Ssam 56324007Ssam gottype: 56424007Ssam /* 56524007Ssam * Add local net header. If no space in first mbuf, 56624007Ssam * allocate another. 56724007Ssam */ 56824007Ssam if (m->m_off > MMAXOFF || 56924007Ssam #ifdef notdef 57024007Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 57124007Ssam #else 57224007Ssam MMINOFF + 14 > m->m_off) { 57324007Ssam #endif 57424007Ssam m = m_get(M_DONTWAIT, MT_HEADER); 57524007Ssam if (m == 0) { 57624007Ssam error = ENOBUFS; 57724007Ssam goto bad; 57824007Ssam } 57924007Ssam m->m_next = m0; 58024007Ssam m->m_off = MMINOFF; 58124007Ssam #ifdef notdef 58224007Ssam m->m_len = sizeof (struct ether_header); 58324007Ssam #else 58424007Ssam m->m_len = 14; 58524007Ssam #endif 58624007Ssam } else { 58724007Ssam #ifdef notdef 58824007Ssam m->m_off -= sizeof (struct ether_header); 58924007Ssam m->m_len += sizeof (struct ether_header); 59024007Ssam #else 59124007Ssam m->m_off -= 14; 59224007Ssam m->m_len += 14; 59324007Ssam #endif 59424007Ssam } 59524007Ssam ace = mtod(m, struct ether_header *); 59625694Ssam bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst)); 59725694Ssam bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost, 59825694Ssam sizeof (is->is_addr)); 59924007Ssam ace->ether_type = htons((u_short)type); 60024007Ssam 60124007Ssam /* 60224007Ssam * Queue message on interface, and start output if interface 60324007Ssam * not yet active. 60424007Ssam */ 60524007Ssam s = splimp(); 60624007Ssam if (IF_QFULL(&ifp->if_snd)) { 60724007Ssam IF_DROP(&ifp->if_snd); 60824007Ssam error = ENOBUFS; 60924007Ssam goto qfull; 61024007Ssam } 61124007Ssam IF_ENQUEUE(&ifp->if_snd, m); 61224007Ssam splx(s); 613*25927Ssam acestart(ifp->if_unit); 61424007Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 61524007Ssam qfull: 61624007Ssam m0 = m; 61724007Ssam splx(s); 61824007Ssam bad: 61924007Ssam m_freem(m0); 62024007Ssam if (mcopy) 62124007Ssam m_freem(mcopy); 62224007Ssam return (error); 62324007Ssam } 62424007Ssam 62524007Ssam /* 62624007Ssam * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 62724007Ssam * If packet size is less than the minimum legal size, 62824007Ssam * the buffer is expanded. We probably should zero out the extra 62924007Ssam * bytes for security, but that would slow things down. 63024007Ssam */ 63125694Ssam /*ARGSUSED*/ 63224007Ssam aceput(unit, txbuf, m) 63325855Ssam int unit; 63425694Ssam char *txbuf; 63524007Ssam struct mbuf *m; 63624007Ssam { 63725855Ssam register u_char *bp, *mcp; 63825855Ssam register short *s1, *s2; 63925694Ssam register u_int len; 64024007Ssam register struct mbuf *mp; 64125694Ssam int total; 64224007Ssam 64324007Ssam total = 0; 64425694Ssam bp = (u_char *)txbuf; 64525694Ssam for (mp = m; (mp); mp = mp->m_next) { 64624007Ssam len = mp->m_len; 64724007Ssam if (len == 0) 64824007Ssam continue; 64924007Ssam total += len; 65024007Ssam mcp = mtod(mp, u_char *); 65124007Ssam if (((int)mcp & 01) && ((int)bp & 01)) { 65224007Ssam /* source & destination at odd addresses */ 65325694Ssam movob(bp++, *mcp++); 65424007Ssam --len; 65524007Ssam } 65624007Ssam if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 65725694Ssam register u_int l; 65824007Ssam 65924007Ssam s1 = (short *)bp; 66024007Ssam s2 = (short *)mcp; 66124007Ssam l = len >> 1; /* count # of shorts */ 66225694Ssam while (l-- != 0) 66325694Ssam movow(s1++, *s2++); 66424007Ssam len &= 1; /* # remaining bytes */ 66524007Ssam bp = (u_char *)s1; 66624007Ssam mcp = (u_char *)s2; 66724007Ssam } 66825694Ssam while (len-- != 0) 66925694Ssam movob(bp++, *mcp++); 67024007Ssam } 67124007Ssam m_freem(m); 67224007Ssam return (total); 67324007Ssam } 67424007Ssam 67524007Ssam /* 67624007Ssam * Routine to copy from VERSAbus memory into mbufs. 67724007Ssam * 67824007Ssam * Warning: This makes the fairly safe assumption that 67924007Ssam * mbufs have even lengths. 68024007Ssam */ 68125694Ssam /*ARGSUSED*/ 68224007Ssam struct mbuf * 68325855Ssam aceget(rxbuf, totlen, off0, ifp) 68424007Ssam u_char *rxbuf; 68524007Ssam int totlen, off0; 68625855Ssam struct ifnet *ifp; 68724007Ssam { 68825855Ssam register u_char *cp, *mcp; 68924007Ssam register int tlen; 69024007Ssam register struct mbuf *m; 69124007Ssam struct mbuf *top = 0, **mp = ⊤ 69224007Ssam int len, off = off0; 69324007Ssam 69424007Ssam #ifdef notdef 69524007Ssam cp = rxbuf + sizeof (struct ether_header); 69624007Ssam #else 69724007Ssam cp = rxbuf + 14; 69824007Ssam #endif 69924007Ssam while (totlen > 0) { 70024007Ssam MGET(m, M_DONTWAIT, MT_DATA); 70124007Ssam if (m == 0) 70224007Ssam goto bad; 70324007Ssam if (off) { 70424007Ssam len = totlen - off; 70524007Ssam #ifdef notdef 70624007Ssam cp = rxbuf + sizeof (struct ether_header) + off; 70724007Ssam #else 70824007Ssam cp = rxbuf + 14 + off; 70924007Ssam #endif 71024007Ssam } else 71124007Ssam len = totlen; 71225855Ssam if (ifp) 71325855Ssam len += sizeof(ifp); 71424007Ssam if (len >= CLBYTES) { 71524007Ssam struct mbuf *p; 71624007Ssam 71724007Ssam MCLGET(p, 1); 71824007Ssam if (p != 0) { 71924007Ssam m->m_len = len = CLBYTES; 72024007Ssam m->m_off = (int)p - (int)m; 72124007Ssam } else { 72224007Ssam m->m_len = len = MIN(MLEN, len); 72324007Ssam m->m_off = MMINOFF; 72424007Ssam } 72524007Ssam } else { 72624007Ssam m->m_len = len = MIN(MLEN, len); 72724007Ssam m->m_off = MMINOFF; 72824007Ssam } 72924007Ssam mcp = mtod(m, u_char *); 73025855Ssam if (ifp) { 73125855Ssam /* 73225855Ssam * Prepend interface pointer to first mbuf. 73325855Ssam */ 73425855Ssam *(mtod(m, struct ifnet **)) = ifp; 73525855Ssam mcp += sizeof(ifp); 73625855Ssam len -= sizeof(ifp); 73725855Ssam ifp = (struct ifnet *)0; 73825855Ssam } 73924007Ssam /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 74024007Ssam /*cp += len; mcp += len;*/ 74124007Ssam tlen = len; 74224007Ssam if (((int)mcp & 01) && ((int)cp & 01)) { 74324007Ssam /* source & destination at odd addresses */ 74424007Ssam *mcp++ = *cp++; 74524007Ssam --tlen; 74624007Ssam } 74724007Ssam if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 74824007Ssam register short *s1, *s2; 74924007Ssam register int l; 75024007Ssam 75124007Ssam s1 = (short *)mcp; 75224007Ssam s2 = (short *)cp; 75324007Ssam l = tlen >> 1; /* count # of shorts */ 75424007Ssam while (l-- > 0) /* copy shorts */ 75524007Ssam *s1++ = *s2++; 75624007Ssam tlen &= 1; /* # remaining bytes */ 75724007Ssam mcp = (u_char *)s1; 75824007Ssam cp = (u_char *)s2; 75924007Ssam } 76024007Ssam while (tlen-- > 0) 76124007Ssam *mcp++ = *cp++; 76224007Ssam *mp = m; 76324007Ssam mp = &m->m_next; 76424007Ssam if (off == 0) { 76524007Ssam totlen -= len; 76624007Ssam continue; 76724007Ssam } 76824007Ssam off += len; 76924007Ssam if (off == totlen) { 77024007Ssam #ifdef notdef 77124007Ssam cp = rxbuf + sizeof (struct ether_header); 77224007Ssam #else 77324007Ssam cp = rxbuf + 14; 77424007Ssam #endif 77524007Ssam off = 0; 77624007Ssam totlen = off0; 77724007Ssam } 77824007Ssam } 77924007Ssam return (top); 78024007Ssam bad: 78124007Ssam m_freem(top); 78224007Ssam return (0); 78324007Ssam } 78424007Ssam 78524007Ssam acebakoff(is, txseg, retries) 78624007Ssam struct ace_softc *is; 78724007Ssam struct tx_segment *txseg; 78824007Ssam register int retries; 78924007Ssam { 79024007Ssam register short *pBakNum, random_num; 79124007Ssam short *pMask; 79224007Ssam 79324007Ssam pMask = &random_mask_tbl[0]; 79424007Ssam pBakNum = &txseg->tx_backoff[0]; 79524007Ssam while (--retries >= 0) { 79624007Ssam random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 79724007Ssam random_num &= *pMask++; 79824007Ssam *pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC); 79924007Ssam } 80024007Ssam } 80124007Ssam 80224007Ssam /* 80324007Ssam * Process an ioctl request. 80424007Ssam */ 80524007Ssam aceioctl(ifp, cmd, data) 80624007Ssam register struct ifnet *ifp; 80724007Ssam int cmd; 80824007Ssam caddr_t data; 80924007Ssam { 81025694Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 81125855Ssam struct acedevice *addr; 81225694Ssam int s = splimp(), error = 0; 81324007Ssam 81424007Ssam switch (cmd) { 81524007Ssam 81624007Ssam case SIOCSIFADDR: 81725694Ssam ifp->if_flags |= IFF_UP; 81825855Ssam switch (ifa->ifa_addr.sa_family) { 81925855Ssam #ifdef INET 82025855Ssam case AF_INET: 82125855Ssam aceinit(ifp->if_unit); /* before arpwhohas */ 82225855Ssam ((struct arpcom *)ifp)->ac_ipaddr = 82325855Ssam IA_SIN(ifa)->sin_addr; 82425855Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 82525855Ssam break; 82625855Ssam #endif 82725855Ssam #ifdef NS 82825855Ssam case AF_NS: { 82925855Ssam struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 83025855Ssam 83125855Ssam if (!ns_nullhost(*ina)) { 83225855Ssam ifp->if_flags &= ~IFF_RUNNING; 83325855Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 83425855Ssam addr = (struct acedevice *) 83525855Ssam (aceinfo[ifp->if_unit]->ui_addr); 83625855Ssam movow(&addr->csr, CSR_RESET); 83725855Ssam DELAY(10000); 83825855Ssam /* set station address & copy addr to arp */ 83925855Ssam acesetetaddr(ifp->if_unit, addr, 84025855Ssam ina->x_host.c_host); 84125855Ssam } else 84225855Ssam ina->x_host = *(union ns_host *)(es->es_addr); 84325855Ssam aceinit(ifp->if_unit); 84425855Ssam break; 84525855Ssam } 84625855Ssam #endif 84725855Ssam default: 84825855Ssam aceinit(ifp->if_unit); 84925855Ssam break; 85025855Ssam } 85124007Ssam break; 85224007Ssam 85325855Ssam case SIOCSIFFLAGS: 85425855Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 85525855Ssam addr = (struct acedevice *) 85625855Ssam (aceinfo[ifp->if_unit]->ui_addr); 85725855Ssam movow(&addr->csr, CSR_RESET); 85825855Ssam ifp->if_flags &= ~IFF_RUNNING; 85925855Ssam } else if (ifp->if_flags&IFF_UP && 86025855Ssam (ifp->if_flags&IFF_RUNNING) == 0) 86125855Ssam aceinit(ifp->if_unit); 86224007Ssam break; 86324007Ssam 86424007Ssam default: 86524007Ssam error = EINVAL; 86624007Ssam } 86724007Ssam splx(s); 86824007Ssam return (error); 86924007Ssam } 87024007Ssam 871*25927Ssam acesetup(unit) 87224007Ssam int unit; 87324007Ssam { 87424007Ssam register struct ace_softc *is = &ace_softc[unit]; 875*25927Ssam register char *pData1; 87625694Ssam register short i; 877*25927Ssam struct acedevice *addr; 87824007Ssam 879*25927Ssam bzero(is->is_dpm, 16384*2); 88024007Ssam is->is_currnd = 49123; 881*25927Ssam addr = (struct acedevice *)aceinfo[unit]->ui_addr; 88224007Ssam is->is_segboundry = (addr->segb >> 11) & 0xf; 883*25927Ssam pData1 = is->is_dpm + (is->is_segboundry << 11); 88424007Ssam for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 88524007Ssam acebakoff(is, (struct tx_segment *)pData1, 15); 88624007Ssam pData1 += sizeof (struct tx_segment); 88724007Ssam } 88824007Ssam is->is_eictr = 0; 88924007Ssam is->is_eoctr = is->is_txnext = is->is_segboundry; 89024007Ssam bzero((char *)&is->is_stats, sizeof (is->is_stats)); 89124007Ssam } 89224007Ssam #endif 893