X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/0da80bb641a50f024c905e1a4c0f17d505f13031..4a404244ad5a6e8679d302ed44ecc61cac172725:/usr/src/sys/vax/if/if_ec.c diff --git a/usr/src/sys/vax/if/if_ec.c b/usr/src/sys/vax/if/if_ec.c index 33f918e625..3aa5f69b5c 100644 --- a/usr/src/sys/vax/if/if_ec.c +++ b/usr/src/sys/vax/if/if_ec.c @@ -1,7 +1,8 @@ -/* if_ec.c 4.4 82/04/12 */ +/* if_ec.c 4.12 82/05/27 */ #include "ec.h" #include "imp.h" +#include "loop.h" /* * 3Com Ethernet Controller interface @@ -38,11 +39,14 @@ struct uba_device *ecinfo[NEC]; u_short ecstd[] = { 0 }; struct uba_driver ecdriver = { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo }; +u_char ec_iltop[3] = { 0x02, 0x07, 0x01 }; #define ECUNIT(x) minor(x) int ecinit(),ecoutput(),ecreset(); struct mbuf *ecget(); +extern struct ifnet loif; + /* * Ethernet software status per interface. * @@ -58,11 +62,7 @@ struct mbuf *ecget(); struct ec_softc { struct ifnet es_if; /* network-visible interface */ struct ifuba es_ifuba; /* UNIBUS resources */ - short es_delay; /* current output delay */ short es_mask; /* mask for current output delay */ -#ifdef notdef - long es_lastx; /* host last transmitted to */ -#endif short es_oactive; /* is output active? */ caddr_t es_buf[16]; /* virtual addresses of buffers */ u_char es_enaddr[6]; /* board's ethernet address */ @@ -84,6 +84,10 @@ COUNT(ECPROBE); br = 0; cvec = br; br = cvec; ecrint(0); ecxint(0); eccollide(0); #endif + /* + * Make sure memory is turned on + */ + addr->ec_rcr = EC_AROM; /* * Check for existence of buffers on Unibus. * This won't work on a 780 until more work is done. @@ -182,7 +186,7 @@ COUNT(ECATTACH); #if NIMP == 0 /* here's one for you john baby.... */ if (ui->ui_flags &~ 0xff) - eclhinit((ui->ui_flags &~ 0xff) | 0x0a); + eclhinit(&es->es_if, (ui->ui_flags &~ 0xff) | 0x0a); #endif } @@ -216,19 +220,13 @@ ecinit(unit) register i; int s; -#ifdef notdef - if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, - sizeof (struct ec_header), (int)btoc(ECMTU)) == 0) { - printf("ec%d: can't initialize\n", unit); - es->es_if.if_flags &= ~IFF_UP; - return; - } -#endif addr = (struct ecdevice *)ui->ui_addr; /* * Hang receive buffers and start any pending * writes by faking a transmit complete. + * Writing into the rcr also makes sure the memory + * is turned on. */ s = splimp(); for (i=ECRHBF; i>=ECRLBF; i--) @@ -240,16 +238,10 @@ ecinit(unit) if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP); } -#ifdef notdef -int enalldelay = 0; -int eclastdel = 25; -int enlastmask = (~0) << 5; -#endif - /* * Start or restart output on interface. * If interface is already active, then this is a retransmit - * after a collision, and just restuff registers and delay. + * after a collision, and just restuff registers. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. @@ -279,27 +271,8 @@ COUNT(ECSTART); es->es_oactive = 0; return; } -#ifdef notdef - dest = mtod(m, struct ec_header *)->ec_dhost; /* wrong! */ -#endif ecput(es->es_buf[ECTBF], m); -#ifdef notdef - /* - * Ethernet cannot take back-to-back packets (no - * buffering in interface). To avoid overrunning - * receivers, enforce a small delay (about 1ms) in interface: - * * between all packets when ecalldelay - * * whenever last packet was broadcast - * * whenever this packet is to same host as last packet - */ - if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { - es->es_delay = eclastdel; - es->es_mask = eclastmask; - } - es->es_lastx = dest; -#endif - restart: /* * Start the output. @@ -327,7 +300,6 @@ COUNT(ECXINT); printf("ec%d: strange xmit interrupt!\n", unit); es->es_if.if_opackets++; es->es_oactive = 0; - es->es_delay = 0; es->es_mask = ~0; addr->ec_xcr = EC_XCLR; /* @@ -338,9 +310,6 @@ COUNT(ECXINT); es->es_ifuba.ifu_xtofree = 0; } if (es->es_if.if_snd.ifq_head == 0) { -#ifdef notdef - es->es_lastx = 0; /* ? */ -#endif return; } ecstart(unit); @@ -357,7 +326,7 @@ eccollide(unit) struct ec_softc *es = &ec_softc[unit]; COUNT(ECCOLLIDE); - printf("ec%d: eccollide\n", unit); + printf("ec%d: collision\n", unit); es->es_if.if_collisions++; if (es->es_oactive == 0) return; @@ -368,6 +337,10 @@ ecdocoll(unit) int unit; { register struct ec_softc *es = &ec_softc[unit]; + register struct ecdevice *addr = + (struct ecdevice *)ecinfo[unit]->ui_addr; + register i; + int delay; /* * Es_mask is a 16 bit number with n low zero bits, with @@ -375,31 +348,41 @@ ecdocoll(unit) * backed off 16 times, and give up. */ if (es->es_mask == 0) { + es->es_if.if_oerrors++; printf("ec%d: send error\n", unit); /* - * this makes enxint wrong. fix later. + * Reset interface, then requeue rcv buffers. + * Some incoming packets may be lost, but that + * can't be helped. + */ + addr->ec_xcr = EC_UECLR; + for (i=ECRHBF; i>=ECRLBF; i--) + addr->ec_rcr = EC_READ|i; + /* + * Reset and transmit next packet (if any). */ - ecxint(unit); + es->es_oactive = 0; + es->es_mask = ~0; + if (es->es_if.if_snd.ifq_head) + ecstart(unit); return; } /* - * Another backoff. Restart with delay based on n low bits - * of the interval timer. + * Do exponential backoff. Compute delay based on low bits + * of the interval timer. Then delay for that number of + * slot times. A slot time is 51.2 microseconds (rounded to 51). + * This does not take into account the time already used to + * process the interrupt. */ es->es_mask <<= 1; - es->es_delay = mfpr(ICR) &~ es->es_mask; + delay = mfpr(ICR) &~ es->es_mask; + DELAY(delay * 51); /* - * This should do some sort of delay before calling ecstart. - * I'll figure this out later. + * Clear the controller's collision flag, thus enabling retransmit. */ - ecstart(unit); + addr->ec_xcr = EC_JINTEN|EC_XINTEN|EC_JCLR; } -#ifdef notdef -struct sockaddr_pup pupsrc = { AF_PUP }; -struct sockaddr_pup pupdst = { AF_PUP }; -struct sockproto pupproto = { PF_PUP }; -#endif /* * Ethernet interface receiver interrupt. * If input error just drop packet. @@ -415,9 +398,6 @@ ecrint(unit) struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; COUNT(ECRINT); -#ifdef notdef - printf("ec%d: ecrint:%d\n", unit, addr->ec_rcr & 0xf); -#endif while (addr->ec_rcr & EC_RDONE) ecread(unit); } @@ -442,7 +422,7 @@ COUNT(ECREAD); panic("ecrint"); ecbuf = es->es_buf[buf]; ecoff = *(short *)ecbuf; - if (ecoff <= ECRDOFF || ecoff > ECMTU+ECRDOFF) { + if (ecoff <= ECRDOFF || ecoff > 2046) { es->es_if.if_ierrors++; #ifdef notdef if (es->es_if.if_ierrors % 100 == 0) @@ -497,20 +477,6 @@ COUNT(ECREAD); schednetisr(NETISR_IP); inq = &ipintrq; break; -#endif -#ifdef notdef -#ifdef PUP - case ECPUP_PUPTYPE: { - struct pup_header *pup = mtod(m, struct pup_header *); - - pupproto.sp_protocol = pup->pup_type; - pupdst.spup_addr = pup->pup_dport; - pupsrc.spup_addr = pup->pup_sport; - raw_input(m, &pupproto, (struct sockaddr *)&pupsrc, - (struct sockaddr *)&pupdst); - goto setup; - } -#endif #endif default: m_freem(m); @@ -535,6 +501,9 @@ setup: * 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. + * If destination is this address or broadcast, send packet to + * loop device to kludge around the fact that 3com interfaces can't + * talk to themselves. */ ecoutput(ifp, m0, dst) struct ifnet *ifp; @@ -547,6 +516,7 @@ ecoutput(ifp, m0, dst) register struct ec_header *ec; register int off; register int i; + struct mbuf *mcopy = (struct mbuf *) 0; /* Null */ COUNT(ECOUTPUT); switch (dst->sa_family) { @@ -554,6 +524,13 @@ COUNT(ECOUTPUT); #ifdef INET case AF_INET: dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; + if ((dest &~ 0xff) == 0) + mcopy = m_copy(m, 0, M_COPYALL); + else if (dest == ((struct sockaddr_in *)&es->es_if.if_addr)-> + sin_addr.s_addr) { + mcopy = m; + goto gotlocal; + } 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)) { @@ -567,15 +544,6 @@ COUNT(ECOUTPUT); type = ECPUP_IPTYPE; off = 0; goto gottype; -#endif -#ifdef notdef -#ifdef PUP - case AF_PUP: - dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host; - type = ECPUP_PUPTYPE; - off = 0; - goto gottype; -#endif #endif default: @@ -623,10 +591,16 @@ gottype: for (i=0; i<6; i++) ec->ec_dhost[i] = 0xff; else { - ec->ec_dhost[0] = es->es_enaddr[0]; - ec->ec_dhost[1] = es->es_enaddr[1]; - ec->ec_dhost[2] = es->es_enaddr[2]; - ec->ec_dhost[3] = (dest>>8) & 0xff; + if (dest & 0x8000) { + ec->ec_dhost[0] = ec_iltop[0]; + ec->ec_dhost[1] = ec_iltop[1]; + ec->ec_dhost[2] = ec_iltop[2]; + } else { + ec->ec_dhost[0] = es->es_enaddr[0]; + ec->ec_dhost[1] = es->es_enaddr[1]; + ec->ec_dhost[2] = es->es_enaddr[2]; + } + ec->ec_dhost[3] = (dest>>8) & 0x7f; ec->ec_dhost[4] = (dest>>16) & 0xff; ec->ec_dhost[5] = (dest>>24) & 0xff; } @@ -646,7 +620,11 @@ gottype: if (es->es_oactive == 0) ecstart(ifp->if_unit); splx(s); - return (0); +gotlocal: + if (mcopy) /* Kludge, but it works! */ + return(looutput(&loif, mcopy, dst)); + else + return (0); qfull: m0 = m; splx(s); @@ -677,7 +655,19 @@ COUNT(ECPUT); mp = m; while (mp) { mcp = mtod(mp, char *); + i = 0; + if ((int)bp&1) { + *bp++ = *mcp++; + i++; + } for (i=0; im_len; i++) + while (i < mp->m_len) { + *(short *)bp = *(short *)mcp; + bp += 2; + mcp += 2; + i += 2; + } + if (mp->m_len&1) *bp++ = *mcp++; mp = m_free(mp); } @@ -688,6 +678,9 @@ COUNT(ECPUT); /* * Routine to copy from UNIBUS memory into mbufs. * Similar in spirit to if_rubaget. + * + * Warning: This makes the fairly safe assumption that + * mbufs have even lengths. */ struct mbuf * ecget(ecbuf, totlen, off0) @@ -729,7 +722,12 @@ COUNT(ECGET); m->m_off = MMINOFF; } mcp = mtod(m, char *); - for (i=0; im_next; @@ -760,15 +758,15 @@ bad: */ struct ifnet eclhif; -int eclhoutput(); +int looutput(); /* * Called by localnet interface to allow logical - * host interface to "attach". Nothing should ever - * be sent locally to this interface, it's purpose + * host interface to "attach", it's purpose * is simply to establish the host's arpanet address. */ -eclhinit(addr) +eclhinit(ecifp, addr) + struct ifnet *ecifp; int addr; { register struct ifnet *ifp = &eclhif; @@ -780,20 +778,12 @@ COUNT(ECLHINIT); sin = (struct sockaddr_in *)&ifp->if_addr; sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr; + sin->sin_addr.s_lh = ecifp->if_host[0]; ifp->if_net = sin->sin_addr.s_net; - ifp->if_flags = IFF_UP; - ifp->if_output = eclhoutput; /* should never be used */ + ifp->if_dstaddr = ifp->if_addr; + ifp->if_flags = IFF_UP|IFF_POINTOPOINT; + ifp->if_output = looutput; if_attach(ifp); -} - -eclhoutput(ifp, m0, dst) - struct ifnet *ifp; - struct mbuf *m0; - struct sockaddr *dst; -{ -COUNT(ECLHOUTPUT); - ifp->if_oerrors++; - m_freem(m0); - return (0); + rtinit(&ifp->if_addr, &ifp->if_addr, RTF_UP|RTF_DIRECT|RTF_HOST); } #endif