137110Ssklower /* 237110Ssklower * Copyright (c) 1989 The Regents of the University of California. 337110Ssklower * All rights reserved. 437110Ssklower * 537110Ssklower * This code is derived from software contributed to Berkeley by 637110Ssklower * Excelan Inc. 737110Ssklower * 8*44532Sbostic * %sccs.include.redist.c% 937110Ssklower * 10*44532Sbostic * @(#)if_ex.c 7.4 (Berkeley) 06/28/90 1137110Ssklower */ 1237110Ssklower 1337110Ssklower #include "ex.h" 1437110Ssklower 1537110Ssklower #if NEX > 0 1637110Ssklower 1737110Ssklower /* 1837110Ssklower * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers 1937110Ssklower */ 2037110Ssklower #include "param.h" 2137110Ssklower #include "systm.h" 2237110Ssklower #include "mbuf.h" 2337110Ssklower #include "buf.h" 2437110Ssklower #include "protosw.h" 2537110Ssklower #include "socket.h" 2637110Ssklower #include "vmmac.h" 2737110Ssklower #include "ioctl.h" 2837110Ssklower #include "errno.h" 2937110Ssklower #include "vmparam.h" 3037110Ssklower #include "syslog.h" 3137110Ssklower #include "uio.h" 3237110Ssklower 3337110Ssklower #include "../net/if.h" 3437110Ssklower #include "../net/netisr.h" 3537110Ssklower #include "../net/route.h" 3637110Ssklower 3737110Ssklower #ifdef INET 3837110Ssklower #include "../netinet/in.h" 3937110Ssklower #include "../netinet/in_systm.h" 4037110Ssklower #include "../netinet/in_var.h" 4137110Ssklower #include "../netinet/ip.h" 4237110Ssklower #include "../netinet/if_ether.h" 4337110Ssklower #endif 4437110Ssklower 4537110Ssklower #ifdef NS 4637110Ssklower #include "../netns/ns.h" 4737110Ssklower #include "../netns/ns_if.h" 4837110Ssklower #endif 4937110Ssklower 5037474Ssklower #ifdef ISO 5137474Ssklower #include "../netiso/iso.h" 5237474Ssklower #include "../netiso/iso_var.h" 5343339Ssklower extern char all_es_snpa[], all_is_snpa[]; 5437474Ssklower #endif 5537474Ssklower 5637110Ssklower #include "../tahoe/cpu.h" 5737110Ssklower #include "../tahoe/pte.h" 5837110Ssklower #include "../tahoe/mtpr.h" 5937110Ssklower 6037110Ssklower #include "../tahoevba/vbavar.h" 6137110Ssklower #include "if_exreg.h" 6237110Ssklower #include "if_vba.h" 6337110Ssklower 6437110Ssklower 6537110Ssklower #define NH2X 32 /* Host to eXcelan request buffers */ 6637110Ssklower 6737110Ssklower #define NX2H 16 /* eXcelan to Host reply buffers */ 6837110Ssklower #define NREC 16 /* Number of RECeive buffers */ 6937110Ssklower #define NTRB 4 /* Number of TRansmit Buffers */ 7037110Ssklower #define NVBI (NREC + NTRB) 7137110Ssklower 7237110Ssklower #define EXWATCHINTVL 10 /* call exwatch every x secs */ 7337110Ssklower 7437110Ssklower int exprobe(), exslave(), exattach(), exintr(), exstart(); 7537110Ssklower struct vba_device *exinfo[NEX]; 7637110Ssklower 7737110Ssklower long exstd[] = { 0 }; 7837110Ssklower 7937110Ssklower 8037110Ssklower struct vba_driver exdriver = 8137110Ssklower { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; 8237110Ssklower int exinit(),ether_output(),exioctl(),exreset(),exwatch(); 8337110Ssklower struct ex_msg *exgetcbuf(); 8437110Ssklower int ex_ncall = 0; /* counts calls to exprobe */ 8537110Ssklower u_long busoff; 8637110Ssklower 8737110Ssklower /* 8837110Ssklower * Ethernet software status per interface. 8937110Ssklower * 9037110Ssklower * Each interface is referenced by a network interface structure, xs_if, which 9137110Ssklower * the routing code uses to locate the interface. This structure contains the 9237110Ssklower * output queue for the interface, its address, ... NOTE: To configure multiple 9337110Ssklower * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). 9437110Ssklower */ 9537110Ssklower struct ex_softc { 9637110Ssklower struct arpcom xs_ac; /* Ethernet common part */ 9737110Ssklower #define xs_if xs_ac.ac_if /* network-visible interface */ 9837110Ssklower #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 9937110Ssklower int xs_flags; /* private flags */ 10037110Ssklower #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ 10137110Ssklower #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ 10237110Ssklower #define EX_RUNNING (1<<2) /* board is running */ 10337110Ssklower #define EX_SETADDR (1<<3) /* physaddr has been changed */ 10437110Ssklower int xs_cvec; /* probe stores cvec here */ 10537110Ssklower short xs_enetunit; /* unit number for enet filtering */ 10637110Ssklower short xs_enetinit; /* enet inetrface is initialized */ 10737110Ssklower struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 10837110Ssklower struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 10937110Ssklower u_long xs_qbaddr; /* map info for structs below */ 11037474Ssklower struct ex_shm { 11137110Ssklower /* the following structures are always mapped in */ 11237474Ssklower u_short sm_h2xhdr; /* EXOS's request queue header */ 11337474Ssklower u_short sm_x2hhdr; /* EXOS's reply queue header */ 11437474Ssklower struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ 11537474Ssklower struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ 11637474Ssklower struct ex_conf sm_cm; /* configuration message */ 11737474Ssklower struct ex_stat sm_xsa; /* EXOS writes stats here */ 11837110Ssklower /* end mapped area */ 11937474Ssklower } *xs_shm; /* host pointer to shared area */ 12037474Ssklower #define xs_h2xhdr xs_shm->sm_h2xhdr 12137474Ssklower #define xs_x2hhdr xs_shm->sm_x2hhdr 12237474Ssklower #define xs_h2xent xs_shm->sm_h2xent 12337474Ssklower #define xs_x2hent xs_shm->sm_x2hent 12437474Ssklower #define xs_cm xs_shm->sm_cm 12537474Ssklower #define xs_xsa xs_shm->sm_xsa 12637474Ssklower #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF)) 12737474Ssklower #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0)) 12837474Ssklower #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0) 12937474Ssklower /* we will arrange that the shared memory begins on a 16 byte boundary */ 13037474Ssklower #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0) 13137474Ssklower #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0) 13237474Ssklower #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr) 13337474Ssklower #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr) 13437474Ssklower #define H2XENT_OFFSET LVAL_OFF(sm_h2xent) 13537474Ssklower #define X2HENT_OFFSET LVAL_OFF(sm_x2hent) 13637474Ssklower #define CM_OFFSET RVAL_OFF(sm_cm) 13737474Ssklower #define SA_OFFSET RVAL_OFF(sm_xsa) 13837110Ssklower struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ 13937110Ssklower struct ifvba *xs_pkblist; /* free list of above */ 14037474Ssklower #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ 14137474Ssklower (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf)) 14237474Ssklower #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ 14337474Ssklower (xs->xs_pkblist = v)) 14437110Ssklower char xs_nrec; /* number of pending receive buffers */ 14537110Ssklower char xs_ntrb; /* number of pending transmit buffers */ 14637110Ssklower } ex_softc[NEX]; 14737110Ssklower 14837110Ssklower int ex_padcheck = sizeof (struct ex_softc); 14937110Ssklower 15037110Ssklower exprobe(reg, vi) 15137110Ssklower caddr_t reg; 15237110Ssklower struct vba_device *vi; 15337110Ssklower { 15437110Ssklower register br, cvec; /* r12, r11 value-result */ 15537110Ssklower register struct exdevice *exaddr = (struct exdevice *)reg; 15637110Ssklower int i; 15737110Ssklower 15837474Ssklower if (badaddr((caddr_t)exaddr, 2)) 15937110Ssklower return 0; 16037110Ssklower /* 16137110Ssklower * Reset EXOS and run self-test (should complete within 2 seconds). 16237110Ssklower */ 16337110Ssklower movow(&exaddr->ex_porta, EX_RESET); 16437110Ssklower for (i = 1000000; i; i--) { 16537110Ssklower uncache(&(exaddr->ex_portb)); 16637110Ssklower if (exaddr->ex_portb & EX_TESTOK) 16737110Ssklower break; 16837110Ssklower } 16937110Ssklower if ((exaddr->ex_portb & EX_TESTOK) == 0) 17037110Ssklower return 0; 17137110Ssklower br = 0x15; 17237110Ssklower cvec = --vi->ui_hd->vh_lastiv; 17337110Ssklower ex_softc[vi->ui_unit].xs_cvec = cvec; 17437110Ssklower ex_ncall++; 17537110Ssklower return (sizeof(struct exdevice)); 17637110Ssklower } 17737110Ssklower 17837110Ssklower /* 17937110Ssklower * Interface exists: make available by filling in network interface record. 18037110Ssklower * System will initialize the interface when it is ready to accept packets. 18137110Ssklower * A NET_ADDRS command is done to get the ethernet address. 18237110Ssklower */ 18337110Ssklower exattach(ui) 18437110Ssklower register struct vba_device *ui; 18537110Ssklower { 18637110Ssklower register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 18737110Ssklower register struct ifnet *ifp = &xs->xs_if; 18837110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 18937110Ssklower register struct ex_msg *bp; 19037110Ssklower 19137110Ssklower ifp->if_unit = ui->ui_unit; 19237110Ssklower ifp->if_name = "ex"; 19337110Ssklower ifp->if_mtu = ETHERMTU; 19437110Ssklower ifp->if_init = exinit; 19537110Ssklower ifp->if_ioctl = exioctl; 19637110Ssklower ifp->if_output = ether_output; 19737110Ssklower ifp->if_reset = exreset; 19837110Ssklower ifp->if_start = exstart; 19937474Ssklower ifp->if_flags = IFF_BROADCAST; 20037110Ssklower 20137474Ssklower /* 20237474Ssklower * Note: extra memory gets returned by if_vbareserve() 20337474Ssklower * first, so, being page alligned, it is also 16-byte alligned. 20437474Ssklower */ 20537474Ssklower if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, 20637474Ssklower (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) 20737110Ssklower return; 20837110Ssklower /* 20937110Ssklower * Temporarily map queues in order to configure EXOS 21037110Ssklower */ 21137110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 21237110Ssklower exconfig(ui, 0); /* without interrupts */ 21337110Ssklower if (xs->xs_cm.cm_cc) 21437110Ssklower return; /* bad conf */ 21537110Ssklower /* 21637110Ssklower * Get Ethernet address. 21737110Ssklower */ 21837110Ssklower if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) 21937110Ssklower panic("exattach"); 22037110Ssklower bp->mb_na.na_mask = READ_OBJ; 22137110Ssklower bp->mb_na.na_slot = PHYSSLOT; 22237110Ssklower bp->mb_status |= MH_EXOS; 22337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 22437110Ssklower bp = xs->xs_x2hnext; 22537474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 22637110Ssklower printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n", 22737110Ssklower ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], 22837110Ssklower xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], 22937110Ssklower ether_sprintf(bp->mb_na.na_addrs)); 23037110Ssklower bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, 23137110Ssklower sizeof(xs->xs_addr)); 23237110Ssklower if_attach(ifp); 23337110Ssklower } 23437110Ssklower 23537110Ssklower /* 23637110Ssklower * Reset of interface after BUS reset. 23737110Ssklower * If interface is on specified vba, reset its state. 23837110Ssklower */ 23937110Ssklower exreset(unit) 24037110Ssklower int unit; 24137110Ssklower { 24237110Ssklower register struct vba_device *ui; 24337110Ssklower 24437110Ssklower if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) 24537110Ssklower return; 24637110Ssklower printf(" ex%d", unit); 24737110Ssklower ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 24837110Ssklower ex_softc[unit].xs_flags &= ~EX_RUNNING; 24937110Ssklower 25037110Ssklower exinit(unit); 25137110Ssklower } 25237110Ssklower 25337110Ssklower /* 25437110Ssklower * Initialization of interface; clear recorded pending operations, and 25537110Ssklower * reinitialize BUS usage. Called at boot time, and at ifconfig time via 25637110Ssklower * exioctl, with interrupts disabled. 25737110Ssklower */ 25837110Ssklower exinit(unit) 25937110Ssklower int unit; 26037110Ssklower { 26137110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 26237110Ssklower register struct vba_device *ui = exinfo[unit]; 26337110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 26437110Ssklower register struct ifnet *ifp = &xs->xs_if; 26537110Ssklower register struct sockaddr_in *sin; 26637110Ssklower register struct ex_msg *bp; 26737110Ssklower int s; 26837110Ssklower 26937110Ssklower /* not yet, if address still unknown */ 27037110Ssklower if (ifp->if_addrlist == (struct ifaddr *)0) 27137110Ssklower return; 27237110Ssklower if (xs->xs_flags & EX_RUNNING) 27337110Ssklower return; 27437110Ssklower 27537110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 27637110Ssklower exconfig(ui, 4); /* with vectored interrupts*/ 27737110Ssklower 27837110Ssklower /* 27937110Ssklower * Put EXOS on the Ethernet, using NET_MODE command 28037110Ssklower */ 28137110Ssklower if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) 28237110Ssklower panic("exinit"); 28337110Ssklower bp->mb_nm.nm_mask = WRITE_OBJ; 28437110Ssklower bp->mb_nm.nm_optn = 0; 28537110Ssklower bp->mb_nm.nm_mode = MODE_PERF; 28637110Ssklower bp->mb_status |= MH_EXOS; 28737110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 28837110Ssklower bp = xs->xs_x2hnext; 28937474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 29037474Ssklower ; 29137110Ssklower bp->mb_length = MBDATALEN; 29237110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 29337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 29437110Ssklower xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 29537110Ssklower 29637110Ssklower ifp->if_watchdog = exwatch; 29737110Ssklower ifp->if_timer = EXWATCHINTVL; 29837110Ssklower s = splimp(); /* are interrupts disabled here, anyway? */ 29937110Ssklower exhangrcv(unit); 30037110Ssklower xs->xs_if.if_flags |= IFF_RUNNING; 30137110Ssklower xs->xs_flags |= EX_RUNNING; 30237110Ssklower if (xs->xs_flags & EX_SETADDR) 30337110Ssklower ex_setaddr((u_char *)0, unit); 30437474Ssklower #ifdef ISO 30543339Ssklower ex_setmulti(all_es_snpa, unit, 1); 30643339Ssklower ex_setmulti(all_is_snpa, unit, 2); 30737474Ssklower #endif 30837110Ssklower exstart(&ex_softc[unit].xs_if); /* start transmits */ 30937110Ssklower splx(s); /* are interrupts disabled here, anyway? */ 31037110Ssklower } 31137110Ssklower 31237110Ssklower /* 31337110Ssklower * Reset, test, and configure EXOS. It is called by exinit, and exattach. 31437110Ssklower * Returns 0 if successful, 1 if self-test failed. 31537110Ssklower */ 31637110Ssklower exconfig(ui, itype) 31737110Ssklower struct vba_device *ui; 31837110Ssklower int itype; 31937110Ssklower { 32037110Ssklower register int unit = ui->ui_unit; 32137110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 32237110Ssklower register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; 32337474Ssklower register struct ex_conf *cm = &xs->xs_cm; 32437110Ssklower register struct ex_msg *bp; 32537110Ssklower register struct ifvba *pkb; 32637110Ssklower int i; 32737110Ssklower u_long shiftreg; 32837110Ssklower static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; 32937110Ssklower 33037110Ssklower xs->xs_flags = 0; 33137110Ssklower /* 33237110Ssklower * Reset EXOS, wait for self-test to complete 33337110Ssklower */ 33437110Ssklower movow(&exaddr->ex_porta, EX_RESET); 33537110Ssklower do { 33637110Ssklower uncache(&exaddr->ex_portb); 33737110Ssklower } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; 33837110Ssklower /* 33937110Ssklower * Set up configuration message. 34037110Ssklower */ 34137110Ssklower cm->cm_1rsrv = 1; 34237110Ssklower cm->cm_cc = 0xFF; 34337110Ssklower cm->cm_opmode = 0; /* link-level controller mode */ 34437110Ssklower cm->cm_dfo = 0x0101; /* enable host data order conversion */ 34537110Ssklower cm->cm_dcn1 = 1; 34637110Ssklower cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; 34737110Ssklower cm->cm_ham = 3; /* absolute address mode */ 34837110Ssklower cm->cm_3rsrv = 0; 34937110Ssklower cm->cm_mapsiz = 0; 35037110Ssklower cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 35137110Ssklower cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 35237110Ssklower cm->cm_byteptrn[2] = 0x07; 35337110Ssklower cm->cm_byteptrn[3] = 0x0F; 35437110Ssklower cm->cm_wordptrn[0] = 0x0103; 35537110Ssklower cm->cm_wordptrn[1] = 0x070F; 35637110Ssklower cm->cm_lwordptrn = 0x0103070F; 35737110Ssklower for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 35837110Ssklower cm->cm_mba = 0xFFFFFFFF; 35937110Ssklower cm->cm_nproc = 0xFF; 36037110Ssklower cm->cm_nmbox = 0xFF; 36137110Ssklower cm->cm_nmcast = 0xFF; 36237110Ssklower cm->cm_nhost = 1; 36337110Ssklower cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); 36437110Ssklower cm->cm_h2xhdr = H2XHDR_OFFSET; 36537110Ssklower cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 36637110Ssklower cm->cm_x2hba = cm->cm_h2xba; 36737110Ssklower cm->cm_x2hhdr = X2HHDR_OFFSET; 36837110Ssklower cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 36937110Ssklower cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ 37037110Ssklower /* 37137110Ssklower * Set up message queues and headers. 37237110Ssklower * First the request queue 37337110Ssklower */ 37437110Ssklower for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { 37537110Ssklower bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 37637110Ssklower bp->mb_rsrv = 0; 37737110Ssklower bp->mb_length = MBDATALEN; 37837110Ssklower bp->mb_status = MH_HOST; 37937110Ssklower bp->mb_next = bp+1; 38037110Ssklower } 38137110Ssklower xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; 38237110Ssklower xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; 38337110Ssklower 38437110Ssklower /* Now the reply queue. */ 38537110Ssklower for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 38637110Ssklower bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 38737110Ssklower bp->mb_rsrv = 0; 38837110Ssklower bp->mb_length = MBDATALEN; 38937110Ssklower bp->mb_status = MH_EXOS; 39037110Ssklower bp->mb_next = bp+1; 39137110Ssklower } 39237110Ssklower xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; 39337110Ssklower xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; 39437110Ssklower xs->xs_nrec = 0; 39537110Ssklower xs->xs_ntrb = 0; 39637110Ssklower xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; 39737474Ssklower for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) 39837110Ssklower pkb->iff_mbuf = (struct mbuf *)(pkb - 1); 39937110Ssklower xs->xs_vbinfo[0].iff_mbuf = 0; 40037110Ssklower 40137110Ssklower /* 40237110Ssklower * Write config msg address to EXOS and wait for configuration to 40337110Ssklower * complete (guaranteed response within 2 seconds). 40437110Ssklower */ 40537110Ssklower shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; 40637110Ssklower for (i = 4; i < 8; i++) { 40737110Ssklower cmaddr[i] = (u_char)(shiftreg & 0xFF); 40837110Ssklower shiftreg >>= 8; 40937110Ssklower } 41037110Ssklower for (i = 0; i < 8; i++) { 41137110Ssklower do { 41237110Ssklower uncache(&exaddr->ex_portb); 41337110Ssklower } while (exaddr->ex_portb & EX_UNREADY) ; 41437110Ssklower DELAY(500); 41537110Ssklower movow(&exaddr->ex_portb, cmaddr[i]); 41637110Ssklower } 41737110Ssklower for (i = 500000; i; --i) { 41837110Ssklower DELAY(10); 41937110Ssklower uncache(&cm->cm_cc); 42037110Ssklower if (cm->cm_cc != 0xFF) 42137110Ssklower break; 42237110Ssklower } 42337110Ssklower if (cm->cm_cc) 42437110Ssklower printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); 42537110Ssklower } 42637110Ssklower 42737110Ssklower /* 42837110Ssklower * Start or re-start output on interface. Get another datagram to send off of 42937110Ssklower * the interface queue, and map it to the interface before starting the output. 43037110Ssklower * This routine is called by exinit(), exoutput(), and excdint(). In all cases, 43137110Ssklower * interrupts by EXOS are disabled. 43237110Ssklower */ 43337110Ssklower exstart(ifp) 43437110Ssklower struct ifnet *ifp; 43537110Ssklower { 43637110Ssklower int unit = ifp->if_unit; 43737110Ssklower struct vba_device *ui = exinfo[unit]; 43837110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 43937110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 44037110Ssklower register struct ex_msg *bp; 44137110Ssklower register struct mbuf *m; 44237110Ssklower int len; 44337110Ssklower register struct ifvba *pkb; 44437474Ssklower struct mbuf *m0 = 0; 44537474Ssklower register int nb = 0, tlen = 0; 44637110Ssklower union l_util { 44737110Ssklower u_long l; 44837110Ssklower struct i86_long i; 44937110Ssklower } l_util; 45037110Ssklower 45137110Ssklower if (xs->xs_ntrb >= NTRB) 45237110Ssklower return; 45337110Ssklower if (xs->xs_pkblist == 0) { 45437110Ssklower printf("ex%d: vbinfo exhausted, would panic", unit); 45537110Ssklower return; 45637110Ssklower } 45737110Ssklower IF_DEQUEUE(&xs->xs_if.if_snd, m); 45837110Ssklower if (m == 0) 45937110Ssklower return; 46037110Ssklower /* 46137110Ssklower * Get a transmit request. 46237110Ssklower */ 46337110Ssklower if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { 46437110Ssklower m_freem(m); 46537110Ssklower printf("exstart: no command buffers\n"); 46637110Ssklower return; 46737110Ssklower } 46837110Ssklower xs->xs_ntrb++; 46937474Ssklower GetPkBuf(bp, pkb); 47037110Ssklower pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ 47137110Ssklower /* 47237110Ssklower * point directly to the first group of mbufs to be transmitted. The 47337110Ssklower * hardware can only support NFRAGMENTS descriptors. 47437110Ssklower */ 47537110Ssklower while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { 47637474Ssklower l_util.l = BUSADDR(mtod(m, caddr_t)); 47737110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; 47837110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 47937474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 48037474Ssklower /* Here, the phys memory for the mbuf is out 48137474Ssklower of range for the vmebus to talk to it */ 48237474Ssklower if (m == pkb->iff_mbuf) 48337474Ssklower pkb->iff_mbuf = 0; 48437474Ssklower break; 48537474Ssklower } 48637110Ssklower tlen += m->m_len; 48737110Ssklower m0 = m; 48837110Ssklower m = m->m_next; 48937110Ssklower nb++; 49037110Ssklower } 49137110Ssklower 49237110Ssklower /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ 49337110Ssklower if (m0) 49437110Ssklower m0->m_next = 0; 49537110Ssklower 49637110Ssklower /* 49737110Ssklower * if not all of the descriptors would fit then merge remaining data 49837110Ssklower * into the transmit buffer, and point to it. Note: the mbufs are freed 49937110Ssklower * during the merge, they do not have to be freed when we get the 50037110Ssklower * transmit interrupt. 50137110Ssklower */ 50237110Ssklower if (m) { 50337474Ssklower if (m == pkb->iff_mbuf) { 50437474Ssklower printf("ex%d: exstart insanity\n", unit); 50537474Ssklower pkb->iff_mbuf = 0; 50637474Ssklower } 50737474Ssklower len = if_vbaput(pkb->iff_buffer, m, 0); 50837110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 50937110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)len; 51037110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 51137110Ssklower tlen += len; 51237110Ssklower nb++; 51337110Ssklower } 51437110Ssklower 51537110Ssklower /* 51637474Ssklower * If the total length of the packet is too small, 51737474Ssklower * pad the last fragment. (May run into very obscure problems) 51837110Ssklower */ 51937474Ssklower if (tlen < sizeof(struct ether_header) + ETHERMIN) { 52037110Ssklower len = (ETHERMIN + sizeof(struct ether_header)) - tlen; 52137110Ssklower bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; 52237110Ssklower tlen += len; 52337474Ssklower #ifdef notdef 52437474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 52537474Ssklower must copy last frag into private buffer 52637474Ssklower } 52737474Ssklower #endif 52837110Ssklower } 52937110Ssklower 53037110Ssklower /* set number of fragments in descriptor */ 53137110Ssklower bp->mb_et.et_nblock = nb; 53237110Ssklower bp->mb_status |= MH_EXOS; 53337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 53437110Ssklower } 53537110Ssklower 53637110Ssklower /* 53737110Ssklower * interrupt service routine. 53837110Ssklower */ 53937110Ssklower exintr(unit) 54037110Ssklower int unit; 54137110Ssklower { 54237110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 54337110Ssklower register struct ex_msg *bp = xs->xs_x2hnext; 54437110Ssklower struct vba_device *ui = exinfo[unit]; 54537110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 54637474Ssklower struct ex_msg *next_bp; 54737110Ssklower 54837110Ssklower while ((bp->mb_status & MH_OWNER) == MH_HOST) { 54937110Ssklower switch (bp->mb_rqst) { 55037110Ssklower case LLRECEIVE: 55137474Ssklower if (--xs->xs_nrec < 0) { 55237474Ssklower printf("ex%d: internal receive check\n", unit); 55337110Ssklower xs->xs_nrec = 0; 55437474Ssklower } 55537110Ssklower exrecv(unit, bp); 55637110Ssklower FreePkBuf(bp->mb_pkb); 55737110Ssklower bp->mb_pkb = (struct ifvba *)0; 55837110Ssklower exhangrcv(unit); 55937110Ssklower break; 56037110Ssklower 56137110Ssklower case LLTRANSMIT: 56237110Ssklower case LLRTRANSMIT: 56337474Ssklower if (--xs->xs_ntrb < 0) { 56437474Ssklower printf("ex%d: internal transmit check\n", unit); 56537110Ssklower xs->xs_ntrb = 0; 56637474Ssklower } 56737110Ssklower xs->xs_if.if_opackets++; 56837474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 56937110Ssklower ; 57037110Ssklower else if (bp->mb_rply & LLXM_1RTRY) 57137110Ssklower xs->xs_if.if_collisions++; 57237110Ssklower else if (bp->mb_rply & LLXM_RTRYS) 57337110Ssklower xs->xs_if.if_collisions += 2; /* guess */ 57437110Ssklower else if (bp->mb_rply & LLXM_ERROR) 57537110Ssklower if (xs->xs_if.if_oerrors++ % 100 == 0) 57637110Ssklower printf("ex%d: 100 transmit errors=%b\n", 57737110Ssklower unit, bp->mb_rply, XMIT_BITS); 57837110Ssklower if (bp->mb_pkb->iff_mbuf) { 57937110Ssklower m_freem(bp->mb_pkb->iff_mbuf); 58037110Ssklower bp->mb_pkb->iff_mbuf = (struct mbuf *)0; 58137110Ssklower } 58237110Ssklower FreePkBuf(bp->mb_pkb); 58337110Ssklower bp->mb_pkb = (struct ifvba *)0; 58437474Ssklower exstart(&xs->xs_if); 58537110Ssklower exhangrcv(unit); 58637110Ssklower break; 58737110Ssklower 58837110Ssklower case LLNET_STSTCS: 58937110Ssklower xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; 59037110Ssklower xs->xs_flags &= ~EX_STATPENDING; 59137474Ssklower case LLNET_ADDRS: 59237474Ssklower case LLNET_RECV: 59337474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 59437474Ssklower ; 59537474Ssklower else 59637474Ssklower printf("ex%d: %s, request 0x%x, reply 0x%x\n", 59737474Ssklower unit, "unsucessful stat or address change", 59837474Ssklower bp->mb_rqst, bp->mb_rply); 59937110Ssklower break; 60037110Ssklower 60137110Ssklower default: 60237110Ssklower printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); 60337110Ssklower } 60437110Ssklower bp->mb_length = MBDATALEN; 60537474Ssklower next_bp = bp->mb_next; 60637110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 60737474Ssklower bp = next_bp; /* paranoia about race */ 60837110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ 60937110Ssklower } 61037110Ssklower xs->xs_x2hnext = bp; 61137110Ssklower } 61237110Ssklower 61337110Ssklower /* 61437110Ssklower * Get a request buffer, fill in standard values, advance pointer. 61537110Ssklower */ 61637110Ssklower struct ex_msg * 61737110Ssklower exgetcbuf(xs, req) 61837110Ssklower struct ex_softc *xs; 61937110Ssklower int req; 62037110Ssklower { 62137110Ssklower register struct ex_msg *bp; 62237110Ssklower struct ifvba *pkb; 62337110Ssklower int s = splimp(); 62437110Ssklower 62537110Ssklower bp = xs->xs_h2xnext; 62637110Ssklower if ((bp->mb_status & MH_OWNER) == MH_EXOS) { 62737110Ssklower splx(s); 62837110Ssklower return (struct ex_msg *)0; 62937110Ssklower } 63037110Ssklower xs->xs_h2xnext = bp->mb_next; 63137110Ssklower bp->mb_1rsrv = 0; 63237110Ssklower bp->mb_rqst = req; 63337110Ssklower bp->mb_length = MBDATALEN; 63437110Ssklower bp->mb_pkb = (struct ifvba *)0; 63537110Ssklower splx(s); 63637110Ssklower return bp; 63737110Ssklower } 63837110Ssklower 63937110Ssklower /* 64037110Ssklower * Process Ethernet receive completion: If input error just drop packet, 64137110Ssklower * otherwise examine packet to determine type. If can't determine length from 64237110Ssklower * type, then have to drop packet, otherwise decapsulate packet based on type 64337110Ssklower * and pass to type-specific higher-level input routine. 64437110Ssklower */ 64537110Ssklower exrecv(unit, bp) 64637110Ssklower int unit; 64737110Ssklower register struct ex_msg *bp; 64837110Ssklower { 64937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 65037110Ssklower register struct ether_header *eh; 65137110Ssklower register struct mbuf *m; 65237110Ssklower int len, off, resid; 65337110Ssklower register struct ifqueue *inq; 65437110Ssklower int s; 65537110Ssklower 65637110Ssklower xs->xs_if.if_ipackets++; 65737110Ssklower /* total length - header - crc */ 65837110Ssklower len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 65937110Ssklower if (bp->mb_rply != LL_OK) { 66037110Ssklower if (xs->xs_if.if_ierrors++ % 100 == 0) 66137110Ssklower printf("ex%d: 100 receive errors=%b\n", 66237110Ssklower unit, bp->mb_rply, RECV_BITS); 66337110Ssklower return; 66437110Ssklower } 66537110Ssklower eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); 66637110Ssklower 66737110Ssklower /* 66837110Ssklower * Deal with trailer protocol: if type is PUP trailer get true type from 66937110Ssklower * first 16-bit word past data. Remember that type was trailer by 67037110Ssklower * setting off. 67137110Ssklower */ 67237110Ssklower eh->ether_type = ntohs((u_short)eh->ether_type); 67337110Ssklower #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 67437110Ssklower if (eh->ether_type >= ETHERTYPE_TRAIL && 67537110Ssklower eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 67637110Ssklower off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 67737110Ssklower if (off >= ETHERMTU) 67837110Ssklower return; /* sanity */ 67937110Ssklower eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 68037110Ssklower resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 68137110Ssklower if (off + resid > len) 68237110Ssklower return; /* sanity */ 68337110Ssklower len = off + resid; 68437110Ssklower } else 68537110Ssklower off = 0; 68637110Ssklower if (len == 0) 68737110Ssklower return; 68837110Ssklower /* 68937110Ssklower * Pull packet off interface. Off is nonzero if packet 69037110Ssklower * has trailing header; if_vbaget will then force this header 69137110Ssklower * information to be at the front, but we still have to drop 69237110Ssklower * the type and length which are at the front of any trailer data. 69337110Ssklower */ 69437110Ssklower m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); 69537110Ssklower if (m == 0) 69637110Ssklower return; 69737110Ssklower ether_input(&xs->xs_if, eh, m); 69837110Ssklower return; 69937110Ssklower } 70037110Ssklower 70137110Ssklower /* 70237110Ssklower * Hang a receive request. This routine is called by exinit and excdint, 70337110Ssklower * with interrupts disabled in both cases. 70437110Ssklower */ 70537110Ssklower exhangrcv(unit) 70637110Ssklower int unit; 70737110Ssklower { 70837110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 70937110Ssklower register struct ex_msg *bp; 71037110Ssklower register struct ifvba *pkb; 71137110Ssklower short mustint = 0; 71237110Ssklower union l_util { 71337110Ssklower u_long l; 71437110Ssklower struct i86_long i; 71537110Ssklower } l_util; 71637110Ssklower 71737110Ssklower while (xs->xs_nrec < NREC) { 71837110Ssklower if (xs->xs_pkblist == (struct ifvba *)0) 71937110Ssklower break; 72037110Ssklower if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { 72137110Ssklower break; 72237110Ssklower } 72337474Ssklower GetPkBuf(bp, pkb); 72437474Ssklower pkb->iff_mbuf = 0; 72537110Ssklower xs->xs_nrec += 1; 72637110Ssklower bp->mb_er.er_nblock = 1; 72737110Ssklower bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 72837110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 72937110Ssklower bp->mb_er.er_blks[0].bb_addr = l_util.i; 73037110Ssklower bp->mb_status |= MH_EXOS; 73137110Ssklower mustint = 1; 73237110Ssklower } 73337110Ssklower if (mustint == 0) 73437110Ssklower return; 73537110Ssklower movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); 73637110Ssklower } 73737110Ssklower 73837110Ssklower /* 73937110Ssklower * Ethernet output routine is ether_output(). 74037110Ssklower */ 74137110Ssklower 74237110Ssklower /* 74337110Ssklower * Watchdog routine (currently not used). Might use this to get stats from EXOS. 74437110Ssklower */ 74537110Ssklower exwatch(unit) 74637110Ssklower int unit; 74737110Ssklower { 74837110Ssklower struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; 74937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 75037110Ssklower register struct ex_msg *bp; 75137110Ssklower int s = splimp(); 75237110Ssklower 75337110Ssklower if (xs->xs_flags & EX_STATPENDING) 75437110Ssklower goto exspnd; 75537110Ssklower if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { 75637110Ssklower splx(s); 75737110Ssklower return; 75837110Ssklower } 75937110Ssklower xs->xs_flags |= EX_STATPENDING; 76037110Ssklower bp->mb_ns.ns_mask = READ_OBJ; 76137110Ssklower bp->mb_ns.ns_rsrv = 0; 76237110Ssklower bp->mb_ns.ns_nobj = 8; 76337110Ssklower bp->mb_ns.ns_xobj = 0; 76437110Ssklower bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; 76537110Ssklower bp->mb_status |= MH_EXOS; 76637110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 76737110Ssklower exspnd: splx(s); 76837110Ssklower xs->xs_if.if_timer = EXWATCHINTVL; 76937110Ssklower } 77037110Ssklower 77137110Ssklower /* 77237110Ssklower * Process an ioctl request. 77337110Ssklower */ 77437110Ssklower exioctl(ifp, cmd, data) 77537110Ssklower register struct ifnet *ifp; 77637110Ssklower int cmd; 77737110Ssklower caddr_t data; 77837110Ssklower { 77937110Ssklower register struct ifaddr *ifa = (struct ifaddr *)data; 78037110Ssklower register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 78137110Ssklower int s = splimp(), error = 0; 78237110Ssklower 78337110Ssklower switch (cmd) { 78437110Ssklower 78537110Ssklower case SIOCSIFADDR: 78637110Ssklower ifp->if_flags |= IFF_UP; 78737110Ssklower exinit(ifp->if_unit); 78837110Ssklower 78937110Ssklower switch (ifa->ifa_addr->sa_family) { 79037110Ssklower #ifdef INET 79137110Ssklower case AF_INET: 79237110Ssklower ((struct arpcom *)ifp)->ac_ipaddr = 79337110Ssklower IA_SIN(ifa)->sin_addr; 79437110Ssklower arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 79537110Ssklower break; 79637110Ssklower #endif 79737110Ssklower #ifdef NS 79837110Ssklower case AF_NS: 79937110Ssklower { 80037110Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 80137110Ssklower 80237110Ssklower if (ns_nullhost(*ina)) 80337110Ssklower ina->x_host = *(union ns_host *)(xs->xs_addr); 80437110Ssklower else 80537110Ssklower ex_setaddr(ina->x_host.c_host,ifp->if_unit); 80637110Ssklower break; 80737110Ssklower } 80837110Ssklower #endif 80937110Ssklower } 81037110Ssklower break; 81137110Ssklower 81237110Ssklower case SIOCSIFFLAGS: 81337110Ssklower if ((ifp->if_flags & IFF_UP) == 0 && 81437110Ssklower xs->xs_flags & EX_RUNNING) { 81537110Ssklower movow(&((struct exdevice *) 81637110Ssklower (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); 81737110Ssklower xs->xs_flags &= ~EX_RUNNING; 81837110Ssklower } else if (ifp->if_flags & IFF_UP && 81937110Ssklower (xs->xs_flags & EX_RUNNING) == 0) 82037110Ssklower exinit(ifp->if_unit); 82137110Ssklower break; 82237110Ssklower 82337110Ssklower default: 82437110Ssklower error = EINVAL; 82537110Ssklower } 82637110Ssklower splx(s); 82737110Ssklower return (error); 82837110Ssklower } 82937110Ssklower 83037110Ssklower /* 83137110Ssklower * set ethernet address for unit 83237110Ssklower */ 83337110Ssklower ex_setaddr(physaddr, unit) 83437110Ssklower u_char *physaddr; 83537110Ssklower int unit; 83637110Ssklower { 83737110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 83837110Ssklower 83937110Ssklower if (physaddr) { 84037110Ssklower xs->xs_flags |= EX_SETADDR; 84137110Ssklower bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 84237110Ssklower } 84337474Ssklower ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); 84437474Ssklower } 84537474Ssklower 84637474Ssklower /* 84737474Ssklower * Enable multicast reception for unit. 84837474Ssklower */ 84937474Ssklower ex_setmulti(linkaddr, unit, slot) 85037474Ssklower u_char *linkaddr; 85137474Ssklower int unit, slot; 85237474Ssklower { 85337474Ssklower register struct ex_softc *xs = &ex_softc[unit]; 85437474Ssklower struct vba_device *ui = exinfo[unit]; 85537474Ssklower register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 85637474Ssklower register struct ex_msg *bp; 85737474Ssklower 85837474Ssklower if (!(xs->xs_flags & EX_RUNNING)) 85937110Ssklower return; 86037474Ssklower bp = exgetcbuf(xs, LLNET_ADDRS); 86137110Ssklower bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 86237474Ssklower bp->mb_na.na_slot = slot; 86337474Ssklower bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); 86437110Ssklower bp->mb_status |= MH_EXOS; 86537110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 86637110Ssklower bp = xs->xs_x2hnext; 86737474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 86837110Ssklower #ifdef DEBUG 86937474Ssklower log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, 87037474Ssklower (slot == PHYSSLOT ? "reset addr" : "add multicast" 87137474Ssklower ether_sprintf(bp->mb_na.na_addrs), slot); 87237110Ssklower #endif 87337110Ssklower /* 87437474Ssklower * Now, re-enable reception on slot. 87537110Ssklower */ 87637474Ssklower bp = exgetcbuf(xs, LLNET_RECV); 87737110Ssklower bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 87837474Ssklower bp->mb_nr.nr_slot = slot; 87937110Ssklower bp->mb_status |= MH_EXOS; 88037110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 88137110Ssklower bp = xs->xs_x2hnext; 88237474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 88337110Ssklower ; 88437110Ssklower } 88537110Ssklower #endif 886