-- FormatTridentImpl.mesa (edited by: Taft on: 20-Jun-82 17:25:48) DIRECTORY DeviceTypes USING [sa4000], DiskChannel USING [ Address, Create, Delete, Drive, DiskPageNumber, GetDriveAttributes, GetPageAddress, GetPageNumber, Handle, PVHandle], Environment USING [Base, first64K, wordsPerPage], FormatTrident, Inline USING [LowHalf, LongCOPY], MicrocodeFile, PhysicalVolume USING [], -- exports Handle PilotDisk USING [Label, NextLabel], Process USING [Yield], 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], 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, ResidentHeap, SA4000Face, Space, String EXPORTS FormatTrident, PhysicalVolume SHARES DiskChannel =PUBLIC BEGIN OPEN Inline; Handle: PUBLIC TYPE = DiskChannel.PVHandle; DiskPageNumber: PRIVATE TYPE = FormatTrident.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; MicrocodeInstallFailure: SIGNAL [m: FormatTrident.FailureType] = CODE; NotTrident: ERROR = CODE; Format: PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL] = BEGIN ckData: LONG POINTER = Space.LongPointer[space]; cnl: DiskChannel.Handle; label: PilotDisk.Label; 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]}; SetBlock[ckData, Environment.wordsPerPage, 125252B]; SetBlock[@label, SIZE[PilotDisk.Label], 52525B]; Transfer[h, cnl, firstPage, count, w, @label, ckData]; SetBlock[@label, SIZE[PilotDisk.Label], 52525B]; Transfer[h, cnl, firstPage, count, vww, @label, ckData]; SetBlock[@label, SIZE[PilotDisk.Label], 52525B]; Transfer[h, cnl, firstPage, count, vvv, @label, ckData]; 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: 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: PROC [h: Handle, firstPage: DiskPageNumber, count: LONG CARDINAL] = BEGIN label: PilotDisk.Label; cnl: DiskChannel.Handle; AssertTrident[h]; cnl ← DiskChannel.Create[h.drive, [LONG[0]]]; Space.Map[space, Space.defaultWindow]; Transfer[ h, cnl, firstPage, count, vrr, @label, Space.LongPointer[space] ! UNWIND => {Space.Unmap[space]; DiskChannel.Delete[cnl]}]; Space.Unmap[space]; DiskChannel.Delete[cnl]; END; -- Private Procedures AssertTrident: PRIVATE 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: 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 ← 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: 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] = 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 rCount FROM >= retryLimit => 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; = retryLimit/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