DIRECTORY DiskFace, PrincOpsUtils USING[ LowHalf ], SA4000Face; DiskHeadSA4000: CEDAR PROGRAM IMPORTS PrincOpsUtils, SA4000Face EXPORTS DiskFace = BEGIN 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 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] }; 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 ] ] ]; 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. <Cedar Nucleus: TEMPORARY layer implementing DiskFace on top of SA4000Face DiskHeadSA4000.mesa Andrew Birrell May 5, 1983 10:46 am Last Edited by: Levin, August 8, 1983 2:41 pm 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. 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! Ê˘JšœI™IJšœ™Jšœ$™$J™-šÏk ˜ J˜ Jšœœ ˜J˜ —J˜šœœ˜Jšœ˜!Jšœ ˜—J˜Jš˜J˜JšÏbœú™‹J˜JšœœœœÏc(˜RJ˜Jšœœ˜2J˜šÏnœœœœ˜RJš œœœœœ˜U—J˜š  œœœœœ˜[Jšœœ!˜1—J˜š  œœœ,œœœ˜hJšœ/œ)˜g—J˜š œœœ˜2Jšœ$˜+—J˜Jšœœœœ˜