-- OthelloDeviceImplDorado.mesa -- Contains Othello commands and operations that are specific to disks connected to Dorados. -- Last Edited by: Taft, February 15, 1983 11:06 am DIRECTORY Device, DeviceTypes USING [sa4000], FormatTrident, OthelloDefs, OthelloDevice, OthelloOps, PhysicalVolume, String USING [AppendDecimal, AppendString, EquivalentStrings], System USING [GreenwichMeanTime], Volume; OthelloDeviceImplDorado: PROGRAM IMPORTS FormatTrident, OthelloDefs, OthelloOps, PhysicalVolume, String, Volume EXPORTS OthelloDevice = BEGIN OPEN OthelloDefs, OthelloDevice; printNameSA4000: PUBLIC STRING ← "Trident"; logicalVolumeOverhead: CARDINAL = 1; minLogicalVolumeSize: CARDINAL = 50; -- fudge + 1+1+6; maxNameLength: CARDINAL = PhysicalVolume.maxNameLength; -- BUG! The following statement is wrong! physicalVolumeOverhead should be set based upon device type. This will be necessary once Pilot knows how to create bad page tables based upon device types. For the time bbeing, we just KNOW that all bad page tables are one page long, and that as a result there are always two pages of physical volume overhead. physicalVolumeOverhead: CARDINAL = 2; partitionsForPilot: PACKED ARRAY FormatTrident.Partition OF BOOLEAN; partitionsSpecified: BOOLEAN ← FALSE; DiskLayout: TYPE = RECORD [ nDiskPageRuns: CARDINAL, diskPageRuns: ARRAY [0..LAST[FormatTrident.Partition]/2] OF RECORD [ base: PhysicalVolume.PageNumber, size, remaining: Volume.PageCount]]; systemDiskLayout: DiskLayout; -- for drive 0 LvRecord: TYPE = MACHINE DEPENDENT RECORD[ base: PhysicalVolume.PageNumber ← NULL, size: Volume.PageCount ← NULL, type: Volume.Type ← NULL, fill: [0..16000] ← 0, name: StringBody ← [maxlength: maxNameLength, length: 0, text: ], txt: PACKED ARRAY [0..maxNameLength) OF CHARACTER ← NULL]; CallCommandProc: PUBLIC PROC [proc: PROC] = BEGIN proc[ -- All Dorado device-specific SIGNALs are caught here, remaining ones by caller. ! FormatTrident.MicrocodeInstallFailure => BEGIN NewLine[]; ReportError[SELECT m FROM emptyFile => "\rThat remote file is empty!"L, firstPageBad => "\rFirst microcode page of this disk is bad."L, flakeyPageFound => "\rIntermittent page in microcode area."L, microcodeTooBig => "\rMicrocode too large."L, ENDCASE => "\rUnknown Install microcode error."L]; RESUME; END; FormatTrident.BadPage => {WriteString["\rBadPage?"L]; DebugAsk[]; CONTINUE}; FormatTrident.NotTrident => {WriteString["\rNotTrident?"L]; DebugAsk[]; CONTINUE} ]; END; CreateVolume: PUBLIC PROC= BEGIN h: PhysicalVolume.Handle = GetDriveFromUser[]; driveNumber: CARDINAL = GetDriveNumber[h]; layout: DiskLayout; badTable: ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber; bad: CARDINAL ← 0; broughtOnLine: BOOLEAN ← FALSE; nSubVols: CARDINAL; lvID: Volume.ID; lvsize: Volume.PageCount; lvTable: ARRAY [0..10) OF LvRecord ← ALL[[]]; pvID: PhysicalVolume.ID ← PhysicalVolume.nullID; pvName: STRING ← [maxNameLength]; volumeFound: BOOLEAN ← TRUE; run: CARDINAL; currentBase: PhysicalVolume.PageNumber; DO pvID ← PhysicalVolume.GetNext[pvID]; IF pvID=PhysicalVolume.nullID THEN BEGIN volumeFound ← Yes["Shall I try to find an old bad page Table? "L]; IF volumeFound THEN BEGIN broughtOnLine ← TRUE; pvID ← PhysicalVolume.AssertPilotVolume[h ! PhysicalVolume.Error, PhysicalVolume.CanNotScavenge => { volumeFound ← broughtOnLine ← FALSE; CONTINUE }] END; EXIT; END; IF h=PhysicalVolume.GetAttributes[pvID].instance THEN EXIT; ENDLOOP; IF volumeFound THEN BEGIN OPEN PhysicalVolume; badTable[bad] ← GetNextBadPage[pvID, nullBadPage]; WHILE badTable[bad]#nullBadPage DO badTable[bad+1] ← GetNextBadPage[pvID, badTable[bad]]; bad ← bad+1; ENDLOOP; volumeFound ← PhysicalVolume.GetNextLogicalVolume[ pvID, Volume.nullID]#Volume.nullID; END; IF driveNumber=0 AND ~partitionsSpecified THEN PartitionCmd[]; IF driveNumber=0 THEN layout ← systemDiskLayout ELSE BEGIN layout.nDiskPageRuns ← 1; layout.diskPageRuns[0] ← [ base: physicalVolumeOverhead, size: OthelloOps.GetDriveSize[h]-physicalVolumeOverhead, remaining: 0]; END; GetName["New physical volume name: "L, pvName]; nSubVols ← ReadShortNumber[ "Number of logical volumes: "L, 1, PhysicalVolume.maxSubvolumesOnPhysicalVolume, 3]; FOR r: CARDINAL IN [0..layout.nDiskPageRuns) DO layout.diskPageRuns[r].remaining ← layout.diskPageRuns[r].size; ENDLOOP; FOR i: CARDINAL IN [0..nSubVols) DO OPEN lvTable[i]; IF layout.nDiskPageRuns>1 THEN BEGIN WriteString["Remaining space is in "L]; WriteLongNumber[layout.nDiskPageRuns]; WriteString[" runs of "L]; FOR r: CARDINAL IN [0..layout.nDiskPageRuns) DO IF r#0 THEN WriteString[", "]; WriteLongNumber[layout.diskPageRuns[r].remaining]; ENDLOOP; WriteLine[" pages."L]; END; WriteString["Logical volume "L]; WriteLongNumber[LONG[i]]; NewLine[]; DO duplicate: BOOLEAN ← FALSE; GetName[" Name: "L, @name]; FOR j: CARDINAL IN [0..i) WHILE ~duplicate DO duplicate ← String.EquivalentStrings[@name, @lvTable[j].name]; ENDLOOP; IF ~duplicate THEN EXIT; ReportError["Name is already in use; please choose another"L]; ENDLOOP; size ← 0; FOR r: CARDINAL IN [0..layout.nDiskPageRuns) DO size ← MAX[size, layout.diskPageRuns[r].remaining]; ENDLOOP; IF size<minLogicalVolumeSize THEN BEGIN ReportError["Insufficient space for any more volumes"L]; ERROR OthelloDefs.TryAgain; END; size ← ReadNumber[" Pages: "L, minLogicalVolumeSize, size, size/(nSubVols-i)]; -- "best-fit" run assignment run ← LAST[CARDINAL]; FOR r: CARDINAL IN [0..layout.nDiskPageRuns) DO IF size<=layout.diskPageRuns[r].remaining AND (run=LAST[CARDINAL] OR layout.diskPageRuns[r].remaining < layout.diskPageRuns[run].remaining) THEN run ← r; ENDLOOP; base ← layout.diskPageRuns[run].base + layout.diskPageRuns[run].size - layout.diskPageRuns[run].remaining; layout.diskPageRuns[run].remaining ← layout.diskPageRuns[run].remaining-size; type ← GetLvTypeFromUser[" Type: "L]; ENDLOOP; IF broughtOnLine THEN PhysicalVolume.Offline[pvID]; Confirm[IF volumeFound THEN twice ELSE once]; PhysicalVolume.Offline[pvID ! ANY => CONTINUE]; pvID ← PhysicalVolume.CreatePhysicalVolume[h, pvName]; FOR i: CARDINAL IN [0..bad) DO PhysicalVolume.MarkPageBad[pvID, badTable[i]]; ENDLOOP; currentBase ← 0; THROUGH [0..nSubVols) DO -- Create logical volumes in increasing order of base disk address. -- This is required due to peculiar behavior of CreateLogicalVolume. leastBase: PhysicalVolume.PageNumber ← LAST[PhysicalVolume.PageNumber]; lvIndex: CARDINAL; FOR i: CARDINAL IN [0..nSubVols) DO IF lvTable[i].base > currentBase AND lvTable[i].base < leastBase THEN BEGIN lvIndex ← i; leastBase ← lvTable[i].base; END; ENDLOOP; -- Now lvIndex denotes the lowest logical volume not already created. BEGIN OPEN lvTable[lvIndex]; currentBase ← base; lvID ← PhysicalVolume.CreateLogicalVolume[ pvID, size-logicalVolumeOverhead, @name, type, base]; IF (lvsize←Volume.GetAttributes[lvID].volumeSize)#size-logicalVolumeOverhead THEN BEGIN WriteString[@name]; WriteString["'s size decreased (because of bad pages) to "L]; WriteLongNumber[lvsize]; NewLine[]; END; END; ENDLOOP; IF driveNumber=0 THEN InstallUserCredentials[]; END; FetchInitialMicrocode: PUBLIC PROC = BEGIN h: PhysicalVolume.Handle ← GetDriveFromUser[]; msg: STRING ← [100]; t: Device.Type; IF ~ftpOpen THEN {ReportError["Please open a connection first"L]; RETURN}; IF GetDriveNumber[h]#0 THEN { ReportError["Initial microcode can be put on drive 0 only"L]; RETURN}; GetName["File name: "L, file]; Confirm[]; SELECT (t ← GetDriveType[h]) FROM DeviceTypes.sa4000 => BEGIN OPEN FT: FormatTrident; P: PROC [getPage: PROC RETURNS[LONG POINTER]] = {FT.InstallBootMicrocode[h, getPage]}; FT.Format[h, FT.firstHardUCodePage, FT.pagesReservedInPartition1 - FT.firstHardUCodePage ! FT.BadPage => BEGIN WriteString["Warning: page "L]; WriteLongNumber[p]; WriteLine[" is bad (will be skipped). "L]; RESUME; END]; WriteString["Fetching..."L]; [] ← Retrieve[remoteFile: file, msg: msg, destination: [rawWrite[P]] ! CredentialError => { PromptForCredentials[ftpError, message]; RESUME }]; WriteLine["Done"L]; END; ENDCASE => ReportError["Othello can't install microcode on that device."L]; IF msg.length#0 THEN ReportError[msg]; END; FormatCheckDrive: PUBLIC PROC [ bs: POINTER TO ARRAY[0..badTableSize) OF PhysicalVolume.PageNumber, op: FormatCheckOp] RETURNS [couldDo: BOOLEAN, badSpots: CARDINAL, h: PhysicalVolume.Handle] = BEGIN driveNumber: CARDINAL; t: Device.Type; layout: DiskLayout; NoteBad: PROC [p: PhysicalVolume.PageNumber] = BEGIN IF badSpots=0 THEN WriteLine["Bad pages found:"L]; IF badSpots IN [0..LENGTH[bs↑]) THEN bs[badSpots] ← p; WriteFixedWidthNumber[p, 11]; badSpots ← badSpots + 1; IF (badSpots MOD 6)=0 THEN NewLine[]; END; h ← GetDriveFromUser[]; driveNumber ← GetDriveNumber[h]; IF driveNumber=0 AND ~partitionsSpecified THEN PartitionCmd[]; IF driveNumber=0 THEN layout ← systemDiskLayout ELSE BEGIN layout.nDiskPageRuns ← 1; layout.diskPageRuns[0] ← [ base: 0, size: OthelloOps.GetDriveSize[h], remaining: 0]; END; badSpots ← 0; IF op=check THEN Confirm[once] ELSE -- op=format BEGIN p: PhysicalVolume.ID ← PhysicalVolume.nullID; Confirm[twice]; DO p ← PhysicalVolume.GetNext[p]; IF p=PhysicalVolume.nullID THEN EXIT; IF h = PhysicalVolume.GetAttributes[p].instance THEN { PhysicalVolume.Offline[p]; EXIT }; ENDLOOP; END; SELECT (t ← GetDriveType[h]) FROM DeviceTypes.sa4000 => -- kludge, really Trident BEGIN OPEN FormatTrident; proc: PROC[ h: PhysicalVolume.Handle, firstPage: PhysicalVolume.PageNumber, count: LONG CARDINAL]; proc ← IF op=format THEN Format ELSE Scan; IF driveNumber=0 THEN proc[h, 0, pagesReservedInPartition1 ! BadPage => { NoteBad[p]; RESUME }]; FOR r: CARDINAL IN [0..layout.nDiskPageRuns) DO proc[h, layout.diskPageRuns[r].base, layout.diskPageRuns[r].size ! BadPage => { NoteBad[p]; RESUME }]; ENDLOOP; END; ENDCASE => RETURN[FALSE, badSpots, h]; RETURN[TRUE, badSpots, h]; END; IdentifyInitialMicrocode: PUBLIC PROCEDURE [h: PhysicalVolume.Handle, s: STRING] RETURNS [microcodeInstalled: BOOLEAN ← FALSE, time: System.GreenwichMeanTime] = BEGIN SELECT GetDriveType[h] FROM DeviceTypes.sa4000 => -- kludge, really Trident [microcodeInstalled, time] ← FormatTrident.IdentifyInitialMicrocode[h, s]; ENDCASE => NULL; END; IndicateAltoness: PUBLIC PROC = {ReportError["Command not applicable to Dorado."L]}; PartitionCmd: PUBLIC PROC = BEGIN OPEN FormatTrident; first: Partition; partitionsSpecified ← FALSE; WHILE ~partitionsSpecified DO FOR partition: Partition IN Partition DO prompt: STRING ← [50]; String.AppendString[prompt, "Include partition "L]; String.AppendDecimal[prompt, partition]; String.AppendString[prompt, " in the Pilot file system? "L]; partitionsForPilot[partition] ← Yes[prompt]; ENDLOOP; systemDiskLayout.nDiskPageRuns ← 0; first ← FIRST[Partition]; WHILE first IN Partition DO IF partitionsForPilot[first] THEN BEGIN OPEN run: systemDiskLayout.diskPageRuns[systemDiskLayout.nDiskPageRuns]; length: CARDINAL ← 1; overhead: Volume.PageCount ← IF first=FIRST[Partition] THEN pagesReservedInPartition1 ELSE 0; WHILE first+length IN Partition AND partitionsForPilot[first+length] DO length ← length+1; ENDLOOP; run.base ← (first-FIRST[Partition])*pagesInPartition + overhead; run.size ← length*pagesInPartition - overhead; systemDiskLayout.nDiskPageRuns ← systemDiskLayout.nDiskPageRuns+1; first ← first+length; END ELSE first ← first+1; ENDLOOP; partitionsSpecified ← systemDiskLayout.nDiskPageRuns>0; ENDLOOP; END; END. 12-Jun-81 16:15:16 Taft Created file using excerpts from VolumeInitImplA.mesa 17-Jun-82 14:36:08 Taft Re-implement FetchInitialMicrocode 20-Jun-82 16:10:45 Taft Add IdentifyInitialMicrocode September 10, 1982 11:34 am Taft Mods for new Cedar Login