// 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) //----------------------------------------------------------------------------