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