Cedar Nucleus: Dorado implementation of SA4000Face
DiskHeadDorado.mesa
Last Edited by: Taft, February 24, 1983 5:26 pm
Last Edited by: Andrew Birrell, May 5, 1983 2:48 pm
DIRECTORY
DeviceCleanup USING [Await, Item, Reason],
DiskFace USING [Label],
DoradoInputOutput USING [IOAddress, DMuxAddr, Output, ResetDisk, RWMufMan],
PrincOpsUtils USING [BITAND, BITOR, LowHalf],
SA4000Face;
DiskHeadDorado:
PROGRAM
IMPORTS DeviceCleanup, DoradoInputOutput, PrincOpsUtils
EXPORTS SA4000Face
SHARES SA4000Face =
BEGIN OPEN SA4000Face;
Data structures shared with disk microcode
CSBPtr: TYPE = LONG POINTER TO CSB;
CSB:
TYPE =
MACHINE
DEPENDENT
RECORD [
head (0): IOCBQueueHead,
interruptMask (1): WORD,
drive (2): Drive, -- drive currently selected
cylinder (3): CARDINAL, -- negative => need to restore disk
Remainder of CSB is not used by the microcode
tail (4): IOCBLongPtr];
IOCBQueueHead:
TYPE =
MACHINE
DEPENDENT
RECORD [
SELECT
OVERLAID *
FROM
untagged => [iocb: IOCBShortPtr],
tagged => [highBits: [0..77777B], tag: {idle, active}],
ENDCASE];
nilIOCBQueueHead: IOCBQueueHead = [untagged[iocb: nilIOCBShortPtr]];
IOCB must be odd word aligned
IOCBShortPtr: TYPE = SA4000Face.Base RELATIVE POINTER TO IOCB;
IOCBLongPtr: TYPE = LONG POINTER TO IOCB;
IOCB:
TYPE =
MACHINE
DEPENDENT
RECORD [
next (0B): IOCBShortPtr,
seal (1B): CARDINAL,
drive (2B): Drive,
pageCount (3B): CARDINAL,
command (4B): DiskCommand,
diskAddress (5B): DiskAddress,
diskHeader (7B): DiskAddress,
headerPtr (11B): LONG POINTER TO DiskAddress,
headerECC (13B): LONG CARDINAL,
headerStatus (15B): DiskStatus,
labelPtr (16B): LONG POINTER TO DiskFace.Label,
labelECC (20B): LONG CARDINAL,
labelStatus (22B): DiskStatus,
dataPtr (23B): LONG POINTER,
dataECC (25B): LONG CARDINAL,
dataStatus (27B): DiskStatus,
diskLabel (30B): DiskFace.Label];
nilIOCBShortPtr: IOCBShortPtr = LOOPHOLE[0];
DoradoOperationPtr: TYPE = LONG POINTER TO DoradoOperation;
DoradoOperation:
TYPE =
MACHINE
DEPENDENT
RECORD [
operation (0): Operation,
Guarantee required odd word alignment, since Operation is 16-word aligned
iocb (15B): IOCB];
DiskStatus:
TYPE =
MACHINE
DEPENDENT
RECORD [
seekInc (0: 0..0): BOOLEAN,
headOvfl (0: 1..1): BOOLEAN,
devCheck (0: 2..2): BOOLEAN,
notSelected (0: 3..3): BOOLEAN,
notOnLine (0: 4..4): BOOLEAN,
notReady (0: 5..5): BOOLEAN,
sectorOvfl (0: 6..6): BOOLEAN,
fifoUnderflow (0: 7..7): BOOLEAN,
fifoOverflow (0: 8..8): BOOLEAN,
checkErr (0: 9..9): BOOLEAN,
readOnly (0: 10..10): BOOLEAN,
cylOffset (0: 11..11): BOOLEAN,
iobParityErr (0: 12..12): BOOLEAN,
fifoParityErr (0: 13..13): BOOLEAN,
eccErr (0: 14..14): BOOLEAN,
sectorSearchErr (0: 15..15): BOOLEAN];
nullDiskStatus: DiskStatus = LOOPHOLE[0];
errorStatusMask: DiskStatus = [
These bits constitute errors:
seekInc: TRUE, headOvfl: TRUE, devCheck: TRUE, notSelected: TRUE, notOnLine: TRUE,
notReady: TRUE, sectorOvfl: TRUE, fifoUnderflow: TRUE, fifoOverflow: TRUE,
checkErr: TRUE, iobParityErr: TRUE, fifoParityErr: TRUE, eccErr: TRUE,
sectorSearchErr: TRUE,
These are just status bits that do not necessarily constitute errors:
readOnly: FALSE, cylOffset: FALSE];
sealValid: CARDINAL = 125377B;
sealNil: CARDINAL = 0;
cylinderRestore: CARDINAL = 177777B;
cylinderUnknown: CARDINAL = 77777B;
Microcode implements 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): BOOL ← FALSE, -- valid only in label of page 0
temporary (0:14..14): BOOL ← FALSE, -- valid only in label of page 0
zeroSize (0:15..15): BOOL ← FALSE
]
],
raw => [
lowHalf(0): CARDINAL,
highHalf(1): CARDINAL
]
ENDCASE
];
Disk hardware definitions
Output to DiskControl register, and used as diskCommand in IOCBs
diskControl: DoradoInputOutput.IOAddress = 10B;
DiskCommand:
TYPE =
MACHINE
DEPENDENT
RECORD [
incrementDataPtr (0: 0..0): BOOLEAN ← FALSE, -- in IOCB only; not defined in hardware
unused1 (0: 1..4): Filler,
clearEnableRun (0: 5..5): BOOLEAN ← FALSE,
debugMode (0: 6..6): BOOLEAN ← FALSE,
blockTilIndex (0: 7..7): BOOLEAN ← FALSE,
header (0: 8..9): Action ← none,
label (0: 10..11): Action ← none,
data (0: 12..13): Action ← none,
unused2 (0: 14..15): Action ← none];
Action: TYPE = MACHINE DEPENDENT {none, write, check, read};
Output to DiskMuff register
diskMuff: DoradoInputOutput.IOAddress = 11B;
MuffCommand:
TYPE =
MACHINE
DEPENDENT
RECORD [
unused (0: 0..1): Filler,
clearCompareErr (0: 2..2): BOOLEAN ← FALSE,
setChecksumErr (0: 3..3): BOOLEAN ← FALSE,
clearIndexTW (0: 4..4): BOOLEAN ← FALSE,
clearSectorTW (0: 5..5): BOOLEAN ← FALSE,
clearSeekTagTW (0: 6..6): BOOLEAN ← FALSE,
clearErrors (0: 7..7): BOOLEAN ← FALSE,
muffAddr (0: 8..15): MufflerAddress ← tempSense];
Input from DiskMuff register
MuffInput:
TYPE =
MACHINE
DEPENDENT
RECORD [
unused (0: 0..14): Filler,
bit (0: 15..15): BOOLEAN];
Output to DiskTag register
diskTag: DoradoInputOutput.IOAddress = 14B;
TagCommand:
TYPE =
MACHINE
DEPENDENT
RECORD [
driveTag (0: 0..0): BOOLEAN ← FALSE,
cylinderTag (0: 1..1): BOOLEAN ← FALSE,
headTag (0: 2..2): BOOLEAN ← FALSE,
controlTag (0: 3..3): BOOLEAN ← FALSE,
bus (0: 4..15):
SELECT
OVERLAID *
FROM
drive => [
unused (0: 4..5): Filler,
subSectorCount (0: 6..9): [0..17B] ← 0, -- sub-sectors/sector - 1
loadSubSector (0: 10..10): BOOLEAN ← FALSE,
select (0: 11..11): BOOLEAN ← FALSE,
driveNumber (0: 12..15): Drive],
cylinder => [
cylinder (0: 4..15): [0..7777B]],
head => [
unused (0: 4..7): Filler,
offset (0: 8..8): BOOLEAN ← FALSE,
offsetDirection (0: 9..9): {out(0), in(1)} ← out,
headNumber (0: 10..15): [0..77B]],
control => [
syncPattern (0: 4..4): {s201, s001} ← s201, -- s001 is Alto-compatible
unused (0: 5..5): Filler,
strobeLate (0: 6..6): BOOLEAN ← FALSE,
strobeEarly (0: 7..7): BOOLEAN ← FALSE,
write (0: 8..8): BOOLEAN ← FALSE,
read (0: 9..9): BOOLEAN ← FALSE,
addressMark (0: 10..10): BOOLEAN ← FALSE,
headReset (0: 11..11): BOOLEAN ← FALSE,
deviceCheckReset (0: 12..12): BOOLEAN ← FALSE,
headSelect (0: 13..13): BOOLEAN ← FALSE,
rezero (0: 14..14): BOOLEAN ← FALSE,
headAdvance (0: 15..15): BOOLEAN ← FALSE],
ENDCASE];
Muffler addresses for status bits (DskEth-relative)
MufflerAddress:
TYPE =
MACHINE
DEPENDENT {
tempSense(0), indexTW(1), sectorTW(2), seekTagTW(3), rdFifoTW(4), wrFifoTW(5),
readData(6), writeData(7), enableRun(10B), debugMode(11B), notRdOnlyBlock(12B),
notWriteBlock(13B), notCheckBlock(14B), active(15B), select0(16B), select1(17B),
seekInc(20B), headOvfl(21B), devCheck(22B), notSelected(23B), notOnLine(24B),
notReady(25B), sectorOvfl(26B), fifoUnderflow(27B), fifoOverflow(30B),
readDataErr(31B), readOnly(32B), cylOffset(33B), iobParityErr(34B),
fifoParityErr(35B), writeError(36B), readError(37B),
others of interest only to Midas
(177B)};
diskDMuxAddr: [0..7777B] = 2000B; -- DMux address of first disk muffler
Filler: TYPE = [0..1] ← 0;
Data structures private to the software
DiskHandle:
TYPE =
MACHINE
DEPENDENT
RECORD [
unused (0: 0..7): Filler,
drive (0: 8..15): Drive];
nullDiskHandle: DiskHandle = LOOPHOLE [177777B];
Drive: TYPE = [0..drives);
drives: CARDINAL = 16; -- maximum number of drives per controller
The "system" drive is drive 0, which is always assumed to be a T-80 that is
addressed in a funny way. t80 and t300 refer to drives other than drive 0,
which are addressed in the normal way.
Model: TYPE = {nonexistent, system, t80, t300};
modelCylinders:
ARRAY Model
OF
CARDINAL = [
nonexistent: 0, system: 815*5, t80: 815, t300: 815];
modelHeads:
ARRAY Model
OF
CARDINAL = [
nonexistent: 0, system: 1, t80: 5, t300: 19];
modelSectors:
ARRAY Model
OF
CARDINAL = [
nonexistent: 0, system: 28, t80: 28, t300: 28];
Public variables
globalStateSize: PUBLIC CARDINAL ← 0;
an IOCB for label fixup is not required for the Dorado implementation.
nullDeviceHandle: PUBLIC DeviceHandle ← DeviceFromDiskHandle[nullDiskHandle];
operationSize: PUBLIC CARDINAL ← SIZE[DoradoOperation];
Private variables
csb: CSBPtr = LOOPHOLE[LONG[177520B]];
totalErrors: CARDINAL ← 0; -- = total errors reported by Poll
modelTable: ARRAY [0..drives) OF Model ← ALL [nonexistent];
Public procedures
Assumes Initialize is called before GetDeviceAttributes
GetDeviceAttributes:
PUBLIC
PROCEDURE [device: DeviceHandle]
RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] =
BEGIN
diskHandle: DiskHandle = DiskFromDeviceHandle[device];
model: Model = modelTable[diskHandle.drive];
RETURN [
cylinders: modelCylinders[model], movingHeads: modelHeads[model],
fixedHeads: 0, sectorsPerTrack: modelSectors[model]];
END;
Assumes Initialize is called before GetNextDevice
GetNextDevice:
PUBLIC
PROCEDURE [device: DeviceHandle]
RETURNS [DeviceHandle] =
BEGIN
disk: DiskHandle = DiskFromDeviceHandle[device];
IF disk=nullDiskHandle
THEN
-- drive 0 presumed to exist always
RETURN [DeviceFromDiskHandle[[drive: 0]]];
FOR drive: Drive
IN (disk.drive..drives)
DO
IF modelTable[drive]#nonexistent THEN RETURN [DeviceFromDiskHandle[[drive: drive]]];
ENDLOOP;
RETURN [nullDeviceHandle];
END;
Assumes that the disk hardware and microcode are quiescent
Initialize:
PUBLIC
PROCEDURE [t:
WORD, globalState: GlobalStatePtr] =
BEGIN OPEN DoradoInputOutput;
ManualStrobe:
PROCEDURE [tag, data: TagCommand] =
BEGIN
Output[data, diskTag];
Output[PrincOpsUtils.BITOR[tag, data], diskTag];
Output[data, diskTag];
No need to wait: drive is advertised to return status within 200 ns
of its being selected.
END;
AutoStrobe:
PROCEDURE [data: TagCommand] =
BEGIN
Output[data, diskTag];
Need to wait at least 1.2 microseconds for strobe sequence to complete,
plus an unspecified amount of time (probably less than a microsecond)
for the drive to return up-to-date status.
THROUGH [0..10) DO NULL; ENDLOOP;
END;
ReadMuffler:
PROCEDURE [addr: MufflerAddress]
RETURNS [status:
BOOLEAN] =
BEGIN
Reads through system DMux rather than through DskEth muffler interface, because
it's impossible for the disk task to dismiss wakeups without clobbering the
muffler address.
RETURN [
DoradoInputOutput.RWMufMan[
[useDMD: FALSE, dMuxAddr: DMuxFromMufAddr[addr]]].dMuxData#0];
END;
ClassifyDrive:
PROCEDURE [drive: Drive]
RETURNS [model: Model] =
BEGIN
Select the drive. If it doesn't become selected then it doesn't exist.
ManualStrobe[tag: [driveTag:
TRUE, bus: drive[driveNumber: 0]],
data: [bus: drive[select: TRUE, driveNumber: drive]]];
IF ReadMuffler[notSelected] THEN RETURN [nonexistent]
ELSE
BEGIN
Try to select a head which does not exist on a T80.
This causes a headOvfl error on a T80, not on a T300
AutoStrobe[[controlTag: TRUE, bus: control[deviceCheckReset: TRUE]]];
AutoStrobe[[headTag: TRUE, bus: head[headNumber: modelHeads[t80]]]];
model ← IF ReadMuffler[headOvfl] THEN t80 ELSE t300;
AutoStrobe[[controlTag: TRUE, bus: control[deviceCheckReset: TRUE]]];
END;
END;
lastDrive: Drive;
ResetDisk[disable]; -- disable disk task so it won't run and confuse matters
csb^ ← [
head: nilIOCBQueueHead, interruptMask: t, drive: 0,
cylinder: cylinderUnknown, tail: NIL];
modelTable[0] ← system; -- drive 0 presumed to exist always
Drives 0-2 are connected directly to the controller, and drive 3 also if
no multiplexor is present.
If a multiplexor is present, it is connected in place of drive 3.
Drive 17B is presumed not to exist. Try selecting drive 17B. If this succeeds
then what really happened is that no multiplexor is present and drive 3
got selected instead. If this fails then either there is a multiplexor
or there is no multiplexor and no drive 3 is present; it is safe to test each
of drives 4-16 since in this case they will select only if there is a multiplexor.
lastDrive ← (IF ClassifyDrive[LAST[Drive]]=nonexistent THEN LAST[Drive]-1 ELSE 3);
FOR drive: Drive
IN [1..lastDrive]
DO
modelTable[drive] ← ClassifyDrive[drive];
ENDLOOP;
ResetDisk[normal]; -- put disk microcode back in normal state
END;
InitializeCleanup:
PUBLIC
PROCEDURE =
BEGIN OPEN DeviceCleanup;
item: Item;
reason: Reason;
savedCSB: CSB;
DO
reason ← Await[@item];
SELECT reason
FROM
turnOff, kill =>
BEGIN
UNTIL csb.head.tag = idle DO ENDLOOP;
savedCSB ← csb^;
csb.head.iocb ← nilIOCBShortPtr;
END;
turnOn =>
BEGIN
csb^ ← savedCSB;
csb.cylinder ← cylinderUnknown;
END;
ENDCASE
ENDLOOP
END;
Initiate:
PUBLIC
PROCEDURE [operationPtr: OperationPtr] =
BEGIN
doradoOperationPtr: DoradoOperationPtr = LOOPHOLE[operationPtr];
iocb: IOCBLongPtr = @doradoOperationPtr.iocb;
iocbShort: IOCBShortPtr = LOOPHOLE[PrincOpsUtils.LowHalf[iocb]];
diskCommand: DiskCommand ←
SELECT operationPtr.command
FROM
vv => [incrementDataPtr: FALSE, header: check, label: check, data: none],
vvr => [incrementDataPtr: FALSE, header: check, label: check, data: read],
vvw => [incrementDataPtr: FALSE, header: check, label: check, data: write],
vvv => [incrementDataPtr: FALSE, header: check, label: check, data: check],
vw => [incrementDataPtr: FALSE, header: check, label: write, data: none],
vww => [incrementDataPtr: FALSE, header: check, label: write, data: write],
vr => [incrementDataPtr: FALSE, header: check, label: read, data: none],
vrr => [incrementDataPtr: FALSE, header: check, label: read, data: read],
vrw => [incrementDataPtr: FALSE, header: check, label: read, data: write],
vrv => [incrementDataPtr: FALSE, header: check, label: read, data: check],
rv => [incrementDataPtr: FALSE, header: read, label: check, data: none],
rvr => [incrementDataPtr: FALSE, header: read, label: check, data: read],
rvw => [incrementDataPtr: FALSE, header: read, label: check, data: write],
rvv => [incrementDataPtr: FALSE, header: read, label: check, data: check],
rw => [incrementDataPtr: FALSE, header: read, label: write, data: none],
rww => [incrementDataPtr: FALSE, header: read, label: write, data: write],
rr => [incrementDataPtr: FALSE, header: read, label: read, data: none],
rrr => [incrementDataPtr: FALSE, header: read, label: read, data: read],
rrw => [incrementDataPtr: FALSE, header: read, label: read, data: write],
rrv => [incrementDataPtr: FALSE, header: read, label: read, data: check],
w => [incrementDataPtr: FALSE, header: write, label: none, data: none],
www => [incrementDataPtr: FALSE, header: write, label: write, data: write],
ENDCASE => ERROR;
diskCommand.incrementDataPtr ← operationPtr.incrementDataPtr;
BEGIN
-- Fix up label file page number representation
kludge: LONG POINTER TO FilePageRep = LOOPHOLE[@operationPtr.labelPtr.filePage];
IF kludge.highHalf # 0 THEN kludge.pilotHi ← [filePageHi: kludge.highHalf];
END; -- Fix up
iocb^ ← [
next: nilIOCBShortPtr, seal: sealValid,
drive: DiskFromDeviceHandle[operationPtr.device].drive,
pageCount: operationPtr.pageCount, command: diskCommand,
diskAddress: operationPtr.clientHeader, diskHeader: operationPtr.clientHeader,
headerPtr: @iocb.diskHeader, headerECC: 0, headerStatus: nullDiskStatus,
labelPtr: IF diskCommand.label=read THEN operationPtr.labelPtr ELSE @iocb.diskLabel,
labelECC: 0, labelStatus: nullDiskStatus,
dataPtr: operationPtr.dataPtr, dataECC: 0, dataStatus: nullDiskStatus,
diskLabel: operationPtr.labelPtr^];
Chain this IOCB onto CSB for processing by microcode.
IF csb.head.iocb # nilIOCBShortPtr THEN csb.tail.next ← iocbShort;
IF csb.head.iocb = nilIOCBShortPtr
AND iocb.seal = sealValid
THEN
csb.head.iocb ← iocbShort;
csb.tail ← iocb;
END;
Poll:
PUBLIC
PROCEDURE [operationPtr: OperationPtr]
RETURNS [status: Status] =
BEGIN
doradoOperationPtr: DoradoOperationPtr = LOOPHOLE[operationPtr];
iocb: IOCBLongPtr = @doradoOperationPtr.iocb;
iocbShort: IOCBShortPtr = LOOPHOLE[PrincOpsUtils.LowHalf[iocb]];
Capture in-progress/done state here and use it for all subsequent decisions.
If the command finishes during the code below, we will still report inProgress
to the client, who will Poll again and get the real ending state.
status ← IF iocb.seal=sealValid THEN inProgress ELSE goodCompletion;
Copy things back to client that he might want to monitor while the command
is still in progress.
operationPtr.clientHeader ← iocb.diskAddress;
operationPtr.pageCount ← iocb.pageCount;
IF status#inProgress
THEN
BEGIN
Command has completed: successfully if pageCount=0, unsuccessfully otherwise.
IF iocb.pageCount=0
THEN
BEGIN
IF iocb.diskAddress.head = modelHeads[modelTable[iocb.drive]]
THEN
Successful transfer happened to end at a cylinder boundary.
Increment disk address to next cylinder.
BEGIN
iocb.diskAddress.head ← 0;
iocb.diskAddress.cylinder ← iocb.diskAddress.cylinder+1;
END
END
ELSE
BEGIN
Error occurred. Must carefully examine DiskStatus for each block to determine
what happened and to decide what Status to report to the client.
combinedStatus: DiskStatus = PrincOpsUtils.
BITOR[iocb.headerStatus,
PrincOpsUtils.BITOR[iocb.labelStatus, iocb.dataStatus]];
SELECT
TRUE
FROM
First check for problems that might have caused the operation to
malfunction and generated other errors as secondary effects.
combinedStatus.notSelected
OR combinedStatus.notOnLine
OR
combinedStatus.notReady => status ← notReady;
combinedStatus.seekInc => status ← seekTimeout;
combinedStatus.sectorSearchErr => status ← sectorTimeout;
Check for head overflow: means transfer crossed a cylinder boundary.
combinedStatus.headOvfl =>
IF iocb.diskAddress.head = modelHeads[modelTable[iocb.drive]]
THEN
BEGIN
iocb.diskAddress.head ← 0;
iocb.diskAddress.cylinder ← iocb.diskAddress.cylinder+1;
GOTO restart;
END
ELSE status ← hardwareError;
Look for header problems:
iocb.headerStatus.checkErr =>
Header check error: must discriminate possible causes
status ←
SELECT
TRUE
FROM
iocb.diskHeader.cylinder#iocb.diskAddress.cylinder => wrongCylinder,
iocb.diskHeader.head#iocb.diskAddress.head => wrongHead,
ENDCASE => wrongSector;
Would like to distinguish other header errors (e.g., header checksum),
but there is no Status value with which to report them!!
PrincOpsUtils.BITAND[iocb.headerStatus, errorStatusMask]#0 => status ← hardwareError;
Look for label problems:
iocb.labelStatus.sectorOvfl OR iocb.labelStatus.eccErr => status ← labelError;
iocb.labelStatus.checkErr => status ← labelCheck;
PrincOpsUtils.BITAND[iocb.labelStatus, errorStatusMask]#0 => status ← hardwareError;
Look for data problems:
iocb.dataStatus.sectorOvfl OR iocb.dataStatus.eccErr => status ← dataError;
ENDCASE => status ← hardwareError;
Microcode has been deferring ever since the error occurred.
Now zap all deferred operations and allow new ones to be Initiated.
csb.head.iocb ← nilIOCBShortPtr;
totalErrors ← totalErrors+1;
EXITS
restart =>
BEGIN
iocb.headerStatus ← iocb.labelStatus ← iocb.dataStatus ← nullDiskStatus;
iocb.seal ← sealValid;
csb.head.iocb ← iocbShort;
status ← inProgress;
END;
END;
Copy updated information back to client.
We already did clientHeader and pageCount.
Note: if reading label, it was read directly to client so don't clobber it here.
IF iocb.command.label#read THEN operationPtr.labelPtr^ ← iocb.diskLabel;
operationPtr.dataPtr ← iocb.dataPtr;
operationPtr.diskHeader ← iocb.diskHeader;
END;
IF status # inProgress
THEN
-- Fix up label file page number representation
BEGIN
kludge: LONG POINTER TO FilePageRep = LOOPHOLE[@operationPtr.labelPtr.filePage];
IF kludge.highHalf # 0 THEN kludge.highHalf ← kludge.pilotHi.filePageHi;
END; -- Fix up
END;
Recalibrate:
PUBLIC
PROCEDURE [device: DeviceHandle] =
BEGIN csb.cylinder ← cylinderRestore; END;
Reset:
PUBLIC
PROCEDURE [device: DeviceHandle] =
BEGIN
WHAT SHOULD THIS DO?
END;
Private procedures
DiskFromDeviceHandle:
PROCEDURE [device: DeviceHandle]
RETURNS [DiskHandle] =
INLINE
BEGIN RETURN[LOOPHOLE[device]]; END;
DeviceFromDiskHandle:
PROCEDURE [disk: DiskHandle]
RETURNS [DeviceHandle] =
INLINE
BEGIN RETURN[LOOPHOLE[disk]]; END;
DMuxFromMufAddr:
PROCEDURE [mufAdr: MufflerAddress]
RETURNS [DoradoInputOutput.DMuxAddr] = INLINE
BEGIN RETURN[diskDMuxAddr+LOOPHOLE[mufAdr, CARDINAL]]; END;
END.
LOG
Time: August 8, 1979 1:09 AM By: Redell Action: Add log to file from Jarvis
Time: August 17, 1979 1:27 PM By: Gobbel Action: Pilot formatting
Time: August 22, 1979 12:40 PM By: Gobbel Action: Bring up to date with revised device face
Time: October 2, 1979 11:38 PM By: Redell Action: Further cleanup, esp for bootchains (partial label verification)
Time: October 8, 1979 9:22 AM By: McJones Action: Restart controller bug, add hardwareState
Time: October 10, 1979 3:53 PM By: McJones Action: INLINE procedures for speed; labelCheck is cue to call StartLabelFix
Time: October 30, 1979 11:04 AM By: McJones AR2643: Label fix didn't reset iocb.label from user's label
Time: November 1, 1979 1:20 PM By: Frandeen Action: Fix recalibrate after header error; bug in SynchronizeWithController
Time: November 7, 1979 1:17 PM By: McJones AR2739: Label fix up confused by spurious labelCheck status returned by read label command on sector with missing (label?) synch byte
Time: November 9, 1979 8:59 AM By: Frandeen Action: Implement runs of pages. Change interface to Poll. Change LabelFix procedures. Change interface to StartB since we no longer need an extra IOCB for label fixup.
Time: December 13, 1979 11:29 AM By: Gobbel Action: Change name from SA4000D0Head to SA4000HeadD0
Time: January 30, 1980 12:48 PM By: McJones Action: Update to match new face; add StartChain logic
Time: June 25, 1980 10:34 AM By: McJones Action: 48-bit processor ids
Time: July 24, 1980 11:23 AM By: McJones Action: Label fixup must update iocb.operation.clientHeader
Time: December 6, 1980 2:56 PM Taft Convert for Dorado
Time: February 13, 1983 1:24 pm Taft Add support for multiple drives and T-300s
Time: May 5, 1983 2:49 pm By: Andrew Birrell Action: convert to new Cedar nucleus