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

Defined functions

ex_setaddr defined in line 889; used 2 times
exattach defined in line 174; used 2 times
excdint defined in line 464; used 3 times
exconfig defined in line 309; used 2 times
exgetcbuf defined in line 524; used 8 times
exhangrcv defined in line 645; used 2 times
exinit defined in line 245; used 5 times
exioctl defined in line 830; used 2 times
exoutput defined in line 667; used 2 times
exprobe defined in line 134; used 2 times
exrecv defined in line 549; used 1 times
exreset defined in line 225; used 2 times
exstart defined in line 427; used 3 times
exwatch defined in line 802; used 2 times

Defined variables

ex_cvecs defined in line 130; used 4 times
ex_ncall defined in line 132; used 3 times
ex_softc defined in line 121; used 17 times
exdriver defined in line 65; used 1 times
exinfo defined in line 63; used 9 times
exstd defined in line 64; used 1 times
  • in line 66

Defined struct's

ex_cvecs defined in line 127; never used
ex_softc defined in line 82; used 24 times

Defined macros

CM_OFFSET defined in line 117; used 1 times
DEBUG defined in line 56; used 8 times
EXWATCHINTVL defined in line 60; used 2 times
EX_RUNNING defined in line 93; used 7 times
EX_SETADDR defined in line 94; used 2 times
EX_STATPENDING defined in line 92; used 3 times
EX_XPENDING defined in line 91; used 5 times
H2XENT_OFFSET defined in line 115; used 1 times
H2XHDR_OFFSET defined in line 113; used 1 times
INCORE_BASE defined in line 108; used 6 times
INCORE_SIZE defined in line 119; used 2 times
LVAL_OFF defined in line 111; used 2 times
NH2X defined in line 58; used 4 times
NX2H defined in line 59; used 4 times
P_UNIADDR defined in line 99; used 3 times
RVAL_OFF defined in line 109; used 5 times
SA_OFFSET defined in line 118; used 1 times
UNIADDR defined in line 98; used 2 times
X2HENT_OFFSET defined in line 116; used 1 times
X2HHDR_OFFSET defined in line 114; used 1 times
exdataaddr defined in line 575; used 2 times
xs_addr defined in line 85; used 6 times
xs_if defined in line 84; used 15 times
Last modified: 1986-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3126
Valid CSS Valid XHTML 1.0 Strict