DIRECTORY DeviceCleanup USING [Item, Await], DoradoInputOutput USING [InputNoPE, IOAddress, Output], EthernetFace USING [Status], MPCodes USING [Code, ethernetHostChanged], PrincOps USING [alpha, SD, zMISC], PrincOpsUtils USING [BITAND, BITOR, LowHalf], ProcessorFace USING [SetMP, ProcessorID, processorID], TrapSupport USING [BumpPC, OpTrapTable]; EthernetHeadDorado: CEDAR PROGRAM IMPORTS DeviceCleanup, DoradoInputOutput, PrincOpsUtils, ProcessorFace, TrapSupport EXPORTS EthernetFace SHARES ProcessorFace = BEGIN CSB: TYPE = LONG POINTER TO ControllerStatusBlock; ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ host: ProcessorFace.ProcessorID, nextInput: ShortIocb, inputWakeups: WORD, nextOutput: ShortIocb, outputWakeups: WORD, missed: CARDINAL, lastInput: IOCB, -- last IOCB on input queue, valid if nextInput#NIL lastOutput: IOCB]; -- last IOCB on output queue, valid if nextOutput#NIL IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIocb: TYPE = --Base RELATIVE-- POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ bytes: CARDINAL, buffer: LONG POINTER, retries: WORD, -- set by handle used: CARDINAL, -- input only, length of the received packet, in bytes completion: CompletionStatus _ nullCompletion, -- raw status from microcode, nonzero at end next: ShortIocb ]; ECtl: DoradoInputOutput.IOAddress = 26B; CompletionStatus: TYPE = MACHINE DEPENDENT RECORD [ hardware (0: 0..15): SELECT OVERLAID * FROM input => [ overflow (0: 0..0): BOOLEAN, noDribble (0: 1..1): BOOLEAN, fill1 (0: 2..2): [0..1) _ 0, goodCRC (0: 3..3): BOOLEAN, fill2 (0: 4..5): [0..3) _ 0, oddByte (0: 6..6): BOOLEAN, overRun (0: 7..7): BOOLEAN, fill3 (0: 8..15): [0..400B) _ 0], output => [ fill4 (0: 0..7): [0..400B) _ 0, rxOn (0: 8..8): BOOLEAN, txOn (0: 9..9): BOOLEAN, loopBack (0: 10..10): BOOLEAN, IECByPass (0: 11..11): BOOLEAN, -- error if found one by the head noWakeups (0: 12..12): BOOLEAN, -- error if found one by the head txStatus (0: 13..14): {txOK (0), underRun (1), collision (2), maxCollisions (3)}, txDataParityError (0: 15..15): BOOLEAN], ENDCASE]; nullCompletion: CompletionStatus = LOOPHOLE[0]; killedCompletion: CompletionStatus = LOOPHOLE[0FFFFH]; inputStatusMask: input CompletionStatus = LOOPHOLE[176400B]; -- oddByte OK inputGoodStatus: input CompletionStatus = [input[overflow: FALSE, noDribble: TRUE, goodCRC: TRUE, oddByte: FALSE, overRun: FALSE]]; outputErrorMask: output CompletionStatus = [output[rxOn: FALSE, txOn: FALSE, loopBack: FALSE, IECByPass: TRUE, noWakeups: TRUE, txStatus: maxCollisions, txDataParityError: TRUE]]; csb: CSB _ LOOPHOLE[LONG[177700B]]; Shorten: PROCEDURE [iocb: IOCB] RETURNS [ShortIocb] = TRUSTED INLINE { RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]]; }; aOff: PrincOps.alpha = 250B; MakeSureOff: PROC = TRUSTED MACHINE CODE { PrincOps.zMISC, aOff}; Handle: PUBLIC TYPE = LONG POINTER TO ControllerStatusBlock; Status: PUBLIC TYPE = EthernetFace.Status; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; nullHandle: PUBLIC Handle _ NIL; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOLEAN _ TRUE; HWMode: TYPE = MACHINE DEPENDENT {hwNormal (173000B), hwLoopBack (173100B)}; ResetBits: WORD = 40B + 20B; EnableTx: WORD = 47777B; hwMode: HWMode _ hwNormal; LoopbackMode: TYPE = {normal, loopBack}; SetLoopbackMode: PROC [mode: LoopbackMode] = { hwMode _ SELECT mode FROM normal => hwNormal, loopBack => hwLoopBack, ENDCASE => ERROR; }; QueueOutput: PUBLIC PROC [ handle: Handle, buffer: LONG POINTER, bytes: NAT, iocb: IOCB] = TRUSTED { iocb^ _ [ bytes: bytes, buffer: buffer, retries: 0, used: 0, completion: nullCompletion, next: NIL]; IF handle.nextOutput # NIL THEN handle.lastOutput.next _ Shorten[iocb]; IF handle.nextOutput = NIL AND iocb.completion = nullCompletion THEN { handle.nextOutput _ Shorten[iocb]; DoradoInputOutput.Output[EnableTx, ECtl]; }; -- poke hardware handle.lastOutput _ iocb; }; QueueInput: PUBLIC PROC [ handle: Handle, buffer: LONG POINTER, bytes: NAT, iocb: IOCB] = TRUSTED { iocb^ _ [ bytes: bytes, buffer: buffer, retries: 0, used: 0, completion: nullCompletion, next: NIL]; IF handle.nextInput # NIL THEN handle.lastInput.next _ Shorten[iocb]; IF handle.nextInput = NIL AND iocb.completion = nullCompletion THEN handle.nextInput _ Shorten[iocb]; handle.lastInput _ iocb; }; MarkKilled: PUBLIC PROC [iocb: IOCB] = TRUSTED { iocb.completion _ killedCompletion; }; GetStatusAndLength: PUBLIC PROC [iocb: IOCB] RETURNS [status: Status, bytes: NAT] = TRUSTED { IF iocb.completion = nullCompletion THEN RETURN[pending, 0]; IF iocb.completion = killedCompletion THEN RETURN[killedByDriver, 0]; IF LOOPHOLE[PrincOpsUtils.BITAND[LOOPHOLE[iocb.completion], LOOPHOLE[inputStatusMask]], CompletionStatus] = inputGoodStatus THEN status _ ok ELSE SELECT TRUE FROM iocb.completion.overflow => status _ packetTooLong; -- iocb.used = 0 => bounds fault iocb.completion.overRun => status _ overrun; ~iocb.completion.goodCRC => status _ crc; ~iocb.completion.noDribble, iocb.completion.oddByte => status _ badAlignmentButOkCrc; ENDCASE => status _ otherError; IF iocb.used = 0 THEN bytes _ 0 ELSE bytes _ iocb.used - 2; }; GetStatusAndCollisions: PUBLIC PROC [iocb: IOCB] RETURNS [status: Status, collisions: NAT] = TRUSTED { IF iocb.completion = nullCompletion THEN RETURN[pending, 0]; IF iocb.completion = killedCompletion THEN RETURN[killedByDriver, 0]; collisions _ IF iocb.retries = 17 THEN iocb.retries-1 ELSE iocb.retries; IF PrincOpsUtils.BITAND[LOOPHOLE[iocb.completion], LOOPHOLE[outputErrorMask]] = 0 THEN status _ ok ELSE SELECT iocb.completion.txStatus FROM txOK => status _ ok; underRun, collision => status _ underrun; maxCollisions => status _ tooManyCollisions; ENDCASE => status _ otherError; }; GetPacketsMissed: PUBLIC PROC [handle: Handle] RETURNS [CARDINAL] = TRUSTED { RETURN[handle.missed]; }; unimplemented: BOOL _ FALSE; FakeMakeSureOff: PROC = TRUSTED { TrapSupport.BumpPC[2]; unimplemented _ TRUE; }; GetNextDevice: PUBLIC PROC [handle: Handle] RETURNS [new: Handle _ nullHandle] = TRUSTED { opTrapTable: POINTER TO POINTER TO TrapSupport.OpTrapTable = LOOPHOLE[PrincOps.SD+137B]; foo: WORD; IF handle # nullHandle THEN RETURN; opTrapTable.misc[aOff] _ LOOPHOLE[FakeMakeSureOff]; MakeSureOff[]; -- Bogus microcode => UnimplementedInstruction IF unimplemented THEN RETURN; -- Bogus microcode DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; foo _ DoradoInputOutput.InputNoPE[ECtl]; IF foo = 0 THEN RETURN; -- No Hardware (trial and error, 1 test case) new _ csb; }; TurnOn: PUBLIC PROC [ handle: Handle, inInterrupt, outInterrupt: WORD] = TRUSTED { MakeSureOff[]; handle^ _ [ host: ProcessorFace.processorID, nextInput: NIL, inputWakeups: inInterrupt, nextOutput: NIL, outputWakeups: outInterrupt, missed: 0, lastInput: NIL, lastOutput: NIL]; DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; DoradoInputOutput.Output[LOOPHOLE[hwMode], ECtl]; -- turns on receiver }; TurnOff: PUBLIC PROC [handle: Handle] = { MakeSureOff[]; }; SetPromiscuous: PUBLIC PROC [handle: Handle, promiscuous: BOOL] = TRUSTED { SELECT promiscuous FROM TRUE => handle.host _ [0FFFFH, 0FFFFH, 0FFFFH]; FALSE => handle.host _ ProcessorFace.processorID; ENDCASE => ERROR; }; SetOutputDelay: PUBLIC PROC [handle: Handle, microseconds: CARDINAL] = {}; cleanupInitialized: BOOLEAN _ FALSE; savedCSB: ControllerStatusBlock; AddCleanup: PUBLIC PROC [handle: Handle] = TRUSTED { processorID: ProcessorFace.ProcessorID _ ProcessorFace.processorID; item: DeviceCleanup.Item; IF cleanupInitialized THEN RETURN; cleanupInitialized _ TRUE; DO SELECT DeviceCleanup.Await[@item] FROM kill => MakeSureOff[]; turnOff => { MakeSureOff[]; savedCSB _ handle^; handle.nextInput _ NIL; handle.nextOutput _ NIL; }; turnOn => { foo: WORD; MakeSureOff[]; IF processorID # ProcessorFace.processorID THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- InLoaded on another machine? IF unimplemented THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- Changed to wrong microcode DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; foo _ DoradoInputOutput.InputNoPE[ECtl]; IF foo = 0 THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- Hardware vanished handle^ _ [ host: savedCSB.host, nextInput: NIL, inputWakeups: 0, nextOutput: NIL, outputWakeups: 0, missed: 0, lastInput: NIL, lastOutput: NIL]; DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; DoradoInputOutput.Output[LOOPHOLE[hwMode], ECtl]; }; ENDCASE; ENDLOOP}; RemoveCleanup: PUBLIC PROC [handle: Handle] = {}; ErrorHalt: PROC [code: MPCodes.Code] = INLINE { ProcessorFace.SetMP[code]; DO ENDLOOP }; END. -- EthernetHeadDorado. 0EthernetHeadDorado.mesa, HGM, 19-Sep-82 19:14:40 Last Edited by: Willie-Sue, July 12, 1984 1:09:54 pm PDT Hal Murray, April 30, 1986 4:13:59 am PDT These are the data structures that the microcode knows about. If some other module (for example, a diagnostic) ever needs this info, it should probably get split out into a separate module. For now, it is lumped in here to avoid cluttering up the world with yet another file. If the first word of the HostNumber is all ones then the input mode will accept all packets!! The 10MB Ethernet uses TIOA = 26b as Control when output and as Status when it is read. The data reg is TIOA=25b. EtherNetOne uses 177600B for input and 177610B for output Maybe we should check to be sure that the high half is zero Reset 10 MB Ethernet hardware and tasks (should be in DoradoInputOutput) Does NOT turn on either the transmittor or the receiver EXPORTed TYPEs EXPORTed variables private stuff the following HWMode values match those in PilotNSEther.mc, for turning on the 10MB receiver in either regular or loopback mode ?? I don't know if the hardware supports this. CSB change may be needed. There is no way to remove a cleanup procedure yet, so we have a flag to avoid duplicates. Note that this does NOT really put things back together. It simply smashes things to a safe state. The intention is that the driver will notice that nothing is happening and then call TurnOff+TurnOn to reset things. That allows Pilot to reset the GMT clock on the way back from the debugger without getting tangled up with the normal Ethernet driver. Κ g˜šœ0™0Jšœ8™8Icode™)—J˜šΟk ˜ Jšœœ˜"Jšœœ ˜7Jšœ œ ˜Kšœœ˜*Jšœ œ œ ˜"Jšœœœœ ˜-Kšœœ#˜6Kšœ œ˜(J˜—šœ ˜!JšœL˜SJšœ ˜Jšœ˜Jš˜—J˜Jšœ”™”J˜Jšœ]™]Jš œœœœœ˜2J˜š œœœ œœ˜8Jšœ ˜ Jšœ˜Jšœœ˜Jšœ˜Jšœœ˜Jšœœ˜Jšœ œΟc&œ ž˜EJšœ œž'œ ž˜IJ˜—Jš œœœœœ˜,Jš œ œ  œœœ˜>J˜š œœœ œœ˜1Jšœœ˜Jšœœœ˜Jšœ œž˜!Jšœœž7˜HJšœœž,˜[Jšœ˜J˜—J™JšœœœMœ™qJšœ(˜(J˜š œœœ œœ˜3Jšœœœ˜+šœ ˜ Jšœœ˜Jšœœ˜J˜Jšœœ˜J˜Jšœœ˜Jšœœ˜Jšœ!˜!—šœ ˜ Jšœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœž!˜AJšœœž!˜AJ˜QJšœœ˜(—Jšœ˜ —J˜Jšœ#œ˜/Jšœ%œ ˜6Jšœ*œ˜Jšœ)˜)Jš œœ œ œ œ œ˜Y—šœ*˜*Jš œœœ œ œ œ.œ˜ˆ—J˜Jšœ9™9Jšœœœœ ˜#J˜š Οnœ œœœœ˜FJšœ;™;Jšœœ"˜1J˜—Jšœ˜š Ÿ œœœœœ˜AJšœ™J˜—Jšœ™J˜Kš œœœœœœ˜