DiskHeadSA4000.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Cedar Nucleus: TEMPORARY layer implementing DiskFace on top of SA4000Face
Andrew Birrell May 5, 1983 10:46 am
Levin, August 8, 1983 2:41 pm
Russ Atkinson (RRA) January 29, 1985 1:24:19 am PST
Willie-Sue, January 31, 1985 1:29:45 pm PST
Carl Hauser, November 15, 1985 10:42:19 am PST
DIRECTORY
DiskFace,
PrincOpsUtils USING[ LowHalf ],
SA4000Face,
DiskHeadSA4000Private;
DiskHeadSA4000: CEDAR PROGRAM
IMPORTS PrincOpsUtils, SA4000Face
EXPORTS DiskFace, DiskHeadSA4000Private = BEGIN
Programming Note: This module is temporary until we convert to the Trinity/Klamath disk heads, which export DiskFace (a.k.a. PilotDiskFace) directly. Therefore, this module is allowed to be a bit sordid. In particular, it relies on knowing that the layout of DiskFace.Operation is the same as SA4000Face.Operation, except for word 6, which contains DiskFace.(incrementDataPtr, command, tries) and SA4000Face.(incrementDataPtr, command). As with all the heads, this module relies on its client to provide synchronisation.
ControllerHandle: PUBLIC TYPE = CARDINAL; -- not used: we have only one controller
nullControllerHandle: PUBLIC ControllerHandle ← 0;
GetNextController: PUBLIC PROC[old: ControllerHandle] RETURNS [ControllerHandle] =
TRUSTED { RETURN[ IF old = nullControllerHandle THEN 1 ELSE nullControllerHandle ] };
GetControllerAttributes: PUBLIC PROC[ControllerHandle] RETURNS[globalStateSize: CARDINAL] =
TRUSTED { RETURN[ SA4000Face.globalStateSize ] };
InitializeController: PUBLIC PROC[controller: ControllerHandle, globalState: LONG POINTER, mask: WORD] = TRUSTED {
SA4000Face.Initialize[t: mask, globalState: LOOPHOLE[PrincOpsUtils.LowHalf[globalState]] ];
};
InitializeCleanup: PUBLIC PROC[ControllerHandle] = TRUSTED {
SA4000Face.InitializeCleanup[];
};
DeviceHandle: PUBLIC TYPE = RECORD[SA4000Face.DeviceHandle];
nullDeviceHandle: PUBLIC DeviceHandle ← [SA4000Face.nullDeviceHandle];
GetNextDevice: PUBLIC PROC[old: DeviceHandle] RETURNS[DeviceHandle] =
TRUSTED { RETURN[ [SA4000Face.GetNextDevice[old]] ] };
DetermineDiskShape: PUBLIC PROC[device: DeviceHandle, operation: DiskFace.OperationPtr, mode: DiskFace.DeterminationMode, buffer: LONG POINTERNIL] RETURNS [nowKnown: BOOL] =
TRUSTED { RETURN[TRUE] };
GetDeviceType: PUBLIC PROC[DeviceHandle] RETURNS [DiskFace.Type] =
TRUSTED { RETURN[sa4000] };
GetDeviceAttributes: PUBLIC PROC[device: DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] =
TRUSTED { [cylinders, movingHeads, fixedHeads, sectorsPerTrack] ←
SA4000Face.GetDeviceAttributes[device] };
GetTrueDeviceAttributes: PUBLIC PROC[device: DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] =
TRUSTED { [cylinders, movingHeads, fixedHeads, sectorsPerTrack] ←
SA4000Face.GetTrueDeviceAttributes[device] };
SuggestedTries: PUBLIC PROC[DeviceHandle] RETURNS [DiskFace.Tries] =
TRUSTED { RETURN[24] };
Recalibrate: PUBLIC PROC[device: DeviceHandle] =
TRUSTED { SA4000Face.Recalibrate[device] };
Operations: almost transparent, but we are responsible for retrying soft errors. We maintain a queue of currently initiated requests, using "QueueObj"s, which exist in the extra storage at the end of an Operation object. Note that the SA4000Face aborts subsequent requests after a soft error, but DiskFace does not. Remember that our client promised to synchronize for us!
QueueObj: TYPE = RECORD[
next: Queue, tries, initTries: CARDINAL, initCommand: DiskFace.Command ];
Queue: TYPE = LONG POINTER TO QueueObj;
current: Queue ← NIL;
last: Queue ← NIL;
GetOp: PROC[queue: Queue] RETURNS[DiskFace.OperationPtr] = TRUSTED INLINE
{ RETURN[ LOOPHOLE[queue - SA4000Face.operationSize] ] };
GetQueue: PROC[op: DiskFace.OperationPtr] RETURNS[Queue] = TRUSTED INLINE
{ RETURN[ LOOPHOLE[op + SA4000Face.operationSize] ] };
operationSize: PUBLIC CARDINAL ← SA4000Face.operationSize + SIZE[QueueObj];
Reset: PUBLIC PROC[ControllerHandle] =
TRUSTED BEGIN
current ← NIL;
FOR d: DeviceHandle ← GetNextDevice[nullDeviceHandle], GetNextDevice[d]
UNTIL d = nullDeviceHandle
DO SA4000Face.Reset[d] ENDLOOP;
END;
none: SA4000Face.Command = vv;
saCommand: PACKED ARRAY DiskFace.Op OF PACKED ARRAY DiskFace.Op OF PACKED ARRAY DiskFace.Op OF SA4000Face.Command = [
--header--
noOp: [
--label--
noOp: [ --data-- noOp: none, read: none, write: none, verify: none ],
read: [ --data-- noOp: none, read: none, write: none, verify: none ],
write: [ --data-- noOp: none, read: none, write: none, verify: none ],
verify:[ --data-- noOp: none, read: none, write: none, verify: none ] ],
read: [
noOp: [ --data-- noOp: none, read: none, write: none, verify: none ],
read: [ --data-- noOp: rr,  read: rrr,  write: rrw, verify: rrv ],
write: [ --data-- noOp: rw, read: none, write: rww, verify: none ],
verify:[ --data-- noOp: rv, read: rvr,  write: rvw, verify: rvv ] ],
write: [
noOp: [ --data-- noOp: w,  read: none, write: none, verify: none ],
read: [ --data-- noOp: none, read: none, write: none, verify: none ],
write: [ --data-- noOp: none, read: none, write: www, verify: none ],
verify:[ --data-- noOp: none, read: none, write: none, verify: none ] ],
verify: [
noOp: [ --data-- noOp: none, read: none, write: none, verify: none ],
read: [ --data-- noOp: vr, read: vrr,  write: vrw, verify: vrv ],
write: [ --data-- noOp: vw, read: none, write: vww, verify: none ],
verify:[ --data-- noOp: vv, read: vvr, write: vvw, verify: vvv ] ] ];
Lower level heads implement Pilot file page number layout in labels, but Cedar Face expects INT's
FilePageRep: TYPE = MACHINE DEPENDENT RECORD[ n(0): SELECT OVERLAID * FROM
cedar =>
[cedar(0): INT],
pilot => [
filePageLo(0): CARDINAL,
pilotHi(1): RECORD[
filePageHi(0:0..6): [0..128), -- restricts to 23-bit page numbers (32-bit byte counts)
pad1 (0:7..12): [0..64) ← 0, -- always zero
immutable (0:13..13): BOOLFALSE, -- valid only in label of page 0
temporary (0:14..14): BOOLFALSE, -- valid only in label of page 0
zeroSize (0:15..15): BOOLFALSE
]
],
raw => [
lowHalf(0): CARDINAL,
highHalf(1): CARDINAL
]
ENDCASE
];
Initiate: PUBLIC PROC[diskOp: DiskFace.OperationPtr] =
TRUSTED BEGIN
saOp: SA4000Face.OperationPtr = LOOPHOLE[diskOp];
queue: Queue = GetQueue[diskOp];
command: DiskFace.Command = queue.initCommand ← diskOp.command;
queue.tries ← queue.initTries ← diskOp.tries;
saOp.unused ← 0;
saOp.command ← saCommand[command.header][command.label][command.data];
queue.next ← NIL;
IF current = NIL THEN current ← queue ELSE last.next ← queue;
last ← queue;
BEGIN -- Fix up label file page number representation
kludge: LONG POINTER TO FilePageRep = LOOPHOLE[@saOp.labelPtr.filePage];
... AND kludge.filePageHi = 0 is necessary because an operation may be queued more than once due to failure of a previous operation.
IF kludge.highHalf # 0 THEN kludge.pilotHi ← [filePageHi: kludge.highHalf];
END; -- Fix up
SA4000Face.Initiate[saOp];
END;
diskStatus: PACKED ARRAY SA4000Face.Status OF DiskFace.Status = [
inProgress: inProgress,
goodCompletion: goodCompletion,
dataError: dataCRCError,
labelError: labelCRCError,
labelCheck: labelVerifyError,
seekTimeout: seekTimeout,
sectorTimeout: otherError,
notReady: notReady,
wrongSector: otherError,
wrongCylinder: otherError,
wrongHead: otherError,
hardwareError: otherError ];
statusStats: PUBLIC ARRAY SA4000Face.Status OF INTALL[0];
retries: PUBLIC INT ← 0;
recalibrates: PUBLIC INT ← 0;
lastErrorStatus: PUBLIC SA4000Face.Status ← inProgress;
Poll: PUBLIC PROC
[ControllerHandle]
RETURNS [status: DiskFace.Status, op: DiskFace.OperationPtr, retriedCount: CARDINAL] =
TRUSTED BEGIN
completed: Queue;
pollStatus: SA4000Face.Status;
IF current = NIL THEN RETURN[clientError, NIL, 0];
op ← GetOp[current];
pollStatus ← SA4000Face.Poll[LOOPHOLE[op]];
status ← diskStatus[pollStatus];
retriedCount ← current.initTries - current.tries;
SELECT status FROM
goodCompletion => { completed ← current; current ← current.next };
inProgress => completed ← NIL;
ENDCASE => -- some sort of error: possibly retry this one, and requeue all others.
BEGIN
lastErrorStatus ← pollStatus;
current.tries ← current.tries - 1;
IF current.tries = 0
-- RRA sez let's not do this: OR status = labelVerifyError --
THEN { -- give up on this operation -- completed ← current; current ← current.next }
ELSE {
completed ← NIL;
status ← inProgress;
IF current.tries MOD 4 = 0 THEN {Recalibrate[op.device]; recalibrates ← recalibrates + 1};
retries ← retries + 1;
};
FOR other: Queue ← current, other.next UNTIL other = NIL DO
SA4000Face.Initiate[LOOPHOLE[GetOp[other]]];
ENDLOOP;
END;
IF status # inProgress THEN {
--restore word 6--
op.command ← completed.initCommand;
op.tries ← completed.initTries;
BEGIN -- Fix up label file page number representation
kludge: LONG POINTER TO FilePageRep = LOOPHOLE[@op.labelPtr.filePage];
IF kludge.highHalf # 0 THEN kludge.highHalf ← kludge.pilotHi.filePageHi;
END; -- Fix up
};
statusStats[pollStatus] ← statusStats[pollStatus] + 1;
END;
GetFormattingUnit: PUBLIC PROC[DeviceHandle] RETURNS [DiskFace.FormattingUnit] =
TRUSTED { RETURN[arbitrary] };
END.