1*25694Ssam /* if_ace.c 1.2 86/01/05 */ 224007Ssam 324007Ssam /* 424007Ssam * ACC VERSAbus Ethernet controller 524007Ssam */ 624007Ssam #include "ace.h" 724007Ssam #if NACE > 0 824007Ssam 924007Ssam #include "../machine/pte.h" 1024007Ssam 11*25694Ssam #include "param.h" 12*25694Ssam #include "systm.h" 13*25694Ssam #include "mbuf.h" 14*25694Ssam #include "buf.h" 15*25694Ssam #include "protosw.h" 16*25694Ssam #include "socket.h" 17*25694Ssam #include "vmmac.h" 18*25694Ssam #include "ioctl.h" 19*25694Ssam #include "errno.h" 20*25694Ssam #include "vmparam.h" 2124007Ssam 2224007Ssam #include "../net/if.h" 2324007Ssam #include "../net/netisr.h" 2424007Ssam #include "../net/route.h" 2524007Ssam #include "../netinet/in.h" 2624007Ssam #include "../netinet/in_systm.h" 27*25694Ssam #include "../netinet/in_var.h" 2824007Ssam #include "../netinet/ip.h" 2924007Ssam #include "../netinet/ip_var.h" 3024007Ssam #include "../netinet/if_ether.h" 3124007Ssam 3224007Ssam #include "../tahoe/mtpr.h" 3324007Ssam #include "../tahoeif/if_acereg.h" 34*25694Ssam #include "../tahoevba/vbavar.h" 3524007Ssam 3624007Ssam #define LONET 124 3724007Ssam 3824007Ssam /* 3924007Ssam * Configuration table, for 2 units (should be defined by config) 4024007Ssam */ 4124007Ssam #define ACEVECTOR 0x90 4224007Ssam long acestd[] = { 0x0ff0000, 0xff0100 }; /* controller */ 4324007Ssam 4424007Ssam extern char ace0utl[], ace1utl[]; /* dpm */ 4524007Ssam char *acemap[]= { ace0utl, ace1utl }; 46*25694Ssam extern struct pte ACE0map[], ACE1map[]; 47*25694Ssam struct pte *ACEmap[] = { ACE0map, ACE1map }; 48*25694Ssam caddr_t ACEmapa[] = { (caddr_t)0xfff80000, (caddr_t)0xfff90000 }; 4924007Ssam 5024007Ssam /* station address */ 5124007Ssam char ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 }; 5224007Ssam /* multicast hash table initializer */ 5324007Ssam char ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF }; 5424007Ssam /* backoff table masks */ 5524007Ssam short random_mask_tbl[16] = { 5624007Ssam 0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0, 5724007Ssam 0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0 5824007Ssam }; 5924007Ssam 6024007Ssam int aceprobe(), aceattach(), acerint(), acecint(); 6124007Ssam struct vba_device *aceinfo[NACE]; 6224007Ssam struct vba_driver acedriver = 6324007Ssam { aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 }; 6424007Ssam 6524007Ssam #define ACEUNIT(x) minor(x) 6624007Ssam 6724007Ssam int aceinit(), aceoutput(), aceioctl(), acereset(); 6824007Ssam struct mbuf *aceget(); 6924007Ssam 7024007Ssam /* 7124007Ssam * Ethernet software status per interface. 7224007Ssam * 7324007Ssam * Each interface is referenced by a network interface structure, 7424007Ssam * is_if, which the routing code uses to locate the interface. 7524007Ssam * This structure contains the output queue for the interface, its address, ... 7624007Ssam */ 7724007Ssam struct ace_softc { 7824007Ssam struct arpcom is_ac; /* Ethernet common part */ 7924007Ssam #define is_if is_ac.ac_if /* network-visible interface */ 8024007Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 8124007Ssam char *is_dpm; 8224007Ssam short is_flags; 8324007Ssam #define ACEF_OACTIVE 0x1 /* output is active */ 8424007Ssam #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 8524007Ssam short is_promiscuous; /* true is enabled */ 8624007Ssam short is_segboundry; /* first TX Seg in dpm */ 8724007Ssam short is_eictr; /* Rx segment tracking ctr */ 8824007Ssam short is_eoctr; /* Tx segment tracking ctr */ 8924007Ssam short is_txnext; /* Next available Tx segment */ 9024007Ssam short is_currnd; /* current random backoff */ 9124007Ssam struct ace_stats is_stats; /* holds board statistics */ 9224007Ssam short is_xcnt; /* count xmitted segments to be acked 9324007Ssam by the controller */ 9424007Ssam } ace_softc[NACE]; 9524007Ssam extern struct ifnet loif; 9624007Ssam 9724007Ssam aceprobe(reg) 9824007Ssam caddr_t reg; 9924007Ssam { 10024007Ssam register struct acedevice *addr = (struct acedevice *)reg; 10124007Ssam 10224007Ssam #ifdef lint 10324007Ssam acerint(0); acecint(0); 10424007Ssam #endif 10524007Ssam if (badaddr(reg, 2)) 10624007Ssam return(0); 107*25694Ssam movow(&addr->csr, CSR_RESET); 10824007Ssam DELAY(10000); 10924007Ssam return (sizeof (struct acedevice)); 11024007Ssam } 11124007Ssam 11224007Ssam /* 11324007Ssam * Interface exists: make available by filling in network interface 11424007Ssam * record. System will initialize the interface when it is ready 11524007Ssam * to accept packets. 11624007Ssam */ 11724007Ssam aceattach(ui) 11824007Ssam struct vba_device *ui; 11924007Ssam { 12024007Ssam register short unit = ui->ui_unit; 12124007Ssam register struct ace_softc *is = &ace_softc[unit]; 12224007Ssam register struct ifnet *ifp = &is->is_if; 12324007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 12424007Ssam register short *wp, i; 12524007Ssam 12624007Ssam ifp->if_unit = unit; 12724007Ssam ifp->if_name = "ace"; 12824007Ssam ifp->if_mtu = ETHERMTU; 12924007Ssam /* 13024007Ssam * Set station's addresses, multicast 13124007Ssam * hash table, and initialize dual ported memory. 13224007Ssam */ 13324007Ssam ace_station[5] = ~(unit + 1); 13424007Ssam acesetetaddr(unit, addr, ace_station); 13524007Ssam is->is_promiscuous = 0; 13624007Ssam wp = (short *)addr->hash; 13724007Ssam for (i = 0; i < 8; i++) 138*25694Ssam movow(wp++, ace_hash[i]); 139*25694Ssam movow(&addr->bcastena[0], ~0xffff); 140*25694Ssam movow(&addr->bcastena[1], ~0xffff); 14124007Ssam aceclean(unit); 14224007Ssam ifp->if_init = aceinit; 14324007Ssam ifp->if_output = aceoutput; 14424007Ssam ifp->if_ioctl = aceioctl; 14524007Ssam ifp->if_reset = acereset; 146*25694Ssam ifp->if_flags = IFF_BROADCAST; 14724007Ssam if_attach(ifp); 14824007Ssam } 14924007Ssam 15024007Ssam acesetetaddr(unit, addr, station_addr) 15124007Ssam short unit; 15224007Ssam struct acedevice *addr; 15324007Ssam char *station_addr; 15424007Ssam { 15524007Ssam register short *wp, i; 15624007Ssam register char *cp; 15724007Ssam struct ace_softc *is = &ace_softc[unit]; 15824007Ssam 15924007Ssam wp = (short *)addr->station; 16024007Ssam cp = station_addr; 16124007Ssam for (i = 0; i < 6; i++) 162*25694Ssam movow(wp++, *cp++); 16324007Ssam wp = (short *)addr->station; 164*25694Ssam cp = (char *)is->is_addr; 16524007Ssam for (i = 0; i < 6; i++) 16624007Ssam *cp++ = ~(*wp++); 16724007Ssam } 16824007Ssam 16924007Ssam /* 17024007Ssam * Reset of interface after "system" reset. 17124007Ssam */ 17224007Ssam acereset(unit, vban) 17324007Ssam int unit, vban; 17424007Ssam { 17524007Ssam register struct vba_device *ui; 17624007Ssam 17724007Ssam if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 17824007Ssam ui->ui_vbanum != vban) 17924007Ssam return; 18024007Ssam printf(" ace%d", unit); 18124007Ssam aceinit(unit); 18224007Ssam } 18324007Ssam 18424007Ssam /* 18524007Ssam * Initialization of interface; clear recorded pending operations 18624007Ssam */ 18724007Ssam aceinit(unit) 18824007Ssam int unit; 18924007Ssam { 19024007Ssam register struct ace_softc *is = &ace_softc[unit]; 19124007Ssam register struct vba_device *ui = aceinfo[unit]; 19224007Ssam register struct acedevice *addr; 19324007Ssam register struct ifnet *ifp = &is->is_if; 19424007Ssam register short Csr; 195*25694Ssam register int s; 19624007Ssam 197*25694Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 19824007Ssam return; 19924007Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 20024007Ssam /* 20124007Ssam * Reset the controller, initialize the recieve buffers, 20224007Ssam * and turn the controller on again and set board online. 20324007Ssam */ 20424007Ssam addr = (struct acedevice *)ui->ui_addr; 20524007Ssam s = splimp(); 206*25694Ssam movow(&addr->csr, CSR_RESET); 20724007Ssam DELAY(10000); 20824007Ssam 20924007Ssam /* 21024007Ssam * clean up dpm since the controller might 21124007Ssam * jumble dpm after reset 21224007Ssam */ 21324007Ssam aceclean(unit); 214*25694Ssam movow(&addr->csr, CSR_GO); 21524007Ssam Csr = addr->csr; 21624007Ssam if (Csr & CSR_ACTIVE) { 217*25694Ssam movow(&addr->ivct, ACEVECTOR + unit*8); 21824007Ssam Csr |= CSR_IENA | is->is_promiscuous; 219*25694Ssam #ifdef notdef 22024007Ssam if (ifp->if_net == LONET) 22124007Ssam Csr |= CSR_LOOP3; 222*25694Ssam #endif 223*25694Ssam movow(&addr->csr, Csr); 22424007Ssam is->is_flags = 0; 22524007Ssam is->is_xcnt = 0; 226*25694Ssam is->is_if.if_flags |= IFF_RUNNING; 22724007Ssam } 22824007Ssam splx(s); 22924007Ssam } 230*25694Ssam if (is->is_if.if_snd.ifq_head) 23124007Ssam aceStart(unit); 23224007Ssam } 23324007Ssam 23424007Ssam /* 23524007Ssam * Start output on interface. 23624007Ssam * Get another datagram to send off of the interface queue, 23724007Ssam * and map it to the interface before starting the output. 23824007Ssam * 23924007Ssam */ 24024007Ssam acestart(dev) 24124007Ssam dev_t dev; 24224007Ssam { 24324007Ssam register struct tx_segment *txs; 244*25694Ssam register long len; 245*25694Ssam register int s; 24624007Ssam int unit = ACEUNIT(dev); 24724007Ssam register struct ace_softc *is = &ace_softc[unit]; 24824007Ssam struct mbuf *m; 249*25694Ssam short retries; 25024007Ssam 25124007Ssam again: 25224007Ssam txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 25324007Ssam if (txs->tx_csr & TCS_TBFULL) { 25424007Ssam is->is_stats.tx_busy++; 25524007Ssam return; 25624007Ssam } 257*25694Ssam s = splimp(); 25824007Ssam IF_DEQUEUE(&is->is_if.if_snd, m); 259*25694Ssam splx(s); 26024007Ssam if (m == 0) 26124007Ssam return; 26224007Ssam len = aceput(unit, txs->tx_data, m); 26324007Ssam retries = txs->tx_csr & TCS_RTC; 26424007Ssam if (retries > 0) 26524007Ssam acebakoff(is, txs, retries); 26624007Ssam 26724007Ssam /* 26824007Ssam * Ensure minimum packet length. 26924007Ssam * This makes the safe assumtion that there are no virtual holes 27024007Ssam * after the data. 27124007Ssam * For security, it might be wise to zero out the added bytes, 27224007Ssam * but we're mainly interested in speed at the moment. 27324007Ssam */ 27424007Ssam #ifdef notdef 27524007Ssam if (len - sizeof (struct ether_header) < ETHERMIN) 27624007Ssam len = ETHERMIN + sizeof (struct ether_header); 27724007Ssam #else 27824007Ssam if (len - 14 < ETHERMIN) 27924007Ssam len = ETHERMIN + 14; 28024007Ssam #endif 28124007Ssam if (++is->is_txnext > SEG_MAX) 28224007Ssam is->is_txnext = is->is_segboundry; 28324007Ssam is->is_if.if_opackets++; 28424007Ssam is->is_xcnt++; 28524007Ssam len = (len & 0x7fff) | TCS_TBFULL; 286*25694Ssam movow(txs, len); 28724007Ssam goto again; 28824007Ssam } 28924007Ssam 29024007Ssam /* 29124007Ssam * Transmit done interrupt. 29224007Ssam */ 29324007Ssam acecint(unit) 29424007Ssam int unit; 29524007Ssam { 29624007Ssam register struct ace_softc *is = &ace_softc[unit]; 29724007Ssam register struct tx_segment *txseg; 298*25694Ssam short eostat; 29924007Ssam 30024007Ssam if (is->is_xcnt <= 0) { 30124007Ssam printf("ace%d: stray xmit interrupt, xcnt %d\n", 30224007Ssam unit, is->is_xcnt); 30324007Ssam is->is_xcnt = 0; 304*25694Ssam if (is->is_if.if_snd.ifq_head) 305*25694Ssam aceStart(unit); 30624007Ssam return; 30724007Ssam } 30824007Ssam is->is_xcnt--; 30924007Ssam txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 31024007Ssam eostat = txseg->tx_csr; 31124007Ssam if ((eostat & TCS_TBFULL) == 0) { 31224007Ssam is->is_stats.tx_retries += eostat & TCS_RTC; 31324007Ssam if (eostat & TCS_RTFAIL) { 31424007Ssam is->is_stats.tx_discarded++; 31524007Ssam is->is_if.if_oerrors++; 31624007Ssam } else 31724007Ssam is->is_stats.tx_datagrams++; 31824007Ssam if (++is->is_eoctr >= 16) 31924007Ssam is->is_eoctr = is->is_segboundry; 32024007Ssam } 321*25694Ssam if (is->is_if.if_snd.ifq_head) 322*25694Ssam aceStart(unit); 32324007Ssam } 32424007Ssam 32524007Ssam /* 32624007Ssam * Ethernet interface receiver interrupt. 32724007Ssam * If input error just drop packet. 32824007Ssam * Otherwise purge input buffered data path and examine 32924007Ssam * packet to determine type. If can't determine length 33024007Ssam * from type, then have to drop packet. Othewise decapsulate 33124007Ssam * packet based on type and pass to type specific higher-level 33224007Ssam * input routine. 33324007Ssam */ 33424007Ssam acerint(unit) 33524007Ssam int unit; 33624007Ssam { 33724007Ssam register struct ace_softc *is = &ace_softc[unit]; 33824007Ssam register struct ifqueue *inq; 33924007Ssam register struct ether_header *ace; 34024007Ssam register struct rx_segment *rxseg; 34124007Ssam int len, s, off, resid; 34224007Ssam struct mbuf *m; 34324007Ssam short eistat; 34424007Ssam 345*25694Ssam if ((is->is_if.if_flags&IFF_RUNNING) == 0) 346*25694Ssam return; 34724007Ssam again: 34824007Ssam rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 34924007Ssam eistat = rxseg->rx_csr; 35024007Ssam if ((eistat & RCS_RBFULL) == 0) 35124007Ssam return; 35224007Ssam is->is_if.if_ipackets++; 35324007Ssam if (++is->is_eictr >= is->is_segboundry) 35424007Ssam is->is_eictr = 0; 35524007Ssam len = eistat & RCS_RBC; 35624007Ssam if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 35724007Ssam len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 35824007Ssam if (eistat & RCS_ROVRN) 35924007Ssam is->is_stats.rx_overruns++; 36024007Ssam if (eistat & RCS_RCRC) 36124007Ssam is->is_stats.rx_crc_errors++; 36224007Ssam if (eistat & RCS_RODD) 36324007Ssam is->is_stats.rx_align_errors++; 36424007Ssam if (len < ET_MINLEN) 36524007Ssam is->is_stats.rx_underruns++; 36624007Ssam if (len > ET_MAXLEN+CRC_SIZE) 36724007Ssam is->is_stats.rx_overruns++; 36824007Ssam is->is_if.if_ierrors++; 36924007Ssam rxseg->rx_csr = 0; 37024007Ssam return; 37124007Ssam } else 37224007Ssam is->is_stats.rx_datagrams++; 37324007Ssam ace = (struct ether_header *)rxseg->rx_data; 37424007Ssam #ifdef notdef 37524007Ssam len -= sizeof (struct ether_header); 37624007Ssam #else 37724007Ssam len -= 14; 37824007Ssam #endif 37924007Ssam /* 380*25694Ssam * Deal with trailer protocol: if type is trailer 38124007Ssam * get true type from first 16-bit word past data. 38224007Ssam * Remember that type was trailer by setting off. 38324007Ssam */ 38424007Ssam ace->ether_type = ntohs((u_short)ace->ether_type); 38524007Ssam #ifdef notdef 38624007Ssam #define acedataaddr(ace, off, type) \ 38724007Ssam ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 38824007Ssam #else 38924007Ssam #define acedataaddr(ace, off, type) \ 39024007Ssam ((type)(((caddr_t)(((char *)ace)+14)+(off)))) 39124007Ssam #endif 392*25694Ssam if (ace->ether_type >= ETHERTYPE_TRAIL && 393*25694Ssam ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 394*25694Ssam off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; 39524007Ssam if (off >= ETHERMTU) 39624007Ssam goto setup; /* sanity */ 39724007Ssam ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 39824007Ssam resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 39924007Ssam if (off + resid > len) 40024007Ssam goto setup; /* sanity */ 40124007Ssam len = off + resid; 40224007Ssam } else 40324007Ssam off = 0; 40424007Ssam if (len == 0) 40524007Ssam goto setup; 40624007Ssam 40724007Ssam /* 40824007Ssam * Pull packet off interface. Off is nonzero if packet 40924007Ssam * has trailing header; aceget will then force this header 41024007Ssam * information to be at the front, but we still have to drop 41124007Ssam * the type and length which are at the front of any trailer data. 41224007Ssam */ 413*25694Ssam m = aceget(unit, (u_char *)rxseg->rx_data, len, off); 41424007Ssam if (m == 0) 41524007Ssam goto setup; 41624007Ssam if (off) { 41724007Ssam m->m_off += 2 * sizeof (u_short); 41824007Ssam m->m_len -= 2 * sizeof (u_short); 41924007Ssam } 42024007Ssam switch (ace->ether_type) { 42124007Ssam 42224007Ssam #ifdef INET 423*25694Ssam case ETHERTYPE_IP: 42424007Ssam schednetisr(NETISR_IP); 42524007Ssam inq = &ipintrq; 42624007Ssam break; 42724007Ssam 428*25694Ssam case ETHERTYPE_ARP: 42924007Ssam arpinput(&is->is_ac, m); 43024007Ssam goto setup; 43124007Ssam #endif 432*25694Ssam #ifdef NS 433*25694Ssam case ETHERTYPE_NS: 434*25694Ssam schednetisr(NETISR_NS); 435*25694Ssam inq = &nsintrq; 436*25694Ssam break; 437*25694Ssam 438*25694Ssam #endif 43924007Ssam default: 44024007Ssam m_freem(m); 44124007Ssam goto setup; 44224007Ssam } 44324007Ssam if (IF_QFULL(inq)) { 44424007Ssam IF_DROP(inq); 44524007Ssam m_freem(m); 44624007Ssam goto setup; 44724007Ssam } 44824007Ssam s = splimp(); 44924007Ssam IF_ENQUEUE(inq, m); 45024007Ssam splx(s); 45124007Ssam setup: 45224007Ssam rxseg->rx_csr = 0; 45324007Ssam goto again; 45424007Ssam } 45524007Ssam 45624007Ssam /* 45724007Ssam * Ethernet output routine. 45824007Ssam * Encapsulate a packet of type family for the local net. 45924007Ssam * Use trailer local net encapsulation if enough data in first 46024007Ssam * packet leaves a multiple of 512 bytes of data in remainder. 46124007Ssam */ 46224007Ssam aceoutput(ifp, m0, dst) 46324007Ssam struct ifnet *ifp; 46424007Ssam struct mbuf *m0; 46524007Ssam struct sockaddr *dst; 46624007Ssam { 46724007Ssam register struct ace_softc *is = &ace_softc[ifp->if_unit]; 46824007Ssam register struct mbuf *m = m0; 46924007Ssam register struct ether_header *ace; 47024007Ssam register int off; 47124007Ssam struct mbuf *mcopy = (struct mbuf *)0; 47224007Ssam int type, s, error; 473*25694Ssam u_char edst[6]; 47424007Ssam struct in_addr idst; 47524007Ssam 47624007Ssam switch (dst->sa_family) { 47724007Ssam 47824007Ssam #ifdef INET 47924007Ssam case AF_INET: 48024007Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 481*25694Ssam if (!arpresolve(&is->is_ac, m, &idst, edst)) 48224007Ssam return (0); /* if not yet resolved */ 483*25694Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 484*25694Ssam sizeof(edst))) 48524007Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 48624007Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 48724007Ssam /* need per host negotiation */ 48824007Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 && 48924007Ssam (off & 0x1ff) == 0 && 49024007Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 491*25694Ssam type = ETHERTYPE_TRAIL + (off>>9); 49224007Ssam m->m_off -= 2 * sizeof (u_short); 49324007Ssam m->m_len += 2 * sizeof (u_short); 494*25694Ssam *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 49524007Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 49624007Ssam goto gottrailertype; 49724007Ssam } 498*25694Ssam type = ETHERTYPE_IP; 49924007Ssam off = 0; 50024007Ssam goto gottype; 50124007Ssam #endif 502*25694Ssam #ifdef NS 503*25694Ssam case AF_NS: 504*25694Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 505*25694Ssam (caddr_t)edst, sizeof (edst)); 506*25694Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst))) 507*25694Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 508*25694Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 509*25694Ssam sizeof(edst))) 510*25694Ssam return(looutput(&loif, m, dst)); 511*25694Ssam type = ETHERTYPE_NS; 512*25694Ssam off = 0; 513*25694Ssam goto gottype; 514*25694Ssam #endif 51524007Ssam 51624007Ssam case AF_UNSPEC: 51724007Ssam ace = (struct ether_header *)dst->sa_data; 518*25694Ssam bcopy((caddr_t)ace->ether_dhost, (caddr_t)edst, sizeof (edst)); 51924007Ssam type = ace->ether_type; 52024007Ssam goto gottype; 52124007Ssam 52224007Ssam default: 52324007Ssam printf("ace%d: can't handle af%d\n", 52424007Ssam ifp->if_unit, dst->sa_family); 52524007Ssam error = EAFNOSUPPORT; 52624007Ssam goto bad; 52724007Ssam } 52824007Ssam 52924007Ssam gottrailertype: 53024007Ssam /* 53124007Ssam * Packet to be sent as trailer: move first packet 53224007Ssam * (control information) to end of chain. 53324007Ssam */ 53424007Ssam while (m->m_next) 53524007Ssam m = m->m_next; 53624007Ssam m->m_next = m0; 53724007Ssam m = m0->m_next; 53824007Ssam m0->m_next = 0; 53924007Ssam m0 = m; 54024007Ssam 54124007Ssam gottype: 54224007Ssam /* 54324007Ssam * Add local net header. If no space in first mbuf, 54424007Ssam * allocate another. 54524007Ssam */ 54624007Ssam if (m->m_off > MMAXOFF || 54724007Ssam #ifdef notdef 54824007Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 54924007Ssam #else 55024007Ssam MMINOFF + 14 > m->m_off) { 55124007Ssam #endif 55224007Ssam m = m_get(M_DONTWAIT, MT_HEADER); 55324007Ssam if (m == 0) { 55424007Ssam error = ENOBUFS; 55524007Ssam goto bad; 55624007Ssam } 55724007Ssam m->m_next = m0; 55824007Ssam m->m_off = MMINOFF; 55924007Ssam #ifdef notdef 56024007Ssam m->m_len = sizeof (struct ether_header); 56124007Ssam #else 56224007Ssam m->m_len = 14; 56324007Ssam #endif 56424007Ssam } else { 56524007Ssam #ifdef notdef 56624007Ssam m->m_off -= sizeof (struct ether_header); 56724007Ssam m->m_len += sizeof (struct ether_header); 56824007Ssam #else 56924007Ssam m->m_off -= 14; 57024007Ssam m->m_len += 14; 57124007Ssam #endif 57224007Ssam } 57324007Ssam ace = mtod(m, struct ether_header *); 574*25694Ssam bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst)); 575*25694Ssam bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost, 576*25694Ssam sizeof (is->is_addr)); 57724007Ssam ace->ether_type = htons((u_short)type); 57824007Ssam 57924007Ssam /* 58024007Ssam * Queue message on interface, and start output if interface 58124007Ssam * not yet active. 58224007Ssam */ 58324007Ssam s = splimp(); 58424007Ssam if (IF_QFULL(&ifp->if_snd)) { 58524007Ssam IF_DROP(&ifp->if_snd); 58624007Ssam error = ENOBUFS; 58724007Ssam goto qfull; 58824007Ssam } 58924007Ssam IF_ENQUEUE(&ifp->if_snd, m); 59024007Ssam splx(s); 59124007Ssam aceStart(ifp->if_unit); 59224007Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 59324007Ssam qfull: 59424007Ssam m0 = m; 59524007Ssam splx(s); 59624007Ssam bad: 59724007Ssam m_freem(m0); 59824007Ssam if (mcopy) 59924007Ssam m_freem(mcopy); 60024007Ssam return (error); 60124007Ssam } 60224007Ssam 60324007Ssam aceStart(unit) 60424007Ssam int unit; 60524007Ssam { 60624007Ssam register struct ace_softc *is = &ace_softc[unit]; 60724007Ssam 60824007Ssam if (is->is_flags & ACEF_OACTIVE) 60924007Ssam return; 61024007Ssam is->is_flags |= ACEF_OACTIVE; 61124007Ssam acestart((dev_t)unit); 61224007Ssam is->is_flags &= ~ACEF_OACTIVE; 61324007Ssam } 61424007Ssam 61524007Ssam /* 61624007Ssam * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 61724007Ssam * If packet size is less than the minimum legal size, 61824007Ssam * the buffer is expanded. We probably should zero out the extra 61924007Ssam * bytes for security, but that would slow things down. 62024007Ssam */ 621*25694Ssam /*ARGSUSED*/ 62224007Ssam aceput(unit, txbuf, m) 62324007Ssam int unit; /* for statistics collection */ 624*25694Ssam char *txbuf; 62524007Ssam struct mbuf *m; 62624007Ssam { 62724007Ssam register u_char *bp, *mcp; /* known to be r12, r11 */ 62824007Ssam register short *s1, *s2; /* known to be r10, r9 */ 629*25694Ssam register u_int len; 63024007Ssam register struct mbuf *mp; 631*25694Ssam int total; 63224007Ssam 63324007Ssam total = 0; 634*25694Ssam bp = (u_char *)txbuf; 635*25694Ssam for (mp = m; (mp); mp = mp->m_next) { 63624007Ssam len = mp->m_len; 63724007Ssam if (len == 0) 63824007Ssam continue; 63924007Ssam total += len; 64024007Ssam mcp = mtod(mp, u_char *); 64124007Ssam if (((int)mcp & 01) && ((int)bp & 01)) { 64224007Ssam /* source & destination at odd addresses */ 643*25694Ssam movob(bp++, *mcp++); 64424007Ssam --len; 64524007Ssam } 64624007Ssam if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 647*25694Ssam register u_int l; 64824007Ssam 64924007Ssam s1 = (short *)bp; 65024007Ssam s2 = (short *)mcp; 65124007Ssam l = len >> 1; /* count # of shorts */ 652*25694Ssam while (l-- != 0) 653*25694Ssam movow(s1++, *s2++); 65424007Ssam len &= 1; /* # remaining bytes */ 65524007Ssam bp = (u_char *)s1; 65624007Ssam mcp = (u_char *)s2; 65724007Ssam } 658*25694Ssam while (len-- != 0) 659*25694Ssam movob(bp++, *mcp++); 66024007Ssam } 66124007Ssam m_freem(m); 66224007Ssam return (total); 66324007Ssam } 66424007Ssam 66524007Ssam /* 66624007Ssam * Routine to copy from VERSAbus memory into mbufs. 66724007Ssam * 66824007Ssam * Warning: This makes the fairly safe assumption that 66924007Ssam * mbufs have even lengths. 67024007Ssam */ 671*25694Ssam /*ARGSUSED*/ 67224007Ssam struct mbuf * 67324007Ssam aceget(unit, rxbuf, totlen, off0) 67424007Ssam int unit; /* for statistics collection */ 67524007Ssam u_char *rxbuf; 67624007Ssam int totlen, off0; 67724007Ssam { 67824007Ssam register u_char *cp, *mcp; /* known to be r12, r11 */ 67924007Ssam register int tlen; 68024007Ssam register struct mbuf *m; 68124007Ssam struct mbuf *top = 0, **mp = ⊤ 68224007Ssam int len, off = off0; 68324007Ssam 68424007Ssam #ifdef notdef 68524007Ssam cp = rxbuf + sizeof (struct ether_header); 68624007Ssam #else 68724007Ssam cp = rxbuf + 14; 68824007Ssam #endif 68924007Ssam while (totlen > 0) { 69024007Ssam MGET(m, M_DONTWAIT, MT_DATA); 69124007Ssam if (m == 0) 69224007Ssam goto bad; 69324007Ssam if (off) { 69424007Ssam len = totlen - off; 69524007Ssam #ifdef notdef 69624007Ssam cp = rxbuf + sizeof (struct ether_header) + off; 69724007Ssam #else 69824007Ssam cp = rxbuf + 14 + off; 69924007Ssam #endif 70024007Ssam } else 70124007Ssam len = totlen; 70224007Ssam if (len >= CLBYTES) { 70324007Ssam struct mbuf *p; 70424007Ssam 70524007Ssam MCLGET(p, 1); 70624007Ssam if (p != 0) { 70724007Ssam m->m_len = len = CLBYTES; 70824007Ssam m->m_off = (int)p - (int)m; 70924007Ssam } else { 71024007Ssam m->m_len = len = MIN(MLEN, len); 71124007Ssam m->m_off = MMINOFF; 71224007Ssam } 71324007Ssam } else { 71424007Ssam m->m_len = len = MIN(MLEN, len); 71524007Ssam m->m_off = MMINOFF; 71624007Ssam } 71724007Ssam mcp = mtod(m, u_char *); 71824007Ssam /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 71924007Ssam /*cp += len; mcp += len;*/ 72024007Ssam tlen = len; 72124007Ssam if (((int)mcp & 01) && ((int)cp & 01)) { 72224007Ssam /* source & destination at odd addresses */ 72324007Ssam *mcp++ = *cp++; 72424007Ssam --tlen; 72524007Ssam } 72624007Ssam if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 72724007Ssam register short *s1, *s2; 72824007Ssam register int l; 72924007Ssam 73024007Ssam s1 = (short *)mcp; 73124007Ssam s2 = (short *)cp; 73224007Ssam l = tlen >> 1; /* count # of shorts */ 73324007Ssam while (l-- > 0) /* copy shorts */ 73424007Ssam *s1++ = *s2++; 73524007Ssam tlen &= 1; /* # remaining bytes */ 73624007Ssam mcp = (u_char *)s1; 73724007Ssam cp = (u_char *)s2; 73824007Ssam } 73924007Ssam while (tlen-- > 0) 74024007Ssam *mcp++ = *cp++; 74124007Ssam *mp = m; 74224007Ssam mp = &m->m_next; 74324007Ssam if (off == 0) { 74424007Ssam totlen -= len; 74524007Ssam continue; 74624007Ssam } 74724007Ssam off += len; 74824007Ssam if (off == totlen) { 74924007Ssam #ifdef notdef 75024007Ssam cp = rxbuf + sizeof (struct ether_header); 75124007Ssam #else 75224007Ssam cp = rxbuf + 14; 75324007Ssam #endif 75424007Ssam off = 0; 75524007Ssam totlen = off0; 75624007Ssam } 75724007Ssam } 75824007Ssam return (top); 75924007Ssam bad: 76024007Ssam m_freem(top); 76124007Ssam return (0); 76224007Ssam } 76324007Ssam 76424007Ssam acebakoff(is, txseg, retries) 76524007Ssam struct ace_softc *is; 76624007Ssam struct tx_segment *txseg; 76724007Ssam register int retries; 76824007Ssam { 76924007Ssam register short *pBakNum, random_num; 77024007Ssam short *pMask; 77124007Ssam 77224007Ssam pMask = &random_mask_tbl[0]; 77324007Ssam pBakNum = &txseg->tx_backoff[0]; 77424007Ssam while (--retries >= 0) { 77524007Ssam random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 77624007Ssam random_num &= *pMask++; 77724007Ssam *pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC); 77824007Ssam } 77924007Ssam } 78024007Ssam 78124007Ssam /* 78224007Ssam * Process an ioctl request. 78324007Ssam */ 78424007Ssam aceioctl(ifp, cmd, data) 78524007Ssam register struct ifnet *ifp; 78624007Ssam int cmd; 78724007Ssam caddr_t data; 78824007Ssam { 789*25694Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 790*25694Ssam int s = splimp(), error = 0; 79124007Ssam 79224007Ssam switch (cmd) { 79324007Ssam 79424007Ssam case SIOCSIFADDR: 795*25694Ssam ifp->if_flags |= IFF_UP; 79624007Ssam aceinit(ifp->if_unit); 797*25694Ssam ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 798*25694Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 79924007Ssam break; 80024007Ssam 80124007Ssam #ifdef notdef 80224007Ssam case SIOCSETETADDR: { /* set Ethernet station address */ 80324007Ssam struct vba_device *ui; 80424007Ssam struct acedevice *addr; 80524007Ssam struct sockaddr_in *sin; 80624007Ssam 80724007Ssam ifp->if_flags &= ~IFF_RUNNING | IFF_UP; 80824007Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 80924007Ssam ui = aceinfo[ifp->if_unit]; 81024007Ssam addr = (struct acedevice *)ui->ui_addr; 811*25694Ssam movow(&addr->csr, CSR_RESET); 81224007Ssam DELAY(10000); 81324007Ssam /* set station address and copy addr to arp struct */ 81424007Ssam acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]); 81524007Ssam aceinit(ifp->if_unit); /* Re-initialize */ 81624007Ssam break; 81724007Ssam } 81824007Ssam #endif 81924007Ssam 82024007Ssam default: 82124007Ssam error = EINVAL; 82224007Ssam } 82324007Ssam splx(s); 82424007Ssam return (error); 82524007Ssam } 82624007Ssam 82724007Ssam aceclean(unit) 82824007Ssam int unit; 82924007Ssam { 83024007Ssam register struct ace_softc *is = &ace_softc[unit]; 83124007Ssam register struct vba_device *ui = aceinfo[unit]; 83224007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 833*25694Ssam register short i; 83424007Ssam register char *pData1; 83524007Ssam 83624007Ssam ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE); 83724007Ssam is->is_dpm = acemap[unit]; /* init dpm */ 83824007Ssam bzero((char *)is->is_dpm, 16384*2); 83924007Ssam 84024007Ssam is->is_currnd = 49123; 84124007Ssam is->is_segboundry = (addr->segb >> 11) & 0xf; 84224007Ssam pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11)); 84324007Ssam for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 84424007Ssam acebakoff(is, (struct tx_segment *)pData1, 15); 84524007Ssam pData1 += sizeof (struct tx_segment); 84624007Ssam } 84724007Ssam is->is_eictr = 0; 84824007Ssam is->is_eoctr = is->is_txnext = is->is_segboundry; 84924007Ssam bzero((char *)&is->is_stats, sizeof (is->is_stats)); 85024007Ssam } 85124007Ssam #endif 852