<> <> <> <> <> <> <> <<>> <> <<1) GetNextDevice should find all drives on a controller (does this need a microcode change?)>> <<2) The semantics of aborting should be independent of controllers; e.g. aborting could work on all drives, or on an individual drive. (Currently it works on all drives of a controller, but it is hard to see how this can be specified in a controller-independent way.)>> <<>> DIRECTORY Basics USING [LongNumber, LowHalf], D0InputOutput USING [ControllerNumber, GetNextController, IOPage, nullControllerNumber, rdc], DeviceCleanup USING [Await, Item, Reason], DiskFace USING [Label], ProcessorFace USING[ProcessorID], PrincOpsUtils USING[ BITAND, LowHalf], RDC, SA4000Face; SA4000HeadD0: PROGRAM IMPORTS Basics, D0InputOutput, DeviceCleanup, PrincOpsUtils, RDC EXPORTS SA4000Face SHARES ProcessorFace--ProcessorID representation--, SA4000Face = { OPEN RDC, SA4000Face; <<>> <> CSB: TYPE = MACHINE DEPENDENT RECORD [ <> cylinder: ARRAY Drive OF CARDINAL, -- Contains the current cylinder address for each drive or -1 if the drive is to be recalibrated before the next command. state: CSBState]; CSBState: TYPE = MACHINE DEPENDENT RECORD [ <> next: IOCBshortPtr, -- Points to the next IOCB to be processed by the microcode. Points to the last IOCB if an error is reported by the microcode. Contains zero if the queue is empty. This is updated by Initiate and by the microcode. When the microcode finishes processing an IOCB, it replaces next with the next pointer from the IOCB. deferring: INTEGER, -- This is set to -1 by the microcode when it reports an error completion to the Head. The microcode will not process any more IOCBs until this is set to zero again by Poll when the error is reported to the client. In the case of a labelCheck that requires a fixup, the error is not really an error at all, and the client will be unaware of the label fixup. tail: IOCBshortPtr, -- Points to the last IOCB in the queue. Used only by Initiate. transferMask: WORD]; -- This interupt mask is used by the microcode to schedule Mesa processes at the completion of each IOCB. It is initialized by StartB. CSBPtr: TYPE = LONG POINTER TO CSB; DiskHandle: TYPE = MACHINE DEPENDENT RECORD [ -- representation of DeviceHandle zero: [0..16) _ 0, controller: D0InputOutput.ControllerNumber, drive: [0..256)]; Drive: TYPE = [0..drives); <<>> <> drives: CARDINAL = 4; -- maximum number of drives per controller rdcCommands: ARRAY Command OF WORD = [ <> 4110B, -- headerVerifyLabelVerify 4112B, -- headerVerifyLabelVerifyDataRead 4114B, -- headerVerifyLabelVerifyDataWrite 4111B, -- headerVerifyLabelVerifyDataVerify 4140B, -- headerVerifyLabelWrite 4144B, -- headerVerifyLabelWriteDataWrite 4120B, -- headerVerifyLabelRead 4122B, -- headerVerifyLabelReadDataRead 4124B, -- headerVerifyLabelReadDataWrite 4121B, -- headerVerifyLabelReadDataVerify 4510B, -- headerReadLabelVerify 4512B, -- headerReadLabelVerifyDataRead 4514B, -- headerReadLabelVerifyDataWrite 4511B, -- headerReadLabelVerifyDataVerify 4540B, -- headerReadLabelWrite 4544B, -- headerReadLabelWriteDataWrite 4520B, -- headerReadLabelRead 4522B, -- headerReadLabelReadDataRead 4524B, -- headerReadLabelReadDataWrite 4521B, -- headerReadLabelReadDataVerify 4200B, -- headerWrite 4110B]; -- headerWriteLabelWriteDataWrite (not implemented, so this is really "vv"!) labelRead: WORD = 0020B; -- bit of RDC command signifying label read p: RDC.Base = --Environment.first64K--LOOPHOLE[LONG[0]]; nil: RDC.Base RELATIVE POINTER = LOOPHOLE[0]; nullCylinder: CARDINAL = 177777B; -- used for initialization and recalibration nullDiskHandle: DiskHandle = [controller: D0InputOutput.nullControllerNumber, drive: 0]; -- GetNextDevice depends on this value rdcInProgress: WORD = 0; serviceLateRetries: CARDINAL = 1000; -- retries to be performed by the microcode rateErrorRetries: CARDINAL = 1000; -- retries to be performed by the microcode <<>> <> globalStateSize: PUBLIC CARDINAL _ 0; -- an IOCB for label fixup is not required for the D0 implementation. nullDeviceHandle: PUBLIC DeviceHandle _ Seal[nullDiskHandle]; operationSize: PUBLIC CARDINAL _ SIZE[IOCB]; totalErrors: PUBLIC CARDINAL _ 0; -- = total errors reported by Poll uCodeServiceLateRetries: CARDINAL _ 0; -- total serviceLate retries performed by the microcode uCodeRateErrorRetries: CARDINAL _ 0; -- total rateError retries performed by the microcode <<>> <> GetDeviceAttributes: PUBLIC PROC [device: DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] = { <> RETURN[ cylinders: 202, movingHeads: 8, -- actually depends on whether 4004 or 4008 fixedHeads: 0, -- actually depends on option sectorsPerTrack: 28] }; GetTrueDeviceAttributes: PUBLIC PROC [device: DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] = { [cylinders, movingHeads, fixedHeads, sectorsPerTrack] _ GetDeviceAttributes[device]; }; GetNextDevice: PUBLIC PROC [device: DeviceHandle] RETURNS [DeviceHandle] = { <> OPEN D0InputOutput, disk: LOOPHOLE[device, DiskHandle]; controller: ControllerNumber; SELECT disk FROM nullDiskHandle => { controller _ GetNextController[rdc, nullControllerNumber]; IF controller=nullControllerNumber THEN GOTO Null; -- no drives RETURN[Seal[[controller: controller, drive: 0]]] }; ENDCASE => GOTO Null EXITS Null => RETURN[nullDeviceHandle]; }; Initialize: PUBLIC PROC[t: WORD, globalState: GlobalStatePtr] = { OPEN D0InputOutput; csbState: CSBState = [ next: nil, deferring: 0, tail: nil, transferMask: t]; c: ControllerNumber _ nullControllerNumber; WHILE (c _ GetNextController[rdc, c])~=nullControllerNumber DO OPEN csb: LOOPHOLE[@IOPage[c], CSBPtr]; csb.state _ csbState; ENDLOOP; }; InitializeCleanup: PUBLIC PROC = { OPEN D0InputOutput; c: ControllerNumber _ nullControllerNumber; WHILE (c _ GetNextController[rdc, c])~=nullControllerNumber DO OPEN csb: LOOPHOLE[@IOPage[c], CSBPtr]; InitializeCleanupForController[@csb]; ENDLOOP; }; Initiate: PUBLIC PROC [operationPtr: OperationPtr] = { <> iocb: IOCBlongPtr = LOOPHOLE[operationPtr]; iocbShort: IOCBshortPtr = LOOPHOLE[PrincOpsUtils.LowHalf[operationPtr]]; csb: CSBPtr = IGetCSB[iocb.operation.device]; <> <> iocb.clientHeader _ iocb.operation.clientHeader; PackLabel[to: @iocb.clientLabel, from: iocb.operation.labelPtr]; iocb.operation.deviceStatus.a _ rdcInProgress; iocb.rdcCommand _ rdcCommands[iocb.operation.command]; iocb.next _ nil; <> iocb.serviceLateRetryCount _ serviceLateRetries; iocb.rateErrorRetryCount _ rateErrorRetries; <> IF csb.state.next = nil THEN <> csb.state.next _ iocbShort ELSE <> p[csb.state.tail].next _ iocbShort; csb.state.tail _ iocbShort; }; Poll: PUBLIC PROC [operationPtr: OperationPtr] RETURNS [status: Status] = { iocb: IOCBlongPtr = LOOPHOLE[operationPtr]; csb: CSBPtr = IGetCSB[iocb.operation.device]; controllerIdle: BOOLEAN = csb.state.next=nil OR csb.state.deferring<0; -- used to detect race noted in Initiate <> uCodeServiceLateRetries _ uCodeServiceLateRetries + (serviceLateRetries-iocb.serviceLateRetryCount); uCodeRateErrorRetries _ uCodeRateErrorRetries + (rateErrorRetries-iocb.rateErrorRetryCount); status _ DecodeStatus[iocb.operation.deviceStatus.a]; -- check status of specified IOCB IF status=inProgress THEN { <> <> IF controllerIdle THEN csb.state.next _ LOOPHOLE[PrincOpsUtils.LowHalf[operationPtr]]; RETURN }; IF status=goodCompletion THEN NULL <> ELSE { <> <> SELECT status FROM labelCheck => { <> IF MatchLabels[@iocb.clientLabel, @iocb.diskLabel] THEN { <> <> iocb.operation.clientHeader _ iocb.clientHeader; iocb.clientLabel.bootChainLink _ iocb.diskLabel.bootChainLink; iocb.operation.deviceStatus.a _ rdcInProgress; csb.state.deferring _ 0; -- restart the controller RETURN[inProgress] }; }; wrongSector => <> SELECT TRUE FROM iocb.operation.clientHeader.cylinder~=iocb.operation.diskHeader.cylinder => status _ wrongCylinder; iocb.operation.clientHeader.head~=iocb.operation.diskHeader.head => status _ wrongHead; ENDCASE; <> ENDCASE; <> totalErrors _ totalErrors+1; csb.state.next _ nil; -- zap all deferred requests csb.state.deferring _ 0; -- restart the controller }; iocb.operation.clientHeader _ iocb.clientHeader; UnpackLabel[to: iocb.operation.labelPtr, from: IF PrincOpsUtils.BITAND[iocb.rdcCommand, labelRead]~=0 THEN @iocb.diskLabel ELSE @iocb.clientLabel]; }; Recalibrate: PUBLIC PROC [device: DeviceHandle] = { GetCSB[device].cylinder[LOOPHOLE[device, DiskHandle].drive] _ nullCylinder }; Reset: PUBLIC PROC [device: DeviceHandle] = { <> }; <> DecodeStatus: PROC [r: UNSPECIFIED] RETURNS [s: Status] = INLINE { <> RETURN[LOOPHOLE[LOOPHOLE[r, RDC.DeviceStatus].outcome]]; -- completion code in processor field matches Status codes up to wrongSector }; GetCSB: PROC[device: DeviceHandle] RETURNS [CSBPtr] = { RETURN[IGetCSB[device]] }; IGetCSB: PROC[device: DeviceHandle] RETURNS [CSBPtr] = INLINE { RETURN[LOOPHOLE[@D0InputOutput.IOPage[LOOPHOLE[device, DiskHandle].controller]]] }; InitializeCleanupForController: PROC [csb: CSBPtr] = { OPEN DeviceCleanup; item: Item; reason: Reason; csbState: CSBState; DO reason _ Await[@item]; SELECT reason FROM turnOff, kill => { UNTIL csb.state.next=nil OR csb.state.deferring<0 DO ENDLOOP; csbState _ csb.state; -- save state of CSB }; turnOn => csb.state _ csbState; -- restore CSB state ENDCASE ENDLOOP }; MatchLabels: PROC [p1, p2: LONG POINTER TO RDC.PackedLabel] RETURNS [BOOLEAN] = { <> <> MatchableLabel: TYPE = ARRAY [0..8) OF RECORD [UNSPECIFIED]; FOR i: CARDINAL IN [0..7) DO IF LOOPHOLE[p1^, MatchableLabel][i]~=LOOPHOLE[p2^, MatchableLabel][i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] }; UniversalID: PUBLIC TYPE = --SystemInternal.UniversalID-- MACHINE DEPENDENT RECORD[ processor(0): ProcessorFace.ProcessorID, sequence(3): LONG CARDINAL]; PackLabel: PROC [to: LONG POINTER TO RDC.PackedLabel, from: LONG POINTER TO DiskFace.Label] = INLINE { OPEN fileID: LOOPHOLE[from.fileID, UniversalID], -- Mesa AR 4669 seq: LOOPHOLE[--from.--fileID.sequence, Basics.LongNumber], s: LOOPHOLE[seq.highbits, MACHINE DEPENDENT RECORD [ bits0Thru1 (0:0..1): CARDINAL[0..4), bit2 (0:2..2): CARDINAL[0..2), bits3Thru15 (0:3..15): CARDINAL[0..8192)]]; to^ _ [ sequence0Bit2: s.bit2, processorID0: --from.--fileID.processor.a, processorID1: --from.--fileID.processor.b, processorID2: --from.--fileID.processor.c, sequence1: Basics.LowHalf[--from.--fileID.sequence], sequence0Bits3Thru15: s.bits3Thru15, immutable: FALSE, temporary: FALSE, zeroSize: FALSE, filePageLo: from.filePage, type: from.attributes, bootChainLink: PackDiskAddress[LOOPHOLE[from.dontCare]]]; <> <> <> <> <> }; Seal: PROC [disk: DiskHandle] RETURNS [DeviceHandle] = { RETURN[LOOPHOLE[disk]] }; UnpackLabel: PROC [to: LONG POINTER TO DiskFace.Label, from: LONG POINTER TO RDC.PackedLabel] = INLINE { to^ _ [ fileID: LOOPHOLE[UniversalID[ processor: [a: from.processorID0, b: from.processorID1, c: from.processorID2], sequence: LOOPHOLE[Basics.LongNumber[num[ lowbits: from.sequence1, highbits: from.sequence0Bit2*8192+from.sequence0Bits3Thru15]]]]], filePage: from.filePageLo, attributes: from.type, dontCare: LOOPHOLE[UnpackDiskAddress[from.bootChainLink]]]; <> <> <> <> <> }; }. LOG Time: August 8, 1979 1:09 AM By: Redell Action: Add log to file from Jarvis Time: August 17, 1979 1:27 PM By: Gobbel Action: Pilot formatting Time: August 22, 1979 12:40 PM By: Gobbel Action: Bring up to date with revised device face Time: October 2, 1979 11:38 PM By: Redell Action: Further cleanup, esp for bootchains (partial label verification) Time: October 8, 1979 9:22 AM By: McJones Action: Restart controller bug, add hardwareState Time: October 10, 1979 3:53 PM By: McJones Action: INLINE procedures for speed; labelCheck is cue to call StartLabelFix Time: October 30, 1979 11:04 AM By: McJones AR2643: Label fix didn't reset iocb.label from user's label Time: November 1, 1979 1:20 PM By: Frandeen Action: Fix recalibrate after header error; bug in SynchronizeWithController Time: November 7, 1979 1:17 PM By: McJones AR2739: Label fix up confused by spurious labelCheck status returned by read label command on sector with missing (label?) synch byte Time: November 9, 1979 8:59 AM By: Frandeen Action: Implement runs of pages. Change interface to Poll. Change LabelFix procedures. Change interface to StartB since we no longer need an extra IOCB for label fixup. Time: December 13, 1979 11:29 AM By: Gobbel Action: Change name from SA4000D0Head to SA4000HeadD0 Time: January 30, 1980 12:48 PM By: McJones Action: Update to match new face; add StartChain logic Time: June 25, 1980 10:34 AM By: McJones Action: 48-bit processor ids Time: July 24, 1980 11:23 AM By: McJones Action: Label fixup must update iocb.operation.clientHeader Time: November 2, 1983 4:35 pm By: Birrell Action: conversion to 5.0 Time: May 9, 1984 5:55:26 pm PDT By: Bob Hagmann Action: added GetTrueDeviceAttributes