1 /* 2 * Copyright (c) 1989 The 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)if_ex.c 7.1 (Berkeley) 03/09/89 21 */ 22 23 #include "ex.h" 24 25 #if NEX > 0 26 27 /* 28 * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers 29 */ 30 #include "param.h" 31 #include "systm.h" 32 #include "mbuf.h" 33 #include "buf.h" 34 #include "protosw.h" 35 #include "socket.h" 36 #include "vmmac.h" 37 #include "ioctl.h" 38 #include "errno.h" 39 #include "vmparam.h" 40 #include "syslog.h" 41 #include "uio.h" 42 43 #include "../net/if.h" 44 #include "../net/netisr.h" 45 #include "../net/route.h" 46 47 #ifdef INET 48 #include "../netinet/in.h" 49 #include "../netinet/in_systm.h" 50 #include "../netinet/in_var.h" 51 #include "../netinet/ip.h" 52 #include "../netinet/if_ether.h" 53 #endif 54 55 #ifdef NS 56 #include "../netns/ns.h" 57 #include "../netns/ns_if.h" 58 #endif 59 60 #include "../tahoe/cpu.h" 61 #include "../tahoe/pte.h" 62 #include "../tahoe/mtpr.h" 63 64 #include "../tahoevba/vbavar.h" 65 #include "if_exreg.h" 66 #include "if_vba.h" 67 68 69 #define NH2X 32 /* Host to eXcelan request buffers */ 70 71 #define NX2H 16 /* eXcelan to Host reply buffers */ 72 #define NREC 16 /* Number of RECeive buffers */ 73 #define NTRB 4 /* Number of TRansmit Buffers */ 74 #define NVBI (NREC + NTRB) 75 76 #define EXWATCHINTVL 10 /* call exwatch every x secs */ 77 78 int exprobe(), exslave(), exattach(), exintr(), exstart(); 79 struct vba_device *exinfo[NEX]; 80 81 long exstd[] = { 0 }; 82 83 84 struct vba_driver exdriver = 85 { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; 86 int exinit(),ether_output(),exioctl(),exreset(),exwatch(); 87 struct ex_msg *exgetcbuf(); 88 int ex_ncall = 0; /* counts calls to exprobe */ 89 u_long busoff; 90 91 /* 92 * Ethernet software status per interface. 93 * 94 * Each interface is referenced by a network interface structure, xs_if, which 95 * the routing code uses to locate the interface. This structure contains the 96 * output queue for the interface, its address, ... NOTE: To configure multiple 97 * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). 98 */ 99 struct ex_softc { 100 struct arpcom xs_ac; /* Ethernet common part */ 101 #define xs_if xs_ac.ac_if /* network-visible interface */ 102 #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 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 int xs_cvec; /* probe stores cvec here */ 109 short xs_enetunit; /* unit number for enet filtering */ 110 short xs_enetinit; /* enet inetrface is initialized */ 111 struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 112 struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 113 u_long xs_qbaddr; /* map info for structs below */ 114 /* the following structures are always mapped in */ 115 u_short xs_h2xhdr; /* EXOS's request queue header */ 116 u_short xs_x2hhdr; /* EXOS's reply queue header */ 117 struct ex_msg xs_h2xent[NH2X];/* request msg buffers */ 118 struct ex_msg xs_x2hent[NX2H];/* reply msg buffers */ 119 struct confmsg xs_cm; /* configuration message */ 120 struct stat_array xs_xsa; /* EXOS writes stats here */ 121 /* end mapped area */ 122 #define BUSADDR(x) ((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFFF)) + busoff) 123 #define P_BUSADDR(x) ((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFF0)) + busoff) 124 #define INCORE_BASE(p) (((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0) 125 #define RVAL_OFF(n) ((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0])) 126 #define LVAL_OFF(n) ((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0])) 127 #define H2XHDR_OFFSET RVAL_OFF(xs_h2xhdr) 128 #define X2HHDR_OFFSET RVAL_OFF(xs_x2hhdr) 129 #define H2XENT_OFFSET LVAL_OFF(xs_h2xent) 130 #define X2HENT_OFFSET LVAL_OFF(xs_x2hent) 131 #define CM_OFFSET RVAL_OFF(xs_cm) 132 #define SA_OFFSET RVAL_OFF(xs_xsa) 133 #define FreePkBuf(b) (((b)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ 134 (xs->xs_pkblist = b)) 135 struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ 136 struct ifvba *xs_pkblist; /* free list of above */ 137 char xs_nrec; /* number of pending receive buffers */ 138 char xs_ntrb; /* number of pending transmit buffers */ 139 char pad[6]; /* make BUSADDR macros */ 140 } ex_softc[NEX]; 141 142 int ex_padcheck = sizeof (struct ex_softc); 143 144 exprobe(reg, vi) 145 caddr_t reg; 146 struct vba_device *vi; 147 { 148 register br, cvec; /* r12, r11 value-result */ 149 register struct exdevice *exaddr = (struct exdevice *)reg; 150 int i; 151 152 if (badaddr(exaddr, 2)) 153 return 0; 154 /* 155 * Reset EXOS and run self-test (should complete within 2 seconds). 156 */ 157 movow(&exaddr->ex_porta, EX_RESET); 158 for (i = 1000000; i; i--) { 159 uncache(&(exaddr->ex_portb)); 160 if (exaddr->ex_portb & EX_TESTOK) 161 break; 162 } 163 if ((exaddr->ex_portb & EX_TESTOK) == 0) 164 return 0; 165 br = 0x15; 166 cvec = --vi->ui_hd->vh_lastiv; 167 ex_softc[vi->ui_unit].xs_cvec = cvec; 168 ex_ncall++; 169 return (sizeof(struct exdevice)); 170 } 171 172 /* 173 * Interface exists: make available by filling in network interface record. 174 * System will initialize the interface when it is ready to accept packets. 175 * A NET_ADDRS command is done to get the ethernet address. 176 */ 177 exattach(ui) 178 register struct vba_device *ui; 179 { 180 register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 181 register struct ifnet *ifp = &xs->xs_if; 182 register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 183 register struct ex_msg *bp; 184 185 ifp->if_unit = ui->ui_unit; 186 ifp->if_name = "ex"; 187 ifp->if_mtu = ETHERMTU; 188 ifp->if_init = exinit; 189 ifp->if_ioctl = exioctl; 190 ifp->if_output = ether_output; 191 ifp->if_reset = exreset; 192 ifp->if_start = exstart; 193 194 if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF) == 0) 195 return; 196 /* 197 * Temporarily map queues in order to configure EXOS 198 */ 199 xs->xs_qbaddr = INCORE_BASE(xs); 200 exconfig(ui, 0); /* without interrupts */ 201 if (xs->xs_cm.cm_cc) 202 return; /* bad conf */ 203 /* 204 * Get Ethernet address. 205 */ 206 if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) 207 panic("exattach"); 208 bp->mb_na.na_mask = READ_OBJ; 209 bp->mb_na.na_slot = PHYSSLOT; 210 bp->mb_status |= MH_EXOS; 211 movow(&exaddr->ex_portb, EX_NTRUPT); 212 bp = xs->xs_x2hnext; 213 do { 214 uncache(&bp->mb_status); 215 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 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 if_attach(ifp); 223 } 224 225 /* 226 * Reset of interface after BUS reset. 227 * If interface is on specified vba, reset its state. 228 */ 229 exreset(unit) 230 int unit; 231 { 232 register struct vba_device *ui; 233 234 if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) 235 return; 236 printf(" ex%d", unit); 237 ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 238 ex_softc[unit].xs_flags &= ~EX_RUNNING; 239 240 exinit(unit); 241 } 242 243 /* 244 * Initialization of interface; clear recorded pending operations, and 245 * reinitialize BUS usage. Called at boot time, and at ifconfig time via 246 * exioctl, with interrupts disabled. 247 */ 248 exinit(unit) 249 int unit; 250 { 251 register struct ex_softc *xs = &ex_softc[unit]; 252 register struct vba_device *ui = exinfo[unit]; 253 register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 254 register struct ifnet *ifp = &xs->xs_if; 255 register struct sockaddr_in *sin; 256 register struct ex_msg *bp; 257 int s; 258 259 /* not yet, if address still unknown */ 260 if (ifp->if_addrlist == (struct ifaddr *)0) 261 return; 262 if (xs->xs_flags & EX_RUNNING) 263 return; 264 265 xs->xs_qbaddr = INCORE_BASE(xs); 266 exconfig(ui, 4); /* with vectored interrupts*/ 267 268 /* 269 * Put EXOS on the Ethernet, using NET_MODE command 270 */ 271 if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) 272 panic("exinit"); 273 bp->mb_nm.nm_mask = WRITE_OBJ; 274 bp->mb_nm.nm_optn = 0; 275 bp->mb_nm.nm_mode = MODE_PERF; 276 bp->mb_status |= MH_EXOS; 277 movow(&exaddr->ex_portb, EX_NTRUPT); 278 bp = xs->xs_x2hnext; 279 do { 280 uncache(&bp->mb_status); 281 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 282 bp->mb_length = MBDATALEN; 283 bp->mb_status |= MH_EXOS; /* free up buffer */ 284 movow(&exaddr->ex_portb, EX_NTRUPT); 285 xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 286 287 ifp->if_watchdog = exwatch; 288 ifp->if_timer = EXWATCHINTVL; 289 s = splimp(); /* are interrupts disabled here, anyway? */ 290 exhangrcv(unit); 291 xs->xs_if.if_flags |= IFF_RUNNING; 292 xs->xs_flags |= EX_RUNNING; 293 if (xs->xs_flags & EX_SETADDR) 294 ex_setaddr((u_char *)0, unit); 295 exstart(&ex_softc[unit].xs_if); /* start transmits */ 296 splx(s); /* are interrupts disabled here, anyway? */ 297 } 298 299 /* 300 * Reset, test, and configure EXOS. It is called by exinit, and exattach. 301 * Returns 0 if successful, 1 if self-test failed. 302 */ 303 exconfig(ui, itype) 304 struct vba_device *ui; 305 int itype; 306 { 307 register int unit = ui->ui_unit; 308 register struct ex_softc *xs = &ex_softc[unit]; 309 register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; 310 register struct confmsg *cm = &xs->xs_cm; 311 register struct ex_msg *bp; 312 register struct ifvba *pkb; 313 int i; 314 u_long shiftreg; 315 static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; 316 317 xs->xs_flags = 0; 318 /* 319 * Reset EXOS, wait for self-test to complete 320 */ 321 movow(&exaddr->ex_porta, EX_RESET); 322 do { 323 uncache(&exaddr->ex_portb); 324 } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; 325 /* 326 * Set up configuration message. 327 */ 328 cm->cm_1rsrv = 1; 329 cm->cm_cc = 0xFF; 330 cm->cm_opmode = 0; /* link-level controller mode */ 331 cm->cm_dfo = 0x0101; /* enable host data order conversion */ 332 cm->cm_dcn1 = 1; 333 cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; 334 cm->cm_ham = 3; /* absolute address mode */ 335 cm->cm_3rsrv = 0; 336 cm->cm_mapsiz = 0; 337 cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 338 cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 339 cm->cm_byteptrn[2] = 0x07; 340 cm->cm_byteptrn[3] = 0x0F; 341 cm->cm_wordptrn[0] = 0x0103; 342 cm->cm_wordptrn[1] = 0x070F; 343 cm->cm_lwordptrn = 0x0103070F; 344 for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 345 cm->cm_mba = 0xFFFFFFFF; 346 cm->cm_nproc = 0xFF; 347 cm->cm_nmbox = 0xFF; 348 cm->cm_nmcast = 0xFF; 349 cm->cm_nhost = 1; 350 cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); 351 cm->cm_h2xhdr = H2XHDR_OFFSET; 352 cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 353 cm->cm_x2hba = cm->cm_h2xba; 354 cm->cm_x2hhdr = X2HHDR_OFFSET; 355 cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 356 cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ 357 /* 358 * Set up message queues and headers. 359 * First the request queue 360 */ 361 for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { 362 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 363 bp->mb_rsrv = 0; 364 bp->mb_length = MBDATALEN; 365 bp->mb_status = MH_HOST; 366 bp->mb_next = bp+1; 367 } 368 xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; 369 xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; 370 371 /* Now the reply queue. */ 372 for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 373 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 374 bp->mb_rsrv = 0; 375 bp->mb_length = MBDATALEN; 376 bp->mb_status = MH_EXOS; 377 bp->mb_next = bp+1; 378 } 379 xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; 380 xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; 381 xs->xs_nrec = 0; 382 xs->xs_ntrb = 0; 383 xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; 384 for (pkb = xs->xs_pkblist; pkb >= xs->xs_vbinfo; pkb--) 385 pkb->iff_mbuf = (struct mbuf *)(pkb - 1); 386 xs->xs_vbinfo[0].iff_mbuf = 0; 387 388 /* 389 * Write config msg address to EXOS and wait for configuration to 390 * complete (guaranteed response within 2 seconds). 391 */ 392 shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; 393 for (i = 4; i < 8; i++) { 394 cmaddr[i] = (u_char)(shiftreg & 0xFF); 395 shiftreg >>= 8; 396 } 397 for (i = 0; i < 8; i++) { 398 do { 399 uncache(&exaddr->ex_portb); 400 } while (exaddr->ex_portb & EX_UNREADY) ; 401 DELAY(500); 402 movow(&exaddr->ex_portb, cmaddr[i]); 403 } 404 for (i = 500000; i; --i) { 405 DELAY(10); 406 uncache(&cm->cm_cc); 407 if (cm->cm_cc != 0xFF) 408 break; 409 } 410 if (cm->cm_cc) 411 printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); 412 } 413 414 /* 415 * Start or re-start output on interface. Get another datagram to send off of 416 * the interface queue, and map it to the interface before starting the output. 417 * This routine is called by exinit(), exoutput(), and excdint(). In all cases, 418 * interrupts by EXOS are disabled. 419 */ 420 exstart(ifp) 421 struct ifnet *ifp; 422 { 423 int unit = ifp->if_unit; 424 struct vba_device *ui = exinfo[unit]; 425 register struct ex_softc *xs = &ex_softc[unit]; 426 struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 427 register struct ex_msg *bp; 428 register struct mbuf *m; 429 int len; 430 register struct ifvba *pkb; 431 struct mbuf *m0; 432 register int nb, tlen; 433 union l_util { 434 u_long l; 435 struct i86_long i; 436 } l_util; 437 438 if (xs->xs_ntrb >= NTRB) 439 return; 440 if (xs->xs_pkblist == 0) { 441 printf("ex%d: vbinfo exhausted, would panic", unit); 442 return; 443 } 444 IF_DEQUEUE(&xs->xs_if.if_snd, m); 445 if (m == 0) 446 return; 447 /* 448 * Get a transmit request. 449 */ 450 if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { 451 m_freem(m); 452 printf("exstart: no command buffers\n"); 453 return; 454 } 455 xs->xs_ntrb++; 456 bp->mb_pkb = pkb = xs->xs_pkblist; 457 xs->xs_pkblist = (struct ifvba *)pkb->iff_mbuf; 458 nb = 0; tlen = 0; m0 = 0; 459 pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ 460 /* 461 * point directly to the first group of mbufs to be transmitted. The 462 * hardware can only support NFRAGMENTS descriptors. 463 */ 464 while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { 465 l_util.l = BUSADDR(mtod(m, char *)); 466 bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; 467 bp->mb_et.et_blks[nb].bb_addr = l_util.i; 468 tlen += m->m_len; 469 m0 = m; 470 m = m->m_next; 471 nb++; 472 } 473 474 /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ 475 if (m0) 476 m0->m_next = 0; 477 478 /* 479 * if not all of the descriptors would fit then merge remaining data 480 * into the transmit buffer, and point to it. Note: the mbufs are freed 481 * during the merge, they do not have to be freed when we get the 482 * transmit interrupt. 483 */ 484 if (m) { 485 len = if_vbaput(pkb->iff_buffer, m); 486 l_util.l = BUSADDR(pkb->iff_buffer); 487 bp->mb_et.et_blks[nb].bb_len = (u_short)len; 488 bp->mb_et.et_blks[nb].bb_addr = l_util.i; 489 tlen += len; 490 nb++; 491 } 492 493 /* 494 * If the total length of the packet is too small, pad the last frag 495 */ 496 if (tlen - sizeof(struct ether_header) < ETHERMIN) { 497 len = (ETHERMIN + sizeof(struct ether_header)) - tlen; 498 bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; 499 tlen += len; 500 } 501 502 /* set number of fragments in descriptor */ 503 bp->mb_et.et_nblock = nb; 504 bp->mb_status |= MH_EXOS; 505 movow(&exaddr->ex_portb, EX_NTRUPT); 506 } 507 508 /* 509 * interrupt service routine. 510 */ 511 exintr(unit) 512 int unit; 513 { 514 register struct ex_softc *xs = &ex_softc[unit]; 515 register struct ex_msg *bp = xs->xs_x2hnext; 516 struct vba_device *ui = exinfo[unit]; 517 struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 518 519 uncache(&bp->mb_status); 520 while ((bp->mb_status & MH_OWNER) == MH_HOST) { 521 switch (bp->mb_rqst) { 522 case LLRECEIVE: 523 if (--xs->xs_nrec < 0) 524 xs->xs_nrec = 0; 525 exrecv(unit, bp); 526 FreePkBuf(bp->mb_pkb); 527 bp->mb_pkb = (struct ifvba *)0; 528 exhangrcv(unit); 529 break; 530 531 case LLTRANSMIT: 532 case LLRTRANSMIT: 533 if (--xs->xs_ntrb < 0) 534 xs->xs_ntrb = 0; 535 xs->xs_if.if_opackets++; 536 if (bp->mb_rply == LL_OK) 537 ; 538 else if (bp->mb_rply & LLXM_1RTRY) 539 xs->xs_if.if_collisions++; 540 else if (bp->mb_rply & LLXM_RTRYS) 541 xs->xs_if.if_collisions += 2; /* guess */ 542 else if (bp->mb_rply & LLXM_ERROR) 543 if (xs->xs_if.if_oerrors++ % 100 == 0) 544 printf("ex%d: 100 transmit errors=%b\n", 545 unit, bp->mb_rply, XMIT_BITS); 546 if (bp->mb_pkb->iff_mbuf) { 547 m_freem(bp->mb_pkb->iff_mbuf); 548 bp->mb_pkb->iff_mbuf = (struct mbuf *)0; 549 } 550 FreePkBuf(bp->mb_pkb); 551 bp->mb_pkb = (struct ifvba *)0; 552 exstart(&ex_softc[unit].xs_if); 553 exhangrcv(unit); 554 break; 555 556 case LLNET_STSTCS: 557 xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; 558 xs->xs_flags &= ~EX_STATPENDING; 559 break; 560 561 default: 562 printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); 563 } 564 bp->mb_length = MBDATALEN; 565 bp->mb_status |= MH_EXOS; /* free up buffer */ 566 movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ 567 bp = bp->mb_next; 568 uncache(&bp->mb_status); 569 } 570 xs->xs_x2hnext = bp; 571 } 572 573 /* 574 * Get a request buffer, fill in standard values, advance pointer. 575 */ 576 struct ex_msg * 577 exgetcbuf(xs, req) 578 struct ex_softc *xs; 579 int req; 580 { 581 register struct ex_msg *bp; 582 struct ifvba *pkb; 583 int s = splimp(); 584 585 bp = xs->xs_h2xnext; 586 uncache(&bp->mb_status); 587 if ((bp->mb_status & MH_OWNER) == MH_EXOS) { 588 splx(s); 589 return (struct ex_msg *)0; 590 } 591 xs->xs_h2xnext = bp->mb_next; 592 bp->mb_1rsrv = 0; 593 bp->mb_rqst = req; 594 bp->mb_length = MBDATALEN; 595 bp->mb_pkb = (struct ifvba *)0; 596 splx(s); 597 return bp; 598 } 599 600 /* 601 * Process Ethernet receive completion: If input error just drop packet, 602 * otherwise examine packet to determine type. If can't determine length from 603 * type, then have to drop packet, otherwise decapsulate packet based on type 604 * and pass to type-specific higher-level input routine. 605 */ 606 exrecv(unit, bp) 607 int unit; 608 register struct ex_msg *bp; 609 { 610 register struct ex_softc *xs = &ex_softc[unit]; 611 register struct ether_header *eh; 612 register struct mbuf *m; 613 int len, off, resid; 614 register struct ifqueue *inq; 615 int s; 616 617 xs->xs_if.if_ipackets++; 618 /* total length - header - crc */ 619 len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 620 if (bp->mb_rply != LL_OK) { 621 if (xs->xs_if.if_ierrors++ % 100 == 0) 622 printf("ex%d: 100 receive errors=%b\n", 623 unit, bp->mb_rply, RECV_BITS); 624 return; 625 } 626 eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); 627 628 /* 629 * Deal with trailer protocol: if type is PUP trailer get true type from 630 * first 16-bit word past data. Remember that type was trailer by 631 * setting off. 632 */ 633 eh->ether_type = ntohs((u_short)eh->ether_type); 634 #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 635 if (eh->ether_type >= ETHERTYPE_TRAIL && 636 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 637 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 638 if (off >= ETHERMTU) 639 return; /* sanity */ 640 eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 641 resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 642 if (off + resid > len) 643 return; /* sanity */ 644 len = off + resid; 645 } else 646 off = 0; 647 if (len == 0) 648 return; 649 /* 650 * Pull packet off interface. Off is nonzero if packet 651 * has trailing header; if_vbaget will then force this header 652 * information to be at the front, but we still have to drop 653 * the type and length which are at the front of any trailer data. 654 */ 655 m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); 656 if (m == 0) 657 return; 658 ether_input(&xs->xs_if, eh, m); 659 return; 660 } 661 662 /* 663 * Hang a receive request. This routine is called by exinit and excdint, 664 * with interrupts disabled in both cases. 665 */ 666 exhangrcv(unit) 667 int unit; 668 { 669 register struct ex_softc *xs = &ex_softc[unit]; 670 register struct ex_msg *bp; 671 register struct ifvba *pkb; 672 short mustint = 0; 673 union l_util { 674 u_long l; 675 struct i86_long i; 676 } l_util; 677 678 while (xs->xs_nrec < NREC) { 679 if (xs->xs_pkblist == (struct ifvba *)0) 680 break; 681 if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { 682 break; 683 } 684 pkb = bp->mb_pkb = xs->xs_pkblist; 685 xs->xs_pkblist = (struct ifvba *)bp->mb_pkb->iff_mbuf; 686 687 xs->xs_nrec += 1; 688 bp->mb_er.er_nblock = 1; 689 bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 690 l_util.l = BUSADDR(pkb->iff_buffer); 691 bp->mb_er.er_blks[0].bb_addr = l_util.i; 692 bp->mb_status |= MH_EXOS; 693 mustint = 1; 694 } 695 if (mustint == 0) 696 return; 697 movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); 698 } 699 700 /* 701 * Ethernet output routine is ether_output(). 702 */ 703 704 /* 705 * Watchdog routine (currently not used). Might use this to get stats from EXOS. 706 */ 707 exwatch(unit) 708 int unit; 709 { 710 struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; 711 register struct ex_softc *xs = &ex_softc[unit]; 712 register struct ex_msg *bp; 713 int s = splimp(); 714 715 if (xs->xs_flags & EX_STATPENDING) 716 goto exspnd; 717 if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { 718 splx(s); 719 return; 720 } 721 xs->xs_flags |= EX_STATPENDING; 722 bp->mb_ns.ns_mask = READ_OBJ; 723 bp->mb_ns.ns_rsrv = 0; 724 bp->mb_ns.ns_nobj = 8; 725 bp->mb_ns.ns_xobj = 0; 726 bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; 727 bp->mb_status |= MH_EXOS; 728 movow(&exaddr->ex_portb, EX_NTRUPT); 729 exspnd: splx(s); 730 xs->xs_if.if_timer = EXWATCHINTVL; 731 } 732 733 /* 734 * Process an ioctl request. 735 */ 736 exioctl(ifp, cmd, data) 737 register struct ifnet *ifp; 738 int cmd; 739 caddr_t data; 740 { 741 register struct ifaddr *ifa = (struct ifaddr *)data; 742 register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 743 int s = splimp(), error = 0; 744 745 switch (cmd) { 746 747 case SIOCSIFADDR: 748 ifp->if_flags |= IFF_UP; 749 exinit(ifp->if_unit); 750 751 switch (ifa->ifa_addr->sa_family) { 752 #ifdef INET 753 case AF_INET: 754 ((struct arpcom *)ifp)->ac_ipaddr = 755 IA_SIN(ifa)->sin_addr; 756 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 757 break; 758 #endif 759 #ifdef NS 760 case AF_NS: 761 { 762 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 763 764 if (ns_nullhost(*ina)) 765 ina->x_host = *(union ns_host *)(xs->xs_addr); 766 else 767 ex_setaddr(ina->x_host.c_host,ifp->if_unit); 768 break; 769 } 770 #endif 771 } 772 break; 773 774 case SIOCSIFFLAGS: 775 if ((ifp->if_flags & IFF_UP) == 0 && 776 xs->xs_flags & EX_RUNNING) { 777 movow(&((struct exdevice *) 778 (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); 779 xs->xs_flags &= ~EX_RUNNING; 780 } else if (ifp->if_flags & IFF_UP && 781 (xs->xs_flags & EX_RUNNING) == 0) 782 exinit(ifp->if_unit); 783 break; 784 785 default: 786 error = EINVAL; 787 } 788 splx(s); 789 return (error); 790 } 791 792 /* 793 * set ethernet address for unit 794 */ 795 ex_setaddr(physaddr, unit) 796 u_char *physaddr; 797 int unit; 798 { 799 register struct ex_softc *xs = &ex_softc[unit]; 800 struct vba_device *ui = exinfo[unit]; 801 register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 802 register struct ex_msg *bp; 803 804 if (physaddr) { 805 xs->xs_flags |= EX_SETADDR; 806 bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 807 } 808 if (! (xs->xs_flags & EX_RUNNING)) 809 return; 810 bp = exgetcbuf(xs); 811 bp->mb_rqst = LLNET_ADDRS; 812 bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 813 bp->mb_na.na_slot = PHYSSLOT; 814 bcopy((caddr_t)xs->xs_addr, (caddr_t)bp->mb_na.na_addrs, 6); 815 bp->mb_status |= MH_EXOS; 816 movow(&addr->ex_portb, EX_NTRUPT); 817 bp = xs->xs_x2hnext; 818 do { 819 uncache(&bp->mb_status); 820 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 821 #ifdef DEBUG 822 log(LOG_DEBUG, "ex%d: reset addr %s\n", ui->ui_unit, 823 ether_sprintf(bp->mb_na.na_addrs)); 824 #endif 825 /* 826 * Now, re-enable reception on phys slot. 827 */ 828 bp = exgetcbuf(xs); 829 bp->mb_rqst = LLNET_RECV; 830 bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 831 bp->mb_nr.nr_slot = PHYSSLOT; 832 bp->mb_status |= MH_EXOS; 833 movow(&addr->ex_portb, EX_NTRUPT); 834 bp = xs->xs_x2hnext; 835 do { 836 uncache(&bp->mb_status); 837 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 838 ; 839 } 840 #endif 841