Cedar Nucleus: TEMPORARY layer implementing DiskFace on top of SA4000Face
DiskHeadSA4000.mesa
Andrew Birrell May 5, 1983 10:46 am
DIRECTORY
DiskFace,
PrincOpsUtils USING[ LowHalf ],
SA4000Face;
DiskHeadSA4000:
CEDAR
PROGRAM
IMPORTS PrincOpsUtils, SA4000Face
EXPORTS DiskFace =
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: 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
POINTER ←
NIL]
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] };
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: none, 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 ] ] ];
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;
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 ];
Poll:
PUBLIC
PROC[ControllerHandle]
RETURNS [status: DiskFace.Status, op: DiskFace.OperationPtr, retriedCount:
CARDINAL] =
TRUSTED BEGIN
completed: Queue;
IF current = NIL THEN RETURN[clientError, NIL, 0];
op ← GetOp[current];
status ← diskStatus[SA4000Face.Poll[LOOPHOLE[op]]];
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
current.tries ← current.tries - 1;
IF current.tries = 0 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] };
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 };
END;
GetFormattingUnit:
PUBLIC
PROC[DeviceHandle]
RETURNS [DiskFace.FormattingUnit] =
TRUSTED { RETURN[arbitrary] };
END.