// IfsScavPass1.bcpl
// Copyright Xerox Corporation 1979, 1980, 1981
// Last modified November 26, 1981  3:25 PM by Taft

get "IfsScavenger.decl"
get "IfsVMem.decl"
get "Disks.d"
get "Tfs.d"

external
[
// outgoing procedures
Pass1; PVRR; PVWR

// incoming procedures
Pass1Phase1; Pass1Phase2; Pass1Phase3
Pass1Phase4; Pass1Phase5; Scratch
OpenVFileFromFP; CloseVFile; @VRR2; @VWR2
Allocate; Free; IFSError; Zero; DoubleAdd
OpenFile; DeleteFile; Closes
JumpToFa; GetCurrentFa; TruncateDiskStream
OpenDisk; TFSInit; CloseDisk
OpenLPT; CloseLPT; GetLptFa
Ws; ScavConfirm

// outgoing statics
plme; bpl; maxVDA
bytesPerPage; wordsPerPage
ifsPackFlag

// incoming statics
scratchDisk; scavDisk
dsp; keys; sysZone; lpt
debugFlag; initLptFlag; justFixDirFlag; pass
]

static
[
plme; bpl; maxVDA
bytesPerPage; wordsPerPage
ifsPackFlag = true

plmVmd
]

//----------------------------------------------------------------------------
let Pass1(drive; numargs na) = valof
//----------------------------------------------------------------------------
// If called from the top level, there will be no arguments.
// If called from Scavenge() there will be one argument.
[
pass = 1
if scratchDisk eq 0 then unless Scratch(nil) resultis false

// open Scavengee
test drive eq -1 % na eq 0
   ifso scavDisk = OpenDisk("*NScan pack on drive ", 0, true, false)
   ifnot scavDisk = TFSInit(sysZone, 0, drive, 0, true)
if scavDisk eq 0 resultis false
ifsPackFlag = na eq 0? ScavConfirm("*NIs this an IFS pack?"), true
drive = scavDisk>>DSK.driveNumber
let model = scavDisk>>TFSDSK.model
let fs = scavDisk>>TFSDSK.firstVTrack eq 0? 0, 1
wordsPerPage = 1 lshift scavDisk>>DSK.lnPageSize
bytesPerPage = wordsPerPage lshift 1
maxVDA = (scavDisk>>TFSDSK.nVTracks * scavDisk>>TFSDSK.nHeads *
 scavDisk>>TFSDSK.nSectors) -1

unless justFixDirFlag do
   [
   // Page Link Map (PLM) file
   // max size of the PLM in vPages (256 words) is 2048
   let fpPLM = vec lFP; Zero(fpPLM, lFP)
   let plm = OpenFile("IfsScavenger.plm", 0, 0, 0, fpPLM, 0, 0, 0, scratchDisk)
   if plm eq 0 then IFSError(ecScratchFile, "IfsScavenger.plm")
   Closes(plm)
   let vPagesPerDPage = 1 lshift (scratchDisk>>DSK.lnPageSize-8)
   plmVmd = OpenVFileFromFP(fpPLM, scratchDisk, 2048/vPagesPerDPage, 256)
   PVRR(maxVDA)  //extend the plm to full length
   ]

// Here is where the work gets done
lpt = OpenLPT("IfsScavenger.lpt", initLptFlag)
let ok = valof
   [
   unless justFixDirFlag do
      bpl = Allocate(sysZone, wordsPerPage)
   ok = Pass1Phase1()
   unless justFixDirFlag do
      [
      if ok then ok = Pass1Phase2()
      if ok & na eq 0 then
         ok = ScavConfirm("*NMay I alter the disk? ")
      if ok then ok = Pass1Phase3()
      Free(sysZone, bpl)
      if ok then ok = Pass1Phase4(fs lshift 8 + drive)
      ]
   if ok & ifsPackFlag then ok = Pass1Phase5(fs lshift 8 + drive)

   // clean up leader page table
   unless ok % debugFlag do
      [
      JumpToFa(lpt, GetLptFa(lpt))
      TruncateDiskStream(lpt)
      ]
   GetCurrentFa(lpt, GetLptFa(lpt))

   // advance to next logical file system on pack
   if scavDisk ne 0 then scavDisk = CloseDisk(scavDisk, true)
   if fs ne 0 % model ne 300 % ok ne -1 % na eq 0 resultis ok
   fs = fs +1
   scavDisk = TFSInit(sysZone, 0, fs lshift 8+drive, 0, true)  //gently...
   if scavDisk eq 0 resultis ok
   ] repeat

// clean up and go away
if lpt ne 0 then lpt = CloseLPT(lpt, false)
unless justFixDirFlag do
   [
   CloseVFile(plmVmd)
   DeleteFile("IfsScavenger.plm", 0, 0, 0, 0, scratchDisk)
   ]
Ws("*NPass1 complete*N")
resultis ok
]

// Page Link Map VMem routines

//----------------------------------------------------------------------------
and PVRR(vda) = valof
//----------------------------------------------------------------------------
[
let addr = vec 1
addr!0 = vda rshift 13
addr!1 = vda lshift 3
let base = vec 1
base!0 = plmVmd>>VMD.base rshift 8
base!1 = plmVmd>>VMD.base lshift 8
DoubleAdd(addr, base)
resultis VRR2(addr!0, addr!1)
]

//----------------------------------------------------------------------------
and PVWR(vda) = valof
//----------------------------------------------------------------------------
[
let addr = vec 1
addr!0 = vda rshift 13
addr!1 = vda lshift 3
let base = vec 1
base!0 = plmVmd>>VMD.base rshift 8
base!1 = plmVmd>>VMD.base lshift 8
DoubleAdd(addr, base)
resultis VWR2(addr!0, addr!1)
]