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*37474Ssklower * @(#)if_ex.c 7.2 (Berkeley) 04/22/89 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 60*37474Ssklower #ifdef ISO 61*37474Ssklower #include "../netiso/iso.h" 62*37474Ssklower #include "../netiso/iso_var.h" 63*37474Ssklower #include "../netiso/iso_snpac.h" 64*37474Ssklower extern struct snpa_cache all_es, all_is; 65*37474Ssklower #endif 66*37474Ssklower 6737110Ssklower #include "../tahoe/cpu.h" 6837110Ssklower #include "../tahoe/pte.h" 6937110Ssklower #include "../tahoe/mtpr.h" 7037110Ssklower 7137110Ssklower #include "../tahoevba/vbavar.h" 7237110Ssklower #include "if_exreg.h" 7337110Ssklower #include "if_vba.h" 7437110Ssklower 7537110Ssklower 7637110Ssklower #define NH2X 32 /* Host to eXcelan request buffers */ 7737110Ssklower 7837110Ssklower #define NX2H 16 /* eXcelan to Host reply buffers */ 7937110Ssklower #define NREC 16 /* Number of RECeive buffers */ 8037110Ssklower #define NTRB 4 /* Number of TRansmit Buffers */ 8137110Ssklower #define NVBI (NREC + NTRB) 8237110Ssklower 8337110Ssklower #define EXWATCHINTVL 10 /* call exwatch every x secs */ 8437110Ssklower 8537110Ssklower int exprobe(), exslave(), exattach(), exintr(), exstart(); 8637110Ssklower struct vba_device *exinfo[NEX]; 8737110Ssklower 8837110Ssklower long exstd[] = { 0 }; 8937110Ssklower 9037110Ssklower 9137110Ssklower struct vba_driver exdriver = 9237110Ssklower { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; 9337110Ssklower int exinit(),ether_output(),exioctl(),exreset(),exwatch(); 9437110Ssklower struct ex_msg *exgetcbuf(); 9537110Ssklower int ex_ncall = 0; /* counts calls to exprobe */ 9637110Ssklower u_long busoff; 9737110Ssklower 9837110Ssklower /* 9937110Ssklower * Ethernet software status per interface. 10037110Ssklower * 10137110Ssklower * Each interface is referenced by a network interface structure, xs_if, which 10237110Ssklower * the routing code uses to locate the interface. This structure contains the 10337110Ssklower * output queue for the interface, its address, ... NOTE: To configure multiple 10437110Ssklower * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). 10537110Ssklower */ 10637110Ssklower struct ex_softc { 10737110Ssklower struct arpcom xs_ac; /* Ethernet common part */ 10837110Ssklower #define xs_if xs_ac.ac_if /* network-visible interface */ 10937110Ssklower #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 11037110Ssklower int xs_flags; /* private flags */ 11137110Ssklower #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ 11237110Ssklower #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ 11337110Ssklower #define EX_RUNNING (1<<2) /* board is running */ 11437110Ssklower #define EX_SETADDR (1<<3) /* physaddr has been changed */ 11537110Ssklower int xs_cvec; /* probe stores cvec here */ 11637110Ssklower short xs_enetunit; /* unit number for enet filtering */ 11737110Ssklower short xs_enetinit; /* enet inetrface is initialized */ 11837110Ssklower struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 11937110Ssklower struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 12037110Ssklower u_long xs_qbaddr; /* map info for structs below */ 121*37474Ssklower struct ex_shm { 12237110Ssklower /* the following structures are always mapped in */ 123*37474Ssklower u_short sm_h2xhdr; /* EXOS's request queue header */ 124*37474Ssklower u_short sm_x2hhdr; /* EXOS's reply queue header */ 125*37474Ssklower struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ 126*37474Ssklower struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ 127*37474Ssklower struct ex_conf sm_cm; /* configuration message */ 128*37474Ssklower struct ex_stat sm_xsa; /* EXOS writes stats here */ 12937110Ssklower /* end mapped area */ 130*37474Ssklower } *xs_shm; /* host pointer to shared area */ 131*37474Ssklower #define xs_h2xhdr xs_shm->sm_h2xhdr 132*37474Ssklower #define xs_x2hhdr xs_shm->sm_x2hhdr 133*37474Ssklower #define xs_h2xent xs_shm->sm_h2xent 134*37474Ssklower #define xs_x2hent xs_shm->sm_x2hent 135*37474Ssklower #define xs_cm xs_shm->sm_cm 136*37474Ssklower #define xs_xsa xs_shm->sm_xsa 137*37474Ssklower #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF)) 138*37474Ssklower #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0)) 139*37474Ssklower #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0) 140*37474Ssklower /* we will arrange that the shared memory begins on a 16 byte boundary */ 141*37474Ssklower #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0) 142*37474Ssklower #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0) 143*37474Ssklower #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr) 144*37474Ssklower #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr) 145*37474Ssklower #define H2XENT_OFFSET LVAL_OFF(sm_h2xent) 146*37474Ssklower #define X2HENT_OFFSET LVAL_OFF(sm_x2hent) 147*37474Ssklower #define CM_OFFSET RVAL_OFF(sm_cm) 148*37474Ssklower #define SA_OFFSET RVAL_OFF(sm_xsa) 14937110Ssklower struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ 15037110Ssklower struct ifvba *xs_pkblist; /* free list of above */ 151*37474Ssklower #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ 152*37474Ssklower (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf)) 153*37474Ssklower #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ 154*37474Ssklower (xs->xs_pkblist = v)) 15537110Ssklower char xs_nrec; /* number of pending receive buffers */ 15637110Ssklower char xs_ntrb; /* number of pending transmit buffers */ 15737110Ssklower } ex_softc[NEX]; 15837110Ssklower 15937110Ssklower int ex_padcheck = sizeof (struct ex_softc); 16037110Ssklower 16137110Ssklower exprobe(reg, vi) 16237110Ssklower caddr_t reg; 16337110Ssklower struct vba_device *vi; 16437110Ssklower { 16537110Ssklower register br, cvec; /* r12, r11 value-result */ 16637110Ssklower register struct exdevice *exaddr = (struct exdevice *)reg; 16737110Ssklower int i; 16837110Ssklower 169*37474Ssklower if (badaddr((caddr_t)exaddr, 2)) 17037110Ssklower return 0; 17137110Ssklower /* 17237110Ssklower * Reset EXOS and run self-test (should complete within 2 seconds). 17337110Ssklower */ 17437110Ssklower movow(&exaddr->ex_porta, EX_RESET); 17537110Ssklower for (i = 1000000; i; i--) { 17637110Ssklower uncache(&(exaddr->ex_portb)); 17737110Ssklower if (exaddr->ex_portb & EX_TESTOK) 17837110Ssklower break; 17937110Ssklower } 18037110Ssklower if ((exaddr->ex_portb & EX_TESTOK) == 0) 18137110Ssklower return 0; 18237110Ssklower br = 0x15; 18337110Ssklower cvec = --vi->ui_hd->vh_lastiv; 18437110Ssklower ex_softc[vi->ui_unit].xs_cvec = cvec; 18537110Ssklower ex_ncall++; 18637110Ssklower return (sizeof(struct exdevice)); 18737110Ssklower } 18837110Ssklower 18937110Ssklower /* 19037110Ssklower * Interface exists: make available by filling in network interface record. 19137110Ssklower * System will initialize the interface when it is ready to accept packets. 19237110Ssklower * A NET_ADDRS command is done to get the ethernet address. 19337110Ssklower */ 19437110Ssklower exattach(ui) 19537110Ssklower register struct vba_device *ui; 19637110Ssklower { 19737110Ssklower register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 19837110Ssklower register struct ifnet *ifp = &xs->xs_if; 19937110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 20037110Ssklower register struct ex_msg *bp; 20137110Ssklower 20237110Ssklower ifp->if_unit = ui->ui_unit; 20337110Ssklower ifp->if_name = "ex"; 20437110Ssklower ifp->if_mtu = ETHERMTU; 20537110Ssklower ifp->if_init = exinit; 20637110Ssklower ifp->if_ioctl = exioctl; 20737110Ssklower ifp->if_output = ether_output; 20837110Ssklower ifp->if_reset = exreset; 20937110Ssklower ifp->if_start = exstart; 210*37474Ssklower ifp->if_flags = IFF_BROADCAST; 21137110Ssklower 212*37474Ssklower /* 213*37474Ssklower * Note: extra memory gets returned by if_vbareserve() 214*37474Ssklower * first, so, being page alligned, it is also 16-byte alligned. 215*37474Ssklower */ 216*37474Ssklower if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, 217*37474Ssklower (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) 21837110Ssklower return; 21937110Ssklower /* 22037110Ssklower * Temporarily map queues in order to configure EXOS 22137110Ssklower */ 22237110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 22337110Ssklower exconfig(ui, 0); /* without interrupts */ 22437110Ssklower if (xs->xs_cm.cm_cc) 22537110Ssklower return; /* bad conf */ 22637110Ssklower /* 22737110Ssklower * Get Ethernet address. 22837110Ssklower */ 22937110Ssklower if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) 23037110Ssklower panic("exattach"); 23137110Ssklower bp->mb_na.na_mask = READ_OBJ; 23237110Ssklower bp->mb_na.na_slot = PHYSSLOT; 23337110Ssklower bp->mb_status |= MH_EXOS; 23437110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 23537110Ssklower bp = xs->xs_x2hnext; 236*37474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 23737110Ssklower printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n", 23837110Ssklower ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], 23937110Ssklower xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], 24037110Ssklower ether_sprintf(bp->mb_na.na_addrs)); 24137110Ssklower bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, 24237110Ssklower sizeof(xs->xs_addr)); 24337110Ssklower if_attach(ifp); 24437110Ssklower } 24537110Ssklower 24637110Ssklower /* 24737110Ssklower * Reset of interface after BUS reset. 24837110Ssklower * If interface is on specified vba, reset its state. 24937110Ssklower */ 25037110Ssklower exreset(unit) 25137110Ssklower int unit; 25237110Ssklower { 25337110Ssklower register struct vba_device *ui; 25437110Ssklower 25537110Ssklower if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) 25637110Ssklower return; 25737110Ssklower printf(" ex%d", unit); 25837110Ssklower ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 25937110Ssklower ex_softc[unit].xs_flags &= ~EX_RUNNING; 26037110Ssklower 26137110Ssklower exinit(unit); 26237110Ssklower } 26337110Ssklower 26437110Ssklower /* 26537110Ssklower * Initialization of interface; clear recorded pending operations, and 26637110Ssklower * reinitialize BUS usage. Called at boot time, and at ifconfig time via 26737110Ssklower * exioctl, with interrupts disabled. 26837110Ssklower */ 26937110Ssklower exinit(unit) 27037110Ssklower int unit; 27137110Ssklower { 27237110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 27337110Ssklower register struct vba_device *ui = exinfo[unit]; 27437110Ssklower register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 27537110Ssklower register struct ifnet *ifp = &xs->xs_if; 27637110Ssklower register struct sockaddr_in *sin; 27737110Ssklower register struct ex_msg *bp; 27837110Ssklower int s; 27937110Ssklower 28037110Ssklower /* not yet, if address still unknown */ 28137110Ssklower if (ifp->if_addrlist == (struct ifaddr *)0) 28237110Ssklower return; 28337110Ssklower if (xs->xs_flags & EX_RUNNING) 28437110Ssklower return; 28537110Ssklower 28637110Ssklower xs->xs_qbaddr = INCORE_BASE(xs); 28737110Ssklower exconfig(ui, 4); /* with vectored interrupts*/ 28837110Ssklower 28937110Ssklower /* 29037110Ssklower * Put EXOS on the Ethernet, using NET_MODE command 29137110Ssklower */ 29237110Ssklower if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) 29337110Ssklower panic("exinit"); 29437110Ssklower bp->mb_nm.nm_mask = WRITE_OBJ; 29537110Ssklower bp->mb_nm.nm_optn = 0; 29637110Ssklower bp->mb_nm.nm_mode = MODE_PERF; 29737110Ssklower bp->mb_status |= MH_EXOS; 29837110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 29937110Ssklower bp = xs->xs_x2hnext; 300*37474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 301*37474Ssklower ; 30237110Ssklower bp->mb_length = MBDATALEN; 30337110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 30437110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 30537110Ssklower xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 30637110Ssklower 30737110Ssklower ifp->if_watchdog = exwatch; 30837110Ssklower ifp->if_timer = EXWATCHINTVL; 30937110Ssklower s = splimp(); /* are interrupts disabled here, anyway? */ 31037110Ssklower exhangrcv(unit); 31137110Ssklower xs->xs_if.if_flags |= IFF_RUNNING; 31237110Ssklower xs->xs_flags |= EX_RUNNING; 31337110Ssklower if (xs->xs_flags & EX_SETADDR) 31437110Ssklower ex_setaddr((u_char *)0, unit); 315*37474Ssklower #ifdef ISO 316*37474Ssklower ex_setmulti(all_es.sc_snpa, unit, 1); 317*37474Ssklower ex_setmulti(all_is.sc_snpa, unit, 2); 318*37474Ssklower #endif 31937110Ssklower exstart(&ex_softc[unit].xs_if); /* start transmits */ 32037110Ssklower splx(s); /* are interrupts disabled here, anyway? */ 32137110Ssklower } 32237110Ssklower 32337110Ssklower /* 32437110Ssklower * Reset, test, and configure EXOS. It is called by exinit, and exattach. 32537110Ssklower * Returns 0 if successful, 1 if self-test failed. 32637110Ssklower */ 32737110Ssklower exconfig(ui, itype) 32837110Ssklower struct vba_device *ui; 32937110Ssklower int itype; 33037110Ssklower { 33137110Ssklower register int unit = ui->ui_unit; 33237110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 33337110Ssklower register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; 334*37474Ssklower register struct ex_conf *cm = &xs->xs_cm; 33537110Ssklower register struct ex_msg *bp; 33637110Ssklower register struct ifvba *pkb; 33737110Ssklower int i; 33837110Ssklower u_long shiftreg; 33937110Ssklower static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; 34037110Ssklower 34137110Ssklower xs->xs_flags = 0; 34237110Ssklower /* 34337110Ssklower * Reset EXOS, wait for self-test to complete 34437110Ssklower */ 34537110Ssklower movow(&exaddr->ex_porta, EX_RESET); 34637110Ssklower do { 34737110Ssklower uncache(&exaddr->ex_portb); 34837110Ssklower } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; 34937110Ssklower /* 35037110Ssklower * Set up configuration message. 35137110Ssklower */ 35237110Ssklower cm->cm_1rsrv = 1; 35337110Ssklower cm->cm_cc = 0xFF; 35437110Ssklower cm->cm_opmode = 0; /* link-level controller mode */ 35537110Ssklower cm->cm_dfo = 0x0101; /* enable host data order conversion */ 35637110Ssklower cm->cm_dcn1 = 1; 35737110Ssklower cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; 35837110Ssklower cm->cm_ham = 3; /* absolute address mode */ 35937110Ssklower cm->cm_3rsrv = 0; 36037110Ssklower cm->cm_mapsiz = 0; 36137110Ssklower cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 36237110Ssklower cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 36337110Ssklower cm->cm_byteptrn[2] = 0x07; 36437110Ssklower cm->cm_byteptrn[3] = 0x0F; 36537110Ssklower cm->cm_wordptrn[0] = 0x0103; 36637110Ssklower cm->cm_wordptrn[1] = 0x070F; 36737110Ssklower cm->cm_lwordptrn = 0x0103070F; 36837110Ssklower for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 36937110Ssklower cm->cm_mba = 0xFFFFFFFF; 37037110Ssklower cm->cm_nproc = 0xFF; 37137110Ssklower cm->cm_nmbox = 0xFF; 37237110Ssklower cm->cm_nmcast = 0xFF; 37337110Ssklower cm->cm_nhost = 1; 37437110Ssklower cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); 37537110Ssklower cm->cm_h2xhdr = H2XHDR_OFFSET; 37637110Ssklower cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 37737110Ssklower cm->cm_x2hba = cm->cm_h2xba; 37837110Ssklower cm->cm_x2hhdr = X2HHDR_OFFSET; 37937110Ssklower cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 38037110Ssklower cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ 38137110Ssklower /* 38237110Ssklower * Set up message queues and headers. 38337110Ssklower * First the request queue 38437110Ssklower */ 38537110Ssklower for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; 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_HOST; 39037110Ssklower bp->mb_next = bp+1; 39137110Ssklower } 39237110Ssklower xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; 39337110Ssklower xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; 39437110Ssklower 39537110Ssklower /* Now the reply queue. */ 39637110Ssklower for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 39737110Ssklower bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 39837110Ssklower bp->mb_rsrv = 0; 39937110Ssklower bp->mb_length = MBDATALEN; 40037110Ssklower bp->mb_status = MH_EXOS; 40137110Ssklower bp->mb_next = bp+1; 40237110Ssklower } 40337110Ssklower xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; 40437110Ssklower xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; 40537110Ssklower xs->xs_nrec = 0; 40637110Ssklower xs->xs_ntrb = 0; 40737110Ssklower xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; 408*37474Ssklower for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) 40937110Ssklower pkb->iff_mbuf = (struct mbuf *)(pkb - 1); 41037110Ssklower xs->xs_vbinfo[0].iff_mbuf = 0; 41137110Ssklower 41237110Ssklower /* 41337110Ssklower * Write config msg address to EXOS and wait for configuration to 41437110Ssklower * complete (guaranteed response within 2 seconds). 41537110Ssklower */ 41637110Ssklower shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; 41737110Ssklower for (i = 4; i < 8; i++) { 41837110Ssklower cmaddr[i] = (u_char)(shiftreg & 0xFF); 41937110Ssklower shiftreg >>= 8; 42037110Ssklower } 42137110Ssklower for (i = 0; i < 8; i++) { 42237110Ssklower do { 42337110Ssklower uncache(&exaddr->ex_portb); 42437110Ssklower } while (exaddr->ex_portb & EX_UNREADY) ; 42537110Ssklower DELAY(500); 42637110Ssklower movow(&exaddr->ex_portb, cmaddr[i]); 42737110Ssklower } 42837110Ssklower for (i = 500000; i; --i) { 42937110Ssklower DELAY(10); 43037110Ssklower uncache(&cm->cm_cc); 43137110Ssklower if (cm->cm_cc != 0xFF) 43237110Ssklower break; 43337110Ssklower } 43437110Ssklower if (cm->cm_cc) 43537110Ssklower printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); 43637110Ssklower } 43737110Ssklower 43837110Ssklower /* 43937110Ssklower * Start or re-start output on interface. Get another datagram to send off of 44037110Ssklower * the interface queue, and map it to the interface before starting the output. 44137110Ssklower * This routine is called by exinit(), exoutput(), and excdint(). In all cases, 44237110Ssklower * interrupts by EXOS are disabled. 44337110Ssklower */ 44437110Ssklower exstart(ifp) 44537110Ssklower struct ifnet *ifp; 44637110Ssklower { 44737110Ssklower int unit = ifp->if_unit; 44837110Ssklower struct vba_device *ui = exinfo[unit]; 44937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 45037110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 45137110Ssklower register struct ex_msg *bp; 45237110Ssklower register struct mbuf *m; 45337110Ssklower int len; 45437110Ssklower register struct ifvba *pkb; 455*37474Ssklower struct mbuf *m0 = 0; 456*37474Ssklower register int nb = 0, tlen = 0; 45737110Ssklower union l_util { 45837110Ssklower u_long l; 45937110Ssklower struct i86_long i; 46037110Ssklower } l_util; 46137110Ssklower 46237110Ssklower if (xs->xs_ntrb >= NTRB) 46337110Ssklower return; 46437110Ssklower if (xs->xs_pkblist == 0) { 46537110Ssklower printf("ex%d: vbinfo exhausted, would panic", unit); 46637110Ssklower return; 46737110Ssklower } 46837110Ssklower IF_DEQUEUE(&xs->xs_if.if_snd, m); 46937110Ssklower if (m == 0) 47037110Ssklower return; 47137110Ssklower /* 47237110Ssklower * Get a transmit request. 47337110Ssklower */ 47437110Ssklower if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { 47537110Ssklower m_freem(m); 47637110Ssklower printf("exstart: no command buffers\n"); 47737110Ssklower return; 47837110Ssklower } 47937110Ssklower xs->xs_ntrb++; 480*37474Ssklower GetPkBuf(bp, pkb); 48137110Ssklower pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ 48237110Ssklower /* 48337110Ssklower * point directly to the first group of mbufs to be transmitted. The 48437110Ssklower * hardware can only support NFRAGMENTS descriptors. 48537110Ssklower */ 48637110Ssklower while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { 487*37474Ssklower l_util.l = BUSADDR(mtod(m, caddr_t)); 48837110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; 48937110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 490*37474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 491*37474Ssklower /* Here, the phys memory for the mbuf is out 492*37474Ssklower of range for the vmebus to talk to it */ 493*37474Ssklower if (m == pkb->iff_mbuf) 494*37474Ssklower pkb->iff_mbuf = 0; 495*37474Ssklower break; 496*37474Ssklower } 49737110Ssklower tlen += m->m_len; 49837110Ssklower m0 = m; 49937110Ssklower m = m->m_next; 50037110Ssklower nb++; 50137110Ssklower } 50237110Ssklower 50337110Ssklower /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ 50437110Ssklower if (m0) 50537110Ssklower m0->m_next = 0; 50637110Ssklower 50737110Ssklower /* 50837110Ssklower * if not all of the descriptors would fit then merge remaining data 50937110Ssklower * into the transmit buffer, and point to it. Note: the mbufs are freed 51037110Ssklower * during the merge, they do not have to be freed when we get the 51137110Ssklower * transmit interrupt. 51237110Ssklower */ 51337110Ssklower if (m) { 514*37474Ssklower if (m == pkb->iff_mbuf) { 515*37474Ssklower printf("ex%d: exstart insanity\n", unit); 516*37474Ssklower pkb->iff_mbuf = 0; 517*37474Ssklower } 518*37474Ssklower len = if_vbaput(pkb->iff_buffer, m, 0); 51937110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 52037110Ssklower bp->mb_et.et_blks[nb].bb_len = (u_short)len; 52137110Ssklower bp->mb_et.et_blks[nb].bb_addr = l_util.i; 52237110Ssklower tlen += len; 52337110Ssklower nb++; 52437110Ssklower } 52537110Ssklower 52637110Ssklower /* 527*37474Ssklower * If the total length of the packet is too small, 528*37474Ssklower * pad the last fragment. (May run into very obscure problems) 52937110Ssklower */ 530*37474Ssklower if (tlen < sizeof(struct ether_header) + ETHERMIN) { 53137110Ssklower len = (ETHERMIN + sizeof(struct ether_header)) - tlen; 53237110Ssklower bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; 53337110Ssklower tlen += len; 534*37474Ssklower #ifdef notdef 535*37474Ssklower if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { 536*37474Ssklower must copy last frag into private buffer 537*37474Ssklower } 538*37474Ssklower #endif 53937110Ssklower } 54037110Ssklower 54137110Ssklower /* set number of fragments in descriptor */ 54237110Ssklower bp->mb_et.et_nblock = nb; 54337110Ssklower bp->mb_status |= MH_EXOS; 54437110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 54537110Ssklower } 54637110Ssklower 54737110Ssklower /* 54837110Ssklower * interrupt service routine. 54937110Ssklower */ 55037110Ssklower exintr(unit) 55137110Ssklower int unit; 55237110Ssklower { 55337110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 55437110Ssklower register struct ex_msg *bp = xs->xs_x2hnext; 55537110Ssklower struct vba_device *ui = exinfo[unit]; 55637110Ssklower struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; 557*37474Ssklower struct ex_msg *next_bp; 55837110Ssklower 55937110Ssklower while ((bp->mb_status & MH_OWNER) == MH_HOST) { 56037110Ssklower switch (bp->mb_rqst) { 56137110Ssklower case LLRECEIVE: 562*37474Ssklower if (--xs->xs_nrec < 0) { 563*37474Ssklower printf("ex%d: internal receive check\n", unit); 56437110Ssklower xs->xs_nrec = 0; 565*37474Ssklower } 56637110Ssklower exrecv(unit, bp); 56737110Ssklower FreePkBuf(bp->mb_pkb); 56837110Ssklower bp->mb_pkb = (struct ifvba *)0; 56937110Ssklower exhangrcv(unit); 57037110Ssklower break; 57137110Ssklower 57237110Ssklower case LLTRANSMIT: 57337110Ssklower case LLRTRANSMIT: 574*37474Ssklower if (--xs->xs_ntrb < 0) { 575*37474Ssklower printf("ex%d: internal transmit check\n", unit); 57637110Ssklower xs->xs_ntrb = 0; 577*37474Ssklower } 57837110Ssklower xs->xs_if.if_opackets++; 579*37474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 58037110Ssklower ; 58137110Ssklower else if (bp->mb_rply & LLXM_1RTRY) 58237110Ssklower xs->xs_if.if_collisions++; 58337110Ssklower else if (bp->mb_rply & LLXM_RTRYS) 58437110Ssklower xs->xs_if.if_collisions += 2; /* guess */ 58537110Ssklower else if (bp->mb_rply & LLXM_ERROR) 58637110Ssklower if (xs->xs_if.if_oerrors++ % 100 == 0) 58737110Ssklower printf("ex%d: 100 transmit errors=%b\n", 58837110Ssklower unit, bp->mb_rply, XMIT_BITS); 58937110Ssklower if (bp->mb_pkb->iff_mbuf) { 59037110Ssklower m_freem(bp->mb_pkb->iff_mbuf); 59137110Ssklower bp->mb_pkb->iff_mbuf = (struct mbuf *)0; 59237110Ssklower } 59337110Ssklower FreePkBuf(bp->mb_pkb); 59437110Ssklower bp->mb_pkb = (struct ifvba *)0; 595*37474Ssklower exstart(&xs->xs_if); 59637110Ssklower exhangrcv(unit); 59737110Ssklower break; 59837110Ssklower 59937110Ssklower case LLNET_STSTCS: 60037110Ssklower xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; 60137110Ssklower xs->xs_flags &= ~EX_STATPENDING; 602*37474Ssklower case LLNET_ADDRS: 603*37474Ssklower case LLNET_RECV: 604*37474Ssklower if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) 605*37474Ssklower ; 606*37474Ssklower else 607*37474Ssklower printf("ex%d: %s, request 0x%x, reply 0x%x\n", 608*37474Ssklower unit, "unsucessful stat or address change", 609*37474Ssklower bp->mb_rqst, bp->mb_rply); 61037110Ssklower break; 61137110Ssklower 61237110Ssklower default: 61337110Ssklower printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); 61437110Ssklower } 61537110Ssklower bp->mb_length = MBDATALEN; 616*37474Ssklower next_bp = bp->mb_next; 61737110Ssklower bp->mb_status |= MH_EXOS; /* free up buffer */ 618*37474Ssklower bp = next_bp; /* paranoia about race */ 61937110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ 62037110Ssklower } 62137110Ssklower xs->xs_x2hnext = bp; 62237110Ssklower } 62337110Ssklower 62437110Ssklower /* 62537110Ssklower * Get a request buffer, fill in standard values, advance pointer. 62637110Ssklower */ 62737110Ssklower struct ex_msg * 62837110Ssklower exgetcbuf(xs, req) 62937110Ssklower struct ex_softc *xs; 63037110Ssklower int req; 63137110Ssklower { 63237110Ssklower register struct ex_msg *bp; 63337110Ssklower struct ifvba *pkb; 63437110Ssklower int s = splimp(); 63537110Ssklower 63637110Ssklower bp = xs->xs_h2xnext; 63737110Ssklower if ((bp->mb_status & MH_OWNER) == MH_EXOS) { 63837110Ssklower splx(s); 63937110Ssklower return (struct ex_msg *)0; 64037110Ssklower } 64137110Ssklower xs->xs_h2xnext = bp->mb_next; 64237110Ssklower bp->mb_1rsrv = 0; 64337110Ssklower bp->mb_rqst = req; 64437110Ssklower bp->mb_length = MBDATALEN; 64537110Ssklower bp->mb_pkb = (struct ifvba *)0; 64637110Ssklower splx(s); 64737110Ssklower return bp; 64837110Ssklower } 64937110Ssklower 65037110Ssklower /* 65137110Ssklower * Process Ethernet receive completion: If input error just drop packet, 65237110Ssklower * otherwise examine packet to determine type. If can't determine length from 65337110Ssklower * type, then have to drop packet, otherwise decapsulate packet based on type 65437110Ssklower * and pass to type-specific higher-level input routine. 65537110Ssklower */ 65637110Ssklower exrecv(unit, bp) 65737110Ssklower int unit; 65837110Ssklower register struct ex_msg *bp; 65937110Ssklower { 66037110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 66137110Ssklower register struct ether_header *eh; 66237110Ssklower register struct mbuf *m; 66337110Ssklower int len, off, resid; 66437110Ssklower register struct ifqueue *inq; 66537110Ssklower int s; 66637110Ssklower 66737110Ssklower xs->xs_if.if_ipackets++; 66837110Ssklower /* total length - header - crc */ 66937110Ssklower len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 67037110Ssklower if (bp->mb_rply != LL_OK) { 67137110Ssklower if (xs->xs_if.if_ierrors++ % 100 == 0) 67237110Ssklower printf("ex%d: 100 receive errors=%b\n", 67337110Ssklower unit, bp->mb_rply, RECV_BITS); 67437110Ssklower return; 67537110Ssklower } 67637110Ssklower eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); 67737110Ssklower 67837110Ssklower /* 67937110Ssklower * Deal with trailer protocol: if type is PUP trailer get true type from 68037110Ssklower * first 16-bit word past data. Remember that type was trailer by 68137110Ssklower * setting off. 68237110Ssklower */ 68337110Ssklower eh->ether_type = ntohs((u_short)eh->ether_type); 68437110Ssklower #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 68537110Ssklower if (eh->ether_type >= ETHERTYPE_TRAIL && 68637110Ssklower eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 68737110Ssklower off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 68837110Ssklower if (off >= ETHERMTU) 68937110Ssklower return; /* sanity */ 69037110Ssklower eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 69137110Ssklower resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 69237110Ssklower if (off + resid > len) 69337110Ssklower return; /* sanity */ 69437110Ssklower len = off + resid; 69537110Ssklower } else 69637110Ssklower off = 0; 69737110Ssklower if (len == 0) 69837110Ssklower return; 69937110Ssklower /* 70037110Ssklower * Pull packet off interface. Off is nonzero if packet 70137110Ssklower * has trailing header; if_vbaget will then force this header 70237110Ssklower * information to be at the front, but we still have to drop 70337110Ssklower * the type and length which are at the front of any trailer data. 70437110Ssklower */ 70537110Ssklower m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); 70637110Ssklower if (m == 0) 70737110Ssklower return; 70837110Ssklower ether_input(&xs->xs_if, eh, m); 70937110Ssklower return; 71037110Ssklower } 71137110Ssklower 71237110Ssklower /* 71337110Ssklower * Hang a receive request. This routine is called by exinit and excdint, 71437110Ssklower * with interrupts disabled in both cases. 71537110Ssklower */ 71637110Ssklower exhangrcv(unit) 71737110Ssklower int unit; 71837110Ssklower { 71937110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 72037110Ssklower register struct ex_msg *bp; 72137110Ssklower register struct ifvba *pkb; 72237110Ssklower short mustint = 0; 72337110Ssklower union l_util { 72437110Ssklower u_long l; 72537110Ssklower struct i86_long i; 72637110Ssklower } l_util; 72737110Ssklower 72837110Ssklower while (xs->xs_nrec < NREC) { 72937110Ssklower if (xs->xs_pkblist == (struct ifvba *)0) 73037110Ssklower break; 73137110Ssklower if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { 73237110Ssklower break; 73337110Ssklower } 734*37474Ssklower GetPkBuf(bp, pkb); 735*37474Ssklower pkb->iff_mbuf = 0; 73637110Ssklower xs->xs_nrec += 1; 73737110Ssklower bp->mb_er.er_nblock = 1; 73837110Ssklower bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 73937110Ssklower l_util.l = BUSADDR(pkb->iff_buffer); 74037110Ssklower bp->mb_er.er_blks[0].bb_addr = l_util.i; 74137110Ssklower bp->mb_status |= MH_EXOS; 74237110Ssklower mustint = 1; 74337110Ssklower } 74437110Ssklower if (mustint == 0) 74537110Ssklower return; 74637110Ssklower movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); 74737110Ssklower } 74837110Ssklower 74937110Ssklower /* 75037110Ssklower * Ethernet output routine is ether_output(). 75137110Ssklower */ 75237110Ssklower 75337110Ssklower /* 75437110Ssklower * Watchdog routine (currently not used). Might use this to get stats from EXOS. 75537110Ssklower */ 75637110Ssklower exwatch(unit) 75737110Ssklower int unit; 75837110Ssklower { 75937110Ssklower struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; 76037110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 76137110Ssklower register struct ex_msg *bp; 76237110Ssklower int s = splimp(); 76337110Ssklower 76437110Ssklower if (xs->xs_flags & EX_STATPENDING) 76537110Ssklower goto exspnd; 76637110Ssklower if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { 76737110Ssklower splx(s); 76837110Ssklower return; 76937110Ssklower } 77037110Ssklower xs->xs_flags |= EX_STATPENDING; 77137110Ssklower bp->mb_ns.ns_mask = READ_OBJ; 77237110Ssklower bp->mb_ns.ns_rsrv = 0; 77337110Ssklower bp->mb_ns.ns_nobj = 8; 77437110Ssklower bp->mb_ns.ns_xobj = 0; 77537110Ssklower bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; 77637110Ssklower bp->mb_status |= MH_EXOS; 77737110Ssklower movow(&exaddr->ex_portb, EX_NTRUPT); 77837110Ssklower exspnd: splx(s); 77937110Ssklower xs->xs_if.if_timer = EXWATCHINTVL; 78037110Ssklower } 78137110Ssklower 78237110Ssklower /* 78337110Ssklower * Process an ioctl request. 78437110Ssklower */ 78537110Ssklower exioctl(ifp, cmd, data) 78637110Ssklower register struct ifnet *ifp; 78737110Ssklower int cmd; 78837110Ssklower caddr_t data; 78937110Ssklower { 79037110Ssklower register struct ifaddr *ifa = (struct ifaddr *)data; 79137110Ssklower register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 79237110Ssklower int s = splimp(), error = 0; 79337110Ssklower 79437110Ssklower switch (cmd) { 79537110Ssklower 79637110Ssklower case SIOCSIFADDR: 79737110Ssklower ifp->if_flags |= IFF_UP; 79837110Ssklower exinit(ifp->if_unit); 79937110Ssklower 80037110Ssklower switch (ifa->ifa_addr->sa_family) { 80137110Ssklower #ifdef INET 80237110Ssklower case AF_INET: 80337110Ssklower ((struct arpcom *)ifp)->ac_ipaddr = 80437110Ssklower IA_SIN(ifa)->sin_addr; 80537110Ssklower arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 80637110Ssklower break; 80737110Ssklower #endif 80837110Ssklower #ifdef NS 80937110Ssklower case AF_NS: 81037110Ssklower { 81137110Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 81237110Ssklower 81337110Ssklower if (ns_nullhost(*ina)) 81437110Ssklower ina->x_host = *(union ns_host *)(xs->xs_addr); 81537110Ssklower else 81637110Ssklower ex_setaddr(ina->x_host.c_host,ifp->if_unit); 81737110Ssklower break; 81837110Ssklower } 81937110Ssklower #endif 82037110Ssklower } 82137110Ssklower break; 82237110Ssklower 82337110Ssklower case SIOCSIFFLAGS: 82437110Ssklower if ((ifp->if_flags & IFF_UP) == 0 && 82537110Ssklower xs->xs_flags & EX_RUNNING) { 82637110Ssklower movow(&((struct exdevice *) 82737110Ssklower (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); 82837110Ssklower xs->xs_flags &= ~EX_RUNNING; 82937110Ssklower } else if (ifp->if_flags & IFF_UP && 83037110Ssklower (xs->xs_flags & EX_RUNNING) == 0) 83137110Ssklower exinit(ifp->if_unit); 83237110Ssklower break; 83337110Ssklower 83437110Ssklower default: 83537110Ssklower error = EINVAL; 83637110Ssklower } 83737110Ssklower splx(s); 83837110Ssklower return (error); 83937110Ssklower } 84037110Ssklower 84137110Ssklower /* 84237110Ssklower * set ethernet address for unit 84337110Ssklower */ 84437110Ssklower ex_setaddr(physaddr, unit) 84537110Ssklower u_char *physaddr; 84637110Ssklower int unit; 84737110Ssklower { 84837110Ssklower register struct ex_softc *xs = &ex_softc[unit]; 84937110Ssklower 85037110Ssklower if (physaddr) { 85137110Ssklower xs->xs_flags |= EX_SETADDR; 85237110Ssklower bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 85337110Ssklower } 854*37474Ssklower ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); 855*37474Ssklower } 856*37474Ssklower 857*37474Ssklower /* 858*37474Ssklower * Enable multicast reception for unit. 859*37474Ssklower */ 860*37474Ssklower ex_setmulti(linkaddr, unit, slot) 861*37474Ssklower u_char *linkaddr; 862*37474Ssklower int unit, slot; 863*37474Ssklower { 864*37474Ssklower register struct ex_softc *xs = &ex_softc[unit]; 865*37474Ssklower struct vba_device *ui = exinfo[unit]; 866*37474Ssklower register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 867*37474Ssklower register struct ex_msg *bp; 868*37474Ssklower 869*37474Ssklower if (!(xs->xs_flags & EX_RUNNING)) 87037110Ssklower return; 871*37474Ssklower bp = exgetcbuf(xs, LLNET_ADDRS); 87237110Ssklower bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 873*37474Ssklower bp->mb_na.na_slot = slot; 874*37474Ssklower bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); 87537110Ssklower bp->mb_status |= MH_EXOS; 87637110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 87737110Ssklower bp = xs->xs_x2hnext; 878*37474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 87937110Ssklower #ifdef DEBUG 880*37474Ssklower log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, 881*37474Ssklower (slot == PHYSSLOT ? "reset addr" : "add multicast" 882*37474Ssklower ether_sprintf(bp->mb_na.na_addrs), slot); 88337110Ssklower #endif 88437110Ssklower /* 885*37474Ssklower * Now, re-enable reception on slot. 88637110Ssklower */ 887*37474Ssklower bp = exgetcbuf(xs, LLNET_RECV); 88837110Ssklower bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 889*37474Ssklower bp->mb_nr.nr_slot = slot; 89037110Ssklower bp->mb_status |= MH_EXOS; 89137110Ssklower movow(&addr->ex_portb, EX_NTRUPT); 89237110Ssklower bp = xs->xs_x2hnext; 893*37474Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ 89437110Ssklower ; 89537110Ssklower } 89637110Ssklower #endif 897