FormatDiskD0.mesa
Last Edited by: Andrew Birrell December 6, 1983 1:15 pm
Last Edited by: Taft, December 16, 1983 10:57 am
DIRECTORY
BasicTime USING [FromPupTime, GMT, OutOfRange],
ConvertUnsafe USING [ToRope],
Disk USING [Channel, Command, defaultTries, DoIO, GetBootChainLink, Label, PageCount, PageNumber, Request, Status],
DiskFace USING [DontCare],
FormatDisk,
PrincOps USING [zEXCH],
Rope USING [ROPE],
VM USING [AddressForPageNumber, Allocate, Free, Interval, Pin, Unpin];
FormatDiskD0:
MONITOR
-- only one guy in here at a time!
IMPORTS BasicTime, ConvertUnsafe, Disk, VM
EXPORTS FormatDisk =
BEGIN OPEN FormatDisk;
Disk formatting and checking
BadPage: PUBLIC SIGNAL [page: Disk.PageNumber, correctable: BOOLEAN] = CODE;
Error: PUBLIC ERROR [page: Disk.PageNumber, status: Disk.Status] = CODE;
Sweep:
PUBLIC ENTRY
PROC [channel: Disk.Channel, operation: Operation, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, label:
LONG
POINTER
TO Disk.Label, data:
LONG
POINTER] =
BEGIN
IF operation=format
THEN
BEGIN
initialLabel: Disk.Label ← label^;
Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: [write, noOp, noOp], label: label, data: data, reportSoftErrors: TRUE];
label^ ← initialLabel;
END;
Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: commandTable[operation], label: label, data: data, reportSoftErrors: TRUE];
END;
commandTable:
ARRAY Operation
OF Disk.Command = [
format: [verify, write, write], -- see code above; Dolphin can't do [write, write, write]
write: [verify, write, write],
read: [verify, read, read],
verify: [verify, verify, verify]];
Initial microcode
MicrocodeInstallFailure: PUBLIC SIGNAL [why: FailureType] = CODE;
InstallInitialMicrocode:
PUBLIC ENTRY
PROC [channel: Disk.Channel, getPage:
PROC [ptr:
LONG
POINTER]
RETURNS [ok:
BOOLEAN]] =
BEGIN
label: Disk.Label;
vmInterval: VM.Interval ← VM.Allocate[count: 1];
pageBuffer: LONG POINTER ← VM.AddressForPageNumber[vmInterval.page];
thisPage: Disk.PageNumber ← hardUCodeStart;
prevPage: Disk.PageNumber ← [hardUCodeStart-1];
VM.Pin[vmInterval];
BEGIN ENABLE UNWIND => {VM.Unpin[vmInterval]; VM.Free[vmInterval]};
DO
ok: BOOLEAN;
IF (ok ← getPage[pageBuffer])
THEN
BEGIN
ENABLE BadPage, Error =>
IF thisPage=hardUCodeStart THEN GOTO firstPageBad
ELSE {thisPage ← [thisPage+1]; RETRY};
IF thisPage>=hardUCodeStart+hardUCodeSize THEN ERROR MicrocodeInstallFailure[microcodeTooBig];
label ← initialMicrocodeLabel;
label.dontCare ← channel.GetBootChainLink[[thisPage+1]];
Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer];
label ← initialMicrocodeLabel;
Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, verify, verify], label: @label, data: pageBuffer];
END;
IF thisPage#Disk.PageNumber[prevPage+1]
OR ~ok
THEN
BEGIN ENABLE BadPage, Error => GOTO flakeyPageFound;
label ← initialMicrocodeLabel;
Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, verify, read], label: @label, data: pageBuffer];
label ← initialMicrocodeLabel;
label.dontCare ← IF ok THEN channel.GetBootChainLink[thisPage] ELSE eofLink;
Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer];
END;
IF ~ok THEN EXIT;
thisPage ← [(prevPage ← thisPage)+1];
REPEAT
firstPageBad => ERROR MicrocodeInstallFailure[firstPageBad];
flakeyPageFound => ERROR MicrocodeInstallFailure[flakeyPageFound];
ENDLOOP;
END;
VM.Unpin[vmInterval];
VM.Free[vmInterval];
END;
IdentifyInitialMicrocode:
PUBLIC
ENTRY
PROC [channel: Disk.Channel]
RETURNS [microcodeInstalled:
BOOLEAN, time: BasicTime.GMT, name: Rope.
ROPE] =
BEGIN
label: Disk.Label ← initialMicrocodeLabel;
vmInterval: VM.Interval ← VM.Allocate[count: 1];
uCodeHeader: LONG POINTER TO MicrocodeHeader ← VM.AddressForPageNumber[vmInterval.page];
VM.Pin[vmInterval];
microcodeInstalled ←
FALSE;
BEGIN
Transfer[channel: channel, firstPage: hardUCodeStart, pageCount: 1, command: [verify, verify, read], label: @label, data: uCodeHeader !
BadPage, Error => GOTO error];
IF uCodeHeader.name.length
IN [1..uCodeHeader.name.maxlength]
AND uCodeHeader.name.maxlength<=maxNameLength
THEN
BEGIN
time ← BasicTime.FromPupTime[GMTFromBCPLTime[uCodeHeader.createDate] !
BasicTime.OutOfRange => GOTO error];
name ← ConvertUnsafe.ToRope[@uCodeHeader.name];
microcodeInstalled ← TRUE;
END;
END;
VM.Unpin[vmInterval];
VM.Free[vmInterval];
END;
hardUCodeFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 0, 0]; -- boot microcode knows this ID
initialMicrocodeLabel: Disk.Label = [fileID: [abs[LOOPHOLE[hardUCodeFileID]]], filePage: 0, attributes: LOOPHOLE[0], dontCare: LOOPHOLE[LONG[0]]]; -- boot microcode knows this label. All pages of the initial microcode have the same label, except for the boot chain link which is filled in for every page. That is, the initial microcode is not a well-formed file.
nullLink: DiskFace.DontCare = LOOPHOLE[LONG[0]];
eofLink: DiskFace.DontCare = LOOPHOLE[LONG[-1]];
MicrocodeHeader:
TYPE =
MACHINE
DEPENDENT
RECORD [
version (0): CARDINAL,
mustBeZero (1): LONG CARDINAL,
createDate (3): BCPLTime,
name (5): StringBody];
BCPLTime: TYPE = RECORD [LONG CARDINAL];
GMTFromBCPLTime:
PROCEDURE [BCPLTime]
RETURNS [
LONG
CARDINAL] =
This returns what the BasicTime interface calls a "Pup time".
MACHINE CODE {PrincOps.zEXCH};
maxNameLength: CARDINAL = 40;
Reserved disk areas
hardUCodeStart: PUBLIC Disk.PageNumber ← [28];
hardUCodeSize: PUBLIC Disk.PageCount ← 224-hardUCodeStart;
altoRegionJargon: PUBLIC Rope.ROPE ← "model 44s";
altoRegionsMax: PUBLIC INT ← 4;
altoRegionsStart: PUBLIC Disk.PageNumber ← [hardUCodeStart+hardUCodeSize];
altoRegionsSize: PUBLIC Disk.PageCount ← 406*28;
altoRegionsBottomUp: PUBLIC BOOL ← TRUE; -- prefer first model 44
Private
Transfer:
PROC [channel: Disk.Channel, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, command: Disk.Command, label:
LONG
POINTER
TO Disk.Label, data:
LONG
POINTER, reportSoftErrors:
BOOLEAN ←
FALSE] =
! BadPage, Error;
BEGIN
retrying: BOOLEAN ← FALSE;
WHILE pageCount>0
DO
The idea here is as follows. If reportSoftErrors=FALSE then we just make a normal call and let the disk channel (and head) do all the error recovery. But if reportSoftErrors=TRUE, we initially request the disk channel (and head) to perform only one try so that we get to find out the exact address of any error. When an error occurs, we then retry just that one page with full error recovery enabled in order to discover whether the error is correctable.
request: Disk.Request ← [diskPage: firstPage, data: data, incrementDataPtr: FALSE, command: command, tries: IF reportSoftErrors AND ~retrying THEN 1 ELSE Disk.defaultTries, count: IF retrying THEN 1 ELSE pageCount];
countDone: Disk.PageCount;
status: Disk.Status;
[status: status, countDone: countDone] ← channel.DoIO[label: label, request: @request];
WITH s: status
SELECT
FROM
changed => ERROR Error[firstPage, status];
unchanged =>
SELECT s.status
FROM
goodCompletion =>
IF retrying THEN {retrying ← FALSE; SIGNAL BadPage[firstPage, TRUE]};
notReady, recalibrateError, seekTimeout, memoryError, memoryFault, clientError, operationReset => ERROR Error[firstPage, status];
ENDCASE =>
BEGIN
IF ~retrying THEN retrying ← TRUE
ELSE
BEGIN
retrying ← FALSE;
SIGNAL BadPage[firstPage, FALSE];
countDone ← countDone+1; -- skip over the bad page
label.filePage ← label.filePage+1;
END;
END;
ENDCASE => ERROR;
pageCount ← pageCount-countDone;
firstPage ← [firstPage+countDone];
ENDLOOP;
END;
END.