DIRECTORY DeviceCleanup USING [Await, Item, Reason], DiskFace USING [Label], DiskHeadDoradoPrivate, DoradoInputOutput USING [IOAddress, DMuxAddr, Output, ResetDisk, RWMufMan], PrincOpsUtils USING [BITAND, BITOR, LowHalf], SA4000Face; DiskHeadDorado: PROGRAM IMPORTS DeviceCleanup, DoradoInputOutput, PrincOpsUtils EXPORTS DiskHeadDoradoPrivate, SA4000Face SHARES SA4000Face = BEGIN OPEN SA4000Face; 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 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]]; 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, iocb (15B): IOCB]; DiskStatus: TYPE = DiskHeadDoradoPrivate.DoradoDiskHardwareStatus; nullDiskStatus: DiskStatus = DiskHeadDoradoPrivate.nullDiskStatus; errorStatusMask: DiskStatus = [ 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, readOnly: FALSE, cylOffset: FALSE]; sealValid: CARDINAL = 125377B; sealNil: CARDINAL = 0; cylinderRestore: CARDINAL = 177777B; cylinderUnknown: CARDINAL = 77777B; 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}; 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]; MuffInput: TYPE = MACHINE DEPENDENT RECORD [ unused (0: 0..14): Filler, bit (0: 15..15): BOOLEAN]; 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]; 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), (177B)}; diskDMuxAddr: [0..7777B] = 2000B; -- DMux address of first disk muffler Filler: TYPE = [0..1] _ 0; DiskHandle: TYPE = MACHINE DEPENDENT RECORD [ unused (0: 0..7): Filler, drive (0: 8..15): Drive]; nullDiskHandle: DiskHandle = LOOPHOLE [177777B]; Drive: TYPE = DiskHeadDoradoPrivate.Drive; -- TYPE = [0..drives) drives: CARDINAL = DiskHeadDoradoPrivate.drives; -- maximum number of drives per controller Model: TYPE = {nonexistent, system80, system300, t80, t300}; modelCylinders: ARRAY Model OF CARDINAL = [ nonexistent: 0, system80: 815*5, system300: 815*19, t80: 815, t300: 815]; modelTrueCylinders: ARRAY Model OF CARDINAL = [ nonexistent: 0, system80: 815, system300: 815, t80: 815, t300: 815]; modelHeads: ARRAY Model OF CARDINAL = [ nonexistent: 0, system80: 1, system300: 1, t80: 5, t300: 19]; modelTrueHeads: ARRAY Model OF CARDINAL = [ nonexistent: 0, system80: 5, system300: 19, t80: 5, t300: 19]; modelSectors: ARRAY Model OF CARDINAL = [ nonexistent: 0, system80: 28, system300: 28, t80: 28, t300: 28]; globalStateSize: PUBLIC CARDINAL _ 0; nullDeviceHandle: PUBLIC DeviceHandle _ DeviceFromDiskHandle[nullDiskHandle]; operationSize: PUBLIC CARDINAL _ SIZE[DoradoOperation]; totalErrors: PUBLIC CARDINAL _ 0; -- = total errors reported by Poll csb: CSBPtr = LOOPHOLE[LONG[177520B]]; modelTable: ARRAY [0..drives) OF Model _ ALL [nonexistent]; 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; GetTrueDeviceAttributes: PUBLIC PROCEDURE [device: DeviceHandle] RETURNS [cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL] = BEGIN diskHandle: DiskHandle = DiskFromDeviceHandle[device]; model: Model = modelTable[diskHandle.drive]; RETURN [ cylinders: modelTrueCylinders[model], movingHeads: modelTrueHeads[model], fixedHeads: 0, sectorsPerTrack: modelSectors[model]]; END; 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; Initialize: PUBLIC PROCEDURE [t: WORD, globalState: GlobalStatePtr] = BEGIN OPEN DoradoInputOutput; ManualStrobe: PROCEDURE [tag, data: TagCommand] = BEGIN Output[LOOPHOLE[data], diskTag]; Output[PrincOpsUtils.BITOR[LOOPHOLE[tag], LOOPHOLE[data]], diskTag]; Output[LOOPHOLE[data], diskTag]; END; AutoStrobe: PROCEDURE [data: TagCommand] = BEGIN Output[LOOPHOLE[data], diskTag]; THROUGH [0..10) DO NULL; ENDLOOP; END; ReadMuffler: PROCEDURE [addr: MufflerAddress] RETURNS [status: BOOLEAN] = BEGIN RETURN [ DoradoInputOutput.RWMufMan[ [useDMD: FALSE, dMuxAddr: DMuxFromMufAddr[addr]]].dMuxData#0]; END; ClassifyDrive: PROCEDURE [drive: Drive] RETURNS [model: Model] = BEGIN ManualStrobe[tag: [driveTag: TRUE, bus: drive[driveNumber: 0]], data: [bus: drive[select: TRUE, driveNumber: drive]]]; IF ReadMuffler[notSelected] THEN RETURN [nonexistent] ELSE IF ReadMuffler[notOnLine] THEN RETURN [nonexistent] ELSE BEGIN 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] _ SELECT ClassifyDrive[0] FROM nonexistent => nonexistent, t80 => system80, t300 => system300, ENDCASE => ERROR; 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; 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^]; 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; DoradoDiskErrorStatus: TYPE = DiskHeadDoradoPrivate.DoradoDiskErrorStatus; doradoDiskErrorStatusTable: PUBLIC ARRAY [0..DiskHeadDoradoPrivate.drives) OF DoradoDiskErrorStatus _ ALL [[nullDiskStatus, nullDiskStatus, nullDiskStatus]]; Poll: PUBLIC PROCEDURE [operationPtr: OperationPtr] RETURNS [status: Status] = BEGIN doradoOperationPtr: DoradoOperationPtr = LOOPHOLE[operationPtr]; iocb: IOCBLongPtr = @doradoOperationPtr.iocb; iocbShort: IOCBShortPtr = LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]; status _ IF iocb.seal=sealValid THEN inProgress ELSE goodCompletion; operationPtr.clientHeader _ iocb.diskAddress; operationPtr.pageCount _ iocb.pageCount; IF status#inProgress THEN BEGIN IF iocb.pageCount=0 THEN BEGIN IF iocb.diskAddress.head = modelHeads[modelTable[iocb.drive]] THEN BEGIN iocb.diskAddress.head _ 0; iocb.diskAddress.cylinder _ iocb.diskAddress.cylinder+1; END END ELSE BEGIN combinedStatus: DiskStatus = LOOPHOLE[ PrincOpsUtils.BITOR[ LOOPHOLE[iocb.headerStatus], PrincOpsUtils.BITOR[LOOPHOLE[iocb.labelStatus], LOOPHOLE[iocb.dataStatus] ]]]; doradoDiskErrorStatusTable[iocb.drive] _ [iocb.headerStatus, iocb.labelStatus, iocb.dataStatus]; SELECT TRUE FROM combinedStatus.notSelected OR combinedStatus.notOnLine OR combinedStatus.notReady => status _ notReady; combinedStatus.seekInc => status _ seekTimeout; combinedStatus.sectorSearchErr => status _ sectorTimeout; 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; iocb.headerStatus.checkErr => status _ SELECT TRUE FROM iocb.diskHeader.cylinder#iocb.diskAddress.cylinder => wrongCylinder, iocb.diskHeader.head#iocb.diskAddress.head => wrongHead, ENDCASE => wrongSector; PrincOpsUtils.BITAND[ LOOPHOLE[iocb.headerStatus], LOOPHOLE[errorStatusMask] ] # 0 => status _ hardwareError; iocb.labelStatus.sectorOvfl OR iocb.labelStatus.eccErr => status _ labelError; iocb.labelStatus.checkErr => status _ labelCheck; PrincOpsUtils.BITAND[ LOOPHOLE[iocb.labelStatus], LOOPHOLE[errorStatusMask] ] # 0 => status _ hardwareError; iocb.dataStatus.sectorOvfl OR iocb.dataStatus.eccErr => status _ dataError; ENDCASE => status _ hardwareError; 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; IF iocb.command.label#read THEN operationPtr.labelPtr^ _ iocb.diskLabel; operationPtr.dataPtr _ iocb.dataPtr; operationPtr.diskHeader _ iocb.diskHeader; END; END; Recalibrate: PUBLIC PROCEDURE [device: DeviceHandle] = BEGIN csb.cylinder _ cylinderRestore; END; Reset: PUBLIC PROCEDURE [device: DeviceHandle] = BEGIN END; 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 Time: February 14, 1984 12:38:58 pm By: Willie-Sue Action: handle the case of drives that are OnLine but NotReady Time: March 7, 1984 3:59:04 pm By Willie-Sue Action: poll counter Time: May 9, 1984 5:45:03 pm PDT By Bob Hagmann Action: add GetTrueDeviceAttributes Time: January 31, 1985 3:35:50 pm; Orr Action: took out poll counters, put in last error status capture, exports to DiskHeadDoradoPrivate €DiskHeadDorado.mesa: Dorado implementation of SA4000Face Copyright c 1985 by Xerox Corporation. All rights reserved. Taft, January 28, 1984 11:40:33 am PST Andrew Birrell, May 5, 1983 2:48 pm Willie-Sue, January 31, 1985 4:04:01 pm PST Bob Hagmann, March 12, 1984 2:58:03 pm PST Russ Atkinson (RRA) February 19, 1985 2:04:37 pm PST Doug Wyatt, February 22, 1985 4:04:31 pm PST Carl Hauser, November 15, 1985 10:06:31 am PST Data structures shared with disk microcode Remainder of CSB is not used by the microcode IOCB must be odd word aligned Guarantee required odd word alignment, since Operation is 16-word aligned 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]; These bits constitute errors: These are just status bits that do not necessarily constitute errors: Disk hardware definitions Output to DiskControl register, and used as diskCommand in IOCBs Output to DiskMuff register Input from DiskMuff register Output to DiskTag register Muffler addresses for status bits (DskEth-relative) others of interest only to Midas Data structures private to the software The "system" drive is drive 0, which is a T-80 or T-300 (actually AMS-315) that is addressed in a funny way (for compatibility with Alto emulators), with cylinders incrementing before heads. t80 and t300 refer to drives other than drive 0, which are addressed in the conventional way. An AMS-315 is always treated the same as a T-300; that is, the extra 8 cylinders of an AMS-315 are not used. Public variables an IOCB for label fixup is not required for the Dorado implementation. Private variables Public procedures Assumes Initialize is called before GetDeviceAttributes Assumes Initialize is called before GetDeviceAttributes Assumes Initialize is called before GetNextDevice Assumes that the disk hardware and microcode are quiescent No need to wait: drive is advertised to return status within 200 ns of its being selected. 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. 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. Select the drive. If it doesn't become selected then it doesn't exist. Try to select a head which does not exist on a T80. This causes a headOvfl error on a T80, not on a T300 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. Chain this IOCB onto CSB for processing by microcode. 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. Copy things back to client that he might want to monitor while the command is still in progress. Command has completed: successfully if pageCount=0, unsuccessfully otherwise. Successful transfer happened to end at a cylinder boundary. Increment disk address to next cylinder. Error occurred. Must carefully examine DiskStatus for each block to determine what happened and to decide what Status to report to the client. First check for problems that might have caused the operation to malfunction and generated other errors as secondary effects. Check for head overflow: means transfer crossed a cylinder boundary. Look for header problems: Header check error: must discriminate possible causes Would like to distinguish other header errors (e.g., header checksum), but there is no Status value with which to report them!! Look for label problems: Look for data problems: Microcode has been deferring ever since the error occurred. Now zap all deferred operations and allow new ones to be Initiated. 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. WHAT SHOULD THIS DO? Private procedures Carl Hauser, November 13, 1985 6:07:45 pm PST fixed bug causing free pages with bad labels (wrong tFilePage) to be written changes to: Initiate the "Fix up label file page number representation" code must be idempotent: added "AND kludge.filePageHi = 0" to the test. Κσ˜codešœΟc%™8Kšœ Οmœ1™Kš œ ŸœŸœŸœŸœŸœ˜)š ŸœŸœŸœŸ œŸœ˜'K˜Kšœ Ÿœ˜K˜KšœŸœ˜K˜K˜K˜KšœŸœŸœŸœ ˜-KšœŸœŸœ˜K˜KšœŸœŸœŸœ˜/KšœŸœŸœ˜K˜KšœŸœŸœ˜KšœŸœŸœ˜K˜K˜!K˜—Kšœ Ÿœ˜,K˜Kš œŸœŸœŸœŸœ˜;š œŸœŸœŸ œŸœ˜2K˜KšœI™IKšœ Ÿœ˜K˜—š œ ŸœŸœŸ œŸœ™-KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™!KšœŸœ™ KšœŸœ™KšœŸœ™KšœŸœ™KšœŸœ™"KšœŸœ™#KšœŸœ™KšœŸœ™&K™—Kšœ Ÿœ2˜BK˜KšœB˜B˜Kšœ™Kš œ Ÿœ Ÿœ ŸœŸœ Ÿœ˜RKš œ ŸœŸœŸœŸœ˜JKš œ ŸœŸœŸœ Ÿœ˜FKšœŸœ˜KšœE™EKšœ Ÿœ Ÿœ˜#K˜—Kšœ Ÿœ ˜Kšœ Ÿœ˜K˜KšœŸœ ˜$KšœŸœ ˜#K˜K˜Kšœ™K˜Kšœ@™@K˜/š œ ŸœŸœŸ œŸœ˜.KšœŸœŸœ(˜UK˜KšœŸœŸœ˜*KšœŸœŸœ˜%KšœŸœŸœ˜)K˜ K˜!K˜ K˜$—KšœŸœŸœŸ œ˜—šœŸœŸœŸœ˜)K˜@K˜K˜—Kšœ™K˜KšœŸœŸœ˜%KšœF™FKšœŸœ5˜MKšœŸœŸœŸœ˜7K˜Kšœ ŸœŸœ"˜DK˜Kšœ™K˜KšœŸœŸœ ˜&Kšœ Ÿœ Ÿœ Ÿœ˜;K˜Kšœ™K˜Kšœ7™7šΟnœŸœŸ œ˜——KšŸœ˜—š  œŸ œŸœ˜@KšŸ˜KšœG™GšœŸœ˜?KšœŸœ˜6—KšŸœŸœŸœ˜5KšŸœŸœŸœŸœ˜8šŸœŸ˜ Kšœ3™3Kšœ4™4KšœŸœ!Ÿœ˜EKšœŸœ+˜DKšœŸœŸœŸœ˜4KšœŸœ!Ÿœ˜EKšŸœ˜—KšŸœ˜—K˜Kšœ8˜L˜K˜3Kšœ!Ÿœ˜&—KšœH™HKšœ™KšœA™AKšœO™OKšœG™GKšœG™GKšœM™MKšœR™RšœŸœŸ˜,K˜K˜K˜KšŸœŸœ˜—Kš œ ŸœŸœŸœŸœ Ÿœ˜RšŸœŸœŸ˜%K˜)KšŸœ˜—Kšœ*˜=KšŸœ˜K˜—š œŸœŸ œ˜%KšŸœŸœ˜K˜ K˜Kšœ Ÿœ˜šŸ˜K˜šŸœŸ˜˜KšŸ˜KšŸœŸœŸœ˜%K˜K˜ KšŸœ˜—˜ KšŸ˜K˜K˜KšŸœ˜—KšŸ˜—KšŸ˜—KšŸœ˜K˜—š œŸœŸ œ˜9KšŸ˜Kšœ)Ÿœ˜@K˜-KšœŸœ˜@šœŸœŸ˜;KšœŸœ+˜IKšœŸœ+˜JKšœŸœ,˜KKšœŸœ,˜KKšœŸœ+˜IKšœŸœ,˜KKšœŸœ*˜HKšœŸœ*˜IKšœŸœ+˜JKšœŸœ+˜JKšœŸœ*˜HKšœŸœ*˜IKšœŸœ+˜JKšœŸœ+˜JKšœŸœ*˜HKšœŸœ+˜JKšœŸœ)˜GKšœŸœ)˜HKšœŸœ*˜IKšœŸœ*˜IKšœŸœ*˜GKšœŸœ,˜KKšŸœŸœ˜—K˜=K˜˜ K˜'K˜7K˜8K˜NK˜HKšœ ŸœŸœŸœ˜TK˜)K˜FK˜#K˜—Kšœ5™5KšŸœ!Ÿœ˜BšŸœ!ŸœŸ˜AK˜—K˜KšŸœ˜K˜—KšœŸœ/˜JKšœŸ œ#ŸœŸœ4˜K˜š œŸœŸ œŸœ˜NKšŸ˜Kšœ)Ÿœ˜@K˜-KšœŸœ˜@K˜KšœL™LKšœN™NKšœA™AKšœ ŸœŸœ Ÿœ˜DK˜KšœJ™JKšœ™K˜-K˜(K˜šŸœŸ˜KšŸ˜KšœM™MšŸœŸ˜KšŸ˜šŸœ<Ÿ˜BKšœ;™;Kšœ(™(KšŸ˜K˜K˜8KšŸ˜—KšŸ˜—šŸœŸ˜ KšœN™NKšœ@™@šœŸœŸœ˜;šŸœ˜KšœŸœŸœŸœ˜N——K˜šœ(˜(Kšœ7˜7—K˜šŸœŸœŸ˜Kšœ@™@Kšœ<™<šœŸœŸ˜9K˜-—K˜/K˜9K˜KšœD™D˜šŸœ<Ÿ˜BKšŸ˜K˜K˜8KšŸœ ˜ KšŸ˜—KšŸœ˜—Kšœ™˜Kšœ5™5šœ ŸœŸœŸ˜K˜DK˜8KšŸœ˜——KšœF™FKšœ8™8šœŸœ˜šŸœŸœ˜?Kšœ˜——K˜Kšœ™KšœŸœ0˜NK˜1šœŸœ˜šŸœŸœ˜>Kšœ˜——K˜Kšœ™KšœŸœ.˜KKšŸœ˜"K˜—Kšœ;™;KšœC™CK˜ K˜šŸ˜˜ KšŸ˜K˜HK˜K˜K˜KšŸœ˜——KšŸœ˜K˜—Kšœ(™(Kšœ*™*KšœP™PKšŸœŸœ)˜HK˜$K˜*KšŸœ˜—KšŸœ˜K˜—š  œŸœŸ œ˜6KšŸœ!Ÿœ˜*K˜—š œŸœŸ œ˜0KšŸ˜Kšœ™KšŸœ˜—K˜K˜Kšœ™K˜š œŸ œŸœŸ˜TKšŸœŸœŸœ Ÿœ˜$K˜—š œŸ œŸœŸ˜RKšŸœŸœŸœ Ÿœ˜"K˜—š œŸ œ˜3KšŸœ Ÿ˜-Kš ŸœŸœŸœ ŸœŸœ˜;K˜—KšŸœ˜KšŸ˜KšœŸœ/˜LKšœŸœ$˜BKšœŸœ=˜\KšœŸœT˜sKšœŸœ>˜\KšœŸœŸœ>˜xKšœŸœH˜hKšœŸœZ˜yKšœŸœ’˜±KšœŸœ‘Ÿœ˜ΥKšœŸœA˜bKšœŸœC˜cKšœŸœ)˜FKšœŸœH˜eKšœŸœ˜9KšœKŸœ˜QK˜SK˜rK˜BK˜TK˜‰K˜K˜K˜™-K™MKšœ Οrœ,œ#Ÿœ$™—K™—…—F†nω