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