-- 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.