/* * if_qe.c * * SCCSID: @(#)if_qe.c 3.1 12/31/87 * based on "@(#)if_qe.c 1.1 (decvax!rjl)"; */ /********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/include/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* --------------------------------------------------------------------- * Modification History * * 04 Oct. 84 -- jf * Added support for new ioctls to add and delete multicast addresses * and set the physical address. * Add support for general protocols. * * 14 Aug. 84 -- rjl * Integrated Shannon changes. (allow arp above 1024 and ? ) * * 13 Feb. 84 -- rjl * * Initial version of driver. derived from IL driver. * * --------------------------------------------------------------------- */ /* * Digital Q-BUS to NI Adapter */ #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> #include <sys/buf.h> #include <sys/protosw.h> #include <sys/ioctl.h> #include <errno.h> #include <net/if_qe.h> /* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * is_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */ /* * We allocate enough descriptors to do scatter/gather plus 1 to * construct a ring. * * The MicroVAX-I doesn't have an I/O map, therefore all addresses presented * to devices must be physical address. To keep track of mbufs in use the * softc for this device has to record the mbufs because the data addresses * in the ring descriptors are physical addresses instead of virtual. With * an I/O map this will no longer be necessary and we'll be able to use * the mbuf macro's for allocation and deallocation. * * There must be enough descriptors in the receive ring to map at least 2 * of the largest size datagrams so that a race condition doesn't occur in * the receiver. (~1600/252 bytes) * */ /* * This constant should really be 60 because the qna adds 4 bytes of crc. * However when set to 60 our packets are ignored by deuna's , 3coms are * okay ?????????????????????????????????????????? */ #define MINDATA 64 struct qe_softc qe_softc[]; #define QEADDR 0174440 /* alternate value is 0174460 */ #define QEVECT 0400 /* arbitrary, for now... */ extern int nNQE; /* initialised in dds.c */ extern struct protosw *iftype_to_proto(), *iffamily_to_proto(); extern long time; int qeattach(); struct mbuf *qeget(); #define QEUNIT(x) minor(x) int qewrun = 0; int qeinit(),qeoutput(),qeioctl(), qewatch(); int qedebug = 0; extern hz; /* * Watchdog timeout value, in clicks. Three times this value * is the maximum time for us to decide that the deqna transmit * queue is wedged (could be as short as two times this value). */ #define QETIMO 30 /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */ static char QEname[] = { 'q', 'e', '\0' }; qeattach(unit, addr, vector) int unit; register struct qedevice *addr; int vector; { register struct qe_softc *sc; register struct ifnet *ifp; register int i; if (badaddr(addr)) { printf("qe%d: non-existant address %o\n", unit, addr); return; } sc = &qe_softc[unit]; ifp = &sc->is_if; ifp->if_unit = unit; ifp->if_name = QEname; ifp->if_mtu = ETHERMTU; ifp->if_flags |= IFF_BROADCAST | IFF_DYNPROTO; /* * Read the address from the prom and save it. */ for( i=0 ; i<6 ; i++ ) sc->is_addr[i] = addr->qe_sta_addr[i] & 0xff; /* * Save the vector for initialization at reset time. */ sc->qe_intvec = vector; sc->addr = addr; ifp->if_init = qeinit; ifp->if_output = qeoutput; ifp->if_ioctl = qeioctl; ifp->if_reset = 0; if_attach(ifp); } /* * Initialization of interface and allocation of mbufs for receive ring * buffers. */ qeinit(unit) int unit; { register struct qe_softc *sc = &qe_softc[unit]; register struct qedevice *addr = sc->addr; register struct ifnet *ifp = &sc->is_if; /* char (*setup_pkt)[8]; */ char setup_pkt[16][8]; int i, s; /* address not known */ /* DECnet must set this somewhere to make device happy */ if (ifp->if_addrlist == (struct ifaddr *)0) return; /* * Initialize the transmit and receive rings. */ initring(sc->rring, sc->rmbuf, NRECV, QEALLOC); initring(sc->tring, sc->tmbuf, NXMIT, QENOALLOC); sc->nxmit = 0; sc->timeout = 0; sc->otindex = 0; sc->tindex = 0; sc->rindex = 0; /* * Take the interface out of reset, program the vector, * enable interrupts, and tell the world we are up. */ s = splimp(); addr->qe_vector = sc->qe_intvec; if (ifp->if_flags & IFF_LOOPBACK) addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ELOOP; else addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; addr->qe_rcvlist_lo = &sc->rring[sc->rindex]; addr->qe_rcvlist_hi = 0; ifp->if_flags |= IFF_UP | IFF_RUNNING; /* * Get the addr off of the interface and place it into the setup * packet. This code looks strange due to the fact that the address * is placed in the setup packet in col. major order. */ /* setup_pkt = (char (*)[8])m_sget(16*8, 0); if (setup_pkt == NULL) panic("qe_setup"); */ for( i = 0 ; i < 6 ; i++ ) setup_pkt[i][1] = addr->qe_sta_addr[i]; qesetup(sc, setup_pkt); qeissuesetup(sc, "qeinit", setup_pkt); /* MSFREE(setup_pkt); */ qestart( unit ); sc->ztime = time; splx( s ); } /* * Initialize a bdl ring, possibly allocating mbufs * on the way. */ static initring(rp, mbp, cnt, option) register struct qe_ring *rp; register struct mbuf **mbp; register int cnt, option; { struct qe_ring *orp = rp; do { qeinitdesc(rp++, mbp++, option, NULL); } while (--cnt > 0); qeinitdesc(rp, mbp, QENOALLOC, NULL); rp->qe_addr_lo = orp; rp->qe_addr_hi = 0; rp->qe_chain = 1; rp->qe_valid = 1; } /* * Start output on interface. * */ static qestart(dev) dev_t dev; { int unit = QEUNIT(dev); register struct qe_softc *sc = &qe_softc[unit]; register struct qedevice *addr; register struct qe_ring *rp; struct mbuf *m; int desc_needed, i, buf_addr, len, j, tlen, s, diff; /* * Check for enough transmit descriptors to map * this datagram onto the interface. If there will never be enough * throw the packet away and complain. If there will be enough but * there aren't right now just return and if there are enough now, * setup one or more descriptors to map the packet onto the interface * and start it. * * The deqna doesn't look at anything but the valid bit to determine * if it should transmit this packet. If you fill the ring, the * device will loop indefinately and flood the network with packets * until the ring is broken. So, we always make sure there is at * least one empty descriptor. */ s = splimp(); if( (m = sc->is_if.if_snd.ifq_head) == 0 ){ splx( s ); return; /* Nothing on the queue */ } for( desc_needed = 0 ; m ; m = m->m_next ) desc_needed++; if( desc_needed > NXMIT-1 ) panic("qe: xmit packet too big"); /* * See if the required descriptors are available. */ addr = sc->addr; i = 0; j = sc->tindex; while( sc->tring[j].qe_valid == 0 && i <= desc_needed ) { i++; j = ++j % NXMIT; } /* * Fred Canter -- 2/20/86 * Following allowed qestart() to overrun the xmit ring. * This caused the orphaned mbuf problem. */ /* if( desc_needed > i+1 ) { BOGUS! */ if((desc_needed+1) > i) { splx( s ); return; } /* * Record the chain head, attach each mbuf data area to a * descriptor and start the QNA if the transmit list is invalid. */ IF_DEQUEUE(&sc->is_if.if_snd, m); /* * Save the chain head so that we can deallocate it after the * i/o is done. This will not be necessary when we have an i/o map * because we can use virtual addresses ? */ for(i=sc->tindex, sc->tmbuf[i]=m, tlen=0 ; m ; m=m->m_next, i = ++i % NXMIT){ rp = &sc->tring[i]; len = m->m_len; /* * Does buffer end on odd byte ? */ if( len & 1 ) { len++; rp->qe_odd_end = 1; } tlen += len; rp->qe_buf_len = -(len/2); rp->qe_addr_lo = (ctob(m->m_click)&~077) + m->m_off; rp->qe_addr_hi = (m->m_click >> 10) & 077; if( m->m_next == NULL ) { /* * Make sure we don't send a runt. */ if( tlen < MINDATA ) { diff = MINDATA - tlen; if( (len + diff + m->m_off) <= MMAXOFF ) { rp->qe_buf_len = -(len + diff)/2; tlen += diff; } else { /* * This packet is too short. Grab * another descriptor, and point it * to arbitrary data, just so that * we can fill up to the minimum * length. This should probabaly be * an empty buffer, not low core, but * no one should look at it anyway... */ i = ++i % NXMIT; rp = &sc->tring[i]; if( diff & 1 ) diff++; rp->qe_buf_len = -(diff/2); rp->qe_addr_lo = 0; rp->qe_addr_hi = 0; } } rp->qe_eomsg = 1; rp->qe_valid = 1; /* * Last descriptor !! If the QNA is running it could * beat us down the list if we set the valid address * bits in the forward order, so we do it backwards. */ for( j = i ; j != sc->tindex ; ) { j = --j >= 0 ? j : NXMIT; sc->tring[j].qe_valid = 1; } sc->nxmit++; /* a few statistics */ if ((sc->ctrblk.est_bytesent += len) < len) sc->ctrblk.est_bytesent -= len; if (++sc->ctrblk.est_bloksent == 0) --sc->ctrblk.est_bloksent; } } /* * If the watchdog time isn't running kick it. */ sc->timeout = 1; if (!qewrun++) timeout(qewatch, 0, QETIMO); /* * See if the xmit list is invalid. */ if( addr->qe_csr & QE_XL_INVALID ) { addr->qe_xmtlist_lo = &sc->tring[sc->tindex]; addr->qe_xmtlist_hi = 0; } sc->tindex = i; splx( s ); } /* * Ethernet interface interrupt processor */ qeint(unit) int unit; { register struct qe_softc *sc; struct qedevice *addr; int s, csr; mapinfo map; /*@*/ extern char *panicstr; /*@*/ if (panicstr) /*@*/ return; unit = minor(unit); sc = &qe_softc[unit]; addr = sc->addr; csr = addr->qe_csr; if (sc->is_if.if_flags & IFF_LOOPBACK) addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ELOOP; else addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; savemap(map); if (csr & QE_RCV_INT) qerint(unit); if (csr & QE_NEX_MEM_INT) printf("qe%d: NXM intr\n", unit); else if (csr & QE_XMIT_INT) qetint(unit); if (addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET) { addr->qe_rcvlist_lo = (int)&sc->rring[sc->rindex]; addr->qe_rcvlist_hi = 0; } restormap(map); } /* * Ethernet interface transmit interrupt. */ static qetint(unit) int unit; { register struct qe_softc *sc = &qe_softc[unit]; register struct mbuf *mp; register first, index; int i, len, status1; /* int status2; removed, was not used */ while (sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET) { /* * Find the index of the last descriptor in this * packet. ( LASTNOT will be clear ) If we can't find one * then the QNA is still working on it. This is necessary * for subsequent passes because we can't be sure that the * QNA is through with a descriptor until we find the last * in the chain. */ first = index = sc->otindex; while (sc->tring[index].qe_valid && !sc->tring[index].qe_eomsg) index = ++index % NXMIT; /* * Is the QNA done with this packet ? */ if (sc->tring[index].qe_status1 == QE_NOTYET) break; /* * Save the status words from the descriptor so that it can * be released. */ status1 = sc->tring[index].qe_status1; /* status2 = sc->tring[index].qe_status2; not used */ mp = sc->tmbuf[first]; qeinitdesc(&sc->tring[first], &sc->tmbuf[first], QENOALLOC, NULL); if (--sc->nxmit == 0) sc->timeout = 0; if (first == NXMIT-1) sc->tring[NXMIT].qe_flag = QE_NOTYET; while (first != index) { first = ++first % NXMIT; qeinitdesc(&sc->tring[first], &sc->tmbuf[first], QENOALLOC, NULL); if (first == NXMIT-1) sc->tring[NXMIT].qe_flag = QE_NOTYET; } sc->otindex = ++index % NXMIT; /* * Do some statistics. */ sc->is_if.if_opackets++; if (status1 & QE_CCNT) { i = (status1 & QE_CCNT) >> 4; sc->is_if.if_collisions += i; if (i == 1) { if (++sc->ctrblk.est_single == 0) --sc->ctrblk.est_single; } else { if (++sc->ctrblk.est_multiple == 0) --sc->ctrblk.est_multiple; } } if (status1 & QE_FAIL) if (++sc->ctrblk.est_collis == 0) --sc->ctrblk.est_collis; if (status1 & QE_ERROR) { sc->is_if.if_oerrors++; if (++sc->ctrblk.est_sendfail == 0) --sc->ctrblk.est_sendfail; else { if (status1 & QE_ABORT) sc->ctrblk.est_sendfail_bm |= 1; if (status1 & QE_NOCAR) sc->ctrblk.est_sendfail_bm |= 2; } m_freem(mp); } else if (mp) { /* * The QNA doesn't hear it's own packets. Unfortunately * the code above us expects to hear all broadcast * traffic including our own. Therefore if this is a * broadcast packet we have to loop it back, * otherwise we simply free the packets. */ { register short *p; segm map5; saveseg5(map5); p = (int *)(mtod(mp, struct ether_header *) ->ether_dhost); i = *p++ == -1 && *p++ == -1 && *p == -1; restorseg5(map5); } if (i) { register struct mbuf *mp0; for (mp0 = mp, len=0; mp0; mp0 = mp0->m_next) len += mp0->m_len; qerecv(sc, mp, len); } else m_freem(mp); } } qestart(unit); } struct foob { unsigned char lo; unsigned char hi; }; #define lobyte(x) (((struct foob *)&(x))->lo) #define hibyte(x) (((struct foob *)&(x))->hi) /* * Ethernet interface receiver interrupt. * If can't determine length from type, then have to drop packet. * Othewise decapsulate packet based on type and pass to type specific * higher-level input routine. * Fred Canter -- 2/20/86 * Serach the entire receive ring for a completed message * instead of depending on the DEQNA to always put the next * message in the descriptor pointed to by sc->rindex. * Looks like this fixed the "winking out" problem. */ int qe_search = 1; static qerint(unit) int unit; { register struct qe_softc *sc = &qe_softc[unit]; struct mbuf *m, *n; int len, index, first, status1, status2, resid, drop; struct mbuf tmb; int orindex, i; /* * If qe_search set, find where the DEANA really put * the next message (sometimes not where we expect). */ orindex = sc->rindex; i = sc->rindex; while(1) { if(qe_search == 0) break; if(sc->rring[i].qe_status1 != QE_NOTYET) { sc->rindex = i; break; } i = ++i % NRECV; if(i == orindex) return; } /* * Traverse the receive ring looking for packets to pass back. * The search is complete when we find a descriptor not in use. */ while ( sc->rring[sc->rindex].qe_status1 != QE_NOTYET ) { /* * Find the index of the last descriptor in this * packet. ( LASTNOT will be clear ) If we can't find one * then the QNA is still working on it. */ first = index = sc->rindex; while( (sc->rring[index].qe_status1 & QE_MASK) == QE_MASK ) index = ++index % NRECV; /* * If we found an unused descriptor we've beat the QNA */ if( sc->rring[index].qe_status1 == QE_NOTYET ) break; /* * Save the status words from the descriptor so that it can * be released. This thing isn't valid unless the low and * high bytes are the same. */ status2 = sc->rring[index].qe_status2; if (lobyte(status2) != hibyte(status2)) break; status1 = sc->rring[index].qe_status1; sc->is_if.if_ipackets++; /* * Link the mbufs together, reinitialize the descriptors and * pass the mbuf chain off to qerecv if status is okay. */ n = &tmb; drop = 0; for (;;) { m = sc->rmbuf[first]; if (qeinitdesc(&sc->rring[first], &sc->rmbuf[first], QEALLOC, m)) { n->m_next = m; n = m; } else drop++; /* see qeinitdesc() sc->rring[first].qe_status2 = 1; */ if (first == NRECV - 1) sc->rring[NRECV].qe_flag = QE_NOTYET; if (first == index) break; first = ++first % NRECV; } if ((sc->rindex = ++first % NRECV) == NRECV - 1) sc->rring[NRECV].qe_flag = QE_NOTYET; n->m_next = 0; m = tmb.m_next; /* * If this was a setup packet, discard it. */ if (status1 & QE_ESETUP) { if (qedebug) printf("qe%d: setup pkt\n", unit); m_freem( m ); continue; } if (drop) { sc->is_if.if_ierrors++; m_freem( m ); if (qedebug) printf("qe%d: pkt drop\n", unit); continue; } /* * If there was an error discard it. */ if (status1 & QE_ERROR) { sc->is_if.if_ierrors++; m_freem( m ); if (status1&QE_DISCARD) { sc->ctrblk.est_recvfail++; if (status1&QE_CRCERR) { sc->ctrblk.est_recvfail_bm |= 1; if (status1&QE_FRAME) sc->ctrblk.est_recvfail_bm |= 2; } if (status1&QE_OVF) sc->ctrblk.est_recvfail_bm |= 4; if (qedebug) { if (status1&QE_SHORT) printf("qe%d: short pkt\n", unit); if (status1&QE_RUNT) printf("qe%d: runt pkt\n", unit); } } else if (qedebug) { if (status1&QE_RUNT) printf("qe%d: runt pkt\n", unit); else printf("qe%d: long pkt\n", unit); } continue; } /* * Get the actual length and compute the size of data in the * last mbuf. The hardware doesn't have time to count the first * 60 bytes because it is doing address filtering so we add 60. */ len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60; sc->ctrblk.est_bytercvd += len; sc->ctrblk.est_blokrcvd++; /* * The last mbuf may not be full so we have to set the correct * length in it. */ if( resid = len % MLEN ) n->m_len = resid; qerecv( sc, m, len ); } } /* * Process a packet. */ static qerecv( sc, m, len ) struct qe_softc *sc; struct mbuf *m; int len; { register struct mbuf *mp; int off, resid, index; struct ifqueue *inq; register int type; struct protosw *pr; segm map5; /* * Deal with trailer protocol: If type is PUP trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ saveseg5(map5); type = ntohs(mtod(m, struct ether_header *)->ether_type); restorseg5(map5); if (type >= ETHERTYPE_TRAIL && type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = ((type - ETHERTYPE_TRAIL) * 512) + sizeof(struct ether_header);; if (off >= ETHERMTU) goto bad; /* sanity */ for (index=0, mp=m; mp && (index + mp->m_len) <= off; ) { index += mp->m_len; mp = mp->m_next; } if (mp) { register u_short *p; p = mtod(mp, caddr_t) + (off-index); type = ntohs(*p++); resid = ntohs(*p); restorseg5(map5); } else goto bad; if (off + resid > len) goto bad; /* sanity */ len = off + resid; } else off = 0; if (len == 0) goto bad; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; qeget will then force this header * information to be at the front, but we still have to drop * the type and length words which are at the front of any trailer data. */ if (off) { if ((m = qeget(m, mp, off-index)) == 0) return; m->m_off += 2 * sizeof(u_short); m->m_len -= 2 * sizeof(u_short); } else { m->m_off += sizeof(struct ether_header); m->m_len -= sizeof(struct ether_header); } switch (type) { #ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: arpinput(&sc->is_ac, m); return; #endif default: /* * See if other protocol families are defined and * call protocol specific routines. If no other * protocol families are defined then dump the message. */ if (pr = iftype_to_proto(type)) (*pr->pr_ifinput)( m, &sc->is_if, &inq); else { if (++sc->ctrblk.est_unrecog == 0) --sc->ctrblk.est_unrecog; m_freem(m); return; } } if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); return; } IF_ENQUEUE(inq, m); return; /* * If the packet format looks like a trailer but is currupt we exit here * after releasing the mbuf. */ bad: m_freem(m); return; } /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */ qeoutput(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; { int type, s, error; u_char edst[6]; struct in_addr idst; struct protosw *pr; register struct qe_softc *is = &qe_softc[ifp->if_unit]; register struct mbuf *m = m0; register struct ether_header *eh; register int off; segm map5; saveseg5(map5); switch (dst->sa_family) { #ifdef INET case AF_INET: idst = ((struct sockaddr_in *)dst)->sin_addr; if (!arpresolve(&is->is_ac, m, &idst, edst)) return (0); /* if not yet resolved */ /* need per host negotiation */ if ((ifp->if_flags & IFF_NOTRAILERS) == 0) { off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; if (off > 0 && (off & 0x1ff) == 0 && m->m_off >= MMINOFF + 2 * sizeof (u_short)) { u_short *p; type = ETHERTYPE_TRAIL + (off>>9); m->m_off -= 2 * sizeof (u_short); m->m_len += 2 * sizeof (u_short); p = mtod(m, u_short *); *p++ = HTONS(ETHERTYPE_IP); *p = htons(m->m_len); goto gottraqeertype; } } type = ETHERTYPE_IP; off = 0; goto gottype; #endif case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); type = eh->ether_type; goto gottype; default: /* * Try to find other address families and call protocol * specific output routine. */ if (pr = iffamily_to_proto(dst->sa_family)) { (*pr->pr_ifoutput)(ifp, m0, dst, &type, (char *)edst); goto gottype; } else { printf("qe%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto bad; } } gottraqeertype: /* * Packet to be sent as trailer: move first packet * (control information) to end of chain. */ while (m->m_next) m = m->m_next; m->m_next = m0; m = m0->m_next; m0->m_next = 0; m0 = m; gottype: /* * Add local net header. If no space in first mbuf, * allocate another. */ if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct ether_header) > m->m_off) { m = m_get(M_DONTWAIT, MT_HEADER); if (m == 0) { error = ENOBUFS; goto bad; } m->m_next = m0; m->m_off = MMINOFF; m->m_len = sizeof (struct ether_header); } else { m->m_off -= sizeof (struct ether_header); m->m_len += sizeof (struct ether_header); } eh = mtod(m, struct ether_header *); eh->ether_type = htons((u_short)type); bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); bcopy((caddr_t)is->is_addr, (caddr_t)eh->ether_shost, sizeof (is->is_addr)); restorseg5(map5); /* * Queue message on interface, and start output if interface * not yet active. */ s = splimp(); if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(s); m_freem(m); return (ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); qestart(ifp->if_unit); splx(s); return (0); bad: restorseg5(map5); m_freem(m0); return (error); } /* * Process an ioctl request. */ qeioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { struct qe_softc *sc = &qe_softc[ifp->if_unit]; struct sockaddr *sa; struct sockaddr_in *sin; struct ifreq *ifr = (struct ifreq *)data; struct protosw *pr; int i,s = splimp(), error = 0; struct ifaddr *ifa = (struct ifaddr *)data; switch (cmd) { case SIOCSPHYSADDR: { /* char (*setup_pkt)[8]; */ char setup_pkt[16][8]; /* * Before we do anything, make sure we can get the * data space if we need it. */ /* if (ifp->if_flags & IFF_RUNNING) { setup_pkt = (char (*)[8])m_sget(16*8, 0); if (setup_pkt == NULL) { splx(s); return(ENOBUFS); } } */ bcopy(ifr->ifr_addr.sa_data, &sc->is_addr, sizeof(sc->is_addr)); if (ifp->if_flags & IFF_RUNNING) { for (i = 0; i < 6; i++) setup_pkt[i][1] = sc->is_addr[i]; qesetup(sc, setup_pkt); qeissuesetup(sc, "SIOCPHYSADDR", setup_pkt); #ifdef notdef if_rtinit(ifp, -1); #endif /* MSFREE(setup_pkt); */ } qeinit(ifp->if_unit); break; } case SIOCSIFADDR: ifp->if_flags |= IFF_UP; qeinit(ifp->if_unit); switch(ifa->ifa_addr.sa_family) { #ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break; #endif #ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) { ina->x_host = * (union ns_host *) (qe_softc[ifp->if_unit].qe_addr); } else { qe_setaddr(ina->x_host.c_host, ifp->if_unit); } break; } #endif default: if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) { error = (*pr->pr_ifioctl)(ifp, cmd, data); } break; } break; default: error = EINVAL; } done: splx(s); return (error); } /* * Initialize a ring descriptor with mbuf allocation side effects * If we are allocating, and mp2 is non-null, then use it if we * can't allocate a new mbuf. The return value indicates whether * or not we used mp2. */ static qeinitdesc(rp, mp, option, mp2) register struct qe_ring *rp; register struct mbuf **mp; int option; struct mbuf *mp2; { /* * clear the entire descriptor */ bzero(rp, sizeof(*rp)); rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_status2 = 0xff00; /* * Perform the necessary allocation/deallocation */ if (option == QENOALLOC) *mp = NULL; else { register struct mbuf *m; if ((option == QEALLOC) || ((m = *mp) == NULL)) MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { if ((m = mp2) == 0) panic("qe: no mbufs for desc ring"); } *mp = m; rp->qe_buf_len = -(MLEN/2); m->m_len = MLEN; m->m_off = MMINOFF; rp->qe_addr_lo = (ctob(m->m_click)&~077) + m->m_off; rp->qe_addr_hi = (m->m_click >> 10) & 077; /* * Must be last. QNA could be listening. */ rp->qe_valid = 1; return(m != mp2); } return(1); } /* * Pull the trailer info up to the front of the chain. */ static struct mbuf * qeget(m, mtp, off) register struct mbuf *m; /* Pointer to first mbuf in the chain */ register struct mbuf *mtp; /* Pointer to first mbuf in trailer */ int off; /* Offset to trailer in trailer mbuf */ { register struct mbuf *mp; struct mbuf *mp0; /* * The trailer consists of 2 words followed by an IP header. * The rest of the code assumes that the trailer is enclosed in * a single mbuf. In our case the trailer spans two mbufs so it * has to be packed back into a single packet so that other routines * can access it as a structure. */ MGET(mp, M_DONTWAIT, MT_DATA); if (mp == NULL) { m_freem(m); return(0); } mp->m_off = MMINOFF; /* * Copy the portion of the trailer in this mbuf to the new * mbuf and adjust the length. This mbuf now becomes the last * in the packet. */ MBCOPY(mtp, off, mp, 0, mtp->m_len - off); mp->m_len = mtp->m_len - off; mtp->m_len = off; mp0 = mtp; /* Save so we can break the chain */ /* * The remainder of the trailer is in the next mbuf. */ mtp = mtp->m_next; if (mtp) { if (mtp->m_len + mp->m_len > MLEN || mtp->m_next) { /* * Can't fit trailer in an mbuf. Must be insane. */ m_freem(m); m_freem(mp); return(0); } /* * Pull the data up, break the chain and release the old * trailer. */ MBCOPY(mtp, 0, mp, mp->m_len, mtp->m_len); mp->m_len += mtp->m_len; mp0->m_next = NULL; /* Break the chain */ m_freem(mtp); } /* * Move the new trailer to the head of the packet and remove the * ethernet header. */ mp->m_next = m; m->m_off += sizeof (struct ether_header); m->m_len -= sizeof (struct ether_header); return(mp); } /* * Build a setup packet - the physical address will already be present * in first column. */ static qesetup(sc, setup_pkt) struct qe_softc *sc; char setup_pkt[16][8]; { register int i,j; /* * Copy the target address to the rest of the entries in this row. */ for (j = 0; j < 6; j++) for (i = 2; i < 8; i++) setup_pkt[j][i] = setup_pkt[j][1]; /* * Duplicate the first half. */ bcopy(setup_pkt, setup_pkt[8], 64); /* * Fill in the broadcast address. */ for (i = 0; i < 6; i++) setup_pkt[i][2] = 0xff; } /* * Issue a setup packet to the QNA and wait for it's completion. Report an * error if we can't immediately get the transmit ring entry to send the * setup packet or if the transmission fails. */ static qeissuesetup(sc, cmdname, setup_pkt) struct qe_softc *sc; char *cmdname; char setup_pkt[16][8]; { register struct qe_ring *rp = (struct qe_ring *)&sc->tring[sc->tindex]; struct qedevice *addr = sc->addr; if (rp->qe_valid == 0) { sc->tmbuf[sc->tindex] = 0; if (setup_pkt >= 0140000) { /* packet is on stack, get 22 bit address */ long paddr; paddr = ctob((long)*KDSA6) + (long)setup_pkt - 0140000L; rp->qe_addr_lo = (int)(paddr&0177777); rp->qe_addr_hi = (int)((paddr>>16)&077); } else { rp->qe_addr_lo = setup_pkt; rp->qe_addr_hi = 0; } rp->qe_buf_len = -64; rp->qe_setup = 1; rp->qe_eomsg = 1; rp->qe_valid = 1; if (addr->qe_csr & QE_XL_INVALID) { addr->qe_xmtlist_lo = rp; addr->qe_xmtlist_hi = 0; } sc->nxmit++; sc->tindex = ++sc->tindex % NXMIT; while (rp->qe_status1 == QE_NOTYET) ; /* * Avoid an obscure race condition with the hardware continueing * around the transmit ring and finding this setup packet again. */ rp->qe_setup = 0; } else { printf("qe%d: %s failed: no ring entry\n", sc->is_if.if_unit, cmdname); } } qewatch() { register struct qe_softc *sc; register int i, inprogress = 0; for (sc = &qe_softc[0], i = nNQE; i ; --i) { if (sc->timeout) { if (++sc->timeout > 3) qerestart(sc); else inprogress++; } sc++; } if (inprogress) { timeout(qewatch, 0, QETIMO); qewrun++; } else qewrun = 0; } /* * Fred Canter -- 2/20/86 * On a qerestart, if qe_xfree is set free all mbufs * on the transmit ring, otherwise re-transmit them. * Freeing is the recommended approach. */ int qe_xfree = 1; int qe_restarts; /* number of qerestarts since boot */ static qerestart(sc) register struct qe_softc *sc; { register struct ifnet *ifp = &sc->is_if; register struct qedevice *addr = sc->addr; char setup_pkt[16][8]; register i; /* * 1. Reset the device. * 2. Clean out the transmit ring, and put all the pending * transmits back on the send queue. We do this in * reverse order, and stick them at the front of the queue. * 3. Clean out and re-allocate the receive ring, making * sure that we free up any mbufs that don't get re-used! * 4. Turn on interrupts, validate the receive ring, and * issue a setup packet. * 5. Restart the device. */ addr->qe_csr = QE_RESET; /* * Clear of CSR added at the request of hardware * engineering, so the DELQA can be bug for bug * compatible with the DEQNA. * 1/28/86 -- Fred Canter */ addr->qe_csr = 0; sc->timeout = 0; qe_restarts++; if(qe_xfree == 1) { for(i=0; i<NXMIT; i++) { register struct mbuf *m; if (m = sc->tmbuf[i]) m_freem(m); } } if(qe_xfree == 0) { i = sc->tindex; do { register struct mbuf *m; if ( --i < 0) i = NXMIT - 1; if (m = sc->tmbuf[i]) IF_PREPEND(&ifp->if_snd, m); } while(i != sc->otindex); } initring(sc->tring, sc->tmbuf, NXMIT, QENOALLOC); initring(sc->rring, sc->rmbuf, NRECV, QEREALLOC); sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; if (ifp->if_flags & IFF_LOOPBACK) addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ELOOP; else addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; addr->qe_rcvlist_lo = &sc->rring[0]; addr->qe_rcvlist_hi = 0; for( i = 0 ; i < 6 ; i++ ) setup_pkt[i][1] = sc->is_addr[i]; qesetup(sc, setup_pkt); qeissuesetup(sc, "qerestart", setup_pkt); qestart(ifp->if_unit); if (qedebug) printf("qerestart: restarted qe%d\n", ifp->if_unit); }