-- FormatSA1000andSA4000Impl.mesa -- Last Edited by: Taft, May 22, 1983 4:47 pm -- this must be generalized to also do sa1000's. The general theory is the same, but the interface has to be a little different since SA1000's only do cylinders, and don't know about initial microcode yet. -- do something about event counts??? DIRECTORY DeviceTypes USING [sa1000, sa4000], DiskChannel USING [ Address, Create, Delete, Drive, DiskPageNumber, GetDriveAttributes, GetPageAddress, GetPageNumber, Handle, PVHandle], Environment USING [Base, first64K, wordsPerPage], FormatSA1000andSA4000, Inline USING [BITNOT, LowHalf, LongCOPY], MicrocodeFile, PhysicalVolume USING [], -- exports Handle PilotDisk USING [Label, NextLabel, nullLabel], Process USING [Yield], RandomCard USING [Init, Next], ResidentHeap USING [MakeNode], SA4000Face USING [ Command, DeviceHandle, DiskAddress, Initiate, Operation, OperationPtr, operationSize, Poll, Recalibrate, Status], Space USING [ Create, defaultWindow, Handle, LongPointer, Map, Pointer, Unmap, mds], String USING [AppendString], System USING [GreenwichMeanTime], Zone USING [Status]; FormatSA1000andSA4000Impl: PROGRAM -- should be a monitor since globals shared IMPORTS DiskChannel, Inline, MicrocodeFile, PilotDisk, Process, RandomCard, ResidentHeap, SA4000Face, Space, String EXPORTS FormatSA1000andSA4000, PhysicalVolume SHARES DiskChannel = PUBLIC BEGIN OPEN Inline; Handle: PUBLIC TYPE = DiskChannel.PVHandle; DiskPageNumber: PRIVATE TYPE = FormatSA1000andSA4000.DiskPageNumber; RetryLimit: PRIVATE TYPE = [0..10); retryLimit: PRIVATE RetryLimit = LAST[RetryLimit]; space: PRIVATE Space.Handle = Space.Create[ size: 1, parent: Space.mds]; op: PRIVATE SA4000Face.OperationPtr = MakeOperation[]; BadPage: SIGNAL [p: DiskPageNumber] = CODE; PassStarting: PUBLIC SIGNAL [pass: CARDINAL, operation: FormatSA1000andSA4000.Operation] = CODE; MicrocodeInstallFailure: SIGNAL [m: FormatSA1000andSA4000.FailureType] = CODE; NotSA1000orSA4000: ERROR = CODE; SA1000FormatTrackError, SA1000FormatCylinderError: ERROR = CODE; Format: PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL, passes: CARDINAL] = BEGIN ckData: LONG POINTER = Space.LongPointer[space]; cnl: DiskChannel.Handle; label: PilotDisk.Label; formatCount: LONG CARDINAL = AssertSA1000orSA4000[h, firstPage, count]; SetLabel: PROC [value: CARDINAL] = BEGIN SetBlock[@label, SIZE[PilotDisk.Label], value]; label.pad1 _ 0; IF label.filePageLo#0 OR label.filePageHi#0 THEN label.immutable _ label.temporary _ label.zeroSize _ FALSE; END; Space.Map[space, Space.defaultWindow]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; BEGIN ENABLE UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}; SetBlock[@label, SIZE[PilotDisk.Label], 52525B]; FOR countDone: LONG CARDINAL _ 0, countDone + formatCount WHILE countDone < count DO Transfer[h, cnl, firstPage+countDone, formatCount, w, @label, ckData]; ENDLOOP; [] _ RandomCard.Init[-1]; FOR pass: CARDINAL IN [0..passes) DO labelValue: CARDINAL _ (IF pass MOD 2 = 0 THEN RandomCard.Next[] ELSE BITNOT[labelValue]); SIGNAL PassStarting[pass+1, write]; SetLabel[labelValue]; FOR i: CARDINAL IN [0..Environment.wordsPerPage) DO (ckData+i)^ _ (IF pass MOD 2 = 0 THEN RandomCard.Next[] ELSE BITNOT[(ckData+i)^]); ENDLOOP; Transfer[h, cnl, firstPage, count, vww, @label, ckData]; SIGNAL PassStarting[pass+1, read]; SetLabel[labelValue]; Transfer[h, cnl, firstPage, count, vvv, @label, ckData, 1]; ENDLOOP; END; Space.Unmap[space]; DiskChannel.Delete[cnl]; END; IdentifyInitialMicrocode: PUBLIC PROCEDURE [h: Handle, s: STRING] RETURNS [microcodeInstalled: BOOLEAN _ FALSE, time: System.GreenwichMeanTime] = BEGIN label: PilotDisk.Label _ PilotDisk.nullLabel; page: DiskPageNumber; cnl: DiskChannel.Handle; header: POINTER TO MicrocodeFile.Header; [] _ AssertSA1000orSA4000[h]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; page _ IF DiskChannel.GetDriveAttributes[h.drive].deviceType = DeviceTypes.sa4000 THEN FormatSA1000andSA4000.SA4000startOfMicrocode ELSE FormatSA1000andSA4000.SA1000startOfMicrocode; Space.Map[space, Space.defaultWindow]; BEGIN Transfer[h: h, channel: cnl, firstPage: page, count: 1, cmd: vvr, label: @label, data: Space.LongPointer[space] ! BadPage => GOTO error]; header _ Space.Pointer[space]; IF header.name.length IN [1..header.name.maxlength] AND header.name.maxlength<=MicrocodeFile.maxNameLength AND header.name.length<=s.maxlength THEN BEGIN time _ MicrocodeFile.GMTFromBCPLTime[header.createDate]; s.length _ 0; String.AppendString[s, @header.name]; microcodeInstalled _ TRUE; END; EXITS error => NULL; END; Space.Unmap[space]; DiskChannel.Delete[cnl]; END; InstallBootMicrocode: PROC [ h: Handle, getPage: PROC RETURNS [LONG POINTER]] = BEGIN cnl: DiskChannel.Handle; [] _ AssertSA1000orSA4000[h]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; Space.Map[space, Space.defaultWindow]; InstallBootMicrocode1[ h, cnl, Space.LongPointer[space], getPage ! UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}]; Space.Unmap[space]; DiskChannel.Delete[cnl]; END; Scan: PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL, passes: CARDINAL] = BEGIN label: PilotDisk.Label; cnl: DiskChannel.Handle; [] _ AssertSA1000orSA4000[h]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; Space.Map[space, Space.defaultWindow]; FOR pass: CARDINAL IN [0..passes) DO SIGNAL PassStarting[pass+1, read]; Transfer[ h, cnl, firstPage, count, vrr, @label, Space.LongPointer[space] ! UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}]; ENDLOOP; Space.Unmap[space]; DiskChannel.Delete[cnl]; END; -- Private Procedures AssertSA1000orSA4000: PRIVATE PROC [ h: Handle, first: DiskPageNumber _ 0, count: LONG CARDINAL _ 0] RETURNS [countFormat: LONG CARDINAL] = BEGIN SELECT DiskChannel.GetDriveAttributes[h.drive].deviceType FROM DeviceTypes.sa4000 => RETURN[count]; DeviceTypes.sa1000 => BEGIN p: CARDINAL = FormatSA1000andSA4000.SA1000pagesPerTrack; IF (first MOD p) # 0 OR (count MOD p) # 0 THEN ERROR SA1000FormatTrackError; RETURN[FormatSA1000andSA4000.SA1000pagesPerTrack] END; ENDCASE => ERROR NotSA1000orSA4000 END; CopyPage: PRIVATE PROC [from, to: LONG POINTER] = INLINE {LongCOPY[from: from, to: to, nwords: Environment.wordsPerPage]; }; GetDiskAddress: PRIVATE PROC [h: DiskChannel.Handle, p: DiskPageNumber] RETURNS [SA4000Face.DiskAddress] = BEGIN x: DiskChannel.Address = DiskChannel.GetPageAddress[h, p]; RETURN[[cylinder: x.cylinder, head: x.head, sector: x.sector]]; END; GetPageNumber: PRIVATE PROC [ d: DiskChannel.Drive, a: SA4000Face.DiskAddress] RETURNS [DiskPageNumber] = BEGIN RETURN[DiskChannel.GetPageNumber[ d, [cylinder: a.cylinder, head: a.head, sector: a.sector]]] END; -- h has been asserted to be SA4000 InstallBootMicrocode1: PRIVATE PROC [ h: Handle, cnl: DiskChannel.Handle, myPage: LONG POINTER, getPage: PROC RETURNS [LONG POINTER]] = BEGIN bits: LONG POINTER; device: SA4000Face.DeviceHandle = DiskChannel.GetDriveAttributes[ h.drive].deviceHandle; thisPage, prevPage: DiskPageNumber _ 0; stopDa: SA4000Face.DiskAddress = LOOPHOLE[LONG[-1]]; offset, lastPage: DiskPageNumber; GetDA: PROC [p: DiskPageNumber] RETURNS [SA4000Face.DiskAddress] = INLINE {RETURN[GetDiskAddress[cnl, p + offset]]}; IO: PROC [ command: SA4000Face.Command, thisPage, link: SA4000Face.DiskAddress] RETURNS [success: BOOLEAN] = BEGIN label: PilotDisk.Label _ PilotDisk.nullLabel; rCount: RetryLimit _ 0; status: SA4000Face.Status; op^ _ [ command: command, device: device, clientHeader: thisPage, pageCount: 1, labelPtr: @label, dataPtr: myPage, incrementDataPtr: FALSE]; label.bootChainLink _ LOOPHOLE[link]; SA4000Face.Initiate[op]; DO SELECT status _ SA4000Face.Poll[op] FROM inProgress => {Process.Yield[]; LOOP; }; goodCompletion => EXIT; ENDCASE => BEGIN SELECT rCount FROM >= retryLimit => RETURN[FALSE]; = retryLimit/2 => SA4000Face.Recalibrate[device]; ENDCASE => NULL; rCount _ rCount + 1; op.pageCount _ 1; SA4000Face.Initiate[op]; END ENDLOOP; RETURN[IF command = vww THEN IO[vvv, thisPage, link] ELSE TRUE]; END; IF DiskChannel.GetDriveAttributes[h.drive].deviceType = DeviceTypes.sa4000 THEN BEGIN offset _ FormatSA1000andSA4000.SA4000startOfMicrocode; lastPage _ FormatSA1000andSA4000.SA4000lastPageOfMicrocode END ELSE BEGIN offset _ FormatSA1000andSA4000.SA1000startOfMicrocode; lastPage _ FormatSA1000andSA4000.SA1000lastPageOfMicrocode; END; bits _ getPage[]; IF bits = NIL THEN GOTO emptyFile; CopyPage[from: bits, to: myPage]; DO bits _ getPage[]; DO IF thisPage + offset > lastPage THEN GOTO tooBig; IF IO[ vww, GetDA[thisPage], IF bits = NIL THEN stopDa ELSE GetDA[thisPage + 1]] THEN EXIT; IF thisPage = 0 THEN GOTO firstPageBad; thisPage _ thisPage + 1; ENDLOOP; IF thisPage # prevPage + 1 AND thisPage # 0 THEN -- have to fix up previous link if we had an error BEGIN IF ~IO[vvr, GetDA[prevPage], GetDA[prevPage + 1]] THEN GOTO flakey; IF ~IO[vww, GetDA[prevPage], GetDA[thisPage]] THEN GOTO flakey; END; IF bits = NIL THEN EXIT; -- we are done and have written a zero link in the last page CopyPage[from: bits, to: myPage]; prevPage _ thisPage; thisPage _ thisPage + 1; ENDLOOP; EXITS emptyFile => SIGNAL MicrocodeInstallFailure[emptyFile]; firstPageBad => SIGNAL MicrocodeInstallFailure[firstPageBad]; flakey => SIGNAL MicrocodeInstallFailure[flakeyPageFound]; tooBig => SIGNAL MicrocodeInstallFailure[microcodeTooBig]; END; MakeOperation: PRIVATE PROC RETURNS [SA4000Face.OperationPtr] = BEGIN rp: Environment.Base RELATIVE POINTER TO SA4000Face.Operation; NoWay: ERROR = CODE; status: Zone.Status; [rp, status] _ ResidentHeap.MakeNode[n: SA4000Face.operationSize, alignment: a16]; IF status # okay THEN ERROR NoWay; RETURN[@Environment.first64K[rp]] END; SetBlock: PRIVATE PROC [blk: LONG POINTER, length, v: CARDINAL] = INLINE {blk^ _ v; LongCOPY[from: blk, to: blk + 1, nwords: length - 1]; }; -- SA4000-ness has been asserted Transfer: PRIVATE PROC [ h: Handle, channel: DiskChannel.Handle, firstPage: DiskPageNumber, count: LONG CARDINAL, cmd: SA4000Face.Command, label: POINTER TO PilotDisk.Label, data: LONG POINTER, retries: RetryLimit _ retryLimit] = BEGIN device: SA4000Face.DeviceHandle = DiskChannel.GetDriveAttributes[ h.drive].deviceHandle; rCount: RetryLimit _ 0; status: SA4000Face.Status; runStartAddr: SA4000Face.DiskAddress _ GetDiskAddress[channel, firstPage]; Ooops: PROC RETURNS [notDoneYet: BOOLEAN] = BEGIN rCount _ IF op.clientHeader = runStartAddr THEN rCount + 1 ELSE 0; SELECT TRUE FROM rCount >= retries => BEGIN page: DiskPageNumber = GetPageNumber[h.drive, op.clientHeader]; SIGNAL BadPage[page]; op.clientHeader _ GetDiskAddress[channel, page + 1]; op.pageCount _ op.pageCount - 1; PilotDisk.NextLabel[label]; -- Fix up the label to the next page rCount _ 0; END; rCount = retryLimit/2 OR (status IN [wrongSector..wrongHead] AND rCount = retries/2) => SA4000Face.Recalibrate[device]; ENDCASE => NULL; runStartAddr _ op.clientHeader; IF (notDoneYet _ op.pageCount > 0) THEN SA4000Face.Initiate[op]; END; op^ _ [ device: device, clientHeader: runStartAddr, pageCount: LowHalf[count], labelPtr: label, dataPtr: data, incrementDataPtr: FALSE, command: cmd]; IF count > LAST[CARDINAL] THEN ERROR; SA4000Face.Initiate[op]; DO SELECT status _ SA4000Face.Poll[op] FROM inProgress => {Process.Yield[]; LOOP}; goodCompletion => EXIT; ENDCASE => IF Ooops[] THEN LOOP ELSE EXIT; ENDLOOP; END; END.... LOG Time: June 1, 1980 1:23 AM By: Forrest Action: Changed to use sanitized interface. Added limit checking on InstallMicrocode. Trimmed log. Time: July 28, 1980 8:22 AM By: Forrest Action: Retrofited McJones changes for new SA4000face. Converted to SA1000and4000. Time: September 30, 1980 5:31 PM By: Luniewski Action: Increment File Page numbers in labels after finding a bad page in Transfer. 17-Jun-82 17:46:14 Taft ~= => # for Cedar compiler 21-Jun-82 18:21:10 Taft Add IdentifyInitialMicrocode May 22, 1983 4:28 pm Taft Change Format to do multiple passes with random data.