-- FormatTridentImpl.mesa
-- Last Edited by: Taft, May 22, 1983 2:45 pm
DIRECTORY
DeviceTypes USING [sa4000],
DiskChannel USING [
Address, Create, Delete, Drive, DiskPageNumber, GetDriveAttributes,
GetPageAddress, GetPageNumber, Handle, PVHandle],
Environment USING [Base, first64K, wordsPerPage],
FormatTrident,
Inline USING [BITNOT, LowHalf, LongCOPY],
MicrocodeFile,
PhysicalVolume USING [], -- exports Handle
PilotDisk USING [Label, NextLabel],
Process USING [Yield],
RandomCard USING [Init, Next],
ResidentHeap USING [MakeNode],
SA4000Face USING [
Command, DeviceHandle, DiskAddress, Initiate, Operation, OperationPtr,
operationSize, Poll, Recalibrate, Status],
SA4000FaceExtras USING [www],
Space USING [
Create, defaultWindow, Handle, LongPointer, Map, Pointer, Unmap, mds],
SpecialSystem USING [nullProcessorID],
String USING [AppendString],
System USING [GreenwichMeanTime],
SystemInternal USING [UniversalID],
Zone USING [Status];
FormatTridentImpl: PROGRAM -- should be a monitor since globals shared
IMPORTS DiskChannel, Inline, MicrocodeFile, PilotDisk, Process, RandomCard, ResidentHeap,
SA4000Face, Space, String
EXPORTS FormatTrident, PhysicalVolume
SHARES DiskChannel =
BEGIN OPEN Inline;
Handle: PUBLIC TYPE = DiskChannel.PVHandle;
DiskPageNumber: TYPE = FormatTrident.DiskPageNumber;
RetryLimit: TYPE = [0..10);
retryLimit: RetryLimit = LAST[RetryLimit];
space: Space.Handle = Space.Create[
size: 1, parent: Space.mds];
op: SA4000Face.OperationPtr = MakeOperation[];
BadPage: PUBLIC SIGNAL [p: DiskPageNumber] = CODE;
PassStarting: PUBLIC SIGNAL [pass: CARDINAL, operation: FormatTrident.Operation] = CODE;
MicrocodeInstallFailure: PUBLIC SIGNAL [m: FormatTrident.FailureType] = CODE;
NotTrident: PUBLIC ERROR = CODE;
Format: PUBLIC PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL,
passes: CARDINAL] =
BEGIN
ckData: LONG POINTER = Space.LongPointer[space];
cnl: DiskChannel.Handle;
label: PilotDisk.Label;
SetLabel: PROC [value: CARDINAL] =
BEGIN
SetBlock[@label, SIZE[PilotDisk.Label], value];
label.pad1 ← 0;
IF label.filePageLo#0 OR label.filePageHi#0 THEN
label.immutable ← label.temporary ← label.zeroSize ← FALSE;
END;
AssertTrident[h, firstPage, count];
Space.Map[space, Space.defaultWindow];
cnl ← DiskChannel.Create[h.drive, [LONG[0]]];
BEGIN
ENABLE UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]};
[] ← RandomCard.Init[-1];
FOR pass: CARDINAL IN [0..passes) DO
labelValue: CARDINAL ← (IF pass MOD 2 = 0 THEN RandomCard.Next[] ELSE BITNOT[labelValue]);
SIGNAL PassStarting[pass+1, write];
SetLabel[labelValue];
FOR i: CARDINAL IN [0..Environment.wordsPerPage) DO
(ckData+i)↑ ← (IF pass MOD 2 = 0 THEN RandomCard.Next[] ELSE BITNOT[(ckData+i)↑]);
ENDLOOP;
Transfer[h, cnl, firstPage, count,
(IF pass=0 THEN SA4000FaceExtras.www ELSE vww), @label, ckData];
SIGNAL PassStarting[pass+1, read];
SetLabel[labelValue];
Transfer[h, cnl, firstPage, count, vvv, @label, ckData, 1];
ENDLOOP;
END;
Space.Unmap[space];
DiskChannel.Delete[cnl];
END;
initialMicrocodeLabel: PilotDisk.Label = [
fileID: LOOPHOLE[SystemInternal.UniversalID[
processor: SpecialSystem.nullProcessorID, sequence: FormatTrident.hardUCodeSerial]],
filePageLo: 0, filePageHi: 0, immutable: FALSE, temporary: FALSE, zeroSize: FALSE,
type: [0], bootChainLink: LOOPHOLE[LONG[0]]];
IdentifyInitialMicrocode: PUBLIC PROCEDURE [h: Handle, s: STRING]
RETURNS [microcodeInstalled: BOOLEAN ← FALSE, time: System.GreenwichMeanTime] =
BEGIN
label: PilotDisk.Label ← initialMicrocodeLabel;
cnl: DiskChannel.Handle;
header: POINTER TO MicrocodeFile.Header;
AssertTrident[h];
cnl ← DiskChannel.Create[h.drive, [LONG[0]]];
Space.Map[space, Space.defaultWindow];
BEGIN
Transfer[h: h, channel: cnl, firstPage: FormatTrident.firstHardUCodePage, count: 1,
cmd: vvr, label: @label, data: Space.LongPointer[space] !
BadPage => GOTO error];
header ← Space.Pointer[space];
IF header.name.length IN [1..header.name.maxlength] AND
header.name.maxlength<=MicrocodeFile.maxNameLength AND
header.name.length<=s.maxlength THEN
BEGIN
time ← MicrocodeFile.GMTFromBCPLTime[header.createDate];
s.length ← 0;
String.AppendString[s, @header.name];
microcodeInstalled ← TRUE;
END;
EXITS
error => NULL;
END;
Space.Unmap[space];
DiskChannel.Delete[cnl];
END;
InstallBootMicrocode: PUBLIC PROC [
h: Handle, getPage: PROC RETURNS [LONG POINTER]] =
BEGIN
cnl: DiskChannel.Handle;
AssertTrident[h];
cnl ← DiskChannel.Create[h.drive, [LONG[0]]];
Space.Map[space, Space.defaultWindow];
InstallBootMicrocode1[
h, cnl, Space.LongPointer[space], getPage
! UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}];
Space.Unmap[space];
DiskChannel.Delete[cnl];
END;
Scan: PUBLIC PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL,
passes: CARDINAL] =
BEGIN
label: PilotDisk.Label;
cnl: DiskChannel.Handle;
AssertTrident[h];
cnl ← DiskChannel.Create[h.drive, [LONG[0]]];
Space.Map[space, Space.defaultWindow];
FOR pass: CARDINAL IN [0..passes) DO
SIGNAL PassStarting[pass+1, read];
Transfer[
h, cnl, firstPage, count, vrr, @label, Space.LongPointer[space]
! UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}];
ENDLOOP;
Space.Unmap[space];
DiskChannel.Delete[cnl];
END;
-- Private Procedures
AssertTrident: PROC [
h: Handle, first: DiskPageNumber ← 0, count: LONG CARDINAL ← 0] =
BEGIN
SELECT DiskChannel.GetDriveAttributes[h.drive].deviceType FROM
DeviceTypes.sa4000 => RETURN; -- kludge for now, really Trident
ENDCASE => ERROR NotTrident
END;
CopyPage: PROC [from, to: LONG POINTER] = INLINE
{LongCOPY[from: from, to: to, nwords: Environment.wordsPerPage]; };
GetDiskAddress: PROC [h: DiskChannel.Handle, p: DiskPageNumber]
RETURNS [SA4000Face.DiskAddress] =
BEGIN
x: DiskChannel.Address = DiskChannel.GetPageAddress[h, p];
RETURN[[cylinder: x.cylinder, head: x.head, sector: x.sector]];
END;
GetPageNumber: PROC [d: DiskChannel.Drive, a: SA4000Face.DiskAddress]
RETURNS [DiskPageNumber] =
BEGIN
RETURN[DiskChannel.GetPageNumber[
d, [cylinder: a.cylinder, head: a.head, sector: a.sector]]]
END;
-- h has been asserted to be SA4000
InstallBootMicrocode1: PROC [
h: Handle, cnl: DiskChannel.Handle, myPage: LONG POINTER,
getPage: PROC RETURNS [LONG POINTER]] =
BEGIN
bits: LONG POINTER;
device: SA4000Face.DeviceHandle = DiskChannel.GetDriveAttributes[
h.drive].deviceHandle;
thisPage, prevPage: DiskPageNumber ← FormatTrident.firstHardUCodePage;
label: PilotDisk.Label ← initialMicrocodeLabel;
GetDA: PROC [p: DiskPageNumber] RETURNS [SA4000Face.DiskAddress] = INLINE
{RETURN[GetDiskAddress[cnl, p]]};
IO: PROC [command: SA4000Face.Command, diskAddress: SA4000Face.DiskAddress,
label: POINTER TO PilotDisk.Label]
RETURNS [success: BOOLEAN] =
BEGIN
rCount: RetryLimit ← 0;
status: SA4000Face.Status;
op↑ ← [
command: command, device: device, clientHeader: diskAddress,
pageCount: 1,
labelPtr: label, dataPtr: myPage, incrementDataPtr: FALSE];
SA4000Face.Initiate[op];
DO
SELECT status ← SA4000Face.Poll[op] FROM
inProgress => {Process.Yield[]; LOOP; };
goodCompletion => EXIT;
ENDCASE =>
BEGIN
SELECT rCount FROM
>= retryLimit => RETURN[FALSE];
= retryLimit/2 => SA4000Face.Recalibrate[device];
ENDCASE => NULL;
rCount ← rCount + 1;
op.pageCount ← 1;
SA4000Face.Initiate[op];
END
ENDLOOP;
label.filePageLo ← label.filePageLo-1; -- undo +1 done by microcode
RETURN[IF command = vww THEN IO[vvv, diskAddress, label] ELSE TRUE];
END;
bits ← getPage[];
IF bits = NIL THEN GOTO emptyFile;
CopyPage[from: bits, to: myPage];
DO
bits ← getPage[];
label.bootChainLink ← LOOPHOLE[LONG[IF bits=NIL THEN -1 ELSE 0]];
DO
IF thisPage >= FormatTrident.pagesReservedInPartition1 THEN GOTO tooBig;
IF IO[vww, GetDA[thisPage], @label] THEN EXIT;
IF thisPage = FormatTrident.firstHardUCodePage THEN GOTO firstPageBad;
thisPage ← thisPage + 1;
ENDLOOP;
IF thisPage # prevPage + 1 AND thisPage # FormatTrident.firstHardUCodePage THEN
-- have to fix up previous link if we had an error
BEGIN
label.filePageLo ← label.filePageLo-1;
IF ~IO[vvr, GetDA[prevPage], @label] THEN GOTO flakey;
label.bootChainLink ← LOOPHOLE[GetDA[thisPage]];
IF ~IO[vww, GetDA[prevPage], @label] THEN GOTO flakey;
label.filePageLo ← label.filePageLo+1;
END;
IF bits = NIL THEN EXIT;
-- we are done and have written a zero link in the last page
CopyPage[from: bits, to: myPage];
prevPage ← thisPage;
thisPage ← thisPage + 1;
label.filePageLo ← label.filePageLo+1;
ENDLOOP;
EXITS
emptyFile => SIGNAL MicrocodeInstallFailure[emptyFile];
firstPageBad => SIGNAL MicrocodeInstallFailure[firstPageBad];
flakey => SIGNAL MicrocodeInstallFailure[flakeyPageFound];
tooBig => SIGNAL MicrocodeInstallFailure[microcodeTooBig];
END;
MakeOperation: PROC RETURNS [SA4000Face.OperationPtr] =
BEGIN
rp: Environment.Base RELATIVE POINTER TO SA4000Face.Operation;
NoWay: ERROR = CODE;
status: Zone.Status;
[rp, status] ← ResidentHeap.MakeNode[n: SA4000Face.operationSize, alignment: a16];
IF status # okay THEN ERROR NoWay;
RETURN[@Environment.first64K[rp]]
END;
SetBlock: PROC [blk: LONG POINTER, length, v: CARDINAL] = INLINE
{blk↑ ← v; LongCOPY[from: blk, to: blk + 1, nwords: length - 1]; };
-- SA4000-ness has been asserted
Transfer: PROC [
h: Handle, channel: DiskChannel.Handle, firstPage: DiskPageNumber,
count: LONG CARDINAL, cmd: SA4000Face.Command,
label: POINTER TO PilotDisk.Label, data: LONG POINTER,
retries: RetryLimit ← retryLimit] =
BEGIN
device: SA4000Face.DeviceHandle = DiskChannel.GetDriveAttributes[
h.drive].deviceHandle;
rCount: RetryLimit ← 0;
status: SA4000Face.Status;
runStartAddr: SA4000Face.DiskAddress ← GetDiskAddress[channel, firstPage];
Ooops: PROC RETURNS [notDoneYet: BOOLEAN] =
BEGIN
rCount ← IF op.clientHeader = runStartAddr THEN rCount + 1 ELSE 0;
SELECT TRUE FROM
rCount >= retries =>
BEGIN
page: DiskPageNumber = GetPageNumber[h.drive, op.clientHeader];
SIGNAL BadPage[page];
op.clientHeader ← GetDiskAddress[channel, page + 1];
op.pageCount ← op.pageCount - 1;
PilotDisk.NextLabel[label]; -- Fix up the label to the next page
rCount ← 0;
END;
rCount = retryLimit/2 OR (status IN [wrongSector..wrongHead] AND rCount = retries/2) =>
SA4000Face.Recalibrate[device];
ENDCASE => NULL;
runStartAddr ← op.clientHeader;
IF (notDoneYet ← op.pageCount > 0) THEN SA4000Face.Initiate[op];
END;
op↑ ← [
device: device, clientHeader: runStartAddr, pageCount: NULL,
labelPtr: label, dataPtr: data, incrementDataPtr: FALSE, command: cmd];
WHILE count>0 DO
thisCount: CARDINAL = IF count>LAST[CARDINAL] THEN LAST[CARDINAL] ELSE LowHalf[count];
op.pageCount ← thisCount;
SA4000Face.Initiate[op];
DO
SELECT status ← SA4000Face.Poll[op] FROM
inProgress => {Process.Yield[]; LOOP};
goodCompletion => EXIT;
ENDCASE => IF Ooops[] THEN LOOP ELSE EXIT;
ENDLOOP;
count ← count-thisCount;
ENDLOOP;
END;
END.
LOG
Time: June 1, 1980 1:23 AM By: Forrest Action: Changed to use sanitized interface. Added limit checking on InstallMicrocode. Trimmed log.
Time: July 28, 1980 8:22 AM By: Forrest Action: Retrofited McJones changes for new SA4000face. Converted to SA1000and4000.
Time: September 30, 1980 5:31 PM By: Luniewski Action: Increment File Page numbers in labels after finding a bad page in Transfer.
December 12, 1980 10:39 AM Taft Create from FormatSA1000andSA4000impl.mesa for Dorado.
March 10, 1981 5:31 PM: Taft Make Transfer work for run of >65535 pages.
17-Jun-82 10:06:54 Taft Re-implement InstallBootMicrocode for Dorado
20-Jun-82 16:18:48 Taft Add IdentifyInitialMicrocode
May 22, 1983 12:27 pm Taft Change Format to do multiple passes with random data.