DIRECTORY Basics USING [DivMod], D0InputOutput USING [CSB, IOPage, ethernet1In, ethernet1Out, ControllerNumber, GetNextController, nullControllerNumber], DeviceCleanup USING [Item, Await], EthernetOneFace, MPCodes USING [Code, ethernetHostChanged], PrincOps USING [zMISC, zSTARTIO], PrincOpsUtils USING [LowHalf], ProcessorFace USING [SetMP]; EthernetOneHeadD0: PROGRAM IMPORTS Basics, D0InputOutput, DeviceCleanup, PrincOpsUtils, ProcessorFace EXPORTS EthernetOneFace = { OPEN EthernetOneFace; OCSB: TYPE = LONG POINTER TO OutputControllerStatusBlock; OutputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ reserved: WORD, next: ShortIOCB, unused1: WORD, unused2: WORD, interruptBit: WORD, -- words after here are unused by microcode last: IOCB ]; -- last IOCB on output queue, valid if next#noIOCB ICSB: TYPE = LONG POINTER TO InputControllerStatusBlock; InputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ reserved: WORD, next: ShortIOCB, host: LONG CARDINAL, interruptBit: WORD, missed: WORD, -- for debugging only spare1: WORD, spare2: WORD, buffer: ARRAY [0..4) OF CARDINAL, -- words after here are unused by microcode last: IOCB ]; -- last IOCB on input queue, valid if next#noIOCB IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIOCB: TYPE = POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, mask: WORD, spare: WORD, completion: WORD, used: CARDINAL, -- input only length: CARDINAL, buffer: LONG POINTER ]; -- NB: Must be QuadWord Aligned StartIO: PROC [SioParameter] = MACHINE CODE { PrincOps.zSTARTIO }; SioParameter: TYPE = RECORD [WORD]; firstFixupOutput: SioParameter = [1B]; firstFixupInput: SioParameter = [2B]; firstReset: SioParameter = [3B]; secondFixupOutput: SioParameter = [4B]; secondFixupInput: SioParameter = [10B]; secondReset: SioParameter = [14B]; Output: PROC [Command, Register] = MACHINE CODE { PrincOps.zMISC, 6; }; Input: PROC [Register] RETURNS [WORD] = MACHINE CODE { PrincOps.zMISC, 5; }; Command: TYPE = RECORD [WORD]; enableInput: Command = [220B]; enableOutput: Command = [103B]; Register: TYPE = MACHINE DEPENDENT RECORD [ zero: [0..377B] _ 0, controller: D0InputOutput.ControllerNumber, register: [0..17B]]; processed: WORD = 040000B; error: WORD = 020000B; hardwareError: WORD = 010000B; fragment, tooLong: WORD = 004000B; loadOverflow: WORD = 002000B; nothingYet: WORD = 0; noIOCB: ShortIOCB = LOOPHOLE[0]; Device: TYPE = RECORD [ board: Board, in, out: D0InputOutput.ControllerNumber]; Board: TYPE = [0..2); ICSBFronDevice: PROC [device: Device] RETURNS [ICSB] = INLINE { RETURN[LOOPHOLE[@D0InputOutput.IOPage[device.in]]]; }; OCSBFronDevice: PROC [device: Device] RETURNS [OCSB] = INLINE { RETURN[LOOPHOLE[@D0InputOutput.IOPage[device.out]]]; }; ControlRegister: PROC [c: D0InputOutput.ControllerNumber] RETURNS [Register] = INLINE { RETURN[[0,c,0]]; -- Register 0 is the control register }; Shorten: PROC [iocb: IOCB] RETURNS [ShortIOCB] = INLINE { RETURN[PrincOpsUtils.LowHalf[iocb]]; }; DeviceHandle: PUBLIC TYPE = Device; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; nullDeviceHandle: PUBLIC DeviceHandle _ LOOPHOLE[123456B]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOL _ TRUE; fixupInputBits: ARRAY Board OF SioParameter = [firstFixupInput, secondFixupInput]; fixupOutputBits: ARRAY Board OF SioParameter = [firstFixupOutput, secondFixupOutput]; resetBits: ARRAY Board OF SioParameter = [firstReset, secondReset]; QueueOutput: PUBLIC PROC [device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { out: OCSB = OCSBFronDevice[device]; cb^ _ [ next: noIOCB, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer ]; IF out.next=noIOCB THEN { out.next _ Shorten[cb]; Output[enableOutput,ControlRegister[device.out]]; -- poke hardware } ELSE { out.last.next _ Shorten[cb]; IF out.next=noIOCB AND cb.completion=0 THEN { out.next _ Shorten[cb]; Output[enableOutput,ControlRegister[device.out]]; -- poke hardware }; }; out.last _ cb; }; QueueInput: PUBLIC PROC [device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { in: ICSB = ICSBFronDevice[device]; cb^ _ [ next: noIOCB, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer ]; IF in.next#noIOCB THEN in.last.next _ Shorten[cb]; IF in.next=noIOCB AND cb.completion=0 THEN { in.next _ Shorten[cb]; StartIO[fixupInputBits[device.board]]; Output[enableInput,ControlRegister[device.in]]; }; in.last _ cb; }; GetStatus: PUBLIC PROC [cb: IOCB] RETURNS [status: Status] = { RETURN [ SELECT cb.completion FROM 0 => pending, 40000B => ok, 62000B => tooManyCollisions, 61000B => packetTooLong, 70001B => badAlignmentButOkCrc, 70010B => crc, 70011B => crcAndBadAlignment, 70040B, 70041B, 70050B, 70051B => overrun, 70100B, 70120B => underrun, ENDCASE => otherError ]; }; GetRetries: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { RETURN [ SELECT cb.mask FROM 1 => 0, 3 => 1, 7 => 2, 17B => 3, 37B => 4, 77B => 5, 177B => 6, 377B => 7, 777B => 8, 1777B => 9, 3777B => 10, 7777B => 11, 17777B => 12, 37777B => 13, 77777B => 14, 177777B => 15, ENDCASE => 16 ]; }; GetPacketLength: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { RETURN [cb.used]; }; GetPacketsMissed: PUBLIC PROC [device: Device] RETURNS [CARDINAL] = { RETURN [ICSBFronDevice[device].missed]; }; GetNextDevice: PUBLIC PROC [device: Device] RETURNS [Device] = { OPEN D0InputOutput; IF device=nullDeviceHandle THEN device _ [0,nullControllerNumber,nullControllerNumber] ELSE device.board _ device.board + 1; device.in _ GetNextController[ethernet1In,device.in]; device.out _ GetNextController[ethernet1Out,device.out]; IF device.in=nullControllerNumber OR device.out=nullControllerNumber THEN RETURN[nullDeviceHandle]; RETURN[device]; }; GetEthernet1Address: PUBLIC PROC [device: Device] RETURNS [net: [0..256), host: HostAddress] = { reg: Register = [controller: device.in, register: 1]; [net,host] _ Basics.DivMod[Input[reg],400B]; }; TurnOn: PUBLIC PROC [device: Device, host: HostAddress, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = { board: Board = device.board; out: OCSB = OCSBFronDevice[device]; in: ICSB = ICSBFronDevice[device]; StartIO[resetBits[board]]; out^ _ [ reserved: 0, next: noIOCB, unused1: 0, unused2: 0, interruptBit: outInterrupt, last: NIL ]; in^ _ [ reserved: 0, next: noIOCB, host: host, interruptBit: inInterrupt, missed: 0, spare1: 0, spare2: 0, buffer: [0,0,0,0], last: NIL ]; StartIO[fixupInputBits[board]]; StartIO[fixupOutputBits[board]]; Output[enableInput,ControlRegister[device.in]]; }; TurnOff: PUBLIC PROC [device: Device] = { StartIO[resetBits[device.board]]; }; InputHosts: PUBLIC PROC [device: DeviceHandle, inputHosts: LONG POINTER TO HostArray] = { ERROR; }; InputHost: PUBLIC PROC[device: DeviceHandle, host: HostAddress] = { ERROR; }; MulticastCapabilities: PUBLIC PROC[device: DeviceHandle] RETURNS [ canDo: BOOL, multicastsEnabled: BOOL] = { RETURN [ canDo: FALSE, multicastsEnabled: FALSE]; }; alreadyInitializedCleanup: ARRAY Board OF BOOL _ ALL[FALSE]; savedICSB: InputControllerStatusBlock; savedOCSB: OutputControllerStatusBlock; AddCleanup: PUBLIC PROC [device: Device] = { OPEN DeviceCleanup; item: Item; board: Board = device.board; out: OCSB = OCSBFronDevice[device]; in: ICSB = ICSBFronDevice[device]; oldHost: LONG CARDINAL; originalHost: HostAddress; IF alreadyInitializedCleanup[device.board] THEN RETURN; alreadyInitializedCleanup[device.board] _ TRUE; originalHost _ GetEthernet1Address[device].host; DO SELECT Await[@item] FROM kill => { StartIO[resetBits[board]]; }; turnOff => { StartIO[resetBits[board]]; savedICSB _ in^; savedOCSB _ out^; oldHost _ in.host; }; turnOn => { StartIO[resetBits[board]]; IF GetEthernet1Address[device].host#originalHost THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- perhaps InLoaded on another machine out^ _ [ reserved: 0, next: noIOCB, unused1: 0, unused2: 0, interruptBit: 0, last: NIL ]; in^ _ [ reserved: 0, next: noIOCB, host: oldHost, -- Ugh, it would be nice if we could do something better interruptBit: 0, missed: 0, spare1: 0, spare2: 0, buffer: [0,0,0,0], last: NIL ]; StartIO[fixupInputBits[board]]; StartIO[fixupOutputBits[board]]; Output[enableInput,ControlRegister[device.in]]; }; ENDCASE; ENDLOOP; }; RemoveCleanup: PUBLIC PROC [device: Device] = { }; ErrorHalt: PROC [code: MPCodes.Code] = INLINE { ProcessorFace.SetMP[code]; DO ENDLOOP }; }. LOG Time: August 20, 1980 2:01 PM By: BLyon, Action: renamed EthernetFace and EthernetHeadD0 to EthernetOneFace and EthernetOneHeadD0, resp. Time: August 25, 1980 5:36 PM By: BLyon, Action: added [ ELSE h.board _ h.board + 1] clause to GetNextDevice. Time: September 4, 1980 11:02 PM By: HGM, Action: add hearSelf, use exported types. Time: September 14, 1980 6:36 AM By: HGM, Action: bug in bufferOverflow. 8-Jul-82 14:50:19 Taft Cleanup routine checks for Ethernet address changing at turnOn time. Time: September 23, 1982 1:42 pm By: Swinehart, Action: Add Dummy multicast functions. "EthernetOneHeadD0.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Swinehart modified September 23, 1982 1:35 pm Birrell, November 3, 1983 11:20 am Russ Atkinson (RRA) February 27, 1985 8:33:14 pm PST 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. Beware that you don't automatically lengthen one of these. If you do you will end up with a pointer into your MDS rather then the first 64K where the IOCBs live. That won't work unless your MDS is also the first 64K. On old boards, output reg 0 of either task is control word for both tasks On new boards, you must direct the output to the correct half Input from reg 0 is device id Input from reg 1 is net&host number switches completion bits 001000 and 000400 are unused so far Hardware error bits: 001: Bad Alignment 002: Bad Parity (between mem and shifter) 004: Memory Data Fault 010: CRC 020: Collision 040: Input Overrun 100: Output Overrun 200: Jam Maybe we should check to be sure that the high half is zero EXPORTed TYPEs EXPORTed variables Non EXPORTed things. Note that all the state information lives in the CSBs. new iocb, hardware idle output active, add to end of chain oops, hardware went idle Poke the microcode so it will notice this buffer, delete the next line when the microcode is fixed InputHosts and InputHost would support input packets from multiple hosts. They are not supported in this implementation. 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. Κ ˜codešœ™Kšœ Οmœ1™Kšœ žœ˜K˜Kšœžœžœ˜Kšœžœ˜KšœžœŸ˜$Kšœžœ˜ Kšœžœ˜ KšœžœžœžœŸ+˜MKšœžœŸ1˜?K˜—Kš žœžœžœžœžœ˜,KšœΪ™ΪKšœ žœžœžœ˜,š œžœžœž œžœ˜1K˜Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜KšœžœŸ ˜Kšœžœ˜KšœžœžœŸ˜8K˜—šΟnœžœžœžœ˜BK˜—šœžœžœžœ˜#K˜&K˜%K˜ K˜'K˜'K˜"K˜—KšœI™IKšœ=™=Kšœ™Kšœ,™,K˜Kš œžœžœžœ˜Gš  œžœ žœžœžœžœ˜LK˜—šœ žœžœžœ˜K˜K˜K˜—š œ žœžœž œžœ˜+K˜K˜+K˜K˜—šœ™Kšœ žœ ˜Kšœžœ ˜Kšœžœ ˜Kšœžœ ˜"Kšœžœ ˜Kšœ žœ˜Kšœ#™#—K˜šœ™Kšœ™Kšœ)™)Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™—K˜Kšœžœ˜ K˜šœžœžœ˜K˜ K˜)K˜—Kšœžœ ˜K˜š  œžœžœžœžœ˜?Kšžœžœ$˜3Kšœ˜K˜—š  œžœžœžœžœ˜?Kšžœžœ%˜4Kšœ˜K˜—š œžœ%žœžœ˜WKšžœ Ÿ%˜7Kšœ˜K˜—š  œžœžœžœžœ˜9Kšœ;™;Kšžœ˜$Kšœ˜K˜K˜—šœ™Kšœžœžœ ˜#Kšœžœžœ˜1K˜—šœ™K˜Kšœžœžœ ˜:Kšœžœžœ˜%Kšœžœžœžœ˜9Kšœ žœžœžœ˜K˜K˜—šœL™LK˜Kšœžœžœ4˜RKšœžœžœ6˜UKšœ žœžœ*˜CK˜—š  œžœžœžœžœ žœžœ˜_Kšœžœ˜#˜K˜ K˜K˜ K˜K˜K˜K˜—šžœ˜šžœ˜Kšœ™K˜Kšœ3Ÿ˜CKšœ˜—šžœ˜Kšœ"™"K˜šžœžœžœ˜-Kšœ™K˜Kšœ3Ÿ˜CKšœ˜—Kšœ˜——K˜Kšœ˜K˜—š  œžœžœžœžœ žœžœ˜^Kšœžœ˜"˜K˜ K˜K˜ K˜K˜K˜K˜—Kšžœžœ˜2šžœžœž˜*Kšœ˜K˜Kšœb™bK˜&K˜/Kšœ˜—K˜ Kšœ˜K˜—š   œžœžœžœžœ˜>šžœ˜šžœž˜K˜ K˜ K˜K˜K˜K˜K˜K˜*K˜Kšžœ˜——Kšœ˜K˜—š   œžœžœžœžœžœ˜9šžœ˜šžœ ž˜K˜K˜K˜K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜ K˜Kšžœ ˜——Kšœ˜K˜—š  œžœžœžœžœžœ˜>Kšžœ ˜Kšœ˜K˜—š  œžœžœžœžœ˜EKšžœ!˜'Kšœ˜—K˜š  œžœžœžœ ˜@Kšžœ˜Kšžœžœ7˜VKšžœ!˜%K˜5K˜8šžœ žœ!ž˜IKšžœ˜—Kšžœ ˜Kšœ˜K˜—š œžœžœžœ'˜`K˜5Kšœ,˜,Kšœ˜K˜—š œžœžœ@žœ"˜yK˜Kšœžœ˜#Kšœžœ˜"K˜˜K˜ K˜ K˜ K˜ K˜Kšœžœ˜ —˜K˜ K˜ K˜ K˜K˜ K˜ K˜ K˜Kšœžœ˜ —K˜K˜ K˜/Kšœ˜K˜—š œžœžœ˜)K˜!Kšœ˜K˜—KšœW™WKšœ!™!˜š   œžœžœ$žœžœžœ˜YKšžœ˜Kšœ˜K˜—š  œžœžœ-˜CKšžœ˜Kšœ˜K˜—š  œžœžœžœ žœžœ˜lKšžœ žœžœ˜4——K˜KšœY™YKš œžœžœžœžœžœ˜