1*24007Ssam /* if_ace.c 1.1 85/07/21 */ 2*24007Ssam 3*24007Ssam /* 4*24007Ssam * ACC VERSAbus Ethernet controller 5*24007Ssam */ 6*24007Ssam #include "ace.h" 7*24007Ssam #if NACE > 0 8*24007Ssam 9*24007Ssam #include "../machine/pte.h" 10*24007Ssam 11*24007Ssam #include "../h/param.h" 12*24007Ssam #include "../h/systm.h" 13*24007Ssam #include "../h/mbuf.h" 14*24007Ssam #include "../h/buf.h" 15*24007Ssam #include "../h/protosw.h" 16*24007Ssam #include "../h/socket.h" 17*24007Ssam #include "../h/vmmac.h" 18*24007Ssam #include "../h/ioctl.h" 19*24007Ssam #include "../h/errno.h" 20*24007Ssam #include "../h/vmparam.h" 21*24007Ssam 22*24007Ssam #include "../net/if.h" 23*24007Ssam #include "../net/netisr.h" 24*24007Ssam #include "../net/route.h" 25*24007Ssam #include "../netinet/in.h" 26*24007Ssam #include "../netinet/in_systm.h" 27*24007Ssam #include "../netinet/ip.h" 28*24007Ssam #include "../netinet/ip_var.h" 29*24007Ssam #include "../netinet/if_ether.h" 30*24007Ssam #include "../netpup/pup.h" 31*24007Ssam 32*24007Ssam #include "../tahoe/mtpr.h" 33*24007Ssam #include "../tahoeif/if_acereg.h" 34*24007Ssam #include "../vba/vbavar.h" 35*24007Ssam 36*24007Ssam #define LONET 124 37*24007Ssam 38*24007Ssam /* 39*24007Ssam * Configuration table, for 2 units (should be defined by config) 40*24007Ssam */ 41*24007Ssam #define ACEVECTOR 0x90 42*24007Ssam long acestd[] = { 0x0ff0000, 0xff0100 }; /* controller */ 43*24007Ssam 44*24007Ssam extern char ace0utl[], ace1utl[]; /* dpm */ 45*24007Ssam char *acemap[]= { ace0utl, ace1utl }; 46*24007Ssam extern long ACE0map[], ACE1map[]; 47*24007Ssam long *ACEmap[] = { ACE0map, ACE1map }; 48*24007Ssam long ACEmapa[] = { 0xfff80000, 0xfff90000 }; 49*24007Ssam 50*24007Ssam /* station address */ 51*24007Ssam char ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 }; 52*24007Ssam /* multicast hash table initializer */ 53*24007Ssam char ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF }; 54*24007Ssam /* backoff table masks */ 55*24007Ssam short random_mask_tbl[16] = { 56*24007Ssam 0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0, 57*24007Ssam 0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0 58*24007Ssam }; 59*24007Ssam 60*24007Ssam int aceprobe(), aceattach(), acerint(), acecint(); 61*24007Ssam struct vba_device *aceinfo[NACE]; 62*24007Ssam struct vba_driver acedriver = 63*24007Ssam { aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 }; 64*24007Ssam 65*24007Ssam #define ACEUNIT(x) minor(x) 66*24007Ssam 67*24007Ssam int aceinit(), aceoutput(), aceioctl(), acereset(); 68*24007Ssam struct mbuf *aceget(); 69*24007Ssam 70*24007Ssam /* 71*24007Ssam * Ethernet software status per interface. 72*24007Ssam * 73*24007Ssam * Each interface is referenced by a network interface structure, 74*24007Ssam * is_if, which the routing code uses to locate the interface. 75*24007Ssam * This structure contains the output queue for the interface, its address, ... 76*24007Ssam */ 77*24007Ssam struct ace_softc { 78*24007Ssam struct arpcom is_ac; /* Ethernet common part */ 79*24007Ssam #define is_if is_ac.ac_if /* network-visible interface */ 80*24007Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 81*24007Ssam char *is_dpm; 82*24007Ssam short is_flags; 83*24007Ssam #define ACEF_OACTIVE 0x1 /* output is active */ 84*24007Ssam #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 85*24007Ssam short is_promiscuous; /* true is enabled */ 86*24007Ssam short is_segboundry; /* first TX Seg in dpm */ 87*24007Ssam short is_eictr; /* Rx segment tracking ctr */ 88*24007Ssam short is_eoctr; /* Tx segment tracking ctr */ 89*24007Ssam short is_txnext; /* Next available Tx segment */ 90*24007Ssam short is_currnd; /* current random backoff */ 91*24007Ssam struct ace_stats is_stats; /* holds board statistics */ 92*24007Ssam short is_xcnt; /* count xmitted segments to be acked 93*24007Ssam by the controller */ 94*24007Ssam } ace_softc[NACE]; 95*24007Ssam extern struct ifnet loif; 96*24007Ssam 97*24007Ssam aceprobe(reg) 98*24007Ssam caddr_t reg; 99*24007Ssam { 100*24007Ssam register struct acedevice *addr = (struct acedevice *)reg; 101*24007Ssam 102*24007Ssam #ifdef lint 103*24007Ssam acerint(0); acecint(0); 104*24007Ssam #endif 105*24007Ssam if (badaddr(reg, 2)) 106*24007Ssam return(0); 107*24007Ssam movew((short)CSR_RESET, &addr->csr); 108*24007Ssam DELAY(10000); 109*24007Ssam return (sizeof (struct acedevice)); 110*24007Ssam } 111*24007Ssam 112*24007Ssam /* 113*24007Ssam * Interface exists: make available by filling in network interface 114*24007Ssam * record. System will initialize the interface when it is ready 115*24007Ssam * to accept packets. 116*24007Ssam */ 117*24007Ssam aceattach(ui) 118*24007Ssam struct vba_device *ui; 119*24007Ssam { 120*24007Ssam register short unit = ui->ui_unit; 121*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 122*24007Ssam register struct ifnet *ifp = &is->is_if; 123*24007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 124*24007Ssam register short *wp, i; 125*24007Ssam struct sockaddr_in *sin; 126*24007Ssam 127*24007Ssam ifp->if_unit = unit; 128*24007Ssam ifp->if_name = "ace"; 129*24007Ssam ifp->if_mtu = ETHERMTU; 130*24007Ssam /* 131*24007Ssam * Set station's addresses, multicast 132*24007Ssam * hash table, and initialize dual ported memory. 133*24007Ssam */ 134*24007Ssam ace_station[5] = ~(unit + 1); 135*24007Ssam acesetetaddr(unit, addr, ace_station); 136*24007Ssam is->is_promiscuous = 0; 137*24007Ssam wp = (short *)addr->hash; 138*24007Ssam for (i = 0; i < 8; i++) 139*24007Ssam movew((short)ace_hash[i], wp++); 140*24007Ssam movew((short)~0xffff, &addr->bcastena[0]); 141*24007Ssam movew((short)~0xffff, &addr->bcastena[1]); 142*24007Ssam aceclean(unit); 143*24007Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 144*24007Ssam sin->sin_family = AF_INET; 145*24007Ssam ifp->if_init = aceinit; 146*24007Ssam ifp->if_output = aceoutput; 147*24007Ssam ifp->if_ioctl = aceioctl; 148*24007Ssam ifp->if_reset = acereset; 149*24007Ssam if_attach(ifp); 150*24007Ssam } 151*24007Ssam 152*24007Ssam acesetetaddr(unit, addr, station_addr) 153*24007Ssam short unit; 154*24007Ssam struct acedevice *addr; 155*24007Ssam char *station_addr; 156*24007Ssam { 157*24007Ssam register short *wp, i; 158*24007Ssam register char *cp; 159*24007Ssam struct ace_softc *is = &ace_softc[unit]; 160*24007Ssam 161*24007Ssam wp = (short *)addr->station; 162*24007Ssam cp = station_addr; 163*24007Ssam for (i = 0; i < 6; i++) 164*24007Ssam movew((short)*cp++, wp++); 165*24007Ssam wp = (short *)addr->station; 166*24007Ssam cp = (char *)&is->is_addr; 167*24007Ssam for (i = 0; i < 6; i++) 168*24007Ssam *cp++ = ~(*wp++); 169*24007Ssam } 170*24007Ssam 171*24007Ssam /* 172*24007Ssam * Reset of interface after "system" reset. 173*24007Ssam */ 174*24007Ssam acereset(unit, vban) 175*24007Ssam int unit, vban; 176*24007Ssam { 177*24007Ssam register struct vba_device *ui; 178*24007Ssam 179*24007Ssam if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 180*24007Ssam ui->ui_vbanum != vban) 181*24007Ssam return; 182*24007Ssam printf(" ace%d", unit); 183*24007Ssam aceinit(unit); 184*24007Ssam } 185*24007Ssam 186*24007Ssam /* 187*24007Ssam * Initialization of interface; clear recorded pending operations 188*24007Ssam */ 189*24007Ssam aceinit(unit) 190*24007Ssam int unit; 191*24007Ssam { 192*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 193*24007Ssam register struct vba_device *ui = aceinfo[unit]; 194*24007Ssam register struct acedevice *addr; 195*24007Ssam register struct ifnet *ifp = &is->is_if; 196*24007Ssam register struct sockaddr_in *sin; 197*24007Ssam register short Csr; 198*24007Ssam register int i, s; 199*24007Ssam 200*24007Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 201*24007Ssam if (sin->sin_addr.s_addr == 0) /* address still unknown */ 202*24007Ssam return; 203*24007Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 204*24007Ssam /* 205*24007Ssam * Reset the controller, initialize the recieve buffers, 206*24007Ssam * and turn the controller on again and set board online. 207*24007Ssam */ 208*24007Ssam addr = (struct acedevice *)ui->ui_addr; 209*24007Ssam s = splimp(); 210*24007Ssam movew((short)CSR_RESET, &addr->csr); 211*24007Ssam DELAY(10000); 212*24007Ssam 213*24007Ssam /* 214*24007Ssam * clean up dpm since the controller might 215*24007Ssam * jumble dpm after reset 216*24007Ssam */ 217*24007Ssam aceclean(unit); 218*24007Ssam movew((short)CSR_GO, &addr->csr); 219*24007Ssam Csr = addr->csr; 220*24007Ssam if (Csr & CSR_ACTIVE) { 221*24007Ssam movew((short)(ACEVECTOR + unit*8), &addr->ivct); 222*24007Ssam Csr |= CSR_IENA | is->is_promiscuous; 223*24007Ssam if (ifp->if_net == LONET) 224*24007Ssam Csr |= CSR_LOOP3; 225*24007Ssam movew(Csr, &addr->csr); 226*24007Ssam is->is_flags = 0; 227*24007Ssam is->is_xcnt = 0; 228*24007Ssam is->is_if.if_flags |= IFF_UP|IFF_RUNNING; 229*24007Ssam } 230*24007Ssam splx(s); 231*24007Ssam } 232*24007Ssam 233*24007Ssam if (is->is_if.if_flags & IFF_UP) { 234*24007Ssam if_rtinit(&is->is_if, RTF_UP); 235*24007Ssam aceStart(unit); 236*24007Ssam } 237*24007Ssam arpwhohas(&is->is_ac, &sin->sin_addr); 238*24007Ssam } 239*24007Ssam 240*24007Ssam /* 241*24007Ssam * Start output on interface. 242*24007Ssam * Get another datagram to send off of the interface queue, 243*24007Ssam * and map it to the interface before starting the output. 244*24007Ssam * 245*24007Ssam */ 246*24007Ssam acestart(dev) 247*24007Ssam dev_t dev; 248*24007Ssam { 249*24007Ssam register struct tx_segment *txs; 250*24007Ssam register long len, x; 251*24007Ssam int unit = ACEUNIT(dev); 252*24007Ssam struct vba_device *ui = aceinfo[unit]; 253*24007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 254*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 255*24007Ssam struct mbuf *m; 256*24007Ssam short retries, idx; 257*24007Ssam 258*24007Ssam again: 259*24007Ssam txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 260*24007Ssam if (txs->tx_csr & TCS_TBFULL) { 261*24007Ssam is->is_stats.tx_busy++; 262*24007Ssam return; 263*24007Ssam } 264*24007Ssam x = splimp(); 265*24007Ssam IF_DEQUEUE(&is->is_if.if_snd, m); 266*24007Ssam splx(x); 267*24007Ssam if (m == 0) 268*24007Ssam return; 269*24007Ssam len = aceput(unit, txs->tx_data, m); 270*24007Ssam retries = txs->tx_csr & TCS_RTC; 271*24007Ssam if (retries > 0) 272*24007Ssam acebakoff(is, txs, retries); 273*24007Ssam 274*24007Ssam /* 275*24007Ssam * Ensure minimum packet length. 276*24007Ssam * This makes the safe assumtion that there are no virtual holes 277*24007Ssam * after the data. 278*24007Ssam * For security, it might be wise to zero out the added bytes, 279*24007Ssam * but we're mainly interested in speed at the moment. 280*24007Ssam */ 281*24007Ssam #ifdef notdef 282*24007Ssam if (len - sizeof (struct ether_header) < ETHERMIN) 283*24007Ssam len = ETHERMIN + sizeof (struct ether_header); 284*24007Ssam #else 285*24007Ssam if (len - 14 < ETHERMIN) 286*24007Ssam len = ETHERMIN + 14; 287*24007Ssam #endif 288*24007Ssam if (++is->is_txnext > SEG_MAX) 289*24007Ssam is->is_txnext = is->is_segboundry; 290*24007Ssam is->is_if.if_opackets++; 291*24007Ssam is->is_xcnt++; 292*24007Ssam len = (len & 0x7fff) | TCS_TBFULL; 293*24007Ssam movew((short)len, txs); 294*24007Ssam goto again; 295*24007Ssam } 296*24007Ssam 297*24007Ssam /* 298*24007Ssam * Transmit done interrupt. 299*24007Ssam */ 300*24007Ssam acecint(unit) 301*24007Ssam int unit; 302*24007Ssam { 303*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 304*24007Ssam struct vba_device *ui = aceinfo[unit]; 305*24007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 306*24007Ssam register struct tx_segment *txseg; 307*24007Ssam short txidx, eostat; 308*24007Ssam 309*24007Ssam if (is->is_xcnt <= 0) { 310*24007Ssam txidx = (addr->tseg >> 11) & 0xf; 311*24007Ssam printf("ace%d: stray xmit interrupt, xcnt %d\n", 312*24007Ssam unit, is->is_xcnt); 313*24007Ssam is->is_xcnt = 0; 314*24007Ssam aceStart(unit); 315*24007Ssam return; 316*24007Ssam } 317*24007Ssam is->is_xcnt--; 318*24007Ssam txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 319*24007Ssam eostat = txseg->tx_csr; 320*24007Ssam if ((eostat & TCS_TBFULL) == 0) { 321*24007Ssam is->is_stats.tx_retries += eostat & TCS_RTC; 322*24007Ssam if (eostat & TCS_RTFAIL) { 323*24007Ssam is->is_stats.tx_discarded++; 324*24007Ssam is->is_if.if_oerrors++; 325*24007Ssam } else 326*24007Ssam is->is_stats.tx_datagrams++; 327*24007Ssam if (++is->is_eoctr >= 16) 328*24007Ssam is->is_eoctr = is->is_segboundry; 329*24007Ssam } 330*24007Ssam aceStart(unit); 331*24007Ssam } 332*24007Ssam 333*24007Ssam /* 334*24007Ssam * Ethernet interface receiver interrupt. 335*24007Ssam * If input error just drop packet. 336*24007Ssam * Otherwise purge input buffered data path and examine 337*24007Ssam * packet to determine type. If can't determine length 338*24007Ssam * from type, then have to drop packet. Othewise decapsulate 339*24007Ssam * packet based on type and pass to type specific higher-level 340*24007Ssam * input routine. 341*24007Ssam */ 342*24007Ssam acerint(unit) 343*24007Ssam int unit; 344*24007Ssam { 345*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 346*24007Ssam register struct ifqueue *inq; 347*24007Ssam register struct ether_header *ace; 348*24007Ssam register struct rx_segment *rxseg; 349*24007Ssam struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr; 350*24007Ssam int len, s, off, resid; 351*24007Ssam struct mbuf *m; 352*24007Ssam short eistat; 353*24007Ssam 354*24007Ssam again: 355*24007Ssam rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 356*24007Ssam eistat = rxseg->rx_csr; 357*24007Ssam if ((eistat & RCS_RBFULL) == 0) 358*24007Ssam return; 359*24007Ssam is->is_if.if_ipackets++; 360*24007Ssam if (++is->is_eictr >= is->is_segboundry) 361*24007Ssam is->is_eictr = 0; 362*24007Ssam len = eistat & RCS_RBC; 363*24007Ssam if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 364*24007Ssam len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 365*24007Ssam if (eistat & RCS_ROVRN) 366*24007Ssam is->is_stats.rx_overruns++; 367*24007Ssam if (eistat & RCS_RCRC) 368*24007Ssam is->is_stats.rx_crc_errors++; 369*24007Ssam if (eistat & RCS_RODD) 370*24007Ssam is->is_stats.rx_align_errors++; 371*24007Ssam if (len < ET_MINLEN) 372*24007Ssam is->is_stats.rx_underruns++; 373*24007Ssam if (len > ET_MAXLEN+CRC_SIZE) 374*24007Ssam is->is_stats.rx_overruns++; 375*24007Ssam is->is_if.if_ierrors++; 376*24007Ssam rxseg->rx_csr = 0; 377*24007Ssam return; 378*24007Ssam } else 379*24007Ssam is->is_stats.rx_datagrams++; 380*24007Ssam ace = (struct ether_header *)rxseg->rx_data; 381*24007Ssam #ifdef notdef 382*24007Ssam len -= sizeof (struct ether_header); 383*24007Ssam #else 384*24007Ssam len -= 14; 385*24007Ssam #endif 386*24007Ssam /* 387*24007Ssam * Deal with trailer protocol: if type is PUP trailer 388*24007Ssam * get true type from first 16-bit word past data. 389*24007Ssam * Remember that type was trailer by setting off. 390*24007Ssam */ 391*24007Ssam ace->ether_type = ntohs((u_short)ace->ether_type); 392*24007Ssam #ifdef notdef 393*24007Ssam #define acedataaddr(ace, off, type) \ 394*24007Ssam ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 395*24007Ssam #else 396*24007Ssam #define acedataaddr(ace, off, type) \ 397*24007Ssam ((type)(((caddr_t)(((char *)ace)+14)+(off)))) 398*24007Ssam #endif 399*24007Ssam if (ace->ether_type >= ETHERPUP_TRAIL && 400*24007Ssam ace->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) { 401*24007Ssam off = (ace->ether_type - ETHERPUP_TRAIL) * 512; 402*24007Ssam if (off >= ETHERMTU) 403*24007Ssam goto setup; /* sanity */ 404*24007Ssam ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 405*24007Ssam resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 406*24007Ssam if (off + resid > len) 407*24007Ssam goto setup; /* sanity */ 408*24007Ssam len = off + resid; 409*24007Ssam } else 410*24007Ssam off = 0; 411*24007Ssam if (len == 0) 412*24007Ssam goto setup; 413*24007Ssam 414*24007Ssam /* 415*24007Ssam * Pull packet off interface. Off is nonzero if packet 416*24007Ssam * has trailing header; aceget will then force this header 417*24007Ssam * information to be at the front, but we still have to drop 418*24007Ssam * the type and length which are at the front of any trailer data. 419*24007Ssam */ 420*24007Ssam m = aceget(unit, rxseg->rx_data, len, off); 421*24007Ssam if (m == 0) 422*24007Ssam goto setup; 423*24007Ssam if (off) { 424*24007Ssam m->m_off += 2 * sizeof (u_short); 425*24007Ssam m->m_len -= 2 * sizeof (u_short); 426*24007Ssam } 427*24007Ssam switch (ace->ether_type) { 428*24007Ssam 429*24007Ssam #ifdef INET 430*24007Ssam case ETHERPUP_IPTYPE: 431*24007Ssam schednetisr(NETISR_IP); 432*24007Ssam inq = &ipintrq; 433*24007Ssam break; 434*24007Ssam 435*24007Ssam case ETHERPUP_ARPTYPE: 436*24007Ssam arpinput(&is->is_ac, m); 437*24007Ssam goto setup; 438*24007Ssam #endif 439*24007Ssam default: 440*24007Ssam m_freem(m); 441*24007Ssam goto setup; 442*24007Ssam } 443*24007Ssam if (IF_QFULL(inq)) { 444*24007Ssam IF_DROP(inq); 445*24007Ssam m_freem(m); 446*24007Ssam goto setup; 447*24007Ssam } 448*24007Ssam s = splimp(); 449*24007Ssam IF_ENQUEUE(inq, m); 450*24007Ssam splx(s); 451*24007Ssam setup: 452*24007Ssam rxseg->rx_csr = 0; 453*24007Ssam goto again; 454*24007Ssam } 455*24007Ssam 456*24007Ssam /* 457*24007Ssam * Ethernet output routine. 458*24007Ssam * Encapsulate a packet of type family for the local net. 459*24007Ssam * Use trailer local net encapsulation if enough data in first 460*24007Ssam * packet leaves a multiple of 512 bytes of data in remainder. 461*24007Ssam */ 462*24007Ssam aceoutput(ifp, m0, dst) 463*24007Ssam struct ifnet *ifp; 464*24007Ssam struct mbuf *m0; 465*24007Ssam struct sockaddr *dst; 466*24007Ssam { 467*24007Ssam register struct ace_softc *is = &ace_softc[ifp->if_unit]; 468*24007Ssam register struct mbuf *m = m0; 469*24007Ssam register struct ether_header *ace; 470*24007Ssam register int off; 471*24007Ssam struct mbuf *mcopy = (struct mbuf *)0; 472*24007Ssam int type, s, error; 473*24007Ssam struct ether_addr edst; 474*24007Ssam struct in_addr idst; 475*24007Ssam 476*24007Ssam switch (dst->sa_family) { 477*24007Ssam 478*24007Ssam #ifdef INET 479*24007Ssam case AF_INET: 480*24007Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 481*24007Ssam if (!arpresolve(&is->is_ac, m, &idst, &edst)) 482*24007Ssam return (0); /* if not yet resolved */ 483*24007Ssam if (in_lnaof(idst) == INADDR_ANY) 484*24007Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 485*24007Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 486*24007Ssam /* need per host negotiation */ 487*24007Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 && 488*24007Ssam (off & 0x1ff) == 0 && 489*24007Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 490*24007Ssam type = ETHERPUP_TRAIL + (off>>9); 491*24007Ssam m->m_off -= 2 * sizeof (u_short); 492*24007Ssam m->m_len += 2 * sizeof (u_short); 493*24007Ssam *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE); 494*24007Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 495*24007Ssam goto gottrailertype; 496*24007Ssam } 497*24007Ssam type = ETHERPUP_IPTYPE; 498*24007Ssam off = 0; 499*24007Ssam goto gottype; 500*24007Ssam #endif 501*24007Ssam 502*24007Ssam case AF_UNSPEC: 503*24007Ssam ace = (struct ether_header *)dst->sa_data; 504*24007Ssam #ifdef notdef 505*24007Ssam edst = ace->ether_dhost; 506*24007Ssam #else 507*24007Ssam bcopy((caddr_t)ace->ether_dhost, (caddr_t)&edst, 6); 508*24007Ssam #endif 509*24007Ssam type = ace->ether_type; 510*24007Ssam goto gottype; 511*24007Ssam 512*24007Ssam default: 513*24007Ssam printf("ace%d: can't handle af%d\n", 514*24007Ssam ifp->if_unit, dst->sa_family); 515*24007Ssam error = EAFNOSUPPORT; 516*24007Ssam goto bad; 517*24007Ssam } 518*24007Ssam 519*24007Ssam gottrailertype: 520*24007Ssam /* 521*24007Ssam * Packet to be sent as trailer: move first packet 522*24007Ssam * (control information) to end of chain. 523*24007Ssam */ 524*24007Ssam while (m->m_next) 525*24007Ssam m = m->m_next; 526*24007Ssam m->m_next = m0; 527*24007Ssam m = m0->m_next; 528*24007Ssam m0->m_next = 0; 529*24007Ssam m0 = m; 530*24007Ssam 531*24007Ssam gottype: 532*24007Ssam /* 533*24007Ssam * Add local net header. If no space in first mbuf, 534*24007Ssam * allocate another. 535*24007Ssam */ 536*24007Ssam if (m->m_off > MMAXOFF || 537*24007Ssam #ifdef notdef 538*24007Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 539*24007Ssam #else 540*24007Ssam MMINOFF + 14 > m->m_off) { 541*24007Ssam #endif 542*24007Ssam m = m_get(M_DONTWAIT, MT_HEADER); 543*24007Ssam if (m == 0) { 544*24007Ssam error = ENOBUFS; 545*24007Ssam goto bad; 546*24007Ssam } 547*24007Ssam m->m_next = m0; 548*24007Ssam m->m_off = MMINOFF; 549*24007Ssam #ifdef notdef 550*24007Ssam m->m_len = sizeof (struct ether_header); 551*24007Ssam #else 552*24007Ssam m->m_len = 14; 553*24007Ssam #endif 554*24007Ssam } else { 555*24007Ssam #ifdef notdef 556*24007Ssam m->m_off -= sizeof (struct ether_header); 557*24007Ssam m->m_len += sizeof (struct ether_header); 558*24007Ssam #else 559*24007Ssam m->m_off -= 14; 560*24007Ssam m->m_len += 14; 561*24007Ssam #endif 562*24007Ssam } 563*24007Ssam ace = mtod(m, struct ether_header *); 564*24007Ssam #ifdef notdef 565*24007Ssam ace->ether_dhost = edst; 566*24007Ssam ace->ether_shost = is->is_addr; 567*24007Ssam #else 568*24007Ssam bcopy((caddr_t)&edst, (caddr_t)ace->ether_dhost, 6); 569*24007Ssam bcopy((caddr_t)&is->is_addr, (caddr_t)ace->ether_shost, 6); 570*24007Ssam #endif 571*24007Ssam ace->ether_type = htons((u_short)type); 572*24007Ssam 573*24007Ssam /* 574*24007Ssam * Queue message on interface, and start output if interface 575*24007Ssam * not yet active. 576*24007Ssam */ 577*24007Ssam s = splimp(); 578*24007Ssam if (IF_QFULL(&ifp->if_snd)) { 579*24007Ssam IF_DROP(&ifp->if_snd); 580*24007Ssam error = ENOBUFS; 581*24007Ssam goto qfull; 582*24007Ssam } 583*24007Ssam IF_ENQUEUE(&ifp->if_snd, m); 584*24007Ssam splx(s); 585*24007Ssam aceStart(ifp->if_unit); 586*24007Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 587*24007Ssam qfull: 588*24007Ssam m0 = m; 589*24007Ssam splx(s); 590*24007Ssam bad: 591*24007Ssam m_freem(m0); 592*24007Ssam if (mcopy) 593*24007Ssam m_freem(mcopy); 594*24007Ssam return (error); 595*24007Ssam } 596*24007Ssam 597*24007Ssam aceStart(unit) 598*24007Ssam int unit; 599*24007Ssam { 600*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 601*24007Ssam 602*24007Ssam if (is->is_flags & ACEF_OACTIVE) 603*24007Ssam return; 604*24007Ssam is->is_flags |= ACEF_OACTIVE; 605*24007Ssam acestart((dev_t)unit); 606*24007Ssam is->is_flags &= ~ACEF_OACTIVE; 607*24007Ssam } 608*24007Ssam 609*24007Ssam /* 610*24007Ssam * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 611*24007Ssam * If packet size is less than the minimum legal size, 612*24007Ssam * the buffer is expanded. We probably should zero out the extra 613*24007Ssam * bytes for security, but that would slow things down. 614*24007Ssam */ 615*24007Ssam aceput(unit, txbuf, m) 616*24007Ssam int unit; /* for statistics collection */ 617*24007Ssam u_char *txbuf; 618*24007Ssam struct mbuf *m; 619*24007Ssam { 620*24007Ssam register u_char *bp, *mcp; /* known to be r12, r11 */ 621*24007Ssam register short *s1, *s2; /* known to be r10, r9 */ 622*24007Ssam register unsigned len; 623*24007Ssam register struct mbuf *mp; 624*24007Ssam int total, idx; 625*24007Ssam 626*24007Ssam total = 0; 627*24007Ssam bp = txbuf; 628*24007Ssam for (mp = m;(mp); mp = mp->m_next) { 629*24007Ssam len = mp->m_len; 630*24007Ssam if (len == 0) 631*24007Ssam continue; 632*24007Ssam total += len; 633*24007Ssam mcp = mtod(mp, u_char *); 634*24007Ssam if (((int)mcp & 01) && ((int)bp & 01)) { 635*24007Ssam /* source & destination at odd addresses */ 636*24007Ssam /* *bp++ = *mcp++; */ 637*24007Ssam asm("movob (r11),(r12)"); 638*24007Ssam bp++, mcp++; 639*24007Ssam --len; 640*24007Ssam } 641*24007Ssam if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 642*24007Ssam register int l; 643*24007Ssam 644*24007Ssam s1 = (short *)bp; 645*24007Ssam s2 = (short *)mcp; 646*24007Ssam l = len >> 1; /* count # of shorts */ 647*24007Ssam while (l-- > 0) { 648*24007Ssam /* *s1++ = *s2++; */ 649*24007Ssam asm("movow (r9),(r10)"); 650*24007Ssam s1++, s2++; 651*24007Ssam } 652*24007Ssam len &= 1; /* # remaining bytes */ 653*24007Ssam bp = (u_char *)s1; 654*24007Ssam mcp = (u_char *)s2; 655*24007Ssam } 656*24007Ssam while (len-- > 0) { 657*24007Ssam /* *bp++ = *mcp++; */ 658*24007Ssam asm("movob (r11),(r12)"); 659*24007Ssam bp++, mcp++; 660*24007Ssam } 661*24007Ssam } 662*24007Ssam m_freem(m); 663*24007Ssam return (total); 664*24007Ssam } 665*24007Ssam 666*24007Ssam movew(data, to) 667*24007Ssam short data, *to; 668*24007Ssam { 669*24007Ssam 670*24007Ssam asm("movow 6(fp),*8(fp)"); 671*24007Ssam } 672*24007Ssam 673*24007Ssam /* 674*24007Ssam * Routine to copy from VERSAbus memory into mbufs. 675*24007Ssam * 676*24007Ssam * Warning: This makes the fairly safe assumption that 677*24007Ssam * mbufs have even lengths. 678*24007Ssam */ 679*24007Ssam struct mbuf * 680*24007Ssam aceget(unit, rxbuf, totlen, off0) 681*24007Ssam int unit; /* for statistics collection */ 682*24007Ssam u_char *rxbuf; 683*24007Ssam int totlen, off0; 684*24007Ssam { 685*24007Ssam register u_char *cp, *mcp; /* known to be r12, r11 */ 686*24007Ssam register int tlen; 687*24007Ssam register struct mbuf *m; 688*24007Ssam struct mbuf *top = 0, **mp = ⊤ 689*24007Ssam int len, off = off0; 690*24007Ssam 691*24007Ssam #ifdef notdef 692*24007Ssam cp = rxbuf + sizeof (struct ether_header); 693*24007Ssam #else 694*24007Ssam cp = rxbuf + 14; 695*24007Ssam #endif 696*24007Ssam while (totlen > 0) { 697*24007Ssam register int words; 698*24007Ssam 699*24007Ssam MGET(m, M_DONTWAIT, MT_DATA); 700*24007Ssam if (m == 0) 701*24007Ssam goto bad; 702*24007Ssam if (off) { 703*24007Ssam len = totlen - off; 704*24007Ssam #ifdef notdef 705*24007Ssam cp = rxbuf + sizeof (struct ether_header) + off; 706*24007Ssam #else 707*24007Ssam cp = rxbuf + 14 + off; 708*24007Ssam #endif 709*24007Ssam } else 710*24007Ssam len = totlen; 711*24007Ssam if (len >= CLBYTES) { 712*24007Ssam struct mbuf *p; 713*24007Ssam 714*24007Ssam MCLGET(p, 1); 715*24007Ssam if (p != 0) { 716*24007Ssam m->m_len = len = CLBYTES; 717*24007Ssam m->m_off = (int)p - (int)m; 718*24007Ssam } else { 719*24007Ssam m->m_len = len = MIN(MLEN, len); 720*24007Ssam m->m_off = MMINOFF; 721*24007Ssam } 722*24007Ssam } else { 723*24007Ssam m->m_len = len = MIN(MLEN, len); 724*24007Ssam m->m_off = MMINOFF; 725*24007Ssam } 726*24007Ssam mcp = mtod(m, u_char *); 727*24007Ssam /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 728*24007Ssam /*cp += len; mcp += len;*/ 729*24007Ssam tlen = len; 730*24007Ssam if (((int)mcp & 01) && ((int)cp & 01)) { 731*24007Ssam /* source & destination at odd addresses */ 732*24007Ssam *mcp++ = *cp++; 733*24007Ssam --tlen; 734*24007Ssam } 735*24007Ssam if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 736*24007Ssam register short *s1, *s2; 737*24007Ssam register int l; 738*24007Ssam 739*24007Ssam s1 = (short *)mcp; 740*24007Ssam s2 = (short *)cp; 741*24007Ssam l = tlen >> 1; /* count # of shorts */ 742*24007Ssam while (l-- > 0) /* copy shorts */ 743*24007Ssam *s1++ = *s2++; 744*24007Ssam tlen &= 1; /* # remaining bytes */ 745*24007Ssam mcp = (u_char *)s1; 746*24007Ssam cp = (u_char *)s2; 747*24007Ssam } 748*24007Ssam while (tlen-- > 0) 749*24007Ssam *mcp++ = *cp++; 750*24007Ssam *mp = m; 751*24007Ssam mp = &m->m_next; 752*24007Ssam if (off == 0) { 753*24007Ssam totlen -= len; 754*24007Ssam continue; 755*24007Ssam } 756*24007Ssam off += len; 757*24007Ssam if (off == totlen) { 758*24007Ssam #ifdef notdef 759*24007Ssam cp = rxbuf + sizeof (struct ether_header); 760*24007Ssam #else 761*24007Ssam cp = rxbuf + 14; 762*24007Ssam #endif 763*24007Ssam off = 0; 764*24007Ssam totlen = off0; 765*24007Ssam } 766*24007Ssam } 767*24007Ssam return (top); 768*24007Ssam bad: 769*24007Ssam m_freem(top); 770*24007Ssam return (0); 771*24007Ssam } 772*24007Ssam 773*24007Ssam acebakoff(is, txseg, retries) 774*24007Ssam struct ace_softc *is; 775*24007Ssam struct tx_segment *txseg; 776*24007Ssam register int retries; 777*24007Ssam { 778*24007Ssam register short *pBakNum, random_num; 779*24007Ssam short *pMask; 780*24007Ssam 781*24007Ssam pMask = &random_mask_tbl[0]; 782*24007Ssam pBakNum = &txseg->tx_backoff[0]; 783*24007Ssam while (--retries >= 0) { 784*24007Ssam random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 785*24007Ssam random_num &= *pMask++; 786*24007Ssam *pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC); 787*24007Ssam } 788*24007Ssam } 789*24007Ssam 790*24007Ssam /* 791*24007Ssam * Process an ioctl request. 792*24007Ssam */ 793*24007Ssam aceioctl(ifp, cmd, data) 794*24007Ssam register struct ifnet *ifp; 795*24007Ssam int cmd; 796*24007Ssam caddr_t data; 797*24007Ssam { 798*24007Ssam register struct ifreq *ifr = (struct ifreq *)data; 799*24007Ssam int s, error = 0; 800*24007Ssam 801*24007Ssam s = splimp(); 802*24007Ssam switch (cmd) { 803*24007Ssam 804*24007Ssam case SIOCSIFADDR: 805*24007Ssam if (ifp->if_flags & IFF_RUNNING) 806*24007Ssam if_rtinit(ifp, -1); /* delete previous route */ 807*24007Ssam acesetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 808*24007Ssam aceinit(ifp->if_unit); 809*24007Ssam break; 810*24007Ssam 811*24007Ssam #ifdef notdef 812*24007Ssam case SIOCSETETADDR: { /* set Ethernet station address */ 813*24007Ssam struct vba_device *ui; 814*24007Ssam struct acedevice *addr; 815*24007Ssam struct sockaddr_in *sin; 816*24007Ssam 817*24007Ssam ifp->if_flags &= ~IFF_RUNNING | IFF_UP; 818*24007Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 819*24007Ssam ui = aceinfo[ifp->if_unit]; 820*24007Ssam addr = (struct acedevice *)ui->ui_addr; 821*24007Ssam movew((short)CSR_RESET, &addr->csr); 822*24007Ssam DELAY(10000); 823*24007Ssam /* set station address and copy addr to arp struct */ 824*24007Ssam acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]); 825*24007Ssam aceinit(ifp->if_unit); /* Re-initialize */ 826*24007Ssam break; 827*24007Ssam } 828*24007Ssam #endif 829*24007Ssam 830*24007Ssam default: 831*24007Ssam error = EINVAL; 832*24007Ssam } 833*24007Ssam splx(s); 834*24007Ssam return (error); 835*24007Ssam } 836*24007Ssam 837*24007Ssam acesetaddr(ifp, sin) 838*24007Ssam register struct ifnet *ifp; 839*24007Ssam register struct sockaddr_in *sin; 840*24007Ssam { 841*24007Ssam 842*24007Ssam ifp->if_addr = *(struct sockaddr *)sin; 843*24007Ssam ifp->if_net = in_netof(sin->sin_addr); 844*24007Ssam ifp->if_host[0] = in_lnaof(sin->sin_addr); 845*24007Ssam sin = (struct sockaddr_in *)&ifp->if_broadaddr; 846*24007Ssam sin->sin_family = AF_INET; 847*24007Ssam sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 848*24007Ssam ifp->if_flags |= IFF_BROADCAST; 849*24007Ssam } 850*24007Ssam 851*24007Ssam aceclean(unit) 852*24007Ssam int unit; 853*24007Ssam { 854*24007Ssam register struct ace_softc *is = &ace_softc[unit]; 855*24007Ssam register struct ifnet *ifp = &is->is_if; 856*24007Ssam register struct vba_device *ui = aceinfo[unit]; 857*24007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 858*24007Ssam register short i, data; 859*24007Ssam register char *pData1; 860*24007Ssam 861*24007Ssam ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE); 862*24007Ssam is->is_dpm = acemap[unit]; /* init dpm */ 863*24007Ssam bzero((char *)is->is_dpm, 16384*2); 864*24007Ssam 865*24007Ssam is->is_currnd = 49123; 866*24007Ssam is->is_segboundry = (addr->segb >> 11) & 0xf; 867*24007Ssam pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11)); 868*24007Ssam for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 869*24007Ssam acebakoff(is, (struct tx_segment *)pData1, 15); 870*24007Ssam pData1 += sizeof (struct tx_segment); 871*24007Ssam } 872*24007Ssam is->is_eictr = 0; 873*24007Ssam is->is_eoctr = is->is_txnext = is->is_segboundry; 874*24007Ssam bzero((char *)&is->is_stats, sizeof (is->is_stats)); 875*24007Ssam } 876*24007Ssam #endif 877