<> <> <> <> <> DIRECTORY BasicTime USING [FromPupTime, GMT, OutOfRange], ConvertUnsafe USING [ToRope], Disk USING [Channel, Command, defaultTries, DoIO, GetBootChainLink, Label, PageCount, PageNumber, Request, Status], DiskFace USING [DeviceHandle, DontCare, GetDeviceAttributes, GetNextDevice, nullDeviceHandle], FormatDisk, PrincOps USING [zEXCH], Rope USING [ROPE], VM USING [AddressForPageNumber, Allocate, Free, Interval, Pin, Unpin]; FormatDiskDorado: MONITOR -- only one guy in here at a time! IMPORTS BasicTime, ConvertUnsafe, DiskFace, Disk, VM EXPORTS FormatDisk = { OPEN FormatDisk; <> BadPage: PUBLIC SIGNAL [page: Disk.PageNumber, correctable: BOOLEAN] = CODE; Error: PUBLIC ERROR [page: Disk.PageNumber, status: Disk.Status] = CODE; Sweep: PUBLIC ENTRY PROC [channel: Disk.Channel, operation: Operation, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, label: LONG POINTER TO Disk.Label, data: LONG POINTER] = { Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: commandTable[operation], label: label, data: data, reportSoftErrors: TRUE]; }; commandTable: ARRAY Operation OF Disk.Command = [ format: [write, write, write], write: [verify, write, write], read: [verify, read, read], verify: [verify, verify, verify]]; <> MicrocodeInstallFailure: PUBLIC SIGNAL [why: FailureType] = CODE; InstallInitialMicrocode: PUBLIC ENTRY PROC [channel: Disk.Channel, getPage: PROC [ptr: LONG POINTER] RETURNS [ok: BOOLEAN]] = { vmInterval: VM.Interval _ VM.Allocate[count: 1]; pageBuffer: LONG POINTER _ VM.AddressForPageNumber[vmInterval.page]; thisPage: Disk.PageNumber _ hardUCodeStart; prevPage: Disk.PageNumber _ [hardUCodeStart-1]; VM.Pin[vmInterval]; { ENABLE UNWIND => {VM.Unpin[vmInterval]; VM.Free[vmInterval]}; DO label: Disk.Label _ initialMicrocodeLabel; ok: BOOLEAN; IF (ok _ getPage[pageBuffer]) THEN { ENABLE BadPage, Error => IF thisPage=hardUCodeStart THEN GOTO firstPageBad ELSE {thisPage _ [thisPage+1]; RETRY}; IF thisPage>=hardUCodeStart+hardUCodeSize THEN ERROR MicrocodeInstallFailure[microcodeTooBig]; label.dontCare _ LOOPHOLE[LONG[0]]; label.filePage _ thisPage-hardUCodeStart; Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer]; label.filePage _ thisPage-hardUCodeStart; Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, verify, verify], label: @label, data: pageBuffer]; }; IF thisPage#Disk.PageNumber[prevPage+1] OR ~ok THEN { ENABLE BadPage, Error => GOTO flakeyPageFound; label.filePage _ prevPage-hardUCodeStart; Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, verify, read], label: @label, data: pageBuffer]; label.filePage _ prevPage-hardUCodeStart; label.dontCare _ IF ok THEN channel.GetBootChainLink[thisPage] ELSE eofLink; Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer]; IF Disk.PageNumber[prevPage+1] < hardUCodeStart+hardUCodeSize THEN <> { label _ nullLabel; Transfer[channel: channel, firstPage: Disk.PageNumber[prevPage+1], pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer ! BadPage, Error => CONTINUE]; }; }; IF ~ok THEN EXIT; thisPage _ [(prevPage _ thisPage)+1]; REPEAT firstPageBad => ERROR MicrocodeInstallFailure[firstPageBad]; flakeyPageFound => ERROR MicrocodeInstallFailure[flakeyPageFound]; ENDLOOP; }; VM.Unpin[vmInterval]; VM.Free[vmInterval]; }; IdentifyInitialMicrocode: PUBLIC ENTRY PROC [channel: Disk.Channel] RETURNS [microcodeInstalled: BOOLEAN, time: BasicTime.GMT, name: Rope.ROPE] = { label: Disk.Label _ initialMicrocodeLabel; vmInterval: VM.Interval _ VM.Allocate[count: 1]; uCodeHeader: LONG POINTER TO MicrocodeHeader _ VM.AddressForPageNumber[vmInterval.page]; VM.Pin[vmInterval]; microcodeInstalled _ FALSE; { Transfer[channel: channel, firstPage: hardUCodeStart, pageCount: 1, command: [verify, verify, read], label: @label, data: uCodeHeader ! BadPage, Error => GOTO error]; IF uCodeHeader.name.length IN [1..uCodeHeader.name.maxlength] AND uCodeHeader.name.maxlength<=maxNameLength THEN { time _ BasicTime.FromPupTime[GMTFromBCPLTime[uCodeHeader.createDate] ! BasicTime.OutOfRange => GOTO error]; name _ ConvertUnsafe.ToRope[@uCodeHeader.name]; microcodeInstalled _ TRUE; }; EXITS error => NULL; }; VM.Unpin[vmInterval]; VM.Free[vmInterval]; }; hardUCodeFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 064732B, 064732B]; -- boot microcode knows this ID initialMicrocodeLabel: Disk.Label = [fileID: [abs[LOOPHOLE[hardUCodeFileID]]], filePage: 0, attributes: LOOPHOLE[0], dontCare: LOOPHOLE[LONG[0]]]; -- boot microcode knows this label nullFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 0, 0]; nullLabel: Disk.Label = [fileID: [abs[LOOPHOLE[nullFileID]]], filePage: 0, attributes: LOOPHOLE[0], dontCare: LOOPHOLE[LONG[0]]]; nullLink: DiskFace.DontCare = LOOPHOLE[LONG[0]]; eofLink: DiskFace.DontCare = LOOPHOLE[LONG[-1]]; MicrocodeHeader: TYPE = MACHINE DEPENDENT RECORD [ version (0): CARDINAL, mustBeZero (1): LONG CARDINAL, createDate (3): BCPLTime, name (5): StringBody]; BCPLTime: TYPE = RECORD [LONG CARDINAL]; GMTFromBCPLTime: PROCEDURE [BCPLTime] RETURNS [LONG CARDINAL] = <> MACHINE CODE {PrincOps.zEXCH}; maxNameLength: CARDINAL = 40; <<>> <> hardUCodeStart: PUBLIC Disk.PageNumber _ [4]; hardUCodeSize: PUBLIC Disk.PageCount _ 3*28-4; -- 3 cylinders overhead altoRegionJargon: PUBLIC Rope.ROPE _ "partitions"; altoRegionsMax: PUBLIC INT; -- computed by Start altoRegionsStart: PUBLIC Disk.PageNumber _ [0]; -- overlaps with initial microcode altoRegionsSize: PUBLIC Disk.PageCount _ 815*28; -- one surface of the disk altoRegionsBottomUp: PUBLIC BOOL _ FALSE; -- prefer highest partition (5 or 19) <<>> <> Start: PUBLIC PROC = { device: DiskFace.DeviceHandle = DiskFace.GetNextDevice[DiskFace.nullDeviceHandle]; cylinders: CARDINAL; IF device=DiskFace.nullDeviceHandle THEN ERROR; cylinders_ DiskFace.GetDeviceAttributes[device].cylinders; <> <> altoRegionsMax _ cylinders/815; -- terrible kludge !!!!! }; <> Transfer: PROC [channel: Disk.Channel, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, command: Disk.Command, label: LONG POINTER TO Disk.Label, data: LONG POINTER, reportSoftErrors: BOOLEAN _ FALSE] = { <> retrying: BOOLEAN _ FALSE; WHILE pageCount>0 DO <> request: Disk.Request _ [diskPage: firstPage, data: data, incrementDataPtr: FALSE, command: command, tries: IF reportSoftErrors AND ~retrying THEN 1 ELSE Disk.defaultTries, count: IF retrying THEN 1 ELSE pageCount]; countDone: Disk.PageCount; status: Disk.Status; [status: status, countDone: countDone] _ channel.DoIO[label: label, request: @request]; WITH s: status SELECT FROM changed => ERROR Error[firstPage, status]; unchanged => SELECT s.status FROM goodCompletion => IF retrying THEN {retrying _ FALSE; SIGNAL BadPage[firstPage, TRUE]}; notReady, recalibrateError, seekTimeout, memoryError, memoryFault, clientError, operationReset => ERROR Error[firstPage, status]; ENDCASE => { IF ~retrying THEN retrying _ TRUE ELSE { retrying _ FALSE; SIGNAL BadPage[firstPage, FALSE]; countDone _ countDone+1; -- skip over the bad page label.filePage _ label.filePage+1; }; }; ENDCASE => ERROR; pageCount _ pageCount-countDone; firstPage _ [firstPage+countDone]; ENDLOOP; }; }.