-- FormatTridentImpl.mesa -- Last Edited by: Taft, May 22, 1983 2:45 pm DIRECTORY DeviceTypes USING [sa4000], DiskChannel USING [ Address, Create, Delete, Drive, DiskPageNumber, GetDriveAttributes, GetPageAddress, GetPageNumber, Handle, PVHandle], Environment USING [Base, first64K, wordsPerPage], FormatTrident, Inline USING [BITNOT, LowHalf, LongCOPY], MicrocodeFile, PhysicalVolume USING [], -- exports Handle PilotDisk USING [Label, NextLabel], Process USING [Yield], RandomCard USING [Init, Next], ResidentHeap USING [MakeNode], SA4000Face USING [ Command, DeviceHandle, DiskAddress, Initiate, Operation, OperationPtr, operationSize, Poll, Recalibrate, Status], SA4000FaceExtras USING [www], Space USING [ Create, defaultWindow, Handle, LongPointer, Map, Pointer, Unmap, mds], SpecialSystem USING [nullProcessorID], String USING [AppendString], System USING [GreenwichMeanTime], SystemInternal USING [UniversalID], Zone USING [Status]; FormatTridentImpl: PROGRAM -- should be a monitor since globals shared IMPORTS DiskChannel, Inline, MicrocodeFile, PilotDisk, Process, RandomCard, ResidentHeap, SA4000Face, Space, String EXPORTS FormatTrident, PhysicalVolume SHARES DiskChannel = BEGIN OPEN Inline; Handle: PUBLIC TYPE = DiskChannel.PVHandle; DiskPageNumber: TYPE = FormatTrident.DiskPageNumber; RetryLimit: TYPE = [0..10); retryLimit: RetryLimit = LAST[RetryLimit]; space: Space.Handle = Space.Create[ size: 1, parent: Space.mds]; op: SA4000Face.OperationPtr = MakeOperation[]; BadPage: PUBLIC SIGNAL [p: DiskPageNumber] = CODE; PassStarting: PUBLIC SIGNAL [pass: CARDINAL, operation: FormatTrident.Operation] = CODE; MicrocodeInstallFailure: PUBLIC SIGNAL [m: FormatTrident.FailureType] = CODE; NotTrident: PUBLIC ERROR = CODE; Format: PUBLIC PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL, passes: CARDINAL] = BEGIN ckData: LONG POINTER = Space.LongPointer[space]; cnl: DiskChannel.Handle; label: PilotDisk.Label; 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; AssertTrident[h, firstPage, count]; Space.Map[space, Space.defaultWindow]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; BEGIN ENABLE UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}; [] _ 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, (IF pass=0 THEN SA4000FaceExtras.www ELSE 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; initialMicrocodeLabel: PilotDisk.Label = [ fileID: LOOPHOLE[SystemInternal.UniversalID[ processor: SpecialSystem.nullProcessorID, sequence: FormatTrident.hardUCodeSerial]], filePageLo: 0, filePageHi: 0, immutable: FALSE, temporary: FALSE, zeroSize: FALSE, type: [0], bootChainLink: LOOPHOLE[LONG[0]]]; IdentifyInitialMicrocode: PUBLIC PROCEDURE [h: Handle, s: STRING] RETURNS [microcodeInstalled: BOOLEAN _ FALSE, time: System.GreenwichMeanTime] = BEGIN label: PilotDisk.Label _ initialMicrocodeLabel; cnl: DiskChannel.Handle; header: POINTER TO MicrocodeFile.Header; AssertTrident[h]; cnl _ DiskChannel.Create[h.drive, [LONG[0]]]; Space.Map[space, Space.defaultWindow]; BEGIN Transfer[h: h, channel: cnl, firstPage: FormatTrident.firstHardUCodePage, 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: PUBLIC PROC [ h: Handle, getPage: PROC RETURNS [LONG POINTER]] = BEGIN cnl: DiskChannel.Handle; AssertTrident[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: PUBLIC PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL, passes: CARDINAL] = BEGIN label: PilotDisk.Label; cnl: DiskChannel.Handle; AssertTrident[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 AssertTrident: PROC [ h: Handle, first: DiskPageNumber _ 0, count: LONG CARDINAL _ 0] = BEGIN SELECT DiskChannel.GetDriveAttributes[h.drive].deviceType FROM DeviceTypes.sa4000 => RETURN; -- kludge for now, really Trident ENDCASE => ERROR NotTrident END; CopyPage: PROC [from, to: LONG POINTER] = INLINE {LongCOPY[from: from, to: to, nwords: Environment.wordsPerPage]; }; GetDiskAddress: 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: 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: 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 _ FormatTrident.firstHardUCodePage; label: PilotDisk.Label _ initialMicrocodeLabel; GetDA: PROC [p: DiskPageNumber] RETURNS [SA4000Face.DiskAddress] = INLINE {RETURN[GetDiskAddress[cnl, p]]}; IO: PROC [command: SA4000Face.Command, diskAddress: SA4000Face.DiskAddress, label: POINTER TO PilotDisk.Label] RETURNS [success: BOOLEAN] = BEGIN rCount: RetryLimit _ 0; status: SA4000Face.Status; op^ _ [ command: command, device: device, clientHeader: diskAddress, pageCount: 1, labelPtr: label, dataPtr: myPage, incrementDataPtr: FALSE]; 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; label.filePageLo _ label.filePageLo-1; -- undo +1 done by microcode RETURN[IF command = vww THEN IO[vvv, diskAddress, label] ELSE TRUE]; END; bits _ getPage[]; IF bits = NIL THEN GOTO emptyFile; CopyPage[from: bits, to: myPage]; DO bits _ getPage[]; label.bootChainLink _ LOOPHOLE[LONG[IF bits=NIL THEN -1 ELSE 0]]; DO IF thisPage >= FormatTrident.pagesReservedInPartition1 THEN GOTO tooBig; IF IO[vww, GetDA[thisPage], @label] THEN EXIT; IF thisPage = FormatTrident.firstHardUCodePage THEN GOTO firstPageBad; thisPage _ thisPage + 1; ENDLOOP; IF thisPage # prevPage + 1 AND thisPage # FormatTrident.firstHardUCodePage THEN -- have to fix up previous link if we had an error BEGIN label.filePageLo _ label.filePageLo-1; IF ~IO[vvr, GetDA[prevPage], @label] THEN GOTO flakey; label.bootChainLink _ LOOPHOLE[GetDA[thisPage]]; IF ~IO[vww, GetDA[prevPage], @label] THEN GOTO flakey; label.filePageLo _ label.filePageLo+1; 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; label.filePageLo _ label.filePageLo+1; ENDLOOP; EXITS emptyFile => SIGNAL MicrocodeInstallFailure[emptyFile]; firstPageBad => SIGNAL MicrocodeInstallFailure[firstPageBad]; flakey => SIGNAL MicrocodeInstallFailure[flakeyPageFound]; tooBig => SIGNAL MicrocodeInstallFailure[microcodeTooBig]; END; MakeOperation: 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: 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: 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: NULL, labelPtr: label, dataPtr: data, incrementDataPtr: FALSE, command: cmd]; WHILE count>0 DO thisCount: CARDINAL = IF count>LAST[CARDINAL] THEN LAST[CARDINAL] ELSE LowHalf[count]; op.pageCount _ thisCount; SA4000Face.Initiate[op]; DO SELECT status _ SA4000Face.Poll[op] FROM inProgress => {Process.Yield[]; LOOP}; goodCompletion => EXIT; ENDCASE => IF Ooops[] THEN LOOP ELSE EXIT; ENDLOOP; count _ count-thisCount; 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. December 12, 1980 10:39 AM Taft Create from FormatSA1000andSA4000impl.mesa for Dorado. March 10, 1981 5:31 PM: Taft Make Transfer work for run of >65535 pages. 17-Jun-82 10:06:54 Taft Re-implement InstallBootMicrocode for Dorado 20-Jun-82 16:18:48 Taft Add IdentifyInitialMicrocode May 22, 1983 12:27 pm Taft Change Format to do multiple passes with random data.