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