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 * 837110Ssklower * Redistribution and use in source and binary forms are permitted 937110Ssklower * provided that the above copyright notice and this paragraph are 1037110Ssklower * duplicated in all such forms and that any documentation, 1137110Ssklower * advertising materials, and other materials related to such 1237110Ssklower * distribution and use acknowledge that the software was developed 1337110Ssklower * by the University of California, Berkeley. The name of the 1437110Ssklower * University may not be used to endorse or promote products derived 1537110Ssklower * from this software without specific prior written permission. 1637110Ssklower * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1737110Ssklower * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1837110Ssklower * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1937110Ssklower * 20*43339Ssklower * @(#)if_ex.c 7.3 (Berkeley) 06/20/90 2137110Ssklower */ 2237110Ssklower 2337110Ssklower #include "ex.h" 2437110Ssklower 2537110Ssklower #if NEX > 0 2637110Ssklower 2737110Ssklower /* 2837110Ssklower * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers 2937110Ssklower */ 3037110Ssklower #include "param.h" 3137110Ssklower #include "systm.h" 3237110Ssklower #include "mbuf.h" 3337110Ssklower #include "buf.h" 3437110Ssklower #include "protosw.h" 3537110Ssklower #include "socket.h" 3637110Ssklower #include "vmmac.h" 3737110Ssklower #include "ioctl.h" 3837110Ssklower #include "errno.h" 3937110Ssklower #include "vmparam.h" 4037110Ssklower #include "syslog.h" 4137110Ssklower #include "uio.h" 4237110Ssklower 4337110Ssklower #include "../net/if.h" 4437110Ssklower #include "../net/netisr.h" 4537110Ssklower #include "../net/route.h" 4637110Ssklower 4737110Ssklower #ifdef INET 4837110Ssklower #include "../netinet/in.h" 4937110Ssklower #include "../netinet/in_systm.h" 5037110Ssklower #include "../netinet/in_var.h" 5137110Ssklower #include "../netinet/ip.h" 5237110Ssklower #include "../netinet/if_ether.h" 5337110Ssklower #endif 5437110Ssklower 5537110Ssklower #ifdef NS 5637110Ssklower #include "../netns/ns.h" 5737110Ssklower #include "../netns/ns_if.h" 5837110Ssklower #endif 5937110Ssklower 6037474Ssklower #ifdef ISO 6137474Ssklower #include "../netiso/iso.h" 6237474Ssklower #include "../netiso/iso_var.h" 63*43339Ssklower extern char all_es_snpa[], all_is_snpa[]; 6437474Ssklower #endif 6537474Ssklower 6637110Ssklower #include "../tahoe/cpu.h" 6737110Ssklower #include "../tahoe/pte.h" 6837110Ssklower #include "../tahoe/mtpr.h" 6937110Ssklower 7037110Ssklower #include "../tahoevba/vbavar.h" 7137110Ssklower #include "if_exreg.h" 7237110Ssklower #include "if_vba.h" 7337110Ssklower 7437110Ssklower 7537110Ssklower #define NH2X 32 /* Host to eXcelan request buffers */ 7637110Ssklower 7737110Ssklower #define NX2H 16 /* eXcelan to Host reply buffers */ 7837110Ssklower #define NREC 16 /* Number of RECeive buffers */ 7937110Ssklower #define NTRB 4 /* Number of TRansmit Buffers */ 8037110Ssklower #define NVBI (NREC + NTRB) 8137110Ssklower 8237110Ssklower #define EXWATCHINTVL 10 /* call exwatch every x secs */ 8337110Ssklower 8437110Ssklower int exprobe(), exslave(), exattach(), exintr(), exstart(); 8537110Ssklower struct vba_device *exinfo[NEX]; 8637110Ssklower 8737110Ssklower long exstd[] = { 0 }; 8837110Ssklower 8937110Ssklower 9037110Ssklower struct vba_driver exdriver = 9137110Ssklower { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; 9237110Ssklower int exinit(),ether_output(),exioctl(),exreset(),exwatch(); 9337110Ssklower struct ex_msg *exgetcbuf(); 9437110Ssklower int ex_ncall = 0; /* counts calls to exprobe */ 9537110Ssklower u_long busoff; 9637110Ssklower 9737110Ssklower /* 9837110Ssklower * Ethernet software status per interface. 9937110Ssklower * 10037110Ssklower * Each interface is referenced by a network interface structure, xs_if, which 10137110Ssklower * the routing code uses to locate the interface. This structure contains the 10237110Ssklower * output queue for the interface, its address, ... NOTE: To configure multiple 10337110Ssklower * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). 10437110Ssklower */ 10537110Ssklower struct ex_softc { 10637110Ssklower struct arpcom xs_ac; /* Ethernet common part */ 10737110Ssklower #define xs_if xs_ac.ac_if /* network-visible interface */ 10837110Ssklower #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 10937110Ssklower int xs_flags; /* private flags */ 11037110Ssklower #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ 11137110Ssklower #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ 11237110Ssklower #define EX_RUNNING (1<<2) /* board is running */ 11337110Ssklower #define EX_SETADDR (1<<3) /* physaddr has been changed */ 11437110Ssklower int xs_cvec; /* probe stores cvec here */ 11537110Ssklower short xs_enetunit; /* unit number for enet filtering */ 11637110Ssklower short xs_enetinit; /* enet inetrface is initialized */ 11737110Ssklower struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 11837110Ssklower struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 11937110Ssklower u_long xs_qbaddr; /* map info for structs below */ 12037474Ssklower struct ex_shm { 12137110Ssklower /* the following structures are always mapped in */ 12237474Ssklower u_short sm_h2xhdr; /* EXOS's request queue header */ 12337474Ssklower u_short sm_x2hhdr; /* EXOS's reply queue header */ 12437474Ssklower struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ 12537474Ssklower struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ 12637474Ssklower struct ex_conf sm_cm; /* configuration message */ 12737474Ssklower struct ex_stat sm_xsa; /* EXOS writes stats here */ 12837110Ssklower /* end mapped area */ 12937474Ssklower } *xs_shm; /* host pointer to shared area */ 13037474Ssklower #define xs_h2xhdr xs_shm->sm_h2xhdr 13137474Ssklower #define xs_x2hhdr xs_shm->sm_x2hhdr 13237474Ssklower #define xs_h2xent xs_shm->sm_h2xent 13337474Ssklower #define xs_x2hent xs_shm->sm_x2hent 13437474Ssklower #define xs_cm xs_shm->sm_cm 13537474Ssklower #define xs_xsa xs_shm->sm_xsa 13637474Ssklower #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF)) 13737474Ssklower #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0)) 13837474Ssklower #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0) 13937474Ssklower /* we will arrange that the shared memory begins on a 16 byte boundary */ 14037474Ssklower #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0) 14137474Ssklower #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0) 14237474Ssklower #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr) 14337474Ssklower #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr) 14437474Ssklower #define H2XENT_OFFSET LVAL_OFF(sm_h2xent) 14537474Ssklower #define X2HENT_OFFSET LVAL_OFF(sm_x2hent) 14637474Ssklower #define CM_OFFSET RVAL_OFF(sm_cm) 14737474Ssklower #define SA_OFFSET RVAL_OFF(sm_xsa) 14837110Ssklower struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ 14937110Ssklower struct ifvba *xs_pkblist; /* free list of above */ 15037474Ssklower #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ 15137474Ssklower (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf)) 15237474Ssklower #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ 15337474Ssklower (xs->xs_pkblist = v)) 15437110Ssklower char xs_nrec; /* number of pending receive buffers */ 15537110Ssklower char xs_ntrb; /* number of pending transmit buffers */ 15637110Ssklower } ex_softc[NEX]; 15737110Ssklower 15837110Ssklower int ex_padcheck = sizeof (struct ex_softc); 15937110Ssklower 16037110Ssklower exprobe(reg, vi) 16137110Ssklower caddr_t reg; 16237110Ssklower struct vba_device *vi; 16337110Ssklower { 16437110Ssklower register br, cvec; /* r12, r11 value-result */ 16537110Ssklower register struct exdevice *exaddr = (struct exdevice *)reg; 16637110Ssklower int i; 16737110Ssklower 16837474Ssklower if (badaddr((caddr_t)exaddr, 2)) 16937110Ssklower return 0; 17037110Ssklower /* 17137110Ssklower * Reset EXOS and run self-test (should complete within 2 seconds). 17237110Ssklower */ 17337110Ssklower movow(&exaddr->ex_porta, EX_RESET); 17437110Ssklower for (i = 1000000; i; i--) { 17537110Ssklower uncache(&(exaddr->ex_portb)); 17637110Ssklower if (exaddr->ex_portb & EX_TESTOK) 17737110Ssklower break; 17837110Ssklower } 17937110Ssklower if ((exaddr->ex_portb & EX_TESTOK) == 0) 18037110Ssklower return 0; 18137110Ssklower br = 0x15; 18237110Ssklower cvec = --vi->ui_hd->vh_lastiv; 18337110Ssklower ex_softc[vi->ui_unit].xs_cvec = cvec; 18437110Ssklower ex_ncall++; 18537110Ssklower return (sizeof(struct exdevice)); 18637110Ssklower } 18737110Ssklower 18837110Ssklower /* 18937110Ssklower * Interface exists: make available by filling in network interface record. 19037110Ssklower * System will initialize the interface when it is ready to accept packets. 19137110Ssklower * A NET_ADDRS command is done to get the ethernet address. 19237110Ssklower */ 19337110Ssklower exattach(ui) 19437110Ssklower register struct vba_device *ui; 19537110Ssklower { 19637110Ssklower register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 19737110Ssklower register struct ifnet *ifp = &xs->xs_if; 19837110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 19937110Ssklower register struct ex_msg *bp; 20037110Ssklower 20137110Ssklower ifp->if_unit = ui->ui_unit; 20237110Ssklower ifp->if_name = "ex"; 20337110Ssklower ifp->if_mtu = ETHERMTU; 20437110Ssklower ifp->if_init = exinit; 20537110Ssklower ifp->if_ioctl = exioctl; 20637110Ssklower ifp->if_output = ether_output; 20737110Ssklower ifp->if_reset = exreset; 20837110Ssklower ifp->if_start = exstart; 20937474Ssklower ifp->if_flags = IFF_BROADCAST; 21037110Ssklower 21137474Ssklower /* 21237474Ssklower * Note: extra memory gets returned by if_vbareserve() 21337474Ssklower * first, so, being page alligned, it is also 16-byte alligned. 21437474Ssklower */ 21537474Ssklower if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, 21637474Ssklower (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) 21737110Ssklower return; 21837110Ssklower /* 21937110Ssklower * Temporarily map queues in order to configure EXOS 22037110Ssklower */ 22137110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 22237110Ssklower exconfig(ui, 0); /* without interrupts */ 22337110Ssklower if (xs->xs_cm.cm_cc) 22437110Ssklower return; /* bad conf */ 22537110Ssklower /* 22637110Ssklower * Get Ethernet address. 22737110Ssklower */ 22837110Ssklower if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) 22937110Ssklower panic("exattach"); 23037110Ssklower bp->mb_na.na_mask = READ_OBJ; 23137110Ssklower bp->mb_na.na_slot = PHYSSLOT; 23237110Ssklower bp->mb_status |= MH_EXOS; 23337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 23437110Ssklower bp = xs->xs_x2hnext; 23537474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 23637110Ssklower printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n", 23737110Ssklower ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], 23837110Ssklower xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], 23937110Ssklower ether_sprintf(bp->mb_na.na_addrs)); 24037110Ssklower bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, 24137110Ssklower sizeof(xs->xs_addr)); 24237110Ssklower if_attach(ifp); 24337110Ssklower } 24437110Ssklower 24537110Ssklower /* 24637110Ssklower * Reset of interface after BUS reset. 24737110Ssklower * If interface is on specified vba, reset its state. 24837110Ssklower */ 24937110Ssklower exreset(unit) 25037110Ssklower int unit; 25137110Ssklower { 25237110Ssklower register struct vba_device *ui; 25337110Ssklower 25437110Ssklower if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) 25537110Ssklower return; 25637110Ssklower printf(" ex%d", unit); 25737110Ssklower ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 25837110Ssklower ex_softc[unit].xs_flags &= ~EX_RUNNING; 25937110Ssklower 26037110Ssklower exinit(unit); 26137110Ssklower } 26237110Ssklower 26337110Ssklower /* 26437110Ssklower * Initialization of interface; clear recorded pending operations, and 26537110Ssklower * reinitialize BUS usage. Called at boot time, and at ifconfig time via 26637110Ssklower * exioctl, with interrupts disabled. 26737110Ssklower */ 26837110Ssklower exinit(unit) 26937110Ssklower int unit; 27037110Ssklower { 27137110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 27237110Ssklower register struct vba_device *ui = exinfo[unit]; 27337110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 27437110Ssklower register struct ifnet *ifp = &xs->xs_if; 27537110Ssklower register struct sockaddr_in *sin; 27637110Ssklower register struct ex_msg *bp; 27737110Ssklower int s; 27837110Ssklower 27937110Ssklower /* not yet, if address still unknown */ 28037110Ssklower if (ifp->if_addrlist == (struct ifaddr *)0) 28137110Ssklower return; 28237110Ssklower if (xs->xs_flags & EX_RUNNING) 28337110Ssklower return; 28437110Ssklower 28537110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 28637110Ssklower exconfig(ui, 4); /* with vectored interrupts*/ 28737110Ssklower 28837110Ssklower /* 28937110Ssklower * Put EXOS on the Ethernet, using NET_MODE command 29037110Ssklower */ 29137110Ssklower if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) 29237110Ssklower panic("exinit"); 29337110Ssklower bp->mb_nm.nm_mask = WRITE_OBJ; 29437110Ssklower bp->mb_nm.nm_optn = 0; 29537110Ssklower bp->mb_nm.nm_mode = MODE_PERF; 29637110Ssklower bp->mb_status |= MH_EXOS; 29737110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 29837110Ssklower bp = xs->xs_x2hnext; 29937474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 30037474Ssklower ; 30137110Ssklower bp->mb_length = MBDATALEN; 30237110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 30337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 30437110Ssklower xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 30537110Ssklower 30637110Ssklower ifp->if_watchdog = exwatch; 30737110Ssklower ifp->if_timer = EXWATCHINTVL; 30837110Ssklower s = splimp(); /* are interrupts disabled here, anyway? */ 30937110Ssklower exhangrcv(unit); 31037110Ssklower xs->xs_if.if_flags |= IFF_RUNNING; 31137110Ssklower xs->xs_flags |= EX_RUNNING; 31237110Ssklower if (xs->xs_flags & EX_SETADDR) 31337110Ssklower ex_setaddr((u_char *)0, unit); 31437474Ssklower #ifdef ISO 315*43339Ssklower ex_setmulti(all_es_snpa, unit, 1); 316*43339Ssklower ex_setmulti(all_is_snpa, unit, 2); 31737474Ssklower #endif 31837110Ssklower exstart(&ex_softc[unit].xs_if); /* start transmits */ 31937110Ssklower splx(s); /* are interrupts disabled here, anyway? */ 32037110Ssklower } 32137110Ssklower 32237110Ssklower /* 32337110Ssklower * Reset, test, and configure EXOS. It is called by exinit, and exattach. 32437110Ssklower * Returns 0 if successful, 1 if self-test failed. 32537110Ssklower */ 32637110Ssklower exconfig(ui, itype) 32737110Ssklower struct vba_device *ui; 32837110Ssklower int itype; 32937110Ssklower { 33037110Ssklower register int unit = ui->ui_unit; 33137110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 33237110Ssklower register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; 33337474Ssklower register struct ex_conf *cm = &xs->xs_cm; 33437110Ssklower register struct ex_msg *bp; 33537110Ssklower register struct ifvba *pkb; 33637110Ssklower int i; 33737110Ssklower u_long shiftreg; 33837110Ssklower static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; 33937110Ssklower 34037110Ssklower xs->xs_flags = 0; 34137110Ssklower /* 34237110Ssklower * Reset EXOS, wait for self-test to complete 34337110Ssklower */ 34437110Ssklower movow(&exaddr->ex_porta, EX_RESET); 34537110Ssklower do { 34637110Ssklower uncache(&exaddr->ex_portb); 34737110Ssklower } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; 34837110Ssklower /* 34937110Ssklower * Set up configuration message. 35037110Ssklower */ 35137110Ssklower cm->cm_1rsrv = 1; 35237110Ssklower cm->cm_cc = 0xFF; 35337110Ssklower cm->cm_opmode = 0; /* link-level controller mode */ 35437110Ssklower cm->cm_dfo = 0x0101; /* enable host data order conversion */ 35537110Ssklower cm->cm_dcn1 = 1; 35637110Ssklower cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; 35737110Ssklower cm->cm_ham = 3; /* absolute address mode */ 35837110Ssklower cm->cm_3rsrv = 0; 35937110Ssklower cm->cm_mapsiz = 0; 36037110Ssklower cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 36137110Ssklower cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 36237110Ssklower cm->cm_byteptrn[2] = 0x07; 36337110Ssklower cm->cm_byteptrn[3] = 0x0F; 36437110Ssklower cm->cm_wordptrn[0] = 0x0103; 36537110Ssklower cm->cm_wordptrn[1] = 0x070F; 36637110Ssklower cm->cm_lwordptrn = 0x0103070F; 36737110Ssklower for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 36837110Ssklower cm->cm_mba = 0xFFFFFFFF; 36937110Ssklower cm->cm_nproc = 0xFF; 37037110Ssklower cm->cm_nmbox = 0xFF; 37137110Ssklower cm->cm_nmcast = 0xFF; 37237110Ssklower cm->cm_nhost = 1; 37337110Ssklower cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); 37437110Ssklower cm->cm_h2xhdr = H2XHDR_OFFSET; 37537110Ssklower cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 37637110Ssklower cm->cm_x2hba = cm->cm_h2xba; 37737110Ssklower cm->cm_x2hhdr = X2HHDR_OFFSET; 37837110Ssklower cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 37937110Ssklower cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ 38037110Ssklower /* 38137110Ssklower * Set up message queues and headers. 38237110Ssklower * First the request queue 38337110Ssklower */ 38437110Ssklower for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { 38537110Ssklower bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 38637110Ssklower bp->mb_rsrv = 0; 38737110Ssklower bp->mb_length = MBDATALEN; 38837110Ssklower bp->mb_status = MH_HOST; 38937110Ssklower bp->mb_next = bp+1; 39037110Ssklower } 39137110Ssklower xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; 39237110Ssklower xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; 39337110Ssklower 39437110Ssklower /* Now the reply queue. */ 39537110Ssklower for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 39637110Ssklower bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 39737110Ssklower bp->mb_rsrv = 0; 39837110Ssklower bp->mb_length = MBDATALEN; 39937110Ssklower bp->mb_status = MH_EXOS; 40037110Ssklower bp->mb_next = bp+1; 40137110Ssklower } 40237110Ssklower xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; 40337110Ssklower xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; 40437110Ssklower xs->xs_nrec = 0; 40537110Ssklower xs->xs_ntrb = 0; 40637110Ssklower xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; 40737474Ssklower for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) 40837110Ssklower pkb->iff_mbuf = (struct mbuf *)(pkb - 1); 40937110Ssklower xs->xs_vbinfo[0].iff_mbuf = 0; 41037110Ssklower 41137110Ssklower /* 41237110Ssklower * Write config msg address to EXOS and wait for configuration to 41337110Ssklower * complete (guaranteed response within 2 seconds). 41437110Ssklower */ 41537110Ssklower shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; 41637110Ssklower for (i = 4; i < 8; i++) { 41737110Ssklower cmaddr[i] = (u_char)(shiftreg & 0xFF); 41837110Ssklower shiftreg >>= 8; 41937110Ssklower } 42037110Ssklower for (i = 0; i < 8; i++) { 42137110Ssklower do { 42237110Ssklower uncache(&exaddr->ex_portb); 42337110Ssklower } while (exaddr->ex_portb & EX_UNREADY) ; 42437110Ssklower DELAY(500); 42537110Ssklower movow(&exaddr->ex_portb, cmaddr[i]); 42637110Ssklower } 42737110Ssklower for (i = 500000; i; --i) { 42837110Ssklower DELAY(10); 42937110Ssklower uncache(&cm->cm_cc); 43037110Ssklower if (cm->cm_cc != 0xFF) 43137110Ssklower break; 43237110Ssklower } 43337110Ssklower if (cm->cm_cc) 43437110Ssklower printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); 43537110Ssklower } 43637110Ssklower 43737110Ssklower /* 43837110Ssklower * Start or re-start output on interface. Get another datagram to send off of 43937110Ssklower * the interface queue, and map it to the interface before starting the output. 44037110Ssklower * This routine is called by exinit(), exoutput(), and excdint(). In all cases, 44137110Ssklower * interrupts by EXOS are disabled. 44237110Ssklower */ 44337110Ssklower exstart(ifp) 44437110Ssklower struct ifnet *ifp; 44537110Ssklower { 44637110Ssklower int unit = ifp->if_unit; 44737110Ssklower struct vba_device *ui = exinfo[unit]; 44837110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 44937110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 45037110Ssklower register struct ex_msg *bp; 45137110Ssklower register struct mbuf *m; 45237110Ssklower int len; 45337110Ssklower register struct ifvba *pkb; 45437474Ssklower struct mbuf *m0 = 0; 45537474Ssklower register int nb = 0, tlen = 0; 45637110Ssklower union l_util { 45737110Ssklower u_long l; 45837110Ssklower struct i86_long i; 45937110Ssklower } l_util; 46037110Ssklower 46137110Ssklower if (xs->xs_ntrb >= NTRB) 46237110Ssklower return; 46337110Ssklower if (xs->xs_pkblist == 0) { 46437110Ssklower printf("ex%d: vbinfo exhausted, would panic", unit); 46537110Ssklower return; 46637110Ssklower } 46737110Ssklower IF_DEQUEUE(&xs->xs_if.if_snd, m); 46837110Ssklower if (m == 0) 46937110Ssklower return; 47037110Ssklower /* 47137110Ssklower * Get a transmit request. 47237110Ssklower */ 47337110Ssklower if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { 47437110Ssklower m_freem(m); 47537110Ssklower printf("exstart: no command buffers\n"); 47637110Ssklower return; 47737110Ssklower } 47837110Ssklower xs->xs_ntrb++; 47937474Ssklower GetPkBuf(bp, pkb); 48037110Ssklower pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ 48137110Ssklower /* 48237110Ssklower * point directly to the first group of mbufs to be transmitted. The 48337110Ssklower * hardware can only support NFRAGMENTS descriptors. 48437110Ssklower */ 48537110Ssklower while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { 48637474Ssklower l_util.l = BUSADDR(mtod(m, caddr_t)); 48737110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; 48837110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 48937474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 49037474Ssklower /* Here, the phys memory for the mbuf is out 49137474Ssklower of range for the vmebus to talk to it */ 49237474Ssklower if (m == pkb->iff_mbuf) 49337474Ssklower pkb->iff_mbuf = 0; 49437474Ssklower break; 49537474Ssklower } 49637110Ssklower tlen += m->m_len; 49737110Ssklower m0 = m; 49837110Ssklower m = m->m_next; 49937110Ssklower nb++; 50037110Ssklower } 50137110Ssklower 50237110Ssklower /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ 50337110Ssklower if (m0) 50437110Ssklower m0->m_next = 0; 50537110Ssklower 50637110Ssklower /* 50737110Ssklower * if not all of the descriptors would fit then merge remaining data 50837110Ssklower * into the transmit buffer, and point to it. Note: the mbufs are freed 50937110Ssklower * during the merge, they do not have to be freed when we get the 51037110Ssklower * transmit interrupt. 51137110Ssklower */ 51237110Ssklower if (m) { 51337474Ssklower if (m == pkb->iff_mbuf) { 51437474Ssklower printf("ex%d: exstart insanity\n", unit); 51537474Ssklower pkb->iff_mbuf = 0; 51637474Ssklower } 51737474Ssklower len = if_vbaput(pkb->iff_buffer, m, 0); 51837110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 51937110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)len; 52037110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 52137110Ssklower tlen += len; 52237110Ssklower nb++; 52337110Ssklower } 52437110Ssklower 52537110Ssklower /* 52637474Ssklower * If the total length of the packet is too small, 52737474Ssklower * pad the last fragment. (May run into very obscure problems) 52837110Ssklower */ 52937474Ssklower if (tlen < sizeof(struct ether_header) + ETHERMIN) { 53037110Ssklower len = (ETHERMIN + sizeof(struct ether_header)) - tlen; 53137110Ssklower bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; 53237110Ssklower tlen += len; 53337474Ssklower #ifdef notdef 53437474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 53537474Ssklower must copy last frag into private buffer 53637474Ssklower } 53737474Ssklower #endif 53837110Ssklower } 53937110Ssklower 54037110Ssklower /* set number of fragments in descriptor */ 54137110Ssklower bp->mb_et.et_nblock = nb; 54237110Ssklower bp->mb_status |= MH_EXOS; 54337110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 54437110Ssklower } 54537110Ssklower 54637110Ssklower /* 54737110Ssklower * interrupt service routine. 54837110Ssklower */ 54937110Ssklower exintr(unit) 55037110Ssklower int unit; 55137110Ssklower { 55237110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 55337110Ssklower register struct ex_msg *bp = xs->xs_x2hnext; 55437110Ssklower struct vba_device *ui = exinfo[unit]; 55537110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 55637474Ssklower struct ex_msg *next_bp; 55737110Ssklower 55837110Ssklower while ((bp->mb_status & MH_OWNER) == MH_HOST) { 55937110Ssklower switch (bp->mb_rqst) { 56037110Ssklower case LLRECEIVE: 56137474Ssklower if (--xs->xs_nrec < 0) { 56237474Ssklower printf("ex%d: internal receive check\n", unit); 56337110Ssklower xs->xs_nrec = 0; 56437474Ssklower } 56537110Ssklower exrecv(unit, bp); 56637110Ssklower FreePkBuf(bp->mb_pkb); 56737110Ssklower bp->mb_pkb = (struct ifvba *)0; 56837110Ssklower exhangrcv(unit); 56937110Ssklower break; 57037110Ssklower 57137110Ssklower case LLTRANSMIT: 57237110Ssklower case LLRTRANSMIT: 57337474Ssklower if (--xs->xs_ntrb < 0) { 57437474Ssklower printf("ex%d: internal transmit check\n", unit); 57537110Ssklower xs->xs_ntrb = 0; 57637474Ssklower } 57737110Ssklower xs->xs_if.if_opackets++; 57837474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 57937110Ssklower ; 58037110Ssklower else if (bp->mb_rply & LLXM_1RTRY) 58137110Ssklower xs->xs_if.if_collisions++; 58237110Ssklower else if (bp->mb_rply & LLXM_RTRYS) 58337110Ssklower xs->xs_if.if_collisions += 2; /* guess */ 58437110Ssklower else if (bp->mb_rply & LLXM_ERROR) 58537110Ssklower if (xs->xs_if.if_oerrors++ % 100 == 0) 58637110Ssklower printf("ex%d: 100 transmit errors=%b\n", 58737110Ssklower unit, bp->mb_rply, XMIT_BITS); 58837110Ssklower if (bp->mb_pkb->iff_mbuf) { 58937110Ssklower m_freem(bp->mb_pkb->iff_mbuf); 59037110Ssklower bp->mb_pkb->iff_mbuf = (struct mbuf *)0; 59137110Ssklower } 59237110Ssklower FreePkBuf(bp->mb_pkb); 59337110Ssklower bp->mb_pkb = (struct ifvba *)0; 59437474Ssklower exstart(&xs->xs_if); 59537110Ssklower exhangrcv(unit); 59637110Ssklower break; 59737110Ssklower 59837110Ssklower case LLNET_STSTCS: 59937110Ssklower xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; 60037110Ssklower xs->xs_flags &= ~EX_STATPENDING; 60137474Ssklower case LLNET_ADDRS: 60237474Ssklower case LLNET_RECV: 60337474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 60437474Ssklower ; 60537474Ssklower else 60637474Ssklower printf("ex%d: %s, request 0x%x, reply 0x%x\n", 60737474Ssklower unit, "unsucessful stat or address change", 60837474Ssklower bp->mb_rqst, bp->mb_rply); 60937110Ssklower break; 61037110Ssklower 61137110Ssklower default: 61237110Ssklower printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); 61337110Ssklower } 61437110Ssklower bp->mb_length = MBDATALEN; 61537474Ssklower next_bp = bp->mb_next; 61637110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 61737474Ssklower bp = next_bp; /* paranoia about race */ 61837110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ 61937110Ssklower } 62037110Ssklower xs->xs_x2hnext = bp; 62137110Ssklower } 62237110Ssklower 62337110Ssklower /* 62437110Ssklower * Get a request buffer, fill in standard values, advance pointer. 62537110Ssklower */ 62637110Ssklower struct ex_msg * 62737110Ssklower exgetcbuf(xs, req) 62837110Ssklower struct ex_softc *xs; 62937110Ssklower int req; 63037110Ssklower { 63137110Ssklower register struct ex_msg *bp; 63237110Ssklower struct ifvba *pkb; 63337110Ssklower int s = splimp(); 63437110Ssklower 63537110Ssklower bp = xs->xs_h2xnext; 63637110Ssklower if ((bp->mb_status & MH_OWNER) == MH_EXOS) { 63737110Ssklower splx(s); 63837110Ssklower return (struct ex_msg *)0; 63937110Ssklower } 64037110Ssklower xs->xs_h2xnext = bp->mb_next; 64137110Ssklower bp->mb_1rsrv = 0; 64237110Ssklower bp->mb_rqst = req; 64337110Ssklower bp->mb_length = MBDATALEN; 64437110Ssklower bp->mb_pkb = (struct ifvba *)0; 64537110Ssklower splx(s); 64637110Ssklower return bp; 64737110Ssklower } 64837110Ssklower 64937110Ssklower /* 65037110Ssklower * Process Ethernet receive completion: If input error just drop packet, 65137110Ssklower * otherwise examine packet to determine type. If can't determine length from 65237110Ssklower * type, then have to drop packet, otherwise decapsulate packet based on type 65337110Ssklower * and pass to type-specific higher-level input routine. 65437110Ssklower */ 65537110Ssklower exrecv(unit, bp) 65637110Ssklower int unit; 65737110Ssklower register struct ex_msg *bp; 65837110Ssklower { 65937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 66037110Ssklower register struct ether_header *eh; 66137110Ssklower register struct mbuf *m; 66237110Ssklower int len, off, resid; 66337110Ssklower register struct ifqueue *inq; 66437110Ssklower int s; 66537110Ssklower 66637110Ssklower xs->xs_if.if_ipackets++; 66737110Ssklower /* total length - header - crc */ 66837110Ssklower len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 66937110Ssklower if (bp->mb_rply != LL_OK) { 67037110Ssklower if (xs->xs_if.if_ierrors++ % 100 == 0) 67137110Ssklower printf("ex%d: 100 receive errors=%b\n", 67237110Ssklower unit, bp->mb_rply, RECV_BITS); 67337110Ssklower return; 67437110Ssklower } 67537110Ssklower eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); 67637110Ssklower 67737110Ssklower /* 67837110Ssklower * Deal with trailer protocol: if type is PUP trailer get true type from 67937110Ssklower * first 16-bit word past data. Remember that type was trailer by 68037110Ssklower * setting off. 68137110Ssklower */ 68237110Ssklower eh->ether_type = ntohs((u_short)eh->ether_type); 68337110Ssklower #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 68437110Ssklower if (eh->ether_type >= ETHERTYPE_TRAIL && 68537110Ssklower eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 68637110Ssklower off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 68737110Ssklower if (off >= ETHERMTU) 68837110Ssklower return; /* sanity */ 68937110Ssklower eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 69037110Ssklower resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 69137110Ssklower if (off + resid > len) 69237110Ssklower return; /* sanity */ 69337110Ssklower len = off + resid; 69437110Ssklower } else 69537110Ssklower off = 0; 69637110Ssklower if (len == 0) 69737110Ssklower return; 69837110Ssklower /* 69937110Ssklower * Pull packet off interface. Off is nonzero if packet 70037110Ssklower * has trailing header; if_vbaget will then force this header 70137110Ssklower * information to be at the front, but we still have to drop 70237110Ssklower * the type and length which are at the front of any trailer data. 70337110Ssklower */ 70437110Ssklower m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); 70537110Ssklower if (m == 0) 70637110Ssklower return; 70737110Ssklower ether_input(&xs->xs_if, eh, m); 70837110Ssklower return; 70937110Ssklower } 71037110Ssklower 71137110Ssklower /* 71237110Ssklower * Hang a receive request. This routine is called by exinit and excdint, 71337110Ssklower * with interrupts disabled in both cases. 71437110Ssklower */ 71537110Ssklower exhangrcv(unit) 71637110Ssklower int unit; 71737110Ssklower { 71837110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 71937110Ssklower register struct ex_msg *bp; 72037110Ssklower register struct ifvba *pkb; 72137110Ssklower short mustint = 0; 72237110Ssklower union l_util { 72337110Ssklower u_long l; 72437110Ssklower struct i86_long i; 72537110Ssklower } l_util; 72637110Ssklower 72737110Ssklower while (xs->xs_nrec < NREC) { 72837110Ssklower if (xs->xs_pkblist == (struct ifvba *)0) 72937110Ssklower break; 73037110Ssklower if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { 73137110Ssklower break; 73237110Ssklower } 73337474Ssklower GetPkBuf(bp, pkb); 73437474Ssklower pkb->iff_mbuf = 0; 73537110Ssklower xs->xs_nrec += 1; 73637110Ssklower bp->mb_er.er_nblock = 1; 73737110Ssklower bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 73837110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 73937110Ssklower bp->mb_er.er_blks[0].bb_addr = l_util.i; 74037110Ssklower bp->mb_status |= MH_EXOS; 74137110Ssklower mustint = 1; 74237110Ssklower } 74337110Ssklower if (mustint == 0) 74437110Ssklower return; 74537110Ssklower movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); 74637110Ssklower } 74737110Ssklower 74837110Ssklower /* 74937110Ssklower * Ethernet output routine is ether_output(). 75037110Ssklower */ 75137110Ssklower 75237110Ssklower /* 75337110Ssklower * Watchdog routine (currently not used). Might use this to get stats from EXOS. 75437110Ssklower */ 75537110Ssklower exwatch(unit) 75637110Ssklower int unit; 75737110Ssklower { 75837110Ssklower struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; 75937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 76037110Ssklower register struct ex_msg *bp; 76137110Ssklower int s = splimp(); 76237110Ssklower 76337110Ssklower if (xs->xs_flags & EX_STATPENDING) 76437110Ssklower goto exspnd; 76537110Ssklower if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { 76637110Ssklower splx(s); 76737110Ssklower return; 76837110Ssklower } 76937110Ssklower xs->xs_flags |= EX_STATPENDING; 77037110Ssklower bp->mb_ns.ns_mask = READ_OBJ; 77137110Ssklower bp->mb_ns.ns_rsrv = 0; 77237110Ssklower bp->mb_ns.ns_nobj = 8; 77337110Ssklower bp->mb_ns.ns_xobj = 0; 77437110Ssklower bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; 77537110Ssklower bp->mb_status |= MH_EXOS; 77637110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 77737110Ssklower exspnd: splx(s); 77837110Ssklower xs->xs_if.if_timer = EXWATCHINTVL; 77937110Ssklower } 78037110Ssklower 78137110Ssklower /* 78237110Ssklower * Process an ioctl request. 78337110Ssklower */ 78437110Ssklower exioctl(ifp, cmd, data) 78537110Ssklower register struct ifnet *ifp; 78637110Ssklower int cmd; 78737110Ssklower caddr_t data; 78837110Ssklower { 78937110Ssklower register struct ifaddr *ifa = (struct ifaddr *)data; 79037110Ssklower register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 79137110Ssklower int s = splimp(), error = 0; 79237110Ssklower 79337110Ssklower switch (cmd) { 79437110Ssklower 79537110Ssklower case SIOCSIFADDR: 79637110Ssklower ifp->if_flags |= IFF_UP; 79737110Ssklower exinit(ifp->if_unit); 79837110Ssklower 79937110Ssklower switch (ifa->ifa_addr->sa_family) { 80037110Ssklower #ifdef INET 80137110Ssklower case AF_INET: 80237110Ssklower ((struct arpcom *)ifp)->ac_ipaddr = 80337110Ssklower IA_SIN(ifa)->sin_addr; 80437110Ssklower arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 80537110Ssklower break; 80637110Ssklower #endif 80737110Ssklower #ifdef NS 80837110Ssklower case AF_NS: 80937110Ssklower { 81037110Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 81137110Ssklower 81237110Ssklower if (ns_nullhost(*ina)) 81337110Ssklower ina->x_host = *(union ns_host *)(xs->xs_addr); 81437110Ssklower else 81537110Ssklower ex_setaddr(ina->x_host.c_host,ifp->if_unit); 81637110Ssklower break; 81737110Ssklower } 81837110Ssklower #endif 81937110Ssklower } 82037110Ssklower break; 82137110Ssklower 82237110Ssklower case SIOCSIFFLAGS: 82337110Ssklower if ((ifp->if_flags & IFF_UP) == 0 && 82437110Ssklower xs->xs_flags & EX_RUNNING) { 82537110Ssklower movow(&((struct exdevice *) 82637110Ssklower (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); 82737110Ssklower xs->xs_flags &= ~EX_RUNNING; 82837110Ssklower } else if (ifp->if_flags & IFF_UP && 82937110Ssklower (xs->xs_flags & EX_RUNNING) == 0) 83037110Ssklower exinit(ifp->if_unit); 83137110Ssklower break; 83237110Ssklower 83337110Ssklower default: 83437110Ssklower error = EINVAL; 83537110Ssklower } 83637110Ssklower splx(s); 83737110Ssklower return (error); 83837110Ssklower } 83937110Ssklower 84037110Ssklower /* 84137110Ssklower * set ethernet address for unit 84237110Ssklower */ 84337110Ssklower ex_setaddr(physaddr, unit) 84437110Ssklower u_char *physaddr; 84537110Ssklower int unit; 84637110Ssklower { 84737110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 84837110Ssklower 84937110Ssklower if (physaddr) { 85037110Ssklower xs->xs_flags |= EX_SETADDR; 85137110Ssklower bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 85237110Ssklower } 85337474Ssklower ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); 85437474Ssklower } 85537474Ssklower 85637474Ssklower /* 85737474Ssklower * Enable multicast reception for unit. 85837474Ssklower */ 85937474Ssklower ex_setmulti(linkaddr, unit, slot) 86037474Ssklower u_char *linkaddr; 86137474Ssklower int unit, slot; 86237474Ssklower { 86337474Ssklower register struct ex_softc *xs = &ex_softc[unit]; 86437474Ssklower struct vba_device *ui = exinfo[unit]; 86537474Ssklower register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 86637474Ssklower register struct ex_msg *bp; 86737474Ssklower 86837474Ssklower if (!(xs->xs_flags & EX_RUNNING)) 86937110Ssklower return; 87037474Ssklower bp = exgetcbuf(xs, LLNET_ADDRS); 87137110Ssklower bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 87237474Ssklower bp->mb_na.na_slot = slot; 87337474Ssklower bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); 87437110Ssklower bp->mb_status |= MH_EXOS; 87537110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 87637110Ssklower bp = xs->xs_x2hnext; 87737474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 87837110Ssklower #ifdef DEBUG 87937474Ssklower log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, 88037474Ssklower (slot == PHYSSLOT ? "reset addr" : "add multicast" 88137474Ssklower ether_sprintf(bp->mb_na.na_addrs), slot); 88237110Ssklower #endif 88337110Ssklower /* 88437474Ssklower * Now, re-enable reception on slot. 88537110Ssklower */ 88637474Ssklower bp = exgetcbuf(xs, LLNET_RECV); 88737110Ssklower bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 88837474Ssklower bp->mb_nr.nr_slot = slot; 88937110Ssklower bp->mb_status |= MH_EXOS; 89037110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 89137110Ssklower bp = xs->xs_x2hnext; 89237474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 89337110Ssklower ; 89437110Ssklower } 89537110Ssklower #endif 896