FormatDiskDorado.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Birrell December 6, 1983 1:15 pm
Taft, January 31, 1984 11:54:45 am PST
Willie-Sue, February 24, 1984 6:15:42 pm PST
DIRECTORY
BasicTime USING [FromPupTime, GMT, OutOfRange],
ConvertUnsafe USING [ToRope],
Disk USING [Channel, Command, defaultTries, DoIO, GetBootChainLink, Label, PageCount, PageNumber, Request, Status],
DiskFace USING [DeviceHandle, DontCare, GetDeviceAttributes, GetNextDevice, nullDeviceHandle],
FormatDisk,
PrincOps USING [zEXCH],
Rope USING [ROPE],
VM USING [AddressForPageNumber, Allocate, Free, Interval, Pin, Unpin];
FormatDiskDorado:
MONITOR
-- only one guy in here at a time!
IMPORTS BasicTime, ConvertUnsafe, DiskFace, Disk, VM
EXPORTS FormatDisk = { 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] = {
Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: commandTable[operation], label: label, data: data, reportSoftErrors: TRUE];
};
commandTable:
ARRAY Operation
OF Disk.Command = [
format: [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]] = {
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];
{ ENABLE UNWIND => {VM.Unpin[vmInterval]; VM.Free[vmInterval]};
DO
label: Disk.Label ← initialMicrocodeLabel;
ok: BOOLEAN;
IF (ok ← getPage[pageBuffer])
THEN
{
ENABLE BadPage, Error =>
IF thisPage=hardUCodeStart THEN GOTO firstPageBad
ELSE {thisPage ← [thisPage+1]; RETRY};
IF thisPage>=hardUCodeStart+hardUCodeSize THEN ERROR MicrocodeInstallFailure[microcodeTooBig];
label.dontCare ← LOOPHOLE[LONG[0]];
label.filePage ← thisPage-hardUCodeStart;
Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer];
label.filePage ← thisPage-hardUCodeStart;
Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, verify, verify], label: @label, data: pageBuffer];
};
IF thisPage#Disk.PageNumber[prevPage+1]
OR ~ok
THEN
{ ENABLE BadPage, Error => GOTO flakeyPageFound;
label.filePage ← prevPage-hardUCodeStart;
Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, verify, read], label: @label, data: pageBuffer];
label.filePage ← prevPage-hardUCodeStart;
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];
IF Disk.PageNumber[prevPage+1] < hardUCodeStart+hardUCodeSize
THEN
Write different label at page after EOF or break in run so as to assure that a label check error will occur during reading and the bootChainLink will be noticed
{
label ← nullLabel;
Transfer[channel: channel, firstPage: Disk.PageNumber[prevPage+1], pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer ! BadPage, Error => CONTINUE];
};
};
IF ~ok THEN EXIT;
thisPage ← [(prevPage ← thisPage)+1];
REPEAT
firstPageBad => ERROR MicrocodeInstallFailure[firstPageBad];
flakeyPageFound => ERROR MicrocodeInstallFailure[flakeyPageFound];
ENDLOOP;
};
VM.Unpin[vmInterval];
VM.Free[vmInterval];
};
IdentifyInitialMicrocode:
PUBLIC
ENTRY
PROC [channel: Disk.Channel]
RETURNS [microcodeInstalled:
BOOLEAN, time: BasicTime.GMT, name: Rope.
ROPE] = {
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;
{
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
{
time ← BasicTime.FromPupTime[GMTFromBCPLTime[uCodeHeader.createDate] !
BasicTime.OutOfRange => GOTO error];
name ← ConvertUnsafe.ToRope[@uCodeHeader.name];
microcodeInstalled ← TRUE;
};
};
VM.Unpin[vmInterval];
VM.Free[vmInterval];
};
hardUCodeFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 064732B, 064732B]; -- 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
nullFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 0, 0];
nullLabel: Disk.Label = [fileID: [abs[LOOPHOLE[nullFileID]]], filePage: 0, attributes: LOOPHOLE[0], dontCare: LOOPHOLE[LONG[0]]];
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 ← [4];
hardUCodeSize: PUBLIC Disk.PageCount ← 3*28-4; -- 3 cylinders overhead
altoRegionJargon: PUBLIC Rope.ROPE ← "partitions";
altoRegionsMax: PUBLIC INT; -- computed by Start
altoRegionsStart: PUBLIC Disk.PageNumber ← [0]; -- overlaps with initial microcode
altoRegionsSize: PUBLIC Disk.PageCount ← 815*28; -- one surface of the disk
altoRegionsBottomUp: PUBLIC BOOL ← FALSE; -- prefer highest partition (5 or 19)
Initialization
Start:
PUBLIC
PROC =
{
device: DiskFace.DeviceHandle = DiskFace.GetNextDevice[DiskFace.nullDeviceHandle];
cylinders: CARDINAL;
IF device=DiskFace.nullDeviceHandle THEN ERROR;
cylinders← DiskFace.GetDeviceAttributes[device].cylinders;
moving heads is ALWAYS 1 for a "system" disk (RD0), so the following call doesn't work
altoRegionsMax ← DiskFace.GetDeviceAttributes[device].movingHeads;
altoRegionsMax ← cylinders/815; -- terrible kludge !!!!!
};
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;
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 =>
{
IF ~retrying THEN retrying ← TRUE
ELSE {
retrying ← FALSE;
SIGNAL BadPage[firstPage, FALSE];
countDone ← countDone+1; -- skip over the bad page
label.filePage ← label.filePage+1;
};
};
ENDCASE => ERROR;
pageCount ← pageCount-countDone;
firstPage ← [firstPage+countDone];
ENDLOOP;
};
}.