DIRECTORY Basics USING [HighByte], DeviceCleanup USING [Item, Await], DoradoInputOutput USING [Input, IOAddress, Output, ResetEther], EthernetOneFace, PrincOpsUtils USING [BITAND, LowHalf], MPCodes USING [Code, ethernetHostChanged], ProcessorFace USING [SetMP]; EthernetOneHeadDorado: PROGRAM IMPORTS Basics, DeviceCleanup, DoradoInputOutput, PrincOpsUtils, ProcessorFace EXPORTS EthernetOneFace = BEGIN OPEN EthernetOneFace; OCSB: TYPE = LONG POINTER TO OutputControllerStatusBlock; OutputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, interruptBit: WORD, minPacketSpacing: CARDINAL, last: IOCB]; -- last IOCB on output queue, valid if next#noIOCB ICSB: TYPE = LONG POINTER TO InputControllerStatusBlock; InputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, interruptBit: WORD, host: WORD, -- if >=0, old-style single-host receive microcode will be used. missed: CARDINAL, last: IOCB, -- last IOCB on input queue, valid if next#noIOCB interstices: ARRAY [6..30B) OF WORD_NULL, -- hosts start 30B beyond next hosts: HostArray]; -- current set of hosts to which receiver code responds IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIOCB: TYPE = POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, completion: CompletionStatus, used: CARDINAL, -- input only load: CARDINAL, -- output only length: CARDINAL, buffer: LONG POINTER, direction: {input, output}, fill: [0..77777B] _ NULL]; CompletionStatus: TYPE = MACHINE DEPENDENT RECORD [ microcode (0: 0..7): {pending (0), done (1), bufferOverflow (2), loadOverflow (3)}, hardware (0: 8..15): SELECT OVERLAID * FROM input => [ rxCollision (0: 8..8), fill1 (0: 9..9), rxDataLate (0: 10..10), fill2 (0: 11..11), rxCRCError (0: 12..12), fill3 (0: 13..14), rxIncTrans (0: 15..15): BOOLEAN], output => [ rxOn (0: 8..8), txOn (0: 9..9), loopBack (0: 10..10), txCollision (0: 11..11), noWakeups (0: 12..12), txDataLate (0: 13..13), singleStep (0: 14..14), txFifoPE (0: 15..15): BOOLEAN], ENDCASE]; multiHosts: CARDINAL = 177777B; inputErrorMask: input CompletionStatus = [ microcode: pending, hardware: input[rxCollision: TRUE, fill1: FALSE, rxDataLate: TRUE, fill2: FALSE, rxCRCError: TRUE, fill3: FALSE, rxIncTrans: TRUE]]; outputErrorMask: output CompletionStatus = [ microcode: pending, hardware: output[rxOn: FALSE, txOn: FALSE, loopBack: FALSE, txCollision: TRUE, noWakeups: FALSE, txDataLate: TRUE, singleStep: FALSE, txFifoPE: TRUE]]; nullCompletion: CompletionStatus = LOOPHOLE[0]; Command: TYPE = RECORD [WORD]; enableInput: Command = [173377B]; enableOutput: Command = [047777B]; control: DoradoInputOutput.IOAddress = 16B; noIOCB: ShortIOCB = LOOPHOLE[0]; Device: TYPE = RECORD [WORD]; Shorten: PROCEDURE [iocb: IOCB] RETURNS [ShortIOCB] = INLINE BEGIN RETURN[PrincOpsUtils.LowHalf[iocb]]; END; DeviceHandle: PUBLIC TYPE = Device; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; nullDeviceHandle: PUBLIC DeviceHandle _ LOOPHOLE[123456B]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOLEAN _ TRUE; oCSB: OCSB = LOOPHOLE[LONG[177610B]]; iCSB: ICSB = LOOPHOLE[LONG[177600B]]; QueueOutput: PUBLIC PROCEDURE [ device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN cb^ _ [next: noIOCB, completion: nullCompletion, used: 0, load: 0, length: length, buffer: buffer, direction: output]; IF oCSB.next # noIOCB THEN oCSB.last.next _ Shorten[cb]; IF oCSB.next = noIOCB AND cb.completion = nullCompletion THEN BEGIN oCSB.next _ Shorten[cb]; DoradoInputOutput.Output[enableOutput, control]; END; oCSB.last _ cb; END; QueueInput: PUBLIC PROCEDURE [ device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN cb^ _ [next: noIOCB, completion: nullCompletion, used: 0, load: 0, length: length, buffer: buffer, direction: input]; IF iCSB.next # noIOCB THEN iCSB.last.next _ Shorten[cb]; IF iCSB.next = noIOCB AND cb.completion = nullCompletion THEN iCSB.next _ Shorten[cb]; iCSB.last _ cb; END; GetStatus: PUBLIC PROCEDURE [cb: IOCB] RETURNS [status: Status] = BEGIN OPEN cb.completion; RETURN[ SELECT microcode FROM pending => pending, done => SELECT cb.direction FROM input => IF PrincOpsUtils.BITAND[cb.completion, inputErrorMask]=0 THEN ok ELSE SELECT TRUE FROM rxCollision => otherError, rxDataLate => overrun, rxCRCError => IF rxIncTrans THEN crcAndBadAlignment ELSE crc, rxIncTrans => badAlignmentButOkCrc, ENDCASE => otherError, output => IF PrincOpsUtils.BITAND[cb.completion, outputErrorMask]=0 THEN ok ELSE SELECT TRUE FROM txCollision => tooManyCollisions, txDataLate => underrun, txFifoPE => otherError, ENDCASE => otherError, ENDCASE => otherError, bufferOverflow => packetTooLong, loadOverflow => tooManyCollisions, ENDCASE => otherError]; END; GetRetries: PUBLIC PROCEDURE [cb: IOCB] RETURNS [CARDINAL] = BEGIN RETURN[ SELECT cb.load 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]; END; GetPacketLength: PUBLIC PROCEDURE [cb: IOCB] RETURNS [CARDINAL] = BEGIN RETURN[cb.used]; END; GetPacketsMissed: PUBLIC PROCEDURE [device: Device] RETURNS [CARDINAL] = BEGIN RETURN[iCSB.missed]; END; nonNullDeviceHandle: DeviceHandle = LOOPHOLE[22334]; -- # nullDeviceHandle GetNextDevice: PUBLIC PROCEDURE [device: Device] RETURNS [Device] = BEGIN RETURN[IF device=nullDeviceHandle THEN nonNullDeviceHandle ELSE nullDeviceHandle]; END; GetEthernet1Address: PUBLIC PROCEDURE [device: Device] RETURNS [net: [0..256), host: HostAddress] = BEGIN RETURN[net: 0, host: Basics.HighByte[DoradoInputOutput.Input[control]]]; END; TurnOn: PUBLIC PROCEDURE [ device: Device, host: HostAddress, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = BEGIN DoradoInputOutput.ResetEther[]; iCSB.next _ noIOCB; iCSB.interruptBit_inInterrupt; iCSB.missed_0; iCSB.last_NIL; IF iCSB.host#multiHosts THEN iCSB.host_host ELSE IF host = 0 THEN iCSB.hosts_ALL[TRUE] ELSE iCSB.hosts[host]_TRUE; oCSB^ _ [next: noIOCB, interruptBit: outInterrupt, last: NIL, minPacketSpacing: 500/32]; DoradoInputOutput.Output[enableInput, control]; END; TurnOff: PUBLIC PROCEDURE [device: Device] = BEGIN DoradoInputOutput.ResetEther[]; END; InputHosts: PUBLIC PROCEDURE [device: DeviceHandle, inputHosts: LONG POINTER TO HostArray] = { iCSB.hosts_inputHosts^; iCSB.host_multiHosts; }; -- enable multicast host array InputHost: PUBLIC PROCEDURE[device: DeviceHandle, host: HostAddress] = { iCSB.host_host; }; -- disable multicast host array, specify host. MulticastCapabilities: PUBLIC PROCEDURE[device: DeviceHandle] RETURNS [ canDo: BOOLEAN, multicastsEnabled: BOOLEAN] = { RETURN [ canDo: TRUE, multicastsEnabled: iCSB.host = multiHosts]; }; alreadyInitializedCleanup: BOOLEAN _ FALSE; savedICSB: InputControllerStatusBlock; savedOCSB: OutputControllerStatusBlock; AddCleanup: PUBLIC PROCEDURE [device: Device] = BEGIN OPEN DeviceCleanup; item: Item; originalHost: HostAddress _ GetEthernet1Address[device].host; IF alreadyInitializedCleanup THEN RETURN; alreadyInitializedCleanup _ TRUE; DO SELECT Await[@item] FROM kill => BEGIN DoradoInputOutput.ResetEther[]; END; turnOff => BEGIN DoradoInputOutput.ResetEther[]; savedICSB _ iCSB^; savedOCSB _ oCSB^; END; turnOn => BEGIN DoradoInputOutput.ResetEther[]; IF GetEthernet1Address[device].host#originalHost THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- InLoaded on another machine? iCSB^ _ [ next: noIOCB, interruptBit: 0, host: savedICSB.host, hosts: savedICSB.hosts, missed: 0, last: NIL]; oCSB^ _ [ next: noIOCB, interruptBit: 0, minPacketSpacing: savedOCSB.minPacketSpacing, last: NIL]; DoradoInputOutput.Output[enableInput, control]; END; ENDCASE; ENDLOOP; END; RemoveCleanup: PUBLIC PROCEDURE [device: Device] = BEGIN END; ErrorHalt: PROC [code: MPCodes.Code] = INLINE { ProcessorFace.SetMP[code]; DO ENDLOOP }; ethernetHostChanged: MPCodes.Code = 933; END. -- EthernetOneHeadDorado. 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. Time: December 5, 1980 9:50 PM By: Taft, Action: convert for Dorado. 8-Jul-82 14:19:21 Taft Cleanup routine checks for Ethernet address changing at turnOn time. Time: September 17, 1982 1:08 pm By: Swinehart, Action: add multicast input Requires PilotEther microcode that knows about multicast as well. EthernetOneHeadDorado.mesa Last Edited by: Taft, February 13, 1983 1:20 pm Some modifications should be made to clean up multicast receiving, but they would cause incompatibilities in existing volumes (Germ, Othello, CoPilot, etc.) Last Edited by: Levin, August 8, 1983 3:04 pm words after here are unused by microcode words after here (except "hosts") are unused by microcode for compatibility with existing location of oCSB. words after here are unused by microcode This implementation has no concept of a "device", but something has to be exported to EthernetOneFace (see below) 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. If in multiHost mode, set all hosts true for promiscuous mode, or add specified host to currently-accepted list. for now, always space output packets at least 500 microseconds apart The next three procedure should probably be monitored, or be called from properly locked places. inputHosts is complete specification (including 0, if broadcasts are to be accepted), of the hosts whose input packets the microcode will accept. 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. Ugh, it would be nice if we could do something better Move this to PilotMP.mesa next time we get a chance to change it: Other routines to keep the rest of the world happy Ê 2˜J˜J˜Jšœ™Jšœ/™/J˜JšœW™WJšœD™DJ™-šÏk ˜ Jšœœ ˜Jšœœ˜"Jšœœ(˜?J˜Jšœœœ ˜&Jšœœ˜*Jšœœ ˜J˜—šœ˜JšœG˜NJšœ˜Jšœœ˜J˜Jš œœœœœ˜9š œœœ œœ˜>J˜Jšœœ˜Jšœœ˜Jšœ(™(JšœœÏc2˜?J˜—Jš œœœœœ˜8š œœœ œœ˜=J˜Jšœœ˜Jšœœž@˜MJšœœ˜Jšœ9™9Jšœœž1˜=š œ œ œœœž˜HJšœ1™1—Jšœž7˜JJ˜—Jš œœœœœ˜,Jšœ œœœ˜,š œœœ œœ˜1J˜J˜Jšœœž ˜Jšœœž˜Jšœœ˜Jšœœœ˜Jšœ(™(J˜Jšœœ˜J˜—š œœœ œœ˜3J˜Sšœœœ˜+˜ J˜J˜J˜J˜J˜J˜Jšœœ˜!—˜ J˜J˜J˜J˜J˜J˜J˜Jšœœ˜—Jšœ˜ J˜——Jšœ œ ˜J˜˜*J˜š œœ œœ œ˜PJšœ œ œœ˜3——˜,J˜š œœœ œœ˜NJš œ œœœ œ˜H——Jšœ#œ˜/J˜Jšœ œœœ˜J˜!J˜"J˜+J˜Jšœœ˜ J˜JšœF™FJšœ*™*Jšœœœœ˜J˜š Ïnœ œœœ˜œ˜CJ˜Jš˜J˜J˜J˜J˜Jšœ œ˜JšœO™OJšœ ™ Jšœœ˜+Jš œœ œ œœ˜*Jšœœ˜šœ9œ˜=JšœD™DJ˜—J˜/Jšœ˜J˜—šŸœœ œ˜,Jšœ!œ˜*J˜—JšœQ™QJšœ™JšœU™UJšœ;™;šŸ œœ œ˜3Jšœ œœœ˜*J˜Jšœž˜7J˜—šŸ œœ œ-˜HJšœž.˜EJ˜—šŸœœ œ˜=Jšœ œœ˜9Jšœ œ0˜DJ˜——JšœY™Y˜Jšœœœ˜+J˜J˜&J˜'J˜šŸ œœ œ˜/Jšœœ˜J˜ J˜=Jšœœœ˜)Jšœœ˜!š˜šœ˜Jšœœ!œ˜2˜ Jš˜J˜J˜J˜Jšœ˜—˜ Jš˜Jšœ8™8JšœK™KJšœK™KJšœJ™JJšœD™DJ˜šœ/˜5Jšœ)ž˜H—˜ J˜MJšœ5™5Jšœœ˜—˜ J˜Jšœ4œ˜9—J˜/Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜—Jš Ÿ œœ œœœ˜=J˜Jš Ÿ œœœœœ˜XJ˜JšœA™AJ˜(J˜Jšœ2™2J˜Jšœž˜J˜—Jš˜Jšœœk˜‰Jšœœœ1˜oJšœœœ,˜UJšœœœ!˜Jšœœ'˜FJ˜^—˜KJ˜AJ˜J˜——…—"T4Œ