-- File: DiskControl.mesa -- Last edited by Levin: 11-May-81 15:07:42 DIRECTORY AltoFileDefs USING [DirDA, DirFP, DiskShape, FIP, LD], DiskDriver USING [busyTail, cbAvailable, completedTail, completerToDie, completionsExist, diskInterruptCV, freeHead, interruptHandlerToDie, longTermWait, totalErrors], DiskIODefs USING [ CompletionStatus, DISK, DiskError, DiskRequest, InitiateDiskIO, NormalCompletionProcedure, XferSpec], DiskIOPrivate USING [ CB, CBPtr, Completer, DiskInterruptHandler, diskInterruptLevel, diskReads, diskWrites, FinalizeCompleter, FinalizeInterruptHandler, FreeCB, GetCBs, IOSynch, maxOps, nSafetyDCBs, scratchPage, standardDisk, SynchRecord, sysDisk, VirtualDA], FrameDefs USING [GlobalFrame, IsBound, MakeCodeResident, UnlockCode], LogDefs USING [DisplayNumber, WriteLogEntry], ProcessDefs USING [CV, MsecToTicks, Yield], StringDefs USING [AppendOctal, AppendString], VMStorage USING [AllocatePage, FreePage, longTerm]; DiskControl: MONITOR LOCKS synch.LOCK USING synch: DiskIOPrivate.IOSynch IMPORTS DiskDriver, DiskIODefs, DiskIOPrivate, FrameDefs, LogDefs, ProcessDefs, StringDefs, VMStorage EXPORTS DiskIODefs, DiskIOPrivate SHARES DiskDriver = BEGIN OPEN DiskIODefs, DiskIOPrivate; -- Global Variables -- diskInterruptProcess, completerProcess: PROCESS; -- Miscellaneous Declarations -- diskInterruptTimeoutMS: CARDINAL = 250; CBsLost: ERROR = CODE; -- Procedures exported to DiskIOPrivate -- loggingEnabled: PUBLIC BOOLEAN; -- indicates whether statistics logging is enabled. InitializeDiskIO: PUBLIC PROCEDURE [minOps: CARDINAL] RETURNS [nOps: CARDINAL] = -- initializes the storage for CBs and sets up the interrupt handling processes. BEGIN loggingEnabled ← FrameDefs.IsBound[LogDefs.DisplayNumber]; sysDisk ← standardDisk; maxOps ← MAX[minOps, sysDisk.sectors] + nSafetyDCBs; InitializeDiskDriver[]; InitializeDiskRequestor[]; InitializeSysDisk[]; RETURN[maxOps - nSafetyDCBs]; END; FinalizeDiskIO: PUBLIC PROCEDURE = -- shuts down the disk driver and releases associated storage. BEGIN FinalizeDiskDriver[]; FinalizeDiskRequestor[]; END; ResetDiskShape: PUBLIC PROCEDURE [disk: DISK] = {sysDisk ← disk}; WriteErrorToLog: PUBLIC PROCEDURE [cb: CBPtr] = BEGIN OPEN StringDefs; s: STRING ← [30+3*7]; AppendString[s, "Disk error: vDA "L]; AppendOctal[s, VirtualDA[cb.header.diskAddress]]; AppendString[s, ", op "L]; AppendOctal[s, cb.command]; AppendString[s, " status "L]; AppendOctal[s, cb.status]; LogDefs.WriteLogEntry[s]; END; -- Internal Procedures -- InitializeDiskDriver: PROCEDURE = BEGIN OPEN DiskDriver, ProcessDefs; FrameDefs.MakeCodeResident[FrameDefs.GlobalFrame[DiskInterruptHandler]]; START DiskDriver; IF loggingEnabled THEN BEGIN totalErrors ← 0; LogDefs.DisplayNumber["Disk Errors"L, [short[@totalErrors]]]; END; freeHead ← busyTail ← completedTail ← NIL; interruptHandlerToDie ← completerToDie ← FALSE; diskInterruptCV.timeout ← MsecToTicks[diskInterruptTimeoutMS]; CV[diskInterruptLevel] ← @diskInterruptCV; longTermWait.timeout ← 0; diskInterruptProcess ← FORK DiskInterruptHandler; completionsExist.timeout ← 0; cbAvailable.timeout ← 0; completerProcess ← FORK Completer; THROUGH [1..10] DO Yield[] ENDLOOP; -- hack to start interrupt processes END; InitializeDiskRequestor: PROCEDURE = BEGIN IF loggingEnabled THEN BEGIN diskReads ← diskWrites ← 0; LogDefs.DisplayNumber["Disk Reads"L, [long[@diskReads]]]; LogDefs.DisplayNumber["Disk Writes"L, [long[@diskWrites]]]; END; scratchPage ← VMStorage.AllocatePage[]; THROUGH [0..maxOps) DO FreeCB[VMStorage.longTerm.NEW[CB]]; ENDLOOP; END; InitializeSysDisk: PROCEDURE = BEGIN leader: POINTER TO AltoFileDefs.LD = VMStorage.AllocatePage[]; xferSpec: ARRAY [0..1) OF XferSpec ← [[leader, AltoFileDefs.DirDA, 0]]; request: DiskRequest ← [ firstPage: 0, fileID: [1, AltoFileDefs.DirFP.serial], firstPagevDA: , pagesToSkip: 0, nonXferID: , xfers: DESCRIPTOR[@xferSpec, 1], proc: [normal[ProcessCompletion]], noRestore: FALSE, command: ReadD[]]; synch: SynchRecord; IssueRequestAndWait: ENTRY PROCEDURE [synch: IOSynch] = INLINE BEGIN DO synch.status ← noStatus; InitiateDiskIO[@request]; WHILE synch.status = noStatus DO WAIT synch.lastDone ENDLOOP; IF synch.status ~= neverStarted THEN EXIT; ENDLOOP; END; ProcessCompletion: NormalCompletionProcedure = BEGIN DoNotify: ENTRY PROCEDURE [synch: IOSynch] = INLINE {synch.status ← status; NOTIFY synch.lastDone}; DoNotify[@synch]; END; prop: POINTER TO ARRAY OF AltoFileDefs.FIP; IssueRequestAndWait[@synch]; IF synch.status ~= ok THEN ERROR DiskError[synch.status]; prop ← LOOPHOLE[leader, POINTER] + leader.propBegin; FOR i: CARDINAL ← 0, i + prop[i].length UNTIL prop[i].length = 0 OR i >= leader.propLength DO IF prop[i].type = AltoFileDefs.DiskShape THEN {sysDisk ← LOOPHOLE[@prop[i] + 1, POINTER TO DISK]↑; EXIT}; ENDLOOP; VMStorage.FreePage[leader]; END; FinalizeDiskDriver: PROCEDURE = BEGIN FinalizeInterruptHandler[]; JOIN diskInterruptProcess; ProcessDefs.CV[diskInterruptLevel] ← NIL; FinalizeCompleter[]; JOIN completerProcess; FrameDefs.UnlockCode[FinalizeInterruptHandler]; END; FinalizeDiskRequestor: PROCEDURE = BEGIN VMStorage.FreePage[scratchPage]; FOR freedCBs: CARDINAL ← 0, freedCBs + 1 DO cb: CBPtr ← GetCBs[n: 1, wait: FALSE]; IF cb = NIL THEN IF freedCBs = maxOps THEN EXIT ELSE ERROR CBsLost ELSE VMStorage.longTerm.FREE[@cb]; ENDLOOP; END; END.