-- OthelloDeviceImplD0DLion.mesa modified September 12, 1982 1:43 pm by Taft
-- Contains Othello commands and operations that are specific to disks connected to D0s and Dandelions.
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
! FSa.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
t: Device.Type;
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;
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] = IF op=format THEN FSa.Format ELSE FSa.Scan;
FormatConfirm[];
proc[h, 0, ucodeSize ! FSa.BadPage => {NoteBad[p]; RESUME}];
proc[h, pilotStart, GetDriveSize[h]-pilotStart
! FSa.BadPage => {NoteBad[p]; 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