1*25855Ssam /* if_ace.c 1.3 86/01/12 */ 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" 21*25855Ssam #include "syslog.h" 2224007Ssam 2324007Ssam #include "../net/if.h" 2424007Ssam #include "../net/netisr.h" 2524007Ssam #include "../net/route.h" 26*25855Ssam #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" 33*25855Ssam #endif 34*25855Ssam #ifdef NS 35*25855Ssam #include "../netns/ns.h" 36*25855Ssam #include "../netns/ns_if.h" 37*25855Ssam #endif 3824007Ssam 3924007Ssam #include "../tahoe/mtpr.h" 4024007Ssam #include "../tahoeif/if_acereg.h" 4125694Ssam #include "../tahoevba/vbavar.h" 4224007Ssam 4324007Ssam /* 4424007Ssam * Configuration table, for 2 units (should be defined by config) 4524007Ssam */ 4624007Ssam extern char ace0utl[], ace1utl[]; /* dpm */ 4724007Ssam char *acemap[]= { ace0utl, ace1utl }; 4825694Ssam extern struct pte ACE0map[], ACE1map[]; 4925694Ssam struct pte *ACEmap[] = { ACE0map, ACE1map }; 5025694Ssam caddr_t ACEmapa[] = { (caddr_t)0xfff80000, (caddr_t)0xfff90000 }; 5124007Ssam 5224007Ssam /* station address */ 5324007Ssam char ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 }; 5424007Ssam /* multicast hash table initializer */ 5524007Ssam char ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF }; 5624007Ssam /* backoff table masks */ 5724007Ssam short random_mask_tbl[16] = { 5824007Ssam 0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0, 5924007Ssam 0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0 6024007Ssam }; 6124007Ssam 6224007Ssam int aceprobe(), aceattach(), acerint(), acecint(); 6324007Ssam struct vba_device *aceinfo[NACE]; 64*25855Ssam long acestd[] = { 0x0ff0000, 0xff0100, 0 }; 6524007Ssam struct vba_driver acedriver = 6624007Ssam { aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 }; 6724007Ssam 6824007Ssam #define ACEUNIT(x) minor(x) 6924007Ssam 7024007Ssam int aceinit(), aceoutput(), aceioctl(), acereset(); 7124007Ssam struct mbuf *aceget(); 7224007Ssam 7324007Ssam /* 7424007Ssam * Ethernet software status per interface. 7524007Ssam * 7624007Ssam * Each interface is referenced by a network interface structure, 7724007Ssam * is_if, which the routing code uses to locate the interface. 7824007Ssam * This structure contains the output queue for the interface, its address, ... 7924007Ssam */ 8024007Ssam struct ace_softc { 8124007Ssam struct arpcom is_ac; /* Ethernet common part */ 8224007Ssam #define is_if is_ac.ac_if /* network-visible interface */ 8324007Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 8424007Ssam char *is_dpm; 8524007Ssam short is_flags; 8624007Ssam #define ACEF_OACTIVE 0x1 /* output is active */ 8724007Ssam #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 8824007Ssam short is_promiscuous; /* true is enabled */ 8924007Ssam short is_segboundry; /* first TX Seg in dpm */ 9024007Ssam short is_eictr; /* Rx segment tracking ctr */ 9124007Ssam short is_eoctr; /* Tx segment tracking ctr */ 9224007Ssam short is_txnext; /* Next available Tx segment */ 9324007Ssam short is_currnd; /* current random backoff */ 9424007Ssam struct ace_stats is_stats; /* holds board statistics */ 9524007Ssam short is_xcnt; /* count xmitted segments to be acked 9624007Ssam by the controller */ 97*25855Ssam long is_ivec; /* autoconfig interrupt vector base */ 9824007Ssam } ace_softc[NACE]; 9924007Ssam extern struct ifnet loif; 10024007Ssam 101*25855Ssam aceprobe(reg, vi) 10224007Ssam caddr_t reg; 103*25855Ssam struct vba_device *vi; 10424007Ssam { 105*25855Ssam register br, cvec; /* must be r12, r11 */ 106*25855Ssam struct acedevice *ap = (struct acedevice *)reg; 107*25855Ssam struct ace_softc *is = &ace_softc[vi->ui_unit]; 10824007Ssam 10924007Ssam #ifdef lint 11024007Ssam acerint(0); acecint(0); 11124007Ssam #endif 11224007Ssam if (badaddr(reg, 2)) 113*25855Ssam return (0); 114*25855Ssam movow(&ap->csr, CSR_RESET); 11524007Ssam DELAY(10000); 116*25855Ssam #ifdef notdef 117*25855Ssam /* 118*25855Ssam * Select two spaces for the interrupts aligned to an 119*25855Ssam * eight vector boundary and fitting in 8 bits (as 120*25855Ssam * required by the controller) -- YECH. The controller 121*25855Ssam * will be notified later at initialization time. 122*25855Ssam */ 123*25855Ssam if ((vi->ui_hd->vh_lastiv -= 2) > 0xff) 124*25855Ssam vi->ui_hd->vh_lastiv = 0x200; 125*25855Ssam is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7; 126*25855Ssam #else 127*25855Ssam is->is_ivec = 0x90+vi->ui_unit*8; 128*25855Ssam #endif 129*25855Ssam br = 0x14, cvec = is->is_ivec; /* XXX */ 130*25855Ssam return (sizeof (*ap)); 13124007Ssam } 13224007Ssam 13324007Ssam /* 13424007Ssam * Interface exists: make available by filling in network interface 13524007Ssam * record. System will initialize the interface when it is ready 13624007Ssam * to accept packets. 13724007Ssam */ 13824007Ssam aceattach(ui) 13924007Ssam struct vba_device *ui; 14024007Ssam { 14124007Ssam register short unit = ui->ui_unit; 14224007Ssam register struct ace_softc *is = &ace_softc[unit]; 14324007Ssam register struct ifnet *ifp = &is->is_if; 14424007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 14524007Ssam register short *wp, i; 14624007Ssam 14724007Ssam ifp->if_unit = unit; 14824007Ssam ifp->if_name = "ace"; 14924007Ssam ifp->if_mtu = ETHERMTU; 15024007Ssam /* 15124007Ssam * Set station's addresses, multicast 15224007Ssam * hash table, and initialize dual ported memory. 15324007Ssam */ 15424007Ssam ace_station[5] = ~(unit + 1); 15524007Ssam acesetetaddr(unit, addr, ace_station); 15624007Ssam is->is_promiscuous = 0; 15724007Ssam wp = (short *)addr->hash; 15824007Ssam for (i = 0; i < 8; i++) 15925694Ssam movow(wp++, ace_hash[i]); 16025694Ssam movow(&addr->bcastena[0], ~0xffff); 16125694Ssam movow(&addr->bcastena[1], ~0xffff); 16224007Ssam aceclean(unit); 16324007Ssam ifp->if_init = aceinit; 16424007Ssam ifp->if_output = aceoutput; 16524007Ssam ifp->if_ioctl = aceioctl; 16624007Ssam ifp->if_reset = acereset; 16725694Ssam ifp->if_flags = IFF_BROADCAST; 16824007Ssam if_attach(ifp); 16924007Ssam } 17024007Ssam 17124007Ssam acesetetaddr(unit, addr, station_addr) 17224007Ssam short unit; 17324007Ssam struct acedevice *addr; 17424007Ssam char *station_addr; 17524007Ssam { 17624007Ssam register short *wp, i; 17724007Ssam register char *cp; 17824007Ssam struct ace_softc *is = &ace_softc[unit]; 17924007Ssam 18024007Ssam wp = (short *)addr->station; 18124007Ssam cp = station_addr; 18224007Ssam for (i = 0; i < 6; i++) 18325694Ssam movow(wp++, *cp++); 18424007Ssam wp = (short *)addr->station; 18525694Ssam cp = (char *)is->is_addr; 18624007Ssam for (i = 0; i < 6; i++) 18724007Ssam *cp++ = ~(*wp++); 18824007Ssam } 18924007Ssam 19024007Ssam /* 19124007Ssam * Reset of interface after "system" reset. 19224007Ssam */ 19324007Ssam acereset(unit, vban) 19424007Ssam int unit, vban; 19524007Ssam { 19624007Ssam register struct vba_device *ui; 19724007Ssam 19824007Ssam if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 19924007Ssam ui->ui_vbanum != vban) 20024007Ssam return; 20124007Ssam printf(" ace%d", unit); 20224007Ssam aceinit(unit); 20324007Ssam } 20424007Ssam 20524007Ssam /* 20624007Ssam * Initialization of interface; clear recorded pending operations 20724007Ssam */ 20824007Ssam aceinit(unit) 20924007Ssam int unit; 21024007Ssam { 21124007Ssam register struct ace_softc *is = &ace_softc[unit]; 21224007Ssam register struct vba_device *ui = aceinfo[unit]; 21324007Ssam register struct acedevice *addr; 21424007Ssam register struct ifnet *ifp = &is->is_if; 21524007Ssam register short Csr; 21625694Ssam register int s; 21724007Ssam 21825694Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 21924007Ssam return; 22024007Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 22124007Ssam /* 22224007Ssam * Reset the controller, initialize the recieve buffers, 22324007Ssam * and turn the controller on again and set board online. 22424007Ssam */ 22524007Ssam addr = (struct acedevice *)ui->ui_addr; 22624007Ssam s = splimp(); 22725694Ssam movow(&addr->csr, CSR_RESET); 22824007Ssam DELAY(10000); 22924007Ssam 23024007Ssam /* 23124007Ssam * clean up dpm since the controller might 23224007Ssam * jumble dpm after reset 23324007Ssam */ 23424007Ssam aceclean(unit); 23525694Ssam movow(&addr->csr, CSR_GO); 23624007Ssam Csr = addr->csr; 23724007Ssam if (Csr & CSR_ACTIVE) { 238*25855Ssam movow(&addr->ivct, is->is_ivec); 23924007Ssam Csr |= CSR_IENA | is->is_promiscuous; 24025694Ssam movow(&addr->csr, Csr); 24124007Ssam is->is_flags = 0; 24224007Ssam is->is_xcnt = 0; 24325694Ssam is->is_if.if_flags |= IFF_RUNNING; 24424007Ssam } 24524007Ssam splx(s); 24624007Ssam } 24725694Ssam if (is->is_if.if_snd.ifq_head) 24824007Ssam aceStart(unit); 24924007Ssam } 25024007Ssam 25124007Ssam /* 25224007Ssam * Start output on interface. 25324007Ssam * Get another datagram to send off of the interface queue, 25424007Ssam * and map it to the interface before starting the output. 25524007Ssam * 25624007Ssam */ 25724007Ssam acestart(dev) 25824007Ssam dev_t dev; 25924007Ssam { 26024007Ssam register struct tx_segment *txs; 26125694Ssam register long len; 26225694Ssam register int s; 26324007Ssam int unit = ACEUNIT(dev); 26424007Ssam register struct ace_softc *is = &ace_softc[unit]; 26524007Ssam struct mbuf *m; 26625694Ssam short retries; 26724007Ssam 26824007Ssam again: 26924007Ssam txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 27024007Ssam if (txs->tx_csr & TCS_TBFULL) { 27124007Ssam is->is_stats.tx_busy++; 27224007Ssam return; 27324007Ssam } 27425694Ssam s = splimp(); 27524007Ssam IF_DEQUEUE(&is->is_if.if_snd, m); 27625694Ssam splx(s); 27724007Ssam if (m == 0) 27824007Ssam return; 27924007Ssam len = aceput(unit, txs->tx_data, m); 28024007Ssam retries = txs->tx_csr & TCS_RTC; 28124007Ssam if (retries > 0) 28224007Ssam acebakoff(is, txs, retries); 28324007Ssam 28424007Ssam /* 28524007Ssam * Ensure minimum packet length. 28624007Ssam * This makes the safe assumtion that there are no virtual holes 28724007Ssam * after the data. 28824007Ssam * For security, it might be wise to zero out the added bytes, 28924007Ssam * but we're mainly interested in speed at the moment. 29024007Ssam */ 29124007Ssam #ifdef notdef 29224007Ssam if (len - sizeof (struct ether_header) < ETHERMIN) 29324007Ssam len = ETHERMIN + sizeof (struct ether_header); 29424007Ssam #else 29524007Ssam if (len - 14 < ETHERMIN) 29624007Ssam len = ETHERMIN + 14; 29724007Ssam #endif 29824007Ssam if (++is->is_txnext > SEG_MAX) 29924007Ssam is->is_txnext = is->is_segboundry; 30024007Ssam is->is_if.if_opackets++; 30124007Ssam is->is_xcnt++; 30224007Ssam len = (len & 0x7fff) | TCS_TBFULL; 30325694Ssam movow(txs, len); 30424007Ssam goto again; 30524007Ssam } 30624007Ssam 30724007Ssam /* 30824007Ssam * Transmit done interrupt. 30924007Ssam */ 31024007Ssam acecint(unit) 31124007Ssam int unit; 31224007Ssam { 31324007Ssam register struct ace_softc *is = &ace_softc[unit]; 31424007Ssam register struct tx_segment *txseg; 31525694Ssam short eostat; 31624007Ssam 31724007Ssam if (is->is_xcnt <= 0) { 318*25855Ssam log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n", 31924007Ssam unit, is->is_xcnt); 32024007Ssam is->is_xcnt = 0; 32125694Ssam if (is->is_if.if_snd.ifq_head) 32225694Ssam aceStart(unit); 32324007Ssam return; 32424007Ssam } 32524007Ssam is->is_xcnt--; 32624007Ssam txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 32724007Ssam eostat = txseg->tx_csr; 32824007Ssam if ((eostat & TCS_TBFULL) == 0) { 32924007Ssam is->is_stats.tx_retries += eostat & TCS_RTC; 33024007Ssam if (eostat & TCS_RTFAIL) { 33124007Ssam is->is_stats.tx_discarded++; 33224007Ssam is->is_if.if_oerrors++; 33324007Ssam } else 33424007Ssam is->is_stats.tx_datagrams++; 33524007Ssam if (++is->is_eoctr >= 16) 33624007Ssam is->is_eoctr = is->is_segboundry; 33724007Ssam } 33825694Ssam if (is->is_if.if_snd.ifq_head) 33925694Ssam aceStart(unit); 34024007Ssam } 34124007Ssam 34224007Ssam /* 34324007Ssam * Ethernet interface receiver interrupt. 34424007Ssam * If input error just drop packet. 34524007Ssam * Otherwise purge input buffered data path and examine 34624007Ssam * packet to determine type. If can't determine length 34724007Ssam * from type, then have to drop packet. Othewise decapsulate 34824007Ssam * packet based on type and pass to type specific higher-level 34924007Ssam * input routine. 35024007Ssam */ 35124007Ssam acerint(unit) 35224007Ssam int unit; 35324007Ssam { 35424007Ssam register struct ace_softc *is = &ace_softc[unit]; 35524007Ssam register struct ifqueue *inq; 35624007Ssam register struct ether_header *ace; 35724007Ssam register struct rx_segment *rxseg; 35824007Ssam int len, s, off, resid; 35924007Ssam struct mbuf *m; 36024007Ssam short eistat; 36124007Ssam 36225694Ssam if ((is->is_if.if_flags&IFF_RUNNING) == 0) 36325694Ssam return; 36424007Ssam again: 36524007Ssam rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 36624007Ssam eistat = rxseg->rx_csr; 36724007Ssam if ((eistat & RCS_RBFULL) == 0) 36824007Ssam return; 36924007Ssam is->is_if.if_ipackets++; 37024007Ssam if (++is->is_eictr >= is->is_segboundry) 37124007Ssam is->is_eictr = 0; 37224007Ssam len = eistat & RCS_RBC; 37324007Ssam if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 37424007Ssam len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 37524007Ssam if (eistat & RCS_ROVRN) 37624007Ssam is->is_stats.rx_overruns++; 37724007Ssam if (eistat & RCS_RCRC) 37824007Ssam is->is_stats.rx_crc_errors++; 37924007Ssam if (eistat & RCS_RODD) 38024007Ssam is->is_stats.rx_align_errors++; 38124007Ssam if (len < ET_MINLEN) 38224007Ssam is->is_stats.rx_underruns++; 38324007Ssam if (len > ET_MAXLEN+CRC_SIZE) 38424007Ssam is->is_stats.rx_overruns++; 38524007Ssam is->is_if.if_ierrors++; 38624007Ssam rxseg->rx_csr = 0; 38724007Ssam return; 38824007Ssam } else 38924007Ssam is->is_stats.rx_datagrams++; 39024007Ssam ace = (struct ether_header *)rxseg->rx_data; 39124007Ssam #ifdef notdef 39224007Ssam len -= sizeof (struct ether_header); 39324007Ssam #else 39424007Ssam len -= 14; 39524007Ssam #endif 39624007Ssam /* 39725694Ssam * Deal with trailer protocol: if type is trailer 39824007Ssam * get true type from first 16-bit word past data. 39924007Ssam * Remember that type was trailer by setting off. 40024007Ssam */ 40124007Ssam ace->ether_type = ntohs((u_short)ace->ether_type); 40224007Ssam #ifdef notdef 40324007Ssam #define acedataaddr(ace, off, type) \ 40424007Ssam ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 40524007Ssam #else 40624007Ssam #define acedataaddr(ace, off, type) \ 40724007Ssam ((type)(((caddr_t)(((char *)ace)+14)+(off)))) 40824007Ssam #endif 40925694Ssam if (ace->ether_type >= ETHERTYPE_TRAIL && 41025694Ssam ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 41125694Ssam off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; 41224007Ssam if (off >= ETHERMTU) 41324007Ssam goto setup; /* sanity */ 41424007Ssam ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 41524007Ssam resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 41624007Ssam if (off + resid > len) 41724007Ssam goto setup; /* sanity */ 41824007Ssam len = off + resid; 41924007Ssam } else 42024007Ssam off = 0; 42124007Ssam if (len == 0) 42224007Ssam goto setup; 42324007Ssam 42424007Ssam /* 42524007Ssam * Pull packet off interface. Off is nonzero if packet 42624007Ssam * has trailing header; aceget will then force this header 42724007Ssam * information to be at the front, but we still have to drop 42824007Ssam * the type and length which are at the front of any trailer data. 42924007Ssam */ 430*25855Ssam m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if); 43124007Ssam if (m == 0) 43224007Ssam goto setup; 43324007Ssam if (off) { 434*25855Ssam struct ifnet *ifp; 435*25855Ssam 436*25855Ssam ifp = *(mtod(m, struct ifnet **)); 43724007Ssam m->m_off += 2 * sizeof (u_short); 43824007Ssam m->m_len -= 2 * sizeof (u_short); 439*25855Ssam *(mtod(m, struct ifnet **)) = ifp; 44024007Ssam } 44124007Ssam switch (ace->ether_type) { 44224007Ssam 44324007Ssam #ifdef INET 44425694Ssam case ETHERTYPE_IP: 44524007Ssam schednetisr(NETISR_IP); 44624007Ssam inq = &ipintrq; 44724007Ssam break; 448*25855Ssam #endif 44924007Ssam 45025694Ssam case ETHERTYPE_ARP: 45124007Ssam arpinput(&is->is_ac, m); 45224007Ssam goto setup; 45325694Ssam #ifdef NS 45425694Ssam case ETHERTYPE_NS: 45525694Ssam schednetisr(NETISR_NS); 45625694Ssam inq = &nsintrq; 45725694Ssam break; 45825694Ssam 45925694Ssam #endif 46024007Ssam default: 46124007Ssam m_freem(m); 46224007Ssam goto setup; 46324007Ssam } 46424007Ssam if (IF_QFULL(inq)) { 46524007Ssam IF_DROP(inq); 46624007Ssam m_freem(m); 46724007Ssam goto setup; 46824007Ssam } 46924007Ssam s = splimp(); 47024007Ssam IF_ENQUEUE(inq, m); 47124007Ssam splx(s); 47224007Ssam setup: 47324007Ssam rxseg->rx_csr = 0; 47424007Ssam goto again; 47524007Ssam } 47624007Ssam 47724007Ssam /* 47824007Ssam * Ethernet output routine. 47924007Ssam * Encapsulate a packet of type family for the local net. 48024007Ssam * Use trailer local net encapsulation if enough data in first 48124007Ssam * packet leaves a multiple of 512 bytes of data in remainder. 48224007Ssam */ 48324007Ssam aceoutput(ifp, m0, dst) 48424007Ssam struct ifnet *ifp; 48524007Ssam struct mbuf *m0; 48624007Ssam struct sockaddr *dst; 48724007Ssam { 48824007Ssam register struct ace_softc *is = &ace_softc[ifp->if_unit]; 48924007Ssam register struct mbuf *m = m0; 49024007Ssam register struct ether_header *ace; 49124007Ssam register int off; 49224007Ssam struct mbuf *mcopy = (struct mbuf *)0; 49324007Ssam int type, s, error; 49425694Ssam u_char edst[6]; 49524007Ssam struct in_addr idst; 49624007Ssam 497*25855Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 498*25855Ssam error = ENETDOWN; 499*25855Ssam goto bad; 500*25855Ssam } 50124007Ssam switch (dst->sa_family) { 50224007Ssam 50324007Ssam #ifdef INET 50424007Ssam case AF_INET: 50524007Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 50625694Ssam if (!arpresolve(&is->is_ac, m, &idst, edst)) 50724007Ssam return (0); /* if not yet resolved */ 50825694Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 50925694Ssam sizeof(edst))) 51024007Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 51124007Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 51224007Ssam /* need per host negotiation */ 51324007Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 && 51424007Ssam (off & 0x1ff) == 0 && 51524007Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 51625694Ssam type = ETHERTYPE_TRAIL + (off>>9); 51724007Ssam m->m_off -= 2 * sizeof (u_short); 51824007Ssam m->m_len += 2 * sizeof (u_short); 51925694Ssam *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 52024007Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 52124007Ssam goto gottrailertype; 52224007Ssam } 52325694Ssam type = ETHERTYPE_IP; 52424007Ssam off = 0; 52524007Ssam goto gottype; 52624007Ssam #endif 52725694Ssam #ifdef NS 52825694Ssam case AF_NS: 52925694Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 53025694Ssam (caddr_t)edst, sizeof (edst)); 53125694Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst))) 53225694Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 53325694Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 53425694Ssam sizeof(edst))) 53525694Ssam return(looutput(&loif, m, dst)); 53625694Ssam type = ETHERTYPE_NS; 53725694Ssam off = 0; 53825694Ssam goto gottype; 53925694Ssam #endif 54024007Ssam case AF_UNSPEC: 54124007Ssam ace = (struct ether_header *)dst->sa_data; 54225694Ssam bcopy((caddr_t)ace->ether_dhost, (caddr_t)edst, sizeof (edst)); 54324007Ssam type = ace->ether_type; 54424007Ssam goto gottype; 54524007Ssam 54624007Ssam default: 547*25855Ssam log(LOG_ERR, "ace%d: can't handle af%d\n", 54824007Ssam ifp->if_unit, dst->sa_family); 54924007Ssam error = EAFNOSUPPORT; 55024007Ssam goto bad; 55124007Ssam } 55224007Ssam 55324007Ssam gottrailertype: 55424007Ssam /* 55524007Ssam * Packet to be sent as trailer: move first packet 55624007Ssam * (control information) to end of chain. 55724007Ssam */ 55824007Ssam while (m->m_next) 55924007Ssam m = m->m_next; 56024007Ssam m->m_next = m0; 56124007Ssam m = m0->m_next; 56224007Ssam m0->m_next = 0; 56324007Ssam m0 = m; 56424007Ssam 56524007Ssam gottype: 56624007Ssam /* 56724007Ssam * Add local net header. If no space in first mbuf, 56824007Ssam * allocate another. 56924007Ssam */ 57024007Ssam if (m->m_off > MMAXOFF || 57124007Ssam #ifdef notdef 57224007Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 57324007Ssam #else 57424007Ssam MMINOFF + 14 > m->m_off) { 57524007Ssam #endif 57624007Ssam m = m_get(M_DONTWAIT, MT_HEADER); 57724007Ssam if (m == 0) { 57824007Ssam error = ENOBUFS; 57924007Ssam goto bad; 58024007Ssam } 58124007Ssam m->m_next = m0; 58224007Ssam m->m_off = MMINOFF; 58324007Ssam #ifdef notdef 58424007Ssam m->m_len = sizeof (struct ether_header); 58524007Ssam #else 58624007Ssam m->m_len = 14; 58724007Ssam #endif 58824007Ssam } else { 58924007Ssam #ifdef notdef 59024007Ssam m->m_off -= sizeof (struct ether_header); 59124007Ssam m->m_len += sizeof (struct ether_header); 59224007Ssam #else 59324007Ssam m->m_off -= 14; 59424007Ssam m->m_len += 14; 59524007Ssam #endif 59624007Ssam } 59724007Ssam ace = mtod(m, struct ether_header *); 59825694Ssam bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst)); 59925694Ssam bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost, 60025694Ssam sizeof (is->is_addr)); 60124007Ssam ace->ether_type = htons((u_short)type); 60224007Ssam 60324007Ssam /* 60424007Ssam * Queue message on interface, and start output if interface 60524007Ssam * not yet active. 60624007Ssam */ 60724007Ssam s = splimp(); 60824007Ssam if (IF_QFULL(&ifp->if_snd)) { 60924007Ssam IF_DROP(&ifp->if_snd); 61024007Ssam error = ENOBUFS; 61124007Ssam goto qfull; 61224007Ssam } 61324007Ssam IF_ENQUEUE(&ifp->if_snd, m); 61424007Ssam splx(s); 61524007Ssam aceStart(ifp->if_unit); 61624007Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 61724007Ssam qfull: 61824007Ssam m0 = m; 61924007Ssam splx(s); 62024007Ssam bad: 62124007Ssam m_freem(m0); 62224007Ssam if (mcopy) 62324007Ssam m_freem(mcopy); 62424007Ssam return (error); 62524007Ssam } 62624007Ssam 62724007Ssam aceStart(unit) 62824007Ssam int unit; 62924007Ssam { 63024007Ssam register struct ace_softc *is = &ace_softc[unit]; 63124007Ssam 63224007Ssam if (is->is_flags & ACEF_OACTIVE) 63324007Ssam return; 63424007Ssam is->is_flags |= ACEF_OACTIVE; 63524007Ssam acestart((dev_t)unit); 63624007Ssam is->is_flags &= ~ACEF_OACTIVE; 63724007Ssam } 63824007Ssam 63924007Ssam /* 64024007Ssam * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 64124007Ssam * If packet size is less than the minimum legal size, 64224007Ssam * the buffer is expanded. We probably should zero out the extra 64324007Ssam * bytes for security, but that would slow things down. 64424007Ssam */ 64525694Ssam /*ARGSUSED*/ 64624007Ssam aceput(unit, txbuf, m) 647*25855Ssam int unit; 64825694Ssam char *txbuf; 64924007Ssam struct mbuf *m; 65024007Ssam { 651*25855Ssam register u_char *bp, *mcp; 652*25855Ssam register short *s1, *s2; 65325694Ssam register u_int len; 65424007Ssam register struct mbuf *mp; 65525694Ssam int total; 65624007Ssam 65724007Ssam total = 0; 65825694Ssam bp = (u_char *)txbuf; 65925694Ssam for (mp = m; (mp); mp = mp->m_next) { 66024007Ssam len = mp->m_len; 66124007Ssam if (len == 0) 66224007Ssam continue; 66324007Ssam total += len; 66424007Ssam mcp = mtod(mp, u_char *); 66524007Ssam if (((int)mcp & 01) && ((int)bp & 01)) { 66624007Ssam /* source & destination at odd addresses */ 66725694Ssam movob(bp++, *mcp++); 66824007Ssam --len; 66924007Ssam } 67024007Ssam if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 67125694Ssam register u_int l; 67224007Ssam 67324007Ssam s1 = (short *)bp; 67424007Ssam s2 = (short *)mcp; 67524007Ssam l = len >> 1; /* count # of shorts */ 67625694Ssam while (l-- != 0) 67725694Ssam movow(s1++, *s2++); 67824007Ssam len &= 1; /* # remaining bytes */ 67924007Ssam bp = (u_char *)s1; 68024007Ssam mcp = (u_char *)s2; 68124007Ssam } 68225694Ssam while (len-- != 0) 68325694Ssam movob(bp++, *mcp++); 68424007Ssam } 68524007Ssam m_freem(m); 68624007Ssam return (total); 68724007Ssam } 68824007Ssam 68924007Ssam /* 69024007Ssam * Routine to copy from VERSAbus memory into mbufs. 69124007Ssam * 69224007Ssam * Warning: This makes the fairly safe assumption that 69324007Ssam * mbufs have even lengths. 69424007Ssam */ 69525694Ssam /*ARGSUSED*/ 69624007Ssam struct mbuf * 697*25855Ssam aceget(rxbuf, totlen, off0, ifp) 69824007Ssam u_char *rxbuf; 69924007Ssam int totlen, off0; 700*25855Ssam struct ifnet *ifp; 70124007Ssam { 702*25855Ssam register u_char *cp, *mcp; 70324007Ssam register int tlen; 70424007Ssam register struct mbuf *m; 70524007Ssam struct mbuf *top = 0, **mp = ⊤ 70624007Ssam int len, off = off0; 70724007Ssam 70824007Ssam #ifdef notdef 70924007Ssam cp = rxbuf + sizeof (struct ether_header); 71024007Ssam #else 71124007Ssam cp = rxbuf + 14; 71224007Ssam #endif 71324007Ssam while (totlen > 0) { 71424007Ssam MGET(m, M_DONTWAIT, MT_DATA); 71524007Ssam if (m == 0) 71624007Ssam goto bad; 71724007Ssam if (off) { 71824007Ssam len = totlen - off; 71924007Ssam #ifdef notdef 72024007Ssam cp = rxbuf + sizeof (struct ether_header) + off; 72124007Ssam #else 72224007Ssam cp = rxbuf + 14 + off; 72324007Ssam #endif 72424007Ssam } else 72524007Ssam len = totlen; 726*25855Ssam if (ifp) 727*25855Ssam len += sizeof(ifp); 72824007Ssam if (len >= CLBYTES) { 72924007Ssam struct mbuf *p; 73024007Ssam 73124007Ssam MCLGET(p, 1); 73224007Ssam if (p != 0) { 73324007Ssam m->m_len = len = CLBYTES; 73424007Ssam m->m_off = (int)p - (int)m; 73524007Ssam } else { 73624007Ssam m->m_len = len = MIN(MLEN, len); 73724007Ssam m->m_off = MMINOFF; 73824007Ssam } 73924007Ssam } else { 74024007Ssam m->m_len = len = MIN(MLEN, len); 74124007Ssam m->m_off = MMINOFF; 74224007Ssam } 74324007Ssam mcp = mtod(m, u_char *); 744*25855Ssam if (ifp) { 745*25855Ssam /* 746*25855Ssam * Prepend interface pointer to first mbuf. 747*25855Ssam */ 748*25855Ssam *(mtod(m, struct ifnet **)) = ifp; 749*25855Ssam mcp += sizeof(ifp); 750*25855Ssam len -= sizeof(ifp); 751*25855Ssam ifp = (struct ifnet *)0; 752*25855Ssam } 75324007Ssam /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 75424007Ssam /*cp += len; mcp += len;*/ 75524007Ssam tlen = len; 75624007Ssam if (((int)mcp & 01) && ((int)cp & 01)) { 75724007Ssam /* source & destination at odd addresses */ 75824007Ssam *mcp++ = *cp++; 75924007Ssam --tlen; 76024007Ssam } 76124007Ssam if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 76224007Ssam register short *s1, *s2; 76324007Ssam register int l; 76424007Ssam 76524007Ssam s1 = (short *)mcp; 76624007Ssam s2 = (short *)cp; 76724007Ssam l = tlen >> 1; /* count # of shorts */ 76824007Ssam while (l-- > 0) /* copy shorts */ 76924007Ssam *s1++ = *s2++; 77024007Ssam tlen &= 1; /* # remaining bytes */ 77124007Ssam mcp = (u_char *)s1; 77224007Ssam cp = (u_char *)s2; 77324007Ssam } 77424007Ssam while (tlen-- > 0) 77524007Ssam *mcp++ = *cp++; 77624007Ssam *mp = m; 77724007Ssam mp = &m->m_next; 77824007Ssam if (off == 0) { 77924007Ssam totlen -= len; 78024007Ssam continue; 78124007Ssam } 78224007Ssam off += len; 78324007Ssam if (off == totlen) { 78424007Ssam #ifdef notdef 78524007Ssam cp = rxbuf + sizeof (struct ether_header); 78624007Ssam #else 78724007Ssam cp = rxbuf + 14; 78824007Ssam #endif 78924007Ssam off = 0; 79024007Ssam totlen = off0; 79124007Ssam } 79224007Ssam } 79324007Ssam return (top); 79424007Ssam bad: 79524007Ssam m_freem(top); 79624007Ssam return (0); 79724007Ssam } 79824007Ssam 79924007Ssam acebakoff(is, txseg, retries) 80024007Ssam struct ace_softc *is; 80124007Ssam struct tx_segment *txseg; 80224007Ssam register int retries; 80324007Ssam { 80424007Ssam register short *pBakNum, random_num; 80524007Ssam short *pMask; 80624007Ssam 80724007Ssam pMask = &random_mask_tbl[0]; 80824007Ssam pBakNum = &txseg->tx_backoff[0]; 80924007Ssam while (--retries >= 0) { 81024007Ssam random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 81124007Ssam random_num &= *pMask++; 81224007Ssam *pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC); 81324007Ssam } 81424007Ssam } 81524007Ssam 81624007Ssam /* 81724007Ssam * Process an ioctl request. 81824007Ssam */ 81924007Ssam aceioctl(ifp, cmd, data) 82024007Ssam register struct ifnet *ifp; 82124007Ssam int cmd; 82224007Ssam caddr_t data; 82324007Ssam { 82425694Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 825*25855Ssam struct acedevice *addr; 82625694Ssam int s = splimp(), error = 0; 82724007Ssam 82824007Ssam switch (cmd) { 82924007Ssam 83024007Ssam case SIOCSIFADDR: 83125694Ssam ifp->if_flags |= IFF_UP; 832*25855Ssam switch (ifa->ifa_addr.sa_family) { 833*25855Ssam #ifdef INET 834*25855Ssam case AF_INET: 835*25855Ssam aceinit(ifp->if_unit); /* before arpwhohas */ 836*25855Ssam ((struct arpcom *)ifp)->ac_ipaddr = 837*25855Ssam IA_SIN(ifa)->sin_addr; 838*25855Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 839*25855Ssam break; 840*25855Ssam #endif 841*25855Ssam #ifdef NS 842*25855Ssam case AF_NS: { 843*25855Ssam struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 844*25855Ssam 845*25855Ssam if (!ns_nullhost(*ina)) { 846*25855Ssam ifp->if_flags &= ~IFF_RUNNING; 847*25855Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 848*25855Ssam addr = (struct acedevice *) 849*25855Ssam (aceinfo[ifp->if_unit]->ui_addr); 850*25855Ssam movow(&addr->csr, CSR_RESET); 851*25855Ssam DELAY(10000); 852*25855Ssam /* set station address & copy addr to arp */ 853*25855Ssam acesetetaddr(ifp->if_unit, addr, 854*25855Ssam ina->x_host.c_host); 855*25855Ssam } else 856*25855Ssam ina->x_host = *(union ns_host *)(es->es_addr); 857*25855Ssam aceinit(ifp->if_unit); 858*25855Ssam break; 859*25855Ssam } 860*25855Ssam #endif 861*25855Ssam default: 862*25855Ssam aceinit(ifp->if_unit); 863*25855Ssam break; 864*25855Ssam } 86524007Ssam break; 86624007Ssam 867*25855Ssam case SIOCSIFFLAGS: 868*25855Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 869*25855Ssam addr = (struct acedevice *) 870*25855Ssam (aceinfo[ifp->if_unit]->ui_addr); 871*25855Ssam movow(&addr->csr, CSR_RESET); 872*25855Ssam ifp->if_flags &= ~IFF_RUNNING; 873*25855Ssam } else if (ifp->if_flags&IFF_UP && 874*25855Ssam (ifp->if_flags&IFF_RUNNING) == 0) 875*25855Ssam aceinit(ifp->if_unit); 87624007Ssam break; 87724007Ssam 87824007Ssam default: 87924007Ssam error = EINVAL; 88024007Ssam } 88124007Ssam splx(s); 88224007Ssam return (error); 88324007Ssam } 88424007Ssam 88524007Ssam aceclean(unit) 88624007Ssam int unit; 88724007Ssam { 88824007Ssam register struct ace_softc *is = &ace_softc[unit]; 88924007Ssam register struct vba_device *ui = aceinfo[unit]; 89024007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 89125694Ssam register short i; 89224007Ssam register char *pData1; 89324007Ssam 894*25855Ssam vbaaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE); 89524007Ssam is->is_dpm = acemap[unit]; /* init dpm */ 89624007Ssam bzero((char *)is->is_dpm, 16384*2); 89724007Ssam 89824007Ssam is->is_currnd = 49123; 89924007Ssam is->is_segboundry = (addr->segb >> 11) & 0xf; 90024007Ssam pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11)); 90124007Ssam for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 90224007Ssam acebakoff(is, (struct tx_segment *)pData1, 15); 90324007Ssam pData1 += sizeof (struct tx_segment); 90424007Ssam } 90524007Ssam is->is_eictr = 0; 90624007Ssam is->is_eoctr = is->is_txnext = is->is_segboundry; 90724007Ssam bzero((char *)&is->is_stats, sizeof (is->is_stats)); 90824007Ssam } 90924007Ssam #endif 910