1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Excelan Inc. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)if_ex.c 7.9 (Berkeley) 12/16/90 11 */ 12 13 #include "ex.h" 14 #if NEX > 0 15 16 /* 17 * Excelan EXOS 204 Interface 18 * 19 * George Powers 20 * Excelan Inc. 21 */ 22 23 #include "sys/param.h" 24 #include "sys/systm.h" 25 #include "sys/mbuf.h" 26 #include "sys/buf.h" 27 #include "sys/protosw.h" 28 #include "sys/socket.h" 29 #include "sys/vmmac.h" 30 #include "sys/ioctl.h" 31 #include "sys/syslog.h" 32 #include "sys/errno.h" 33 34 #include "net/if.h" 35 #include "net/netisr.h" 36 #include "net/route.h" 37 38 #ifdef INET 39 #include "netinet/in.h" 40 #include "netinet/in_systm.h" 41 #include "netinet/in_var.h" 42 #include "netinet/ip.h" 43 #include "netinet/if_ether.h" 44 #endif 45 46 #ifdef NS 47 #include "netns/ns.h" 48 #include "netns/ns_if.h" 49 #endif 50 51 #ifdef ISO 52 #include "netiso/iso.h" 53 #include "netiso/iso_var.h" 54 extern char all_es_snpa[], all_is_snpa[]; 55 #endif 56 57 #include "../include/pte.h" 58 #include "../include/cpu.h" 59 #include "../include/mtpr.h" 60 #include "if_exreg.h" 61 #include "if_uba.h" 62 #include "../uba/ubareg.h" 63 #include "../uba/ubavar.h" 64 65 /* #define DEBUG /* check for "impossible" events */ 66 67 #define NH2X 4 /* a sufficient number is critical */ 68 #define NX2H 4 /* this is pretty arbitrary */ 69 #define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */ 70 71 int exprobe(), exattach(), excdint(); 72 struct uba_device *exinfo[NEX]; 73 u_short exstd[] = { 0 }; 74 struct uba_driver exdriver = 75 { exprobe, 0, exattach, 0, exstd, "ex", exinfo }; 76 int exinit(),exstart(),ether_output(),exioctl(),exreset(),exwatch(); 77 struct ex_msg *exgetcbuf(); 78 79 /* 80 * Ethernet software status per interface. 81 * 82 * Each interface is referenced by a network interface structure, 83 * xs_if, which the routing code uses to locate the interface. 84 * This structure contains the output queue for the interface, its address, ... 85 * We also have, for each interface, a UBA interface structure, which 86 * contains information about the UNIBUS resources held by the interface: 87 * map registers, buffered data paths, etc. Information is cached in this 88 * structure for use by the if_uba.c routines in running the interface 89 * efficiently. 90 */ 91 struct ex_softc { 92 struct arpcom xs_ac; /* Ethernet common part */ 93 #define xs_if xs_ac.ac_if /* network-visible interface */ 94 #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 95 #ifdef DEBUG 96 int xs_wait; 97 #endif 98 struct ifuba xs_ifuba; /* UNIBUS resources */ 99 int xs_flags; /* private flags */ 100 #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ 101 #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ 102 #define EX_RUNNING (1<<2) /* board is running */ 103 #define EX_SETADDR (1<<3) /* physaddr has been changed */ 104 struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 105 struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 106 int xs_ubaddr; /* map info for structs below */ 107 #define UNIADDR(x) ((u_long)(x)&0x3FFFF) 108 #define P_UNIADDR(x) ((u_long)(x)&0x3FFF0) 109 /* the following structures are always mapped in */ 110 u_short xs_h2xhdr; /* EXOS's request queue header */ 111 u_short xs_x2hhdr; /* EXOS's reply queue header */ 112 struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */ 113 struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */ 114 struct confmsg xs_cm; /* configuration message */ 115 struct stat_array xs_xsa; /* EXOS writes stats here */ 116 /* end mapped area */ 117 #define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0)) 118 #define RVAL_OFF(unit, n) \ 119 ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit])) 120 #define LVAL_OFF(unit, n) \ 121 ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit])) 122 #define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr) 123 #define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr) 124 #define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent) 125 #define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent) 126 #define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm) 127 #define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa) 128 #define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end) 129 int xs_end; /* place holder */ 130 } ex_softc[NEX]; 131 132 /* 133 * The following structure is a kludge to store a cvec value 134 * between the time exprobe is called, and exconfig. 135 */ 136 struct ex_cvecs { 137 struct exdevice *xc_csraddr; 138 int xc_cvec; 139 }ex_cvecs[NEX]; 140 141 int ex_ncall = 0; /* counts calls to exprobe */ 142 143 exprobe(reg) 144 caddr_t reg; 145 { 146 register int br, cvec; /* r11, r10 value-result */ 147 register struct exdevice *addr = (struct exdevice *)reg; 148 register i; 149 150 /* 151 * We program the EXOS interrupt vector, like dmf device. 152 */ 153 br = 0x15; 154 cvec = (uba_hd[numuba].uh_lastiv -= 4); 155 ex_cvecs[ex_ncall].xc_csraddr = addr; 156 ex_cvecs[ex_ncall].xc_cvec = cvec; 157 /* 158 * Reset EXOS and run self-test (guaranteed to 159 * complete within 2 seconds). 160 */ 161 addr->xd_porta = EX_RESET; 162 i = 2000; 163 while (((addr->xd_portb & EX_TESTOK) == 0) && --i) 164 DELAY(1000); 165 if ((addr->xd_portb & EX_TESTOK) == 0) { 166 printf("ex: self-test failed\n"); 167 return 0; 168 } 169 #ifdef lint 170 br = br; 171 excdint(0); 172 #endif 173 ex_ncall++; 174 return (sizeof(struct exdevice)); 175 } 176 177 /* 178 * Interface exists: make available by filling in network interface 179 * record. System will initialize the interface when it is ready 180 * to accept packets. Board is temporarily configured and issues 181 * a NET_ADDRS command, only to get the Ethernet address. 182 */ 183 exattach(ui) 184 register struct uba_device *ui; 185 { 186 register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 187 register struct ifnet *ifp = &xs->xs_if; 188 register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 189 register struct ex_msg *bp; 190 int unit = ui->ui_unit; 191 ifp->if_unit = ui->ui_unit; 192 ifp->if_name = "ex"; 193 ifp->if_mtu = ETHERMTU; 194 195 /* 196 * Temporarily map queues in order to configure EXOS 197 */ 198 xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), 199 INCORE_SIZE(unit), 0); 200 exconfig(ui, 0); /* without interrupts */ 201 if (xs->xs_cm.cm_cc) goto badconf; 202 203 bp = exgetcbuf(xs); 204 bp->mb_rqst = LLNET_ADDRS; 205 bp->mb_na.na_mask = READ_OBJ; 206 bp->mb_na.na_slot = PHYSSLOT; 207 bp->mb_status |= MH_EXOS; 208 addr->xd_portb = EX_NTRUPT; 209 bp = xs->xs_x2hnext; 210 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 211 ; 212 printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n", 213 ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], 214 xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], 215 ether_sprintf(bp->mb_na.na_addrs)); 216 bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, 217 sizeof (xs->xs_addr)); 218 219 ifp->if_init = exinit; 220 ifp->if_output = ether_output; 221 ifp->if_start = exstart; 222 ifp->if_ioctl = exioctl; 223 ifp->if_reset = exreset; 224 ifp->if_flags = IFF_BROADCAST; 225 xs->xs_ifuba.ifu_flags = UBA_CANTWAIT; 226 if_attach(ifp); 227 badconf: 228 ubarelse(ui->ui_ubanum, &xs->xs_ubaddr); 229 } 230 231 /* 232 * Reset of interface after UNIBUS reset. 233 * If interface is on specified uba, reset its state. 234 */ 235 exreset(unit, uban) 236 int unit, uban; 237 { 238 register struct uba_device *ui; 239 240 if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 || 241 ui->ui_ubanum != uban) 242 return; 243 printf(" ex%d", unit); 244 ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 245 ex_softc[unit].xs_flags &= ~EX_RUNNING; 246 exinit(unit); 247 } 248 249 /* 250 * Initialization of interface; clear recorded pending 251 * operations, and reinitialize UNIBUS usage. 252 * Called at boot time (with interrupts disabled?), 253 * and at ifconfig time via exioctl, with interrupts disabled. 254 */ 255 exinit(unit) 256 int unit; 257 { 258 register struct ex_softc *xs = &ex_softc[unit]; 259 register struct uba_device *ui = exinfo[unit]; 260 register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 261 register struct ifnet *ifp = &xs->xs_if; 262 register struct ex_msg *bp; 263 int s; 264 265 /* not yet, if address still unknown */ 266 if (ifp->if_addrlist == (struct ifaddr *)0) 267 return; 268 if (xs->xs_flags & EX_RUNNING) 269 return; 270 271 if ((ifp->if_flags & IFF_RUNNING) == 0) { 272 if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum, 273 sizeof (struct ether_header), 274 (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) { 275 printf("ex%d: can't initialize\n", unit); 276 xs->xs_if.if_flags &= ~IFF_UP; 277 return; 278 } 279 xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), 280 INCORE_SIZE(unit), 0); 281 } 282 exconfig(ui, 4); /* with vectored interrupts*/ 283 /* 284 * Put EXOS on the Ethernet, using NET_MODE command 285 */ 286 bp = exgetcbuf(xs); 287 bp->mb_rqst = LLNET_MODE; 288 bp->mb_nm.nm_mask = WRITE_OBJ; 289 bp->mb_nm.nm_optn = 0; 290 bp->mb_nm.nm_mode = MODE_PERF; 291 bp->mb_status |= MH_EXOS; 292 addr->xd_portb = EX_NTRUPT; 293 bp = xs->xs_x2hnext; 294 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 295 ; 296 bp->mb_length = MBDATALEN; 297 bp->mb_status |= MH_EXOS; /* free up buffer */ 298 addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ 299 xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 300 301 ifp->if_watchdog = exwatch; 302 ifp->if_timer = EXWATCHINTVL; 303 s = splimp(); /* are interrupts always disabled here, anyway? */ 304 exhangrcv(unit); /* hang receive request */ 305 xs->xs_if.if_flags |= IFF_RUNNING; 306 xs->xs_flags |= EX_RUNNING; 307 if (xs->xs_flags & EX_SETADDR) 308 ex_setaddr((u_char *)0, unit); 309 #ifdef ISO 310 ex_setmulti(all_es_snpa, unit, 1); 311 ex_setmulti(all_is_snpa, unit, 2); 312 #endif 313 (void) exstart(&xs->xs_if); /* start transmits */ 314 splx(s); 315 } 316 317 /* 318 * Reset, test, and configure EXOS. This routine assumes 319 * that message queues, etc. have already been mapped into 320 * the UBA. It is called by exinit, and should also be 321 * callable by exattach. 322 */ 323 exconfig(ui, itype) 324 struct uba_device *ui; 325 int itype; 326 { 327 register int unit = ui->ui_unit; 328 register struct ex_softc *xs = &ex_softc[unit]; 329 register struct exdevice *addr = (struct exdevice *) ui->ui_addr; 330 register struct confmsg *cm = &xs->xs_cm; 331 register struct ex_msg *bp; 332 int i; 333 u_long shiftreg; 334 335 xs->xs_flags = 0; 336 /* 337 * Reset EXOS, wait for self-test to complete 338 */ 339 addr->xd_porta = EX_RESET; 340 while ((addr->xd_portb & EX_TESTOK) == 0) 341 ; 342 /* 343 * Set up configuration message. 344 */ 345 cm->cm_1rsrv = 1; 346 cm->cm_cc = 0xFF; 347 cm->cm_opmode = 0; /* link-level controller mode */ 348 cm->cm_dfo = 0x0101; /* enable host data order conversion */ 349 cm->cm_dcn1 = 1; 350 cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; 351 cm->cm_ham = 3; /* absolute address mode */ 352 cm->cm_3rsrv = 0; 353 cm->cm_mapsiz = 0; 354 cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 355 cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 356 cm->cm_byteptrn[2] = 0x07; 357 cm->cm_byteptrn[3] = 0x0F; 358 cm->cm_wordptrn[0] = 0x0103; 359 cm->cm_wordptrn[1] = 0x070F; 360 cm->cm_lwordptrn = 0x0103070F; 361 for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 362 cm->cm_mba = 0xFFFFFFFF; 363 cm->cm_nproc = 0xFF; 364 cm->cm_nmbox = 0xFF; 365 cm->cm_nmcast = 0xFF; 366 cm->cm_nhost = 1; 367 cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr); 368 cm->cm_h2xhdr = H2XHDR_OFFSET(unit); 369 cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 370 cm->cm_x2hba = cm->cm_h2xba; 371 cm->cm_x2hhdr = X2HHDR_OFFSET(unit); 372 cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 373 for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++) 374 #ifdef DEBUG 375 if (i >= NEX) 376 panic("ex: matching csr address not found"); 377 #endif 378 ; 379 cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */ 380 /* 381 * Set up message queues and headers. 382 * First the request queue. 383 */ 384 for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { 385 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 386 bp->mb_rsrv = 0; 387 bp->mb_length = MBDATALEN; 388 bp->mb_status = MH_HOST; 389 bp->mb_next = bp+1; 390 } 391 xs->xs_h2xhdr = 392 xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit); 393 xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; 394 395 /* Now the reply queue. */ 396 for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 397 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 398 bp->mb_rsrv = 0; 399 bp->mb_length = MBDATALEN; 400 bp->mb_status = MH_EXOS; 401 bp->mb_next = bp+1; 402 } 403 xs->xs_x2hhdr = 404 xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit); 405 xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; 406 407 /* 408 * Write config msg address to EXOS and wait for 409 * configuration to complete (guaranteed response 410 * within 2 seconds). 411 */ 412 shiftreg = (u_long)0x0000FFFF; 413 for (i = 0; i < 8; i++) { 414 if (i == 4) 415 shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit); 416 while (addr->xd_portb & EX_UNREADY) 417 ; 418 addr->xd_portb = (u_char)(shiftreg & 0xFF); 419 shiftreg >>= 8; 420 } 421 for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i); 422 if (cm->cm_cc) 423 printf("ex%d: configuration failed; cc = %x\n", 424 unit, cm->cm_cc); 425 } 426 427 /* 428 * Start or re-start output on interface. 429 * Get another datagram to send off of the interface queue, 430 * and map it to the interface before starting the output. 431 * This routine is called by exinit(), ether_output(), and excdint(). 432 * In all cases, interrupts by EXOS are disabled. 433 */ 434 exstart(ifp) 435 struct ifnet *ifp; 436 { 437 int unit = ifp->if_unit; 438 struct uba_device *ui = exinfo[unit]; 439 register struct ex_softc *xs = &ex_softc[unit]; 440 register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 441 register struct ex_msg *bp; 442 struct mbuf *m; 443 int len; 444 445 #ifdef DEBUG 446 if (xs->xs_if.if_flags & IFF_OACTIVE) 447 panic("exstart(): xmit still pending"); 448 #endif 449 IF_DEQUEUE(&xs->xs_if.if_snd, m); 450 if (m == 0) 451 return (0); 452 len = if_wubaput(&xs->xs_ifuba, m); 453 if (len - sizeof(struct ether_header) < ETHERMIN) 454 len = ETHERMIN + sizeof(struct ether_header); 455 /* 456 * Place a transmit request. 457 */ 458 bp = exgetcbuf(xs); 459 bp->mb_rqst = LLRTRANSMIT; 460 bp->mb_et.et_nblock = 1; 461 bp->mb_et.et_blks[0].bb_len = (u_short)len; 462 *(u_long *)bp->mb_et.et_blks[0].bb_addr = 463 UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info); 464 xs->xs_if.if_flags |= IFF_OACTIVE; 465 bp->mb_status |= MH_EXOS; 466 addr->xd_portb = EX_NTRUPT; 467 return (0); 468 } 469 470 /* 471 * Command done interrupt. 472 */ 473 excdint(unit) 474 int unit; 475 { 476 register struct ex_softc *xs = &ex_softc[unit]; 477 register struct ex_msg *bp = xs->xs_x2hnext; 478 struct uba_device *ui = exinfo[unit]; 479 struct exdevice *addr = (struct exdevice *)ui->ui_addr; 480 481 while ((bp->mb_status & MH_OWNER) == MH_HOST) { 482 switch (bp->mb_rqst) { 483 case LLRECEIVE: 484 exrecv(unit, bp); 485 exhangrcv(unit); 486 break; 487 case LLRTRANSMIT: 488 #ifdef DEBUG 489 if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0) 490 panic("exxmit: no xmit pending"); 491 #endif 492 xs->xs_if.if_flags &= ~IFF_OACTIVE; 493 xs->xs_if.if_opackets++; 494 if (bp->mb_rply == LL_OK) { 495 ; 496 } else if (bp->mb_rply & LLXM_1RTRY) { 497 xs->xs_if.if_collisions++; 498 } else if (bp->mb_rply & LLXM_RTRYS) { 499 xs->xs_if.if_collisions += 2; /* guess */ 500 } else if (bp->mb_rply & LLXM_ERROR) { 501 xs->xs_if.if_oerrors++; 502 log(LOG_ERR, "ex%d: transmit error=%b\n", 503 unit, bp->mb_rply, XMIT_BITS); 504 } 505 if (xs->xs_ifuba.ifu_xtofree) { 506 m_freem(xs->xs_ifuba.ifu_xtofree); 507 xs->xs_ifuba.ifu_xtofree = 0; 508 } 509 (void) exstart(&xs->xs_if); 510 break; 511 case LLNET_STSTCS: 512 xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc; 513 xs->xs_flags &= ~EX_STATPENDING; 514 break; 515 case LLNET_ADDRS: 516 case LLNET_RECV: 517 break; 518 #ifdef DEBUG 519 default: 520 panic("ex%d: unknown reply"); 521 #endif 522 } /* end of switch */ 523 bp->mb_length = MBDATALEN; 524 bp->mb_status |= MH_EXOS; /* free up buffer */ 525 addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ 526 bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 527 } 528 } 529 530 /* 531 * Get a request buffer, fill in standard values, advance pointer. 532 */ 533 struct ex_msg * 534 exgetcbuf(xs) 535 struct ex_softc *xs; 536 { 537 register struct ex_msg *bp = xs->xs_h2xnext; 538 539 #ifdef DEBUG 540 if ((bp->mb_status & MH_OWNER) == MH_EXOS) 541 panic("exgetcbuf(): EXOS owns message buffer"); 542 #endif 543 bp->mb_1rsrv = 0; 544 bp->mb_length = MBDATALEN; 545 xs->xs_h2xnext = xs->xs_h2xnext->mb_next; 546 return bp; 547 } 548 549 /* 550 * Process Ethernet receive completion: 551 * If input error just drop packet. 552 * Otherwise purge input buffered data path and examine 553 * packet to determine type. If can't determine length 554 * from type, then have to drop packet. Otherwise decapsulate 555 * packet based on type and pass to type-specific higher-level 556 * input routine. 557 */ 558 exrecv(unit, bp) 559 int unit; 560 register struct ex_msg *bp; 561 { 562 register struct ex_softc *xs = &ex_softc[unit]; 563 register struct ether_header *eh; 564 struct mbuf *m; 565 register int len, off, resid; 566 register struct ifqueue *inq; 567 int s; 568 569 xs->xs_if.if_ipackets++; 570 len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 571 if (bp->mb_rply != LL_OK) { 572 xs->xs_if.if_ierrors++; 573 log(LOG_ERR, "ex%d: receive error=%b\n", 574 unit, bp->mb_rply, RECV_BITS); 575 return; 576 } 577 eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr); 578 579 /* 580 * Deal with trailer protocol: if type is trailer 581 * get true type from first 16-bit word past data. 582 * Remember that type was trailer by setting off. 583 */ 584 eh->ether_type = ntohs((u_short)eh->ether_type); 585 #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 586 if (eh->ether_type >= ETHERTYPE_TRAIL && 587 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 588 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 589 if (off >= ETHERMTU) 590 return; /* sanity */ 591 eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 592 resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 593 if (off + resid > len) 594 return; /* sanity */ 595 len = off + resid; 596 } else 597 off = 0; 598 if (len == 0) 599 return; 600 601 /* 602 * Pull packet off interface. Off is nonzero if packet 603 * has trailing header; if_rubaget will then force this header 604 * information to be at the front, but we still have to drop 605 * the type and length which are at the front of any trailer data. 606 */ 607 m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if); 608 if (m == 0) 609 return; 610 ether_input(&xs->xs_if, eh, m); 611 } 612 613 /* 614 * Send receive request to EXOS. 615 * This routine is called by exinit and excdint, 616 * with interrupts disabled in both cases. 617 */ 618 exhangrcv(unit) 619 int unit; 620 { 621 register struct ex_softc *xs = &ex_softc[unit]; 622 register struct ex_msg *bp = exgetcbuf(xs); 623 struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr; 624 625 bp->mb_rqst = LLRECEIVE; 626 bp->mb_er.er_nblock = 1; 627 bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 628 *(u_long *)bp->mb_er.er_blks[0].bb_addr = 629 UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info); 630 bp->mb_status |= MH_EXOS; 631 addr->xd_portb = EX_NTRUPT; 632 } 633 634 /* 635 * Watchdog routine - place stats request to EXOS 636 * (This could be dispensed with, if you don't care 637 * about the if_ierrors count, or are willing to receive 638 * bad packets in order to derive it.) 639 */ 640 exwatch(unit) 641 int unit; 642 { 643 struct uba_device *ui = exinfo[unit]; 644 struct exdevice *addr = (struct exdevice *)ui->ui_addr; 645 register struct ex_softc *xs = &ex_softc[unit]; 646 register struct ex_msg *bp; 647 int s = splimp(); 648 649 if (xs->xs_flags & EX_STATPENDING) goto exspnd; 650 bp = exgetcbuf(xs); 651 xs->xs_flags |= EX_STATPENDING; 652 bp->mb_rqst = LLNET_STSTCS; 653 bp->mb_ns.ns_mask = READ_OBJ; 654 bp->mb_ns.ns_rsrv = 0; 655 bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */ 656 bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */ 657 bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit); 658 bp->mb_status |= MH_EXOS; 659 addr->xd_portb = EX_NTRUPT; 660 exspnd: 661 splx(s); 662 xs->xs_if.if_timer = EXWATCHINTVL; 663 } 664 665 /* 666 * Process an ioctl request. 667 */ 668 exioctl(ifp, cmd, data) 669 register struct ifnet *ifp; 670 int cmd; 671 caddr_t data; 672 { 673 register struct ifaddr *ifa = (struct ifaddr *)data; 674 register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 675 int s = splimp(), error = 0; 676 677 switch (cmd) { 678 679 case SIOCSIFADDR: 680 ifp->if_flags |= IFF_UP; 681 exinit(ifp->if_unit); 682 683 switch (ifa->ifa_addr->sa_family) { 684 #ifdef INET 685 case AF_INET: 686 ((struct arpcom *)ifp)->ac_ipaddr = 687 IA_SIN(ifa)->sin_addr; 688 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 689 break; 690 #endif 691 #ifdef NS 692 case AF_NS: 693 { 694 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 695 696 if (ns_nullhost(*ina)) 697 ina->x_host = *(union ns_host *)(xs->xs_addr); 698 else 699 ex_setaddr(ina->x_host.c_host,ifp->if_unit); 700 break; 701 } 702 #endif 703 } 704 break; 705 706 case SIOCSIFFLAGS: 707 if ((ifp->if_flags & IFF_UP) == 0 && 708 xs->xs_flags & EX_RUNNING) { 709 ((struct exdevice *) 710 (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET; 711 xs->xs_flags &= ~EX_RUNNING; 712 } else if (ifp->if_flags & IFF_UP && 713 (xs->xs_flags & EX_RUNNING) == 0) 714 exinit(ifp->if_unit); 715 break; 716 717 default: 718 error = EINVAL; 719 } 720 splx(s); 721 return (error); 722 } 723 724 /* 725 * set ethernet address for unit 726 */ 727 ex_setaddr(physaddr, unit) 728 u_char *physaddr; 729 int unit; 730 { 731 register struct ex_softc *xs = &ex_softc[unit]; 732 733 if (physaddr) { 734 xs->xs_flags |= EX_SETADDR; 735 bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 736 } 737 ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); 738 } 739 /* 740 * enable multicast reception on a particular address. 741 */ 742 ex_setmulti(linkaddr, unit, slot) 743 u_char *linkaddr; 744 int unit; 745 { 746 register struct ex_softc *xs = &ex_softc[unit]; 747 struct uba_device *ui = exinfo[unit]; 748 register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 749 register struct ex_msg *bp; 750 751 if (! (xs->xs_flags & EX_RUNNING)) 752 return; 753 bp = exgetcbuf(xs); 754 bp->mb_rqst = LLNET_ADDRS; 755 bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 756 bp->mb_na.na_slot = slot; 757 bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); 758 bp->mb_status |= MH_EXOS; 759 addr->xd_portb = EX_NTRUPT; 760 bp = xs->xs_x2hnext; 761 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 762 ; 763 #ifdef DEBUG 764 log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, 765 (slot == PHYSSLOT ? "reset addr" : "add multicast" 766 ether_sprintf(bp->mb_na.na_addrs), slot); 767 #endif 768 /* 769 * Now, re-enable reception on slot. 770 */ 771 bp = exgetcbuf(xs); 772 bp->mb_rqst = LLNET_RECV; 773 bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 774 bp->mb_nr.nr_slot = slot; 775 bp->mb_status |= MH_EXOS; 776 addr->xd_portb = EX_NTRUPT; 777 bp = xs->xs_x2hnext; 778 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 779 ; 780 } 781 #endif 782