/* dislc.c L. Stewart October 26, 1982 2:41 PM D. Swinehart July 12, 1982 8:45 AM L. Stewart November 13, 1982 4:30 PM, enqueue on clients q, if present L. Stewart November 23, 1982 9:39 AM, put back statics L. Stewart November 28, 1982 3:48 PM, flush Alloc L. Stewart November 28, 1982 5:17 PM, cleanup L. Stewart January 21, 1983 6:13 PM, new EtherHost L. Stewart January 22, 1983 3:33 PM, keep running L. Stewart February 23, 1983 3:01 PM, new EnableInt L. Stewart February 25, 1983 11:02 AM, rename SLCReset L. Stewart March 6, 1983 4:30 PM, remove Alloc.h LCS April 4, 1983, remove GetPBI from interrupt code LCS May 4, 1983, mods to transmit code, possible leak LCS May 31, 1983, Txpkt was not interrupt safe! LCS July 9, 1983, change tx timeout, add statics speed up receive interrupt handler LCS August 15, 1983 6:10 PM, SLCInit(CurrentHost) LCS August 15, 1983 6:49 PM, timestamps */ #include #include #include #include #include struct ccb { char cmda; char *addra; char counta; char stata; }; /* Runtime */ extern int DoubleEq(); extern int ReadTmr(); extern int currentHost; extern int localHost; extern int localNet; extern int lenPup; extern struct SocketEntry pupSockets[1 /*maxPupSockets*/]; static struct SocketEntry *lastSocket; /* transmit and receive SLC control blocks */ #define numRBp1 4 #define numRB 3 static struct ccb rccb[numRBp1]; static struct PBI *rpbi[numRB]; static int nextrx; static int lastrx; static struct ccb txccb; static struct PBI *txPBI; /* if (txPBI != 0) a transmission is in progress */ static int rBufCount; /* byte count of receive buffers */ /* transmit and receive timeout timers */ static int txtmr[1]; static int rxtmr[1]; static struct Queue outQ[1]; /* ether output queue */ static int etherStack[40]; /* stack space */ /* statistics */ static int slcri; /* interrupt counters */ static int slcti; static int slcrp; /* packet counters */ static int slctp; static int slrsmash; /* SLC resets due to timeout */ static int sltsmash; static int noBuffer; /* lost packets due to buffer shortage */ static int nonPup; /* non Pup packets received (and discarded) */ static EtherPr() { for (;;) { Block(); if (TmrExp(rxtmr)) { slrsmash += 1; IWDC(); CSLCReset(); /* violent ! */ DWDC(); }; Block(); if (TmrExp(txtmr)) { IWDC(); if (txPBI && TmrExp(txtmr)) { sltsmash += 1; CSLCReset(); /* violent ! */ }; DWDC(); }; }; }; static int *teei; static mySLTInt() { OutByte(0x0024, 0x000e); if (txPBI) { if (txccb.stata & 0x80) { /* why? */ teei = ((int *) txPBI->pup) - 1; /* encap->type */ *teei = ReadTmr(); /* tx timestamp */ Enqueue(txPBI->queue, txPBI); txPBI = 0; Txpkt(); }; }; slcti += 1; return (true); }; static struct ccb *rxccb; static struct PBI *ripbi; static struct Pup *riPup; static struct EtherEncapsulation *ee; static mySLRInt() { OutByte(0x0020, 0x0009); /* clear MM interrupt */ /* handle a burst of packets */ for (;;) { rxccb = &rccb[nextrx]; if ((rxccb->stata & 0x80) == 0) break; ripbi = rpbi[nextrx]; riPup = ripbi->pup; if (rxccb->stata == 0x88) { ee = (struct EtherEncapsulation *) (((int) riPup) - 4); if (ee->type == typePup) { ee->type = ReadTmr(); /* arrival timestamp */ IntLev1(); /* may change ripbi, invalidates riPup */ rpbi[nextrx] = ripbi; }; else nonPup += 1; }; rxccb->cmda = 0; rxccb->stata = 0; rxccb->counta = rBufCount; /* next line can't use riPup because IntLev1 may have made it invalid */ rxccb->addra = ((char *) ripbi->pup) - 4 rccb[lastrx].cmda = 4; lastrx = nextrx; nextrx += 1; if (nextrx == numRB) nextrx = 0; }; SetTmr(16000, rxtmr); /* if receiver stopped, restart it */ if ((slrstat() & 0x000c) == 0) SLRReset(); slcri += 1; return (true); }; static struct PBI *npbi; static int il1temp, il1i; static int dNet, dHost; static struct PupSocket *dSocket; static struct SocketEntry *socketI; /* The socket dispatch runs at interrupt level, but the associcated procedure is called by pup level 1 process */ IntLev1() { slcrp += 1; if (riPup->sPort.host == 0) goto BcastSource; /* If the destination is not us, discard packet. */ if ((dNet = riPup->dPort.net) == 0) goto ZeroDNet; if (dNet != localNet) { if (!localNet) SetLocalNet(dNet); else goto Misaddressed; }; /* Checksum checking is done in PupImpl. */ /* Pups not addressed to our multicast or specific address cannot be supported. Not sure they could be received, anyhow. */ /* test currentHost first, because we're busiest then */ if ((dHost = riPup->dPort.host) == currentHost) goto DHostOK; if (dHost == localHost) goto DHostOK; if (dHost == 0) goto DHostOK; goto BadHost; DHostOK: dSocket = &riPup->dPort.socket; for (socketI = pupSockets; socketI <= lastSocket; socketI += 1) { if (DoubleEq(&socketI->port.socket, dSocket)) { il1temp = (int) socketI->PortProc; ripbi->clientWord = il1temp; if ((npbi = MaybeGetPBI(0)) != 0) { Enqueue(socketI->q, ripbi) ripbi = npbi; }; else noBuffer += 1; goto FoundIt; }; }; Misaddressed: BcastSource: ZeroDNet: BadHost: FoundIt: }; InitEther(ctxQ, x) struct Queue *ctxQ; int x; { int myc; txPBI = 0; nonPup = noBuffer = slcri = slcti = slrsmash = sltsmash = 0; lastSocket = pupSockets + maxPupSockets; rBufCount = (lenPup + lenEtherEncapsulation) << 1; if (rBufCount > 256) CallSwat(ecPup1 + 19); rBufCount = (-rBufCount) & 0x00ff; myc = InitNContext("EtherPr", etherStack, 50, &EtherPr); Enqueue(ctxQ, myc); InitQueue(outQ); IWDC(); CSLCReset(); DWDC(); EnableInt(&mySLTInt, SLTTyp); EnableInt(&mySLRInt, SLRTyp); }; /* after changing currentHost, call this */ NewHost() { IWDC(); CSLCReset(); DWDC(); }; static CSLCReset() { SLCInit(currentHost); SLRPBISetup(); SLRReset(); OutByte(0x0024, 0x0088); /* enable SLT IO interrupts */ if (txPBI) { Enqueue(txPBI->queue, txPBI); txPBI = 0; IWDC(); Txpkt(); DWDC(); }; }; static SLRPBISetup() { int i; for (i=0; icmda = 0x04; /* chain */ mccb->addra = rpbi[i]->pup; mccb->addra = mccb->addra - 4; mccb->counta = rBufCount; mccb->stata = 0; mccb += 1; }; mccb->cmda = 0x00f1; /* nop plus indirect */ mccb->addra = rccb; mccb->counta = rBufCount; mccb->stata = 0; rccb[numRB-1].cmda = 0; /* not chained! */ nextrx = 0; lastrx = numRB-1; SetTmr(20000, rxtmr); SLRStart(rccb); }; TransmitPacket(tpbi) struct PBI *tpbi; { Enqueue(outQ, tpbi); IWDC(); Txpkt(); DWDC(); }; /* all callers of this procedure are at interrupt level! */ static Txpkt() { int len; if (txPBI) return; SetTmr(60, txtmr); txPBI = Dequeue(outQ); if (txPBI == 0) return; len = Swab(txPBI->pup->length); len = (len + 5) & 0x0fffe; if (len >= 256) CallSwat(ecPup1+20); /* enable IO interrupt */ txccb.cmda = 0x52; txccb.addra = txPBI->pup; txccb.addra = txccb.addra - 4; txccb.counta = len & 0x00ff; txccb.stata = 0; SLTStart(&txccb); slctp += 1; };