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