-- HelloDevImplDLion.Mesa
-- Contains Hello commands specific to DLion disks
-- Masinter 22 Aug 84 from OthelloDeviceImplD0DLion
-- Glassman 17-Jul-81 16:43:40
-- Linda 10-Mar-82 16:17:10
-- Forrest 7-Jan-82 17:40:00
-- Johnsson 8-Nov-83 9:24:59
-- there is a seperate version at least for dorados.
DIRECTORY
Device,
DeviceTypes,
FormatPilotDisk, FormatPilotDiskExtras,
OthelloDefs,
OthelloOps,
PhysicalVolume,
String USING [EquivalentStrings],
Volume;
HelloDevImplDLion: PROGRAM
IMPORTS
FormatPilotDisk, OthelloDefs, OthelloOps, PhysicalVolume, String, Volume =
BEGIN OPEN OthelloDefs, OthelloOps;
commandProcessor: CommandProcessor ← [DiskCommands];
DiskCommands: PROC [index: CARDINAL] = {
SELECT index FROM
0 => CheckDrive[];
1 => CreateVolume[];
2 => Format[];
-- => IndicateAltoness[];
3 => FetchInitialMicrocode[];
ENDCASE => IndexTooLarge};
badTableSize: CARDINAL = 200;
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 being, 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];
<<
IndicateAltoness: PUBLIC PROC = {
h: PhysicalVolume.Handle;
t: Device.Type;
MyNameIs[
myNameIs: "Reserve Alto Volume"L,
myHelpIs: "Reserve space for simulated Alto-mode partitions"L];
IF (t ← GetDriveType[(h ← GetDriveFromUser[])]) # DeviceTypes.sa4000
AND t # DeviceTypes.sa4008 THEN
AbortingCommand["Command is only for SA4000's."L]
ELSE IndicateAltoness1[h]};
>>
CheckDrive: PROC =
BEGIN
badSpots: CARDINAL;
badSpotArray: ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber;
couldDo: BOOLEAN;
h: PhysicalVolume.Handle;
p: PhysicalVolume.ID ← PhysicalVolume.nullID;
wasOnLine: BOOLEAN ← FALSE;
badTableOverflow: BOOLEAN;
MyNameIs[
myNameIs: "Check Drive"L, myHelpIs: "Scan drive for unreadable pages"L];
[couldDo, badSpots, h] ← FormatCheckDrive[@badSpotArray, check];
IF ~couldDo THEN AbortingCommand["Command can't be done for this device."L]
ELSE IF badSpots = 0 THEN {WriteLine["No bad pages found."L]; RETURN}
ELSE IF ~Wizard[] OR ~Yes["\rShall I record these pages in the bad table? "L] THEN RETURN;
-- See if was on line/put on line
DO
p ← PhysicalVolume.GetNext[p];
IF p = PhysicalVolume.nullID THEN {
p ← PhysicalVolume.AssertPilotVolume[h]; EXIT}
ELSE IF h = PhysicalVolume.GetAttributes[p].instance THEN {
wasOnLine ← TRUE; EXIT};
ENDLOOP;
badTableOverflow ← FillBadTable[@badSpotArray, badSpots, p];
IF ~wasOnLine THEN PhysicalVolume.Offline[p];
IF badTableOverflow THEN AbortingCommand["Too many bad spots."L]
ELSE WriteLine["Consider scavenging some volumes."L];
END;
Format: PROC =
BEGIN
badSpots: CARDINAL;
badSpotArray: ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber;
couldDo: BOOLEAN;
h: PhysicalVolume.Handle;
p: PhysicalVolume.ID;
badTableOverflow: BOOLEAN;
IF ~Wizard[] THEN RETURN;
MyNameIs[myNameIs: "Format"L, myHelpIs: "Format a disk drive"L];
[couldDo, badSpots, h] ← FormatCheckDrive[@badSpotArray, format];
IF ~couldDo THEN AbortingCommand["Command can't be done for this device."L];
FOR i: CARDINAL IN [0..MIN[badSpots, LENGTH[badSpotArray]]) DO
IF badSpotArray[i] = 0 THEN {WriteLine["Physical page zero bad"L]; RETURN}
ENDLOOP;
WriteLine["\rCreating Pilot volume named ""Empty"" to hold bad spot table"L];
p ← PhysicalVolume.CreatePhysicalVolume[h, "Empty"L];
badTableOverflow ← FillBadTable[@badSpotArray, badSpots, p];
PhysicalVolume.Offline[p];
IF badTableOverflow THEN AbortingCommand["Too many bad spots."L];
END;
lvTable: ARRAY [0..10) OF RECORD [
size: Volume.PageCount,
type: Volume.Type,
name: LONG STRING] ← ALL[[0, normal, NIL]];
newPvName: LONG STRING ← NIL;
CreateVolume: PROC =
BEGIN
h: PhysicalVolume.Handle;
badTable: ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber;
bad: CARDINAL ← 0;
broughtOnLine: BOOLEAN ← FALSE;
driveSize: LONG CARDINAL;
nSubVols: CARDINAL;
lvID: Volume.ID;
lvsize: Volume.PageCount;
pvID: PhysicalVolume.ID ← PhysicalVolume.nullID;
PagesRippedOff: PROC RETURNS [p: LONG CARDINAL] = INLINE {
--we don't really lose physicalVolumeOverhead
p ← MinPilotPage[h]; IF p # 0 THEN p ← p - physicalVolumeOverhead};
volumeFound: BOOLEAN ← TRUE;
MyNameIs[
myNameIs: "Create Physical Volume"L,
myHelpIs: "Format physical volume into logical volumes (old contents lost)"L];
h ← GetDriveFromUser[];
DO
pvID ← PhysicalVolume.GetNext[pvID];
IF pvID = PhysicalVolume.nullID THEN {
volumeFound ← TRUE; -- Yes["Shall I try to find an old bad page Table? "L];
IF volumeFound THEN {
broughtOnLine ← TRUE;
pvID ← PhysicalVolume.AssertPilotVolume[h !
PhysicalVolume.Error, PhysicalVolume.NeedsScavenging => {
volumeFound ← broughtOnLine ← FALSE; CONTINUE}]};
EXIT};
IF h = PhysicalVolume.GetAttributes[pvID].instance THEN EXIT;
ENDLOOP;
IF volumeFound THEN {
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};
GetName["New physical volume name: "L, @newPvName];
nSubVols ← ReadShortNumber[
"Number of logical volumes: "L, 1,
PhysicalVolume.maxSubvolumesOnPhysicalVolume, 3];
driveSize ← GetDriveSize[h] -
(physicalVolumeOverhead + nSubVols*logicalVolumeOverhead
+ PagesRippedOff[]);
driveSize ← driveSize - ReserveLastCylinderForDiag[h];
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, @lvTable[i].name];
FOR j: CARDINAL IN [0..i) WHILE ~duplicate DO
duplicate ← String.EquivalentStrings[
lvTable[i].name, lvTable[j].name] ENDLOOP;
IF ~duplicate THEN EXIT;
WriteLine["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, type];
ENDLOOP;
IF broughtOnLine THEN PhysicalVolume.Offline[pvID];
Confirm[IF volumeFound THEN twice ELSE once];
PhysicalVolume.Offline[pvID ! ANY => CONTINUE];
pvID ← PhysicalVolume.CreatePhysicalVolume[h, newPvName];
FOR i: CARDINAL IN [0..bad) DO
PhysicalVolume.MarkPageBad[pvID, badTable[i]] ENDLOOP;
FOR i: CARDINAL IN [0..nSubVols) DO
OPEN lvTable[i];
lvID ← Volume.Create[pvID, size, name, type, MinPilotPage[h]];
IF (lvsize ← Volume.GetAttributes[lvID].volumeSize) # size THEN {
WriteString[name];
WriteString["'s size decreased (because of bad pages) to "L];
WriteLongNumber[lvsize];
NewLine[]};
ENDLOOP;
END;
FetchInitialMicrocode: PROC = {
h: PhysicalVolume.Handle;
InstallProc: PROC [getPage: PROC RETURNS [LONG POINTER]] = {
WriteString["Formatting..."L];
PhysicalVolume.AssertNotAPilotVolume[h];
{ENABLE UNWIND => PhysicalVolume.FinishWithNonPilotVolume[h];
FormatPilotDisk.FormatBootMicrocodeArea[h: h, passes: 1, retries: 0 !
FormatPilotDisk.BadPage => {
WriteString["Warning: page "L]; WriteLongNumber[p];
WriteLine[" is bad (will be skipped). "L]; RESUME}];
FormatPilotDisk.InstallBootMicrocode[h, getPage]}; -- ENABLE
PhysicalVolume.FinishWithNonPilotVolume[h]};
MyNameIs[
myNameIs: "Initial Microcode Fetch"L,
myHelpIs: "Fetch and install initial microcode"L];
h ← GetDriveFromUser[];
SELECT TRUE FROM
LOOPHOLE[GetDriveType[h], CARDINAL] IN Device.PilotDisk =>
BEGIN
wasOnline: BOOLEAN = ForceOffline[h];
OthelloDefs.FetchInitialMicrocode[InstallProc
! FormatPilotDisk.MicrocodeInstallFailure =>
SELECT m FROM
emptyFile =>
AbortingCommand["That remote file is empty!"L];
firstPageBad =>
AbortingCommand["First microcode page of this disk is bad."L];
flakeyPageFound => {
WriteLine["Intermittent page in microcode area."L]; RESUME};
microcodeTooBig =>
AbortingCommand["Microcode too large."L];
ENDCASE =>
AbortingCommand["Unknown Install microcode error."L];
FormatPilotDisk.CantInstallUCodeOnThisDevice => GOTO no];
IF wasOnline THEN [] ← PhysicalVolume.AssertPilotVolume[h];
WriteLine["Done"L]
END;
ENDCASE => GOTO no;
EXITS
no => AbortingCommand["microcode can't be installed on this disk"L]};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- support Procs
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- this code depends upon Pilot's bad spot table being smaller than ours,
-- and an error being raised when Pilot's table is full.
FillBadTable: PROC [
badSpotArray: POINTER TO ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber,
badSpots: CARDINAL, p: PhysicalVolume.ID]
RETURNS [badSpotTableFull: BOOLEAN ← FALSE] = {
FOR i: CARDINAL IN [0..badSpots) DO
PhysicalVolume.MarkPageBad[p, badSpotArray[i]
! PhysicalVolume.Error =>
IF error = badSpotTableFull THEN {badSpotTableFull ← TRUE; EXIT}]
ENDLOOP};
ForceOffline: PROC [h: PhysicalVolume.Handle]
RETURNS [wasOnline: BOOLEAN ← FALSE] = {
p: PhysicalVolume.ID ← PhysicalVolume.nullID;
DO
p ← PhysicalVolume.GetNext[p];
IF p = PhysicalVolume.nullID THEN EXIT;
IF h = PhysicalVolume.GetAttributes[p].instance THEN {
wasOnline ← TRUE; PhysicalVolume.Offline[p]; EXIT};
ENDLOOP};
FormatCheckDrive: PUBLIC PROC [
bs: POINTER TO ARRAY [0..badTableSize) OF PhysicalVolume.PageNumber,
op: {format, check}]
RETURNS [couldDo: BOOLEAN, badSpots: CARDINAL, h: PhysicalVolume.Handle] = {
-- leaves pv offline for op = format; restores previous state for op = check
cbs: ARRAY [0..badTableSize) OF CARDINAL ← ALL[0];
tooManyMsg: BOOLEAN ← FALSE;
passes: CARDINAL ← 1;
NoteBad: PROC [p: PhysicalVolume.PageNumber] = {
FOR i: CARDINAL IN [0..badSpots) DO
IF bs[i] = p THEN {cbs[i] ← cbs[i] + 1; WriteBadSpot[p, cbs[i]]; RETURN}
ENDLOOP;
IF badSpots < LENGTH[bs↑] THEN {
bs[badSpots] ← p; cbs[badSpots] ← cbs[badSpots] + 1;
badSpots ← badSpots + 1; WriteBadSpot[p, 1]}
ELSE {
IF ~tooManyMsg THEN {
WriteLine["Too many bad pages"L]; tooManyMsg ← TRUE; column ← 0};
WriteBadSpot[p, 1]};
CheckUserAbort[! UNWIND => FormatSummary[]]};
FormatSummary: PROC = {
IF badSpots > 0 THEN {
column ← 0;
WriteLine["\rSummary of bad pages: badPage(countTimesBad)"L];
FOR i: CARDINAL IN [0..badSpots) DO
WriteBadSpot[bs[i], cbs[i]] ENDLOOP;
NewLine[]}};
column: CARDINAL ← 0;
WriteBadSpot: PROC [p: PhysicalVolume.PageNumber, cnt: CARDINAL] = {
WriteFixedWidthNumber[p, 8]; WriteChar['(];
WriteFixedWidthNumber[
cnt, SELECT passes FROM IN [0..9] => 1, IN [10..99] => 2, ENDCASE => 3];
WriteChar[')];
IF (column MOD 5) = 4 THEN {column ← 0; NewLine[]}
ELSE column ← column+1};
badSpots ← 0;
h ← GetDriveFromUser[];
SELECT TRUE FROM
-- dam compiler won't coerce [CARDINAL] into CARDINAL
LOOPHOLE[GetDriveType[h], CARDINAL] IN Device.PilotDisk => {
OPEN FPD: FormatPilotDisk;
pilotStart: PhysicalVolume.PageNumber = MinPilotPage[h];
retries: FormatPilotDisk.RetryLimit ← 0;
-- number of retries on bad page
cylSize: CARDINAL = CylinderSize[h];
IF op = format THEN {
passes ← ReadShortNumber["Number of passes: "L, 1, 200, 10];
retries ← ReadShortNumber[
"Number of retries: "L, FPD.noRetries, FPD.retryLimit, FPD.noRetries];
Confirm[twice];
[] ← ForceOffline[h];
-- format zero'th cylinder separately
PhysicalVolume.AssertNotAPilotVolume[h];
{ENABLE UNWIND => PhysicalVolume.FinishWithNonPilotVolume[h];
FPD.Format[h, 0, cylSize, passes, retries
! FPD.BadPage => {NoteBad[p]; RESUME}];
-- format rest of disk possibly allowing for alto-type volume
-- or other device dependent dreck
FPD.Format[h, pilotStart, GetDriveSize[h] - pilotStart, passes, retries
! FPD.BadPage => {NoteBad[p]; RESUME}]}; -- ENABLE
PhysicalVolume.FinishWithNonPilotVolume[h]}
ELSE { -- op=scan
wasOnline: BOOLEAN;
Confirm[once];
wasOnline ← ForceOffline[h];
-- scan zero'th cylinder seperatly
FPD.Scan[h, 0, cylSize
! FPD.BadPage => {NoteBad[p]; RESUME}];
-- scan rest of disk possibly allowing for alto-type volume
-- or other device dependent dreck
FPD.Scan[h, pilotStart, GetDriveSize[h] - pilotStart
! FPD.BadPage => {NoteBad[p]; RESUME}];
IF wasOnline THEN [] ← PhysicalVolume.AssertPilotVolume[h]};
FormatSummary[];
RETURN[TRUE, badSpots, h]};
ENDCASE => RETURN[FALSE, badSpots, h]};
<<
IndicateAltoness1: PROC [h: PhysicalVolume.Handle] = {
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[FormatPilotDisk.SA4000Model44Count], 1]};
>>
MinPilotPage: PROC [h: PhysicalVolume.Handle]
RETURNS [PhysicalVolume.PageNumber] = {
OPEN FPD: FormatPilotDisk;
SELECT GetDriveType[h] FROM
DeviceTypes.sa1000, DeviceTypes.sa1004 =>
RETURN[FPD.FirstSA1000PageForPilot];
DeviceTypes.q2000, DeviceTypes.q2010, DeviceTypes.q2020,
DeviceTypes.q2030, DeviceTypes.q2040, DeviceTypes.q2080 =>
RETURN[FPD.FirstQ2000PageForPilot];
DeviceTypes.sa4000, DeviceTypes.sa4008 =>
DO
dn: CARDINAL = GetDriveNumber[h];
IF sa4000Flavor[dn] IN FPD.SA4000Model44Count THEN
RETURN[FPD.SA4000FirstPageForPilot[sa4000Flavor[dn]]];
-- IndicateAltoness1[h]
ENDLOOP;
DeviceTypes.t80 => RETURN[FPD.Firstt80PageForPilot];
DeviceTypes.t300 => RETURN[FPD.Firstt300PageForPilot];
ENDCASE => RETURN[0]};
UnknownCylSize: ERROR = CODE;
CylinderSize: PROC [h: PhysicalVolume.Handle] RETURNS [cylSize: CARDINAL] = {
OPEN FPD: FormatPilotDisk, FPDx: FormatPilotDiskExtras;
SELECT GetDriveType[h] FROM
DeviceTypes.sa1000, DeviceTypes.sa1004 =>
cylSize ← FPD.SA1004pagesPerCylinder;
DeviceTypes.q2000 => cylSize ← FPD.Q2040pagesPerCylinder;
DeviceTypes.q2010 => cylSize ← FPD.Q2010pagesPerCylinder;
DeviceTypes.q2020 => cylSize ← FPD.Q2020pagesPerCylinder;
DeviceTypes.q2030 => cylSize ← FPD.Q2030pagesPerCylinder;
DeviceTypes.q2040 => cylSize ← FPD.Q2040pagesPerCylinder;
DeviceTypes.q2080 => cylSize ← FPDx.Q2080pagesPerCylinder;
DeviceTypes.sa4000, DeviceTypes.sa4008 =>
cylSize ← FPD.SA4008pagesPerCylinder;
DeviceTypes.t80 => cylSize ← FPD.t80pagesPerCylinder;
DeviceTypes.t300 => cylSize ← FPD.t300pagesPerCylinder;
ENDCASE => ERROR UnknownCylSize};
ReserveLastCylinderForDiag: PROC [h: PhysicalVolume.Handle]
RETURNS [ripOff: CARDINAL] = {
ripOff ← CylinderSize[h ! UnknownCylSize => GOTO out];
IF Wizard[] AND ~Yes["Reserve last cylinder for diagnostics? "L] THEN ripOff ← 0;
EXITS out => RETURN[0]};
RegisterCommandProc[@commandProcessor];
END.....
11-Jun-81 10:56:57 Taft Created file using excerpts from VolumeInitImplA.mesa
17-Jun-81 16:39:45 Glassman Action: Prompt for passes and retries for formatting disk, summary after all passes done
17-Jul-81 16:44:52 Glassman Action: Change name of file and print more summary information, OthelloDevice merged into OthelloDefs11-Jun-81 10:56:57 Taft Created file using excerpts from VolumeInitImplA.mesa
26-Aug-81 18:34:22 Forrest 8.0c build
14-Oct-81 20:17:53 Forrest othello reorg/add trident stuff/add diag cylinder stuff
13-Nov-81 16:24:41 Forrest 8.0e build
23-Nov-81 19:10:16 Forrest add stuff for t80, t300
10-Dec-81 16:15:15 Forrest add Quantum support; fix a couple of awful bugs in install ucode
7-Jan-82 17:39:36 Forrest Change for new FormatPilotDisk.CantInstallUCodeOnThisDevice
10-Mar-82 16:17:20 Linda Formating ==> formatting
22-Aug-84 13:06:35 Masinter remove Alto format command stuff