// BFSInit.bcpl
// Copyright Xerox Corporation 1979, 1980
// Last modified November 17, 1980 6:22 PM by Boggs
get "AltoFileSys.d"
get "Disks.d"
get "BFS.d"
get "Streams.d"
get "AltoDefs.d"
external
[
// outgoing procedures
BFSInit; BFSTryDisk
// incoming procedures from other BFS modules
BFSActOnPages; BFSVirtualDA; BFSRealDA; BFSNonEx
BfsInitializeCbStorage; BfsDoDiskCommand; BfsGetCb
BFSWritePages; BFSCreateFile; BFSDeletePages
BFSAssignDiskPage; BFSReleaseDiskPage; BFSCreateDDMgr; BFSClose
// incoming procedures from the OS
ActOnDiskPages; VirtualDiskDA; OpenDD
Zero; MoveBlock; DoubleAdd; Usc
DefaultArgs; Allocate; Free; ReturnFrom
ReadBlock; Closes; Gets; GetCurrentFa; PositionPage
OpenFile; SetWorkingDir
]
//----------------------------------------------------------------------------
let BFSInit(diskZone, allocate, driveNum, ddMgr, freshDisk,
tempZone; numargs na) = valof
//----------------------------------------------------------------------------
// diskZone is the free storage zone from which permanent disk structures
// are allocated.
// If allocate is false, operations involving page allocation/deallocation
// are not permitted.
// DriveNum is the physical unit number on which SysDir starts.
// It may include a partition number (see Bfs.d).
// If ddMgr is zero, a ddMgr is created.
// If freshDisk is true, DiskDescriptor is NOT read.
// TempZone (which defaults to diskZone) is used for temporary storage
// needs during BFSInit.
[
DefaultArgs(lv na, -1, 0, 0, 0, false, diskZone)
// First see if the drive is on line
unless BFSTryDisk(driveNum, 0) resultis 0
// Setup structures needed for subsequent accesses
let disk = Allocate(diskZone, lBFSDSK); Zero(disk, lBFSDSK)
disk>>BFSDSK.zone = diskZone
disk>>BFSDSK.initmode = allocate
disk>>DSK.ActOnDiskPages = BFSActOnPages
disk>>DSK.WriteDiskPages = BFSWritePages
disk>>DSK.CreateDiskFile = BFSCreateFile
disk>>DSK.DeleteDiskPages = BFSDeletePages
disk>>DSK.AssignDiskPage = BFSAssignDiskPage
disk>>DSK.ReleaseDiskPage = BFSReleaseDiskPage
disk>>DSK.CloseDisk = BFSClose
disk>>DSK.VirtualDiskDA = BFSVirtualDA
disk>>DSK.RealDiskDA = BFSRealDA
disk>>DSK.InitializeDiskCBZ = BfsInitializeCbStorage
disk>>DSK.DoDiskCommand = BfsDoDiskCommand
disk>>DSK.GetDiskCb = BfsGetCb
// Deny access in certain cases
// WriteDiskPages is NOT included because it has several uses
// that do not require modifications to the bit table.
unless allocate do
[
disk>>DSK.CreateDiskFile = BFSNonEx
disk>>DSK.DeleteDiskPages = BFSNonEx
disk>>DSK.AssignDiskPage = BFSNonEx
disk>>DSK.ReleaseDiskPage = BFSNonEx
]
// FP's
disk>>DSK.fpSysDir = lv disk>>BFSDSK.fpBFSSysDirblk
disk>>DSK.fpDiskDescriptor = lv disk>>BFSDSK.fpBFSDDblk
disk>>DSK.fpWorkingDir = lv disk>>BFSDSK.fpBFSWDblk
// Other parameters
disk>>DSK.lnPageSize = BFSlnWordsPerPage
disk>>DSK.driveNumber = driveNum
disk>>DSK.retryCount = 8
disk>>DSK.totalErrors = 0
disk>>DSK.diskKd = lv disk>>BFSDSK.kd
disk>>DSK.lengthCBZ = lBFSCBZ
disk>>DSK.lengthCB = lCB
// BFSInit (cont'd)
// This is the physical shape of the disk.
// If we read DiskDescriptor down below,
// we may install a different logical shape
disk>>BFSDSK.nDisks = driveNum<<DriveNumber.drive eq 1? 1,
BFSTryDisk(driveNum+1, 0)? 2, 1
disk>>BFSDSK.nTracks = BFSTryDisk(driveNum, 203)? BFS44NTracks, BFS31NTracks
disk>>BFSDSK.nHeads = BFSmNHeads
disk>>BFSDSK.nSectors = BFSTryDisk(driveNum, 0, 13)? 14, BFSmNSectors
// Setup directory fp and default working dir
let fpBFSSysDir = lv disk>>BFSDSK.fpBFSSysDirblk
MoveBlock(fpBFSSysDir, table [ 100000b; 100; 1; 0; 1 ], lFP)
disk>>DSK.nameWorkingDir = lv disk>>BFSDSK.WDNameblk
SetWorkingDir("<SysDir.", fpBFSSysDir, disk)
unless freshDisk do // Read the disk descriptor
[
// Quick blunder check:
let DAs = vec 2; DAs!1 = 1
let buf = Allocate(tempZone, BFSwordsPerPage)
unless ActOnDiskPages(disk, 0, DAs+1, fpBFSSysDir, 0, 0, DCreadD,
0, 0, buf, 0, lv BFSInitError, true) eq 0 do
[ Free(tempZone, buf); Free(diskZone, disk); resultis 0 ] //no SysDir
// Get the disk shape from the DSHAPE file property in SysDir's
// leader page, if present.
if buf>>LD.propertyBegin ge offset LD.leaderProps/16 &
buf>>LD.propertyBegin + buf>>LD.propertyLength le
(offset LD.leaderProps + size LD.leaderProps)/16 then
[
let fProp = buf + buf>>LD.propertyBegin
let maxFProp = fProp + buf>>LD.propertyLength
until fProp>>FPROP.type eq 0 do
[
let length = fProp>>FPROP.length
if length eq 0 % fProp+length gr maxFProp break
if fProp>>FPROP.type eq fpropTypeDShape then
[
if length ne lDSHAPE+1 break
let dShape = fProp+1
disk>>BFSDSK.nDisks = dShape>>DSHAPE.nDisks
disk>>BFSDSK.nTracks = dShape>>DSHAPE.nTracks
disk>>BFSDSK.nHeads = dShape>>DSHAPE.nHeads
disk>>BFSDSK.nSectors = dShape>>DSHAPE.nSectors
]
fProp = fProp + length
]
]
// If there are two disks, then try reading a sector on DP1.
// If we get a header check error, then its probably DP0 of some
// other file system. This is by no means a fool-proof check.
if disk>>BFSDSK.nDisks eq 2 then
[
let realDA = 0; realDA<<DA.disk = 1
let DAs = vec 2; DAs!1 = VirtualDiskDA(disk, lv realDA)
unless ActOnDiskPages(disk, 0, DAs+1, 0, 0, 0, DCreadLD,
0, 0, buf, 0, lv BFSInitError, true) eq 0 do
[ Free(tempZone, buf); Free(diskZone, disk); resultis 0 ]
]
Free(tempZone, buf)
// BFSInit (cont'd)
let dds = OpenFile("DiskDescriptor", ksTypeReadOnly, wordItem, 0,
disk>>DSK.fpDiskDescriptor, 0, tempZone, 0, disk)
if dds eq 0 then [ Free(diskZone, disk); resultis 0 ] //no DiskDescriptor
ReadBlock(dds, disk>>DSK.diskKd, lKDHeader) //KDH
// Bump the serial number to try to avoid duplicates
let snAdr = lv disk>>BFSDSK.lastSn
DoubleAdd(snAdr, table [ 0; 5 ])
snAdr>>SN.directory = 0 // make sure the terrifying bits are off
snAdr>>SN.random = 0
snAdr>>SN.nolog = 0
// Don't be too gullible:
if Usc(disk>>BFSDSK.defaultVersionsKept, 7) gr 0 then
disk>>BFSDSK.defaultVersionsKept = 7
// count free pages in the file system
let freePages = 0
let diskBTsize = disk>>BFSDSK.diskBTsize
for i = 1 to diskBTsize do
[
let w = Gets(dds)
test w eq 0
ifso freePages = freePages +16
ifnot if w ne -1 then
for j = 0 to 15 do
if ((w rshift j) & 1) eq 0 then
freePages = freePages +1
]
disk>>BFSDSK.freePages = freePages
// Save virtual disk addresses of disk descriptor pages
for i = 1 to (lKDHeader+diskBTsize-1) rshift BFSlnWordsPerPage +1 do
[
PositionPage(dds, i)
let fa = vec lFA
GetCurrentFa(dds, fa)
disk>>BFSDSK.VDAdiskDD↑i = fa>>FA.da
]
Closes(dds)
]
// set up DD manager, if needed
if allocate then
[
if ddMgr eq 0 then
ddMgr = BFSCreateDDMgr(diskZone)
disk>>BFSDSK.ddMgr = ddMgr
OpenDD(ddMgr, disk)
]
// Return handle on disk object
resultis disk
]
// This procedure is passed to ActOnDiskPages by BFSInit when
// attempting to read the leader page of sysDir to see if it is there.
// It may quite legitimately not be, and we don't want to go into Swat.
//----------------------------------------------------------------------------
and BFSInitError(nil, nil, nil) be ReturnFrom(ActOnDiskPages, -1)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
and BFSTryDisk(drive, cylinder, sector; numargs na) = valof
//----------------------------------------------------------------------------
// If trackNumber is 0, returns true if disk is on line
// If trackNumber is 203, returns true if disk is model 44
[
// for Dorados and D0s, verify the partition number
let partition = drive<<DriveNumber.partition
if partition ne 0 then
[
let currentPartition = SetPartition(0) // remember where we are...
unless SetPartition(partition) resultis false // no such partition
SetPartition(currentPartition) // get back to where we were
]
// try seeking to a cylindar address in that partition
let kcb = vec lKCB; Zero(kcb, lKCB)
kcb>>KCB.command = seekOnly
kcb>>KCB.command.partition = partition
kcb>>KCB.diskAddress.disk = drive // <<DriveNumber.drive
kcb>>KCB.diskAddress.track = cylinder
if na ge 3 then kcb>>KCB.diskAddress.sector = sector
until @diskCommand eq 0 loop
@diskCommand = kcb
until kcb>>KCB.status.done loop
resultis (kcb>>KCB.status & DSTgoodStatusMask) eq DSTgoodStatus
]
//----------------------------------------------------------------------------
and SetPartition(partition) = (table [ 61037b; 1401b ])(partition)
//----------------------------------------------------------------------------