-- OthelloDeviceImplD0DLion.mesa -- Contains Othello commands and operations that are specific to disks connected to D0s and Dandelions. -- Last Edited by: Taft, May 22, 1983 4:47 pm DIRECTORY Device, DeviceTypes USING [sa1000, sa4000, sa800], FloppyChannel USING [Status], FormatSA1000andSA4000, FormatSA800, OthelloDefs, OthelloDevice, OthelloOps, PhysicalVolume, String USING [EquivalentStrings], System USING [GreenwichMeanTime], Volume; OthelloDeviceImplD0DLion: PROGRAM IMPORTS FormatSA1000andSA4000, FormatSA800, OthelloDefs, OthelloOps, PhysicalVolume, String, Volume EXPORTS OthelloDevice = BEGIN OPEN OthelloDefs, OthelloOps, OthelloDevice; printNameSA4000: PUBLIC STRING _ "Shugart 4000"; 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; sa4000Flavor: PACKED ARRAY [0..8) OF [0..377B] _ ALL[377B]; LvRecord: TYPE = MACHINE DEPENDENT RECORD[ 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 D0/DLion device-specific SIGNALs are caught here, remaining ones by caller. ! FormatSA1000andSA4000.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; FormatSA800.BadSector, FormatSA1000andSA4000.BadPage => {WriteString["\rBadPage?"L]; DebugAsk[]; CONTINUE}; FormatSA1000andSA4000.NotSA1000orSA4000 => {WriteString["\rNotSAx000?"L]; DebugAsk[]; CONTINUE}; FormatSA1000andSA4000.SA1000FormatCylinderError => {WriteString["\rSA1000CylinderBoundry?"L]; DebugAsk[]; CONTINUE} ]; END; CreateVolume: PUBLIC PROC= BEGIN h: PhysicalVolume.Handle = GetDriveFromUser[]; badTable: ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber; bad: CARDINAL _ 0; broughtOnLine: BOOLEAN _ FALSE; driveSize: LONG CARDINAL; nSubVols: CARDINAL; lvID: Volume.ID; lvsize: Volume.PageCount; lvTable: ARRAY [0..10) OF LvRecord _ ALL[[]]; pvID: PhysicalVolume.ID _ PhysicalVolume.nullID; pvName: STRING _ [maxNameLength]; PagesRippedOff: PROC RETURNS [p: LONG CARDINAL] = --we don't really lose pg 0 INLINE {p _ MinPilotPage[h]; IF p # 0 THEN p _ p - 1}; volumeFound: BOOLEAN _ TRUE; 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; GetName["New physical volume name: "L, pvName]; nSubVols _ ReadShortNumber[ "Number of logical volumes: "L, 1, PhysicalVolume.maxSubvolumesOnPhysicalVolume, 3]; driveSize _ GetDriveSize[h] - (physicalVolumeOverhead + nSubVols*logicalVolumeOverhead + PagesRippedOff[]); FOR i: CARDINAL IN [0..nSubVols) DO OPEN lvTable[i]; 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 _ ReadNumber[" Pages: "L, minLogicalVolumeSize, driveSize-((nSubVols-(i+1)) * minLogicalVolumeSize), driveSize/(nSubVols-i)]; driveSize _ driveSize - 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; FOR i: CARDINAL IN [0..nSubVols) DO OPEN lvTable[i]; lvID _ PhysicalVolume.CreateLogicalVolume[ pvID, size, @name, type, MinPilotPage[h]]; IF (lvsize_Volume.GetAttributes[lvID].volumeSize)#size THEN BEGIN WriteString[@name]; WriteString["'s size decreased (because of bad pages) to "L]; WriteLongNumber[lvsize]; NewLine[]; END; ENDLOOP; 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}; GetName["File name: "L, file]; Confirm[]; SELECT (t _ GetDriveType[h]) FROM DeviceTypes.sa1000, DeviceTypes.sa4000 => BEGIN OPEN FSa: FormatSA1000andSA4000; startOfMicrocode: FSa.DiskPageNumber; cnt: LONG CARDINAL; P: PROC [getPage: PROC RETURNS[LONG POINTER]] = {FSa.InstallBootMicrocode[h, getPage]}; IF t=DeviceTypes.sa1000 THEN BEGIN startOfMicrocode _ FSa.SA1000startOfMicrocode; cnt _ 1+FSa.SA1000lastPageOfMicrocode-FSa.SA1000startOfMicrocode; END ELSE -- SA4000 BEGIN startOfMicrocode _ FSa.SA4000startOfMicrocode; cnt _ 1+FSa.SA4000lastPageOfMicrocode-FSa.SA4000startOfMicrocode; END; FSa.Format[h, startOfMicrocode, cnt, 1 ! FSa.BadPage => BEGIN WriteString["Warning: page "L]; WriteLongNumber[p]; WriteLine[" is bad (will be skipped). "L]; RESUME; END; FSa.PassStarting => RESUME]; 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 t: Device.Type; badSpotsThisPass: CARDINAL _ 0; passes: CARDINAL; NoteBad: PROC [p: PhysicalVolume.PageNumber] = BEGIN FOR i: CARDINAL IN [0..badSpots) DO IF p = bs[i] THEN RETURN; ENDLOOP; IF badSpotsThisPass=0 THEN WriteString[" Bad pages found:"L]; IF (badSpotsThisPass MOD 6)=0 THEN NewLine[]; WriteFixedWidthNumber[p, 11]; IF badSpots IN [0..LENGTH[bs^]) THEN bs[badSpots] _ p; badSpotsThisPass _ badSpotsThisPass + 1; badSpots _ badSpots+1; END; NotePassStarting: PROC [pass: CARDINAL, operation: FormatSA1000andSA4000.Operation] = BEGIN WriteString["\rPass "L]; WriteFixedWidthNumber[pass, 3]; WriteString[IF operation=write THEN ", writing."L ELSE ", reading."L]; badSpotsThisPass _ 0; END; FormatConfirm: PROC = BEGIN 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; END; h _ GetDriveFromUser[]; badSpots _ 0; SELECT (t _ GetDriveType[h]) FROM DeviceTypes.sa1000, DeviceTypes.sa4000 => BEGIN OPEN FSa: FormatSA1000andSA4000; pilotStart: PhysicalVolume.PageNumber = MinPilotPage[h]; ucodeSize: LONG CARDINAL = ( IF t=DeviceTypes.sa1000 THEN FSa.SA1000lastPageOfMicrocode+1 ELSE FSa.SA4000lastPageOfMicrocode+1); proc: PROC[h: PhysicalVolume.Handle, firstPage: PhysicalVolume.PageNumber, count: LONG CARDINAL, passes: CARDINAL] = IF op=format THEN FSa.Format ELSE FSa.Scan; passes _ ReadShortNumber["Number of passes: "L, 1, 1000, (IF op=format THEN 10 ELSE 1)]; FormatConfirm[]; proc[h, 0, ucodeSize, passes ! FSa.BadPage => {NoteBad[p]; RESUME}; FSa.PassStarting => RESUME]; proc[h, pilotStart, GetDriveSize[h]-pilotStart, passes ! FSa.BadPage => {NoteBad[p]; RESUME}; FSa.PassStarting => {NotePassStarting[pass, operation]; RESUME}]; RETURN[TRUE, badSpots, h]; END; DeviceTypes.sa800 => BEGIN OPEN FormatSA800; result: PilotResult; status: FloppyChannel.Status; -- currently for debug purposes FormatConfirm[]; IF op=format THEN BEGIN density: Density = IF Yes["Double density? "L] THEN double ELSE single; name: STRING _ "PilotV"L; GetName["Track 0 Name"L, name]; [status, result] _ FormatPilotDisk[ h, name, density ! BadSector => {NoteBad[p]; RESUME}] END ELSE [status, result] _ ScanPilotDisk[h ! BadSector => {NoteBad[p]; RESUME}]; SELECT result FROM goodDisk => RETURN[TRUE, badSpots, h]; cantSetContext => ReportError["Can't set context"L]; badTrack0 => ReportError["Track 0 bad; disk unusable"L]; badLabelArea => ReportError["Label area bad; disk unusable"L]; ENDCASE => ReportError["Unknown floppy format error"L]; END; ENDCASE; RETURN[FALSE, badSpots, h]; END; IdentifyInitialMicrocode: PUBLIC PROCEDURE [h: PhysicalVolume.Handle, s: STRING] RETURNS [microcodeInstalled: BOOLEAN _ FALSE, time: System.GreenwichMeanTime] = BEGIN SELECT GetDriveType[h] FROM DeviceTypes.sa1000, DeviceTypes.sa4000 => [microcodeInstalled, time] _ FormatSA1000andSA4000.IdentifyInitialMicrocode[h, s]; ENDCASE => NULL; END; IndicateAltoness: PUBLIC PROC= BEGIN h: PhysicalVolume.Handle = GetDriveFromUser[]; IF GetDriveType[h] # DeviceTypes.sa4000 THEN ReportError["Command is only for SA4000's."L] ELSE IndicateAltoness1[h]; END; IndicateAltoness1: PROC[h: PhysicalVolume.Handle]= BEGIN dn: CARDINAL = GetDriveNumber[h]; sa4000Flavor[dn] _ 377B; IF ~Yes["Reserve space for alto volume? "L] THEN {sa4000Flavor[dn] _ 0; RETURN}; sa4000Flavor[dn] _ ReadShortNumber[ "Number of Model 44's:"L, 1, LAST[FormatSA1000andSA4000.SA4000Model44Count], 1]; END; MinPilotPage: PROC [h: PhysicalVolume.Handle] RETURNS[PhysicalVolume.PageNumber] = BEGIN OPEN FSa: FormatSA1000andSA4000; dn: CARDINAL = GetDriveNumber[h]; SELECT GetDriveType[h] FROM DeviceTypes.sa1000 => RETURN[FSa.FirstSA1000PageForPilot]; DeviceTypes.sa4000 => DO IF sa4000Flavor[dn] IN FSa.SA4000Model44Count THEN RETURN[FSa.SA4000FirstPageForPilot[sa4000Flavor[dn]]]; IndicateAltoness1[h] ENDLOOP; ENDCASE => RETURN[0]; END; PartitionCmd: PUBLIC PROC = {ReportError["Command not applicable to Dolphin."L]}; END. 11-Jun-81 10:56:57 Taft Created file using excerpts from VolumeInitImplA.mesa 4-Jun-82 8:23:39 Taft Handle CredentialError from Retrieve 21-Jun-82 18:03:57 Taft Add IdentifyInitialMicrocode September 8, 1982 10:51 am Taft Rename to OthelloDeviceImplD0DLion.mesa September 10, 1982 11:34 am Taft Mods for new Cedar Login May 22, 1983 4:36 pm Taft Modify FormatCheckDrive for multi-pass Format and Scan.