DIRECTORY DeviceCleanup USING [Item, Await], D0InputOutput USING [CSB, IOPage, ethernetIn, ethernetOut, ControllerNumber, GetNextController, nullControllerNumber], EthernetFace, PrincOps USING [zMISC, zSTARTIO], PrincOpsUtils USING [LowHalf]; EthernetHeadD0: PROGRAM IMPORTS D0InputOutput, DeviceCleanup, PrincOpsUtils EXPORTS EthernetFace = { OPEN EthernetFace; OCSB: TYPE = LONG POINTER TO OutputControllerStatusBlock; OutputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, unused1: WORD, unused2: WORD, unused3: 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 [ next: ShortIOCB, host: HostNumber, 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 = [20B]; firstFixupInput: SioParameter = [40B]; firstReset: SioParameter = [60B]; secondFixupOutput: SioParameter = [100B]; secondFixupInput: SioParameter = [200B]; secondReset: SioParameter = [300B]; 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]; 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, 70200B => badAlignmentButOkCrc, 70020B => crc, 70220B => crcAndBadAlignment, 70100B, 70120B, 70300B, 70320B => overrun, 70004B, 70006B => 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[ethernetIn,device.in]; device.out _ GetNextController[ethernetOut,device.out]; IF device.in=nullControllerNumber OR device.out=nullControllerNumber THEN RETURN[nullDeviceHandle]; RETURN[device]; }; TurnOn: PUBLIC PROC [device: Device, host: physical HostNumber, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = { board: Board = device.board; out: OCSB = OCSBFronDevice[device]; in: ICSB = ICSBFronDevice[device]; StartIO[resetBits[board]]; out^ _ [ next: noIOCB, unused1: 0, unused2: 0, unused3: 0, interruptBit: outInterrupt, last: NIL ]; in^ _ [ 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]]; }; 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: HostNumber; IF alreadyInitializedCleanup[device.board] THEN RETURN; alreadyInitializedCleanup[device.board] _ TRUE; DO SELECT Await[@item] FROM kill => { StartIO[resetBits[board]]; }; turnOff => { StartIO[resetBits[board]]; savedICSB _ in^; savedOCSB _ out^; oldHost _ in.host; }; turnOn => { StartIO[resetBits[board]]; out^ _ [ next: noIOCB, unused1: 0, unused2: 0, unused3: 0, interruptBit: 0, last: NIL ]; in^ _ [ 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] = { }; }. LOG Time: September 4, 1980 11:02 PM By: HGM, Action: create file. Time: September 14, 1980 6:33 AM By: HGM, Action: buffer overflow bug. Time: November 3, 1983 11:14 am By: Birrell, Action: conversion to 5.0. ŽEthernetHeadD0.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. HGM on: September 14, 1980 6:33 AM Birrell, November 3, 1983 11:14 am Russ Atkinson (RRA) February 19, 1985 3:06:54 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. Input from reg 0 is device id completion bits 001000 and 000400 are unused so far Hardware error bits: 001: Memory Data Fault (OFault) 002: Collision 004: Output Underrrun 010: Bad Parity (between mem and shifter) 020: CRC 040: Jam 100: Input Overrun 200: Bad Alignment 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 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šœžœžœžœŸ+˜MKšœžœŸ1˜?K˜—Kš žœžœžœžœžœ˜,KšœΪ™ΪKšœ žœžœžœ˜,š œžœžœž œžœ˜1K˜Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜KšœžœŸ ˜Kšœžœ˜KšœžœžœŸ˜8K˜—šΟnœžœžœžœ˜BK˜—šœžœžœžœ˜#K˜'K˜&K˜!K˜)K˜(K˜#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šœžœžœ ˜#Kšœžœžœ˜1K˜Kšœ™K˜Kšœžœžœ ˜:Kšœžœžœ˜%Kšœžœžœžœ˜9Kšœ žœžœžœ˜K˜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˜/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˜;Kšžœ!˜%—K˜4K˜7šžœ žœ!ž˜IKšžœ˜—Kšžœ ˜Kšœ˜K˜—š œžœžœHžœ"˜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šœY™YKš œžœžœžœžœžœ˜