<> <> <> <> <> <> <> <> <> 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; << Assumes Initialize is called before GetDeviceAttributes>> 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 <