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