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

Defined functions

ex_setaddr defined in line 892; used 2 times
exattach defined in line 175; used 2 times
excdint defined in line 465; used 2 times
exconfig defined in line 310; used 2 times
exgetcbuf defined in line 525; used 8 times
exhangrcv defined in line 648; used 2 times
exinit defined in line 246; used 5 times
exioctl defined in line 833; used 2 times
exoutput defined in line 670; used 2 times
exprobe defined in line 135; used 2 times
exrecv defined in line 550; used 1 times
exreset defined in line 226; used 2 times
exstart defined in line 428; used 3 times
exwatch defined in line 805; used 2 times

Defined variables

ex_cvecs defined in line 131; used 4 times
ex_ncall defined in line 133; used 3 times
ex_softc defined in line 122; used 17 times
exdriver defined in line 66; never used
exinfo defined in line 64; used 9 times
exstd defined in line 65; used 1 times
  • in line 67

Defined struct's

ex_cvecs defined in line 128; never used
ex_softc defined in line 83; used 24 times

Defined macros

CM_OFFSET defined in line 118; used 1 times
DEBUG defined in line 57; used 8 times
EXWATCHINTVL defined in line 61; used 2 times
EX_RUNNING defined in line 94; used 7 times
EX_SETADDR defined in line 95; used 2 times
EX_STATPENDING defined in line 93; used 3 times
EX_XPENDING defined in line 92; used 5 times
H2XENT_OFFSET defined in line 116; used 1 times
H2XHDR_OFFSET defined in line 114; used 1 times
INCORE_BASE defined in line 109; used 6 times
INCORE_SIZE defined in line 120; used 2 times
LVAL_OFF defined in line 112; used 2 times
NH2X defined in line 59; used 4 times
NX2H defined in line 60; used 4 times
P_UNIADDR defined in line 100; used 3 times
RVAL_OFF defined in line 110; used 5 times
SA_OFFSET defined in line 119; used 1 times
UNIADDR defined in line 99; used 2 times
X2HENT_OFFSET defined in line 117; used 1 times
X2HHDR_OFFSET defined in line 115; used 1 times
exdataaddr defined in line 577; used 2 times
xs_addr defined in line 86; used 6 times
xs_if defined in line 85; used 15 times
Last modified: 1987-06-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1936
Valid CSS Valid XHTML 1.0 Strict