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