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