summary |
tags |
clone url |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
4c5902e)
SCCS-vsn: sys/vax/if/if_ec.c 4.5
-/* if_ec.c 4.4 82/04/12 */
+/* if_ec.c 4.5 82/04/14 */
#include "ec.h"
#include "imp.h"
#include "ec.h"
#include "imp.h"
/*
* 3Com Ethernet Controller interface
/*
* 3Com Ethernet Controller interface
int ecinit(),ecoutput(),ecreset();
struct mbuf *ecget();
int ecinit(),ecoutput(),ecreset();
struct mbuf *ecget();
+extern struct ifnet loif;
+
/*
* Ethernet software status per interface.
*
/*
* Ethernet software status per interface.
*
struct ec_softc {
struct ifnet es_if; /* network-visible interface */
struct ifuba es_ifuba; /* UNIBUS resources */
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
short es_mask; /* mask for current output delay */
#ifdef notdef
+ short es_delay; /* current output delay */
long es_lastx; /* host last transmitted to */
#endif
short es_oactive; /* is output active? */
long es_lastx; /* host last transmitted to */
#endif
short es_oactive; /* is output active? */
/*
* Start or restart output on interface.
* If interface is already active, then this is a retransmit
/*
* 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.
* 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.
printf("ec%d: strange xmit interrupt!\n", unit);
es->es_if.if_opackets++;
es->es_oactive = 0;
printf("ec%d: strange xmit interrupt!\n", unit);
es->es_if.if_opackets++;
es->es_oactive = 0;
es->es_mask = ~0;
addr->ec_xcr = EC_XCLR;
/*
es->es_mask = ~0;
addr->ec_xcr = EC_XCLR;
/*
struct ec_softc *es = &ec_softc[unit];
COUNT(ECCOLLIDE);
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;
es->es_if.if_collisions++;
if (es->es_oactive == 0)
return;
int unit;
{
register struct ec_softc *es = &ec_softc[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
/*
* Es_mask is a 16 bit number with n low zero bits, with
* backed off 16 times, and give up.
*/
if (es->es_mask == 0) {
* backed off 16 times, and give up.
*/
if (es->es_mask == 0) {
+ es->es_if.if_oerrors++;
printf("ec%d: send error\n", unit);
/*
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).
+ es->es_oactive = 0;
+ es->es_mask = ~0;
+ if (es->es_if.if_snd.ifq_head)
+ ecstart(unit);
- * 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_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.
+ addr->ec_xcr = EC_JCLR;
panic("ecrint");
ecbuf = es->es_buf[buf];
ecoff = *(short *)ecbuf;
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)
es->es_if.if_ierrors++;
#ifdef notdef
if (es->es_if.if_ierrors % 100 == 0)
* 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.
* 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;
*/
ecoutput(ifp, m0, dst)
struct ifnet *ifp;
register struct ec_header *ec;
register int off;
register int i;
register struct ec_header *ec;
register int off;
register int i;
+ struct mbuf *mcopy = (struct mbuf *) 0; /* Null */
COUNT(ECOUTPUT);
switch (dst->sa_family) {
COUNT(ECOUTPUT);
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
#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)) {
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)) {
if (es->es_oactive == 0)
ecstart(ifp->if_unit);
splx(s);
if (es->es_oactive == 0)
ecstart(ifp->if_unit);
splx(s);
+gotlocal:
+ if (mcopy) /* Kludge, but it works! */
+ return(looutput(&loif, mcopy, dst));
+ else
+ return (0);