Disk.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell July 8, 1983 1:25 pm
Russ Atkinson (RRA) January 30, 1985 9:41:28 pm PST
Doug Wyatt, February 27, 1985 8:47:10 am PST
This is the lowest level of shared access to the disks. All drives and controllers are owned by DiskImpl, and must be accessed only through this interface. This interface allows interleaved access to drives, and allows multiple clients to access any particular drive. IO operations provided here are synchronous: the caller is suspended until the IO completes. However, multiple clients may initiate operations without waiting for another client's operation to complete. Lower levels are responsible for suitable device-dependent retries to handle soft errors; errors reported here are hard. Access to the drives is in terms of a "Channel", which corresponds to an occurence of a drive coming online. A channel remains usable for IO transfers until, and only until, the corresponding drive goes offline. Presenting an invalid channel to DoIO causes return code "invalid".
DIRECTORY
DiskFace USING [Command, DeterminationMode, DeviceHandle, DontCare, Label, PageCount, PageNumber, Status, Tries, Type];
Disk: CEDAR DEFINITIONS
= BEGIN
PageNumber: TYPE = DiskFace.PageNumber;
PageCount: TYPE = DiskFace.PageCount;
Add:
PROC [p: PageNumber, n: PageCount]
RETURNS [PageNumber] =
INLINE {
may be negative
RETURN[ [p+n] ]
};
Channel: TYPE = LONG POINTER TO ChannelObject;
ChannelObject: TYPE;
NextChannel:
PROC [prev: Channel, wait:
BOOL ←
FALSE]
RETURNS [Channel];
Enumerates valid handles, in order of their drives coming online. Note that a handle may rapidly become invalid. If "prev" is NIL, returns the oldest online handle. If "wait" and "prev" is the most recent handle, waits until another handle is available, i.e. until some drive comes online.
InspectDiskShape:
PROC [channel: Channel, mode: DiskFace.DeterminationMode]
RETURNS [
BOOL];
Ascertains and remembers the characteristics of the drive and currently mounted pack (if any). Returns FALSE if determination requires drive to be ready and it isn't, or if the shap can't be determined according to the mode.
SameDrive:
PROC [a, b: Channel]
RETURNS [
BOOL];
Tells whether the handles are for the same drive.
GetDeviceFromChannel:
PROC [channel: Channel]
RETURNS [DeviceHandle: DiskFace.DeviceHandle];
Given a channel, return the device it is for
Valid:
PROC [channel: Channel]
RETURNS [
BOOL];
Assuming the handle was once valid, tells whether it is still valid.
DriveAttributes:
PROC [channel: Channel]
RETURNS [type: DiskFace.Type, ordinal:
INT, ready:
BOOL, nPages: PageCount];
nPages = 0 implies that the actual number isn't known. To get the actual number, call InspectDiskShape and persuade that procedure to return TRUE, then call DriveAttributes again.
Command: TYPE = DiskFace.Command;
Label: TYPE = DiskFace.Label;
Tries: TYPE = DiskFace.Tries;
defaultTries: Tries = 24;
Request:
TYPE =
RECORD[
diskPage: PageNumber, -- disk page number of first page of transfer --
data: LONG POINTER, -- first data page
incrementDataPtr: BOOL ← TRUE, -- if TRUE, increment data pointer after each successful page.
command: Command,
tries: Tries ← defaultTries,
count: PageCount, -- number of pages --
seek: PageNumber ← [0] -- optional address for initiating a seek after the transfer
];
Status:
TYPE =
RECORD[
SELECT type: *
FROM
changed => NULL,
unchanged => [status: DiskFace.Status],
ENDCASE
];
ok: Status = [unchanged[goodCompletion]]; -- transfer completed successfully
labelCheck: Status = [unchanged[labelVerifyError]]; -- label verify was requested and failed
notReady: Status = [unchanged[notReady]]; -- drive was not ready at some point in transfer
invalid: Status = [changed[]]; -- drive's ChangeCount changed; no IO performed
Other values of Status reflect hardware error or caller software bug.
DoIO: UNSAFE PROC [channel: Channel,
label: LONG POINTER TO Label, request: LONG POINTER TO Request]
RETURNS [status: Status, countDone: PageCount];
GetBootChainLink:
PROC [channel: Channel, diskPage: PageNumber]
RETURNS [DiskFace.DontCare];
Translates a page number into the form suitable for use as a boot chain link in a label.
GetPageNumber: PROC [channel: Channel, link: DiskFace.DontCare] RETURNS [PageNumber];
Pulses: TYPE = LONG CARDINAL;
GetStatistics:
PROC
RETURNS [active, total: Pulses, reads, writes, readPages, writePages:
INT];
"active" and "total" are measured in fine-grain clock pulses (PrincOpsUtils.GetClockPulses[]). If [a1, t1] and [a2, t2] are results of successive calls of this procedure, then the fraction of time that the disk channel has had requests on a controller queue between the calls is given by (a2-a1)/(t2-t1).
END.