Cedar Nucleus: disk face
DiskFace.mesa
Andrew Birrell May 3, 1983 1:41 pm
DiskFace: CEDAR DEFINITIONS =
BEGIN
Note that the Head does not perform any synchronisation. Clients must make their own arrangements to avoid conflict over use of this interface. Note also that heads may dependent on the layout of MACHINE DEPENDENT types in this interface.
Page size and numbering
wordsPerPage: CARDINAL = 256;
PageNumber: TYPE = RECORD[INT];
Sequential numbering of pages on a pack, starting from 0. Adjacent physical sectors have consecutive PageNumber's.
PageCount: TYPE = INT;
Controllers
ControllerHandle: TYPE[1];
GetNextController: PROC[ControllerHandle] RETURNS [ControllerHandle];
nullControllerHandle: READONLY ControllerHandle;
GetControllerAttributes: PROC[ControllerHandle] RETURNS [globalStateSize: CARDINAL];
InitializeController: PROC[controller: ControllerHandle, globalState: LONG POINTER, mask: WORD];
"globalState" is in first 64K of VM. "mask" indicates naked notify channels
InitializeCleanup: PROC[ControllerHandle];
Reset: PROC[ControllerHandle];
Restore the controller (as nearly as possible) to the state existing immediately after InitializeController. Clients may see operations associated with a reset controller coming back as operationReset.
Devices
Type: TYPE = MACHINE DEPENDENT {
null(0),
sa800(1),
sa1000(2),
sa4000(3),
cdc9730(4),
ethernet(5),
(LAST[CARDINAL])
};
DeviceHandle: TYPE[1];
nullDeviceHandle: READONLY DeviceHandle;
GetNextDevice: PROC[DeviceHandle] RETURNS[DeviceHandle];
DeterminationMode: TYPE = { quickReadOnly, longReadOnly, writeEnabled };
DetermineDiskShape: PROC[device: DeviceHandle, operation: OperationPtr, mode: DeterminationMode, buffer: LONG POINTERNIL] RETURNS [nowKnown: BOOL];
GetDeviceType: PROC[DeviceHandle] RETURNS [Type];
GetDeviceAttributes: PROC[DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL];
Before DetermineDiskShape has returned TRUE, some or all attributes may be unknownAttribute.
unknownAttribute: CARDINAL = LAST[CARDINAL];
Tries: TYPE = (0..400B];
An indication of how hard the head should work when retrying a failed operation. Increasing values of "Tries" indicates that extra effort should be expended in trtrying the operation. Retrying includes device specific error recovery (ECC, recalibrates, ...).
SuggestedTries: PROC[DeviceHandle] RETURNS [Tries];
Value of "Tries" to cause the default error recovery algorithm for the device.
Recalibrate: PROC[DeviceHandle];
Forces a recalibrate at the beginning of the next operation. The Head may also voluntarily supply recalibrates as part of its retry logic.
Operations
DiskAddress: TYPE = MACHINE DEPENDENT RECORD[
cylinder(0): CARDINAL,
head(1:0..7): [0..256),
sector(1:8..15): [0..256)
];
Command: TYPE = MACHINE DEPENDENT RECORD[header, label, data: Op];
Op: TYPE = MACHINE DEPENDENT { noOp, read, write, verify };
Label: TYPE = MACHINE DEPENDENT RECORD[
fileID(0): FileID,
filePage(5): INT,
attributes(7): Attributes,
dontCare(8): DontCare ];
The fields "fileID", "attributes" and "dontCare" have opaque types and are not interpreted by the Head, only by the higher level software. When verifying a label, all fields except "dontCare" must match. When the head/microcode moves to next page of a run, label.filePage is incremented.
FileID: TYPE = MACHINE DEPENDENT RECORD[id(0): SELECT OVERLAID * FROM
rel => [ relID(0): RelID, fill4(4): CARDINAL ← 0],
abs => [ absID(0): AbsID ],
ENDCASE ];
RelID: TYPE[4];
AbsID: TYPE[5];
Attributes: TYPE[1];
DontCare: TYPE[2];
Ignored in label verification. Typically used for boot chain links, in which case it's actually a DiskFace.Address.
DeviceOpStatus: TYPE[2];
device-dependent status information about an operation; used only inside the head.
operationSize: READONLY CARDINAL;
The storage pointed to by an OperationPtr should be at least operationSize words long (i.e. must be longer than SIZE[Operation]), to allow extra words for use by the Head.
OperationPtr: TYPE = LONG POINTER TO Operation;
Operation: TYPE = MACHINE DEPENDENT RECORD[ -- 16-word aligned and in first 64K of VM
clientHeader(0): DiskAddress, -- address of first sector of request
labelPtr(2): LONG POINTER TO Label, -- first label of request. Must not be NIL.
dataPtr(4): LONG POINTER, -- first (VM page aligned) data address of operation
incrementDataPtr(6:0..0): BOOL, -- increment dataPtr after each successful data r/w/v
unused(6:1..1): [0..1] ← NULL,
command(6:2..7): Command,
tries(6:8..15): Tries, -- indication of how hard to retry after errors
pageCount(7): CARDINAL, -- number of (remaining) sectors for this operation
deviceStatus(10B): DeviceOpStatus ← NULL, -- used by the Head
diskHeader(12B): DiskAddress ← NULL, -- if command.header=read, places result here
device(14B): DeviceHandle
];
Initiate: PROC[OperationPtr];
Note a new disk request and arrange for its eventual execution. Note that the client has no control over what controller services the operation. Each controller will notify its naked notify channels when an operation serviced by that controller completes.
Poll: PROC[ControllerHandle] RETURNS [status: Status, op: OperationPtr, retriedCount: CARDINAL];
Poll a particular controller. Polling an idle controller will result in the result [clientError, NIL]. Operations will not necessarily come back in the order they were submitted, and an error in a particular operation does not abort the rest.
Status: TYPE = {
inProgress,
goodCompletion,
notReady,
recalibrateError,
seekTimeout,
headerCRCError,
labelCRCError,
dataCRCError,
headerNotFound,
labelVerifyError,
dataVerifyError,
overrunError,
writeFault,
memoryError,
memoryFault,
clientError,
operationReset,
otherError };
Formatting
FormattingUnit: TYPE = {arbitrary, singleTrack};
GetFormattingUnit: PROC[DeviceHandle] RETURNS [FormattingUnit];
END.