// TFSNewDisk.Bcpl -- Disk refresh sequence
// Copyright Xerox Corporation 1979, 1981
// Last modified April 30, 1981 8:31 PM by Taft
get "Altofilesys.d"
get "Disks.d"
get "Tfs.d"
get "Streams.d"
external
[
//outgoing procedures
TFSNewDisk
//incoming procedures
TFSInit; TFSClose; TFSInitializeCbStorage; TFSGetCb; TFSDoDiskCommand
TFSAssignDiskPage; ActOnDiskPages
RealDiskDA; VirtualDiskDA; AssignDiskPage
DefaultArgs; Allocate; Free; Zero; MoveBlock; SysErr
CreateDiskFile; CreateDiskStream; TruncateDiskStream; SetWorkingDir
WriteBlock; Puts; Closes; FilePos; SetFilePos; PositionPage; GetCurrentFa
//incoming statics
freePageFp
]
manifest
[
dirLen = 25000 //initial size of SysDir in words
bDir = #100000 rshift offset SN.directory
bNoLog = #100000 rshift offset SN.nolog
]
//---------------------------------------------------------------------------
let TFSNewDisk(diskZone, driveNumber, diskSize, ddVDA; numargs na) = valof
//---------------------------------------------------------------------------
//Creates a virgin Alto file system on the specified disk.
//If supplied, diskSize is the number of pages to include in the file system.
//If supplied, ddVDA is the virtual disk address at which to locate the
//DiskDescriptor file (default is in the middle of the disk).
//Allocates storage from diskZone
[
DefaultArgs(lv na, -1, 0, 0, 0)
// init the disk object
let disk = TFSInit(diskZone, true, driveNumber, 0, true)
if disk eq 0 then resultis 0
let defaultDiskSize =
disk>>TFSDSK.nVTracks * disk>>TFSDSK.nHeads * disk>>TFSDSK.nSectors
if diskSize eq 0 % diskSize ugr defaultDiskSize then
diskSize = defaultDiskSize
if ddVDA eq 0 then ddVDA = diskSize rshift 1
let da = vec 2
RealDiskDA(disk, diskSize-1, da)
disk>>TFSDSK.nVTracks = da>>DA.track - disk>>TFSDSK.firstVTrack +1
let buf = Allocate(diskZone, TFSwordsPerPage)
disk>>TFSDSK.initmode = buf // Stick it where NewDiskAssignPage can find it
let kdAddr = lv disk>>TFSDSK.kd
// setup important init conditions for this disk, etc.
disk>>TFSDSK.version = TFSKDversion
let fpTFSSysDir = disk>>DSK.fpSysDir
let fpTFSDiskDescriptor = disk>>DSK.fpDiskDescriptor
// Read physical page 0 to get the bad page list, if there is one.
// Write virgin bad page list if there isn't
unless TransferPage0(disk, buf, DCreadD) & buf>>BPL.seal eq bplSeal do
[
Zero(buf, TFSwordsPerPage)
buf>>BPL.seal = bplSeal
TransferPage0(disk, buf, DCwriteHLD)
]
// Convert real disk addresses to virtual, and discard duplicate entries
// and entries not contained in the portion of the disk we are initializing
let n = 0
for i = 0 to buf>>BPL.nBadPages-1 do
[
let vda = VirtualDiskDA(disk, lv buf>>BPL.da↑i)
for j = 0 to n-1 do if vda eq buf!j then vda = fillInDA
if vda ne fillInDA then [ buf!n = vda; n = n+1 ]
]
Zero(buf+n, TFSwordsPerPage-n)
// Sort the list of virtual addresses
for i = 0 to n-1 do for j = i+1 to n-1 do
if buf!i ugr buf!j then [ let t = buf!i; buf!i = buf!j; buf!j = t ]
// Clear the disk. Overwrite page 0 only if vda 0 is not real da 0.
ClearDisk(disk, buf, (disk>>TFSDSK.firstVTrack eq 0? 1, 0), diskSize-1)
// TFSNewDisk (cont'd)
// Plug in our own AssignDiskPage procedure for initial allocations.
// This procedure will append assigned addresses to the list now in buf.
disk>>DSK.AssignDiskPage = NewDiskAssignPage
// Create SysDir. Its SN must be 100 with the directory bit set.
// Its leader page must be at virtual address 1 (we would otherwise prefer
// to locate the file in the middle of the disk).
(lv disk>>TFSDSK.lastSn)!1 = 99 // Last sn used
let dir = NewDiskMakeFile(disk, "SysDir.",fpTFSSysDir, diskZone, 0, bDir)
let pos = FilePos(dir)
SetFilePos(dir, 0, dirLen lshift 1) // Make nice contiguous dir
SetFilePos(dir, 0, pos)
// Create disk descriptor, and try to make it be consecutively allocated.
// Place it in the middle of the disk to minimize average seek distance
// between bit table pages and all other files.
disk>>TFSDSK.lastPageAlloc = ddVDA
let ddStream = NewDiskMakeFile(disk, "DiskDescriptor.", fpTFSDiskDescriptor,
diskZone, dir, bNoLog)
let diskBTsize = (diskSize-1) rshift 4 +1 //Total number of words in BT
kdAddr>>KDH.diskBTsize = diskBTsize
// Extend disk descriptor to desired length and fill it with zeroes.
// Last word of BT needs special treatment since number of pages on disk
// may not be a multiple of 16.
let q, r = diskSize rshift 4, diskSize & #17
SetFilePos(ddStream, 0, (TFSwordsPerPage+q) lshift 1)
if r ne 0 then Puts(ddStream, -1 rshift r)
// Fill out rest of directory with empties of small enuf size.
[ // repeat
let len = dirLen - FilePos(dir) rshift 1
if len le 0 then break
if len gr 100 then len=100
let a = vec 1
a>>DV.type = dvTypeFree
a>>DV.length = len
WriteBlock(dir, a, len)
] repeat
TruncateDiskStream(dir)
Closes(dir)
// Finish initing the disk descriptor
SetWorkingDir("<SysDir.", fpTFSSysDir, disk)
Zero(lv kdAddr>>TFSKD.nTransfers, 2)
// Save virtual disk addresses of disk descriptor pages
for i = 1 to (TFSwordsPerPage+diskBTsize-1) rshift TFSlnWordsPerPage +1 do
[
PositionPage(ddStream, i)
let fa = vec lFA
GetCurrentFa(ddStream, fa)
disk>>TFSDSK.VDAdiskDD↑i = fa>>FA.da
]
Closes(ddStream)
// TFSNewDisk (cont'd)
// Now put back the normal AssignDiskPage procedure and mark the pages
// we have allocated in the bit table in the normal way.
disk>>DSK.AssignDiskPage = TFSAssignDiskPage
let i = 0
while buf!i ne 0 do
[
if AssignDiskPage(disk, buf!i -1) ne buf!i then
SysErr(disk, ecBadAssignPage)
i = i+1
]
Free(diskZone, buf)
// Assign page zero. This is slightly tricky because zero = eofDA+1
disk>>TFSDSK.lastPageAlloc = 0
if AssignDiskPage(disk, eofDA) ne 0 then SysErr(disk, ecBadAssignPage)
// The TFSClose call will write out the KD onto the disk descriptor file.
TFSClose(disk)
resultis true
]
//---------------------------------------------------------------------------
and NewDiskAssignPage(disk, nil, nil) = valof
//---------------------------------------------------------------------------
// The AssignDiskPage procedure used while creating the initial files
// (SysDir and DiskDescriptor). Always assigns the next page in sequence,
// and keeps a list of assigned pages in the buffer pointed to by
// the initmode word in the disk structure.
[
let vda = disk>>TFSDSK.lastPageAlloc+1
disk>>TFSDSK.lastPageAlloc = vda
let buf = disk>>TFSDSK.initmode
let i = 0
while buf!i ne 0 do
[ //search for first unused slot, and make sure page not already assigned
if vda eq buf!i then [ vda = 0; break ]
i = i+1
]
if vda ne 0 then [ buf!i = vda; resultis vda ]
] repeat
//---------------------------------------------------------------------------
and TransferPage0(disk, buf, action) = valof
//---------------------------------------------------------------------------
// Transfers physical page 0 to or from the buffer, returning true
// if successful and false otherwise.
[
let DAs = vec 2
// Passing a DA of fillInDA causes TFSDoDiskCommand not to compute
// the real DA. Since the CB has been zeroed, a real DA of zero results.
DAs!0 = eofDA; DAs!1 = fillInDA; DAs!2 = eofDA
resultis ActOnDiskPages(disk, lv buf, DAs+1, table [ 0; 0; 0 ], 0, 0, action,
0, 0, 0, 0, 0, true) eq 0
]
//---------------------------------------------------------------------------
and NewDiskMakeFile(disk, nam, fp, diskZone, dirStream, word1) = valof
//---------------------------------------------------------------------------
//Creates the file on the disk and appends a directory entry to dirStream.
//If dirStream is zero, the new file itself is assumed to be the directory
//and the entry is appended to it. Returns an open stream.
[
CreateDiskFile(disk, nam, fp, 0, word1)
// Make stream:
// Will not be logged because nolog on
// temp use of Allocated zone because of CreateDiskStream bug
let s=CreateDiskStream(fp, 0, 0, 0, 0, diskZone, 0, disk)
if s eq 0 then SysErr(disk, ecEssentialFile)
// Now make directory entry
if dirStream eq 0 then dirStream=s // SysDir is first
let dv=vec lDV
dv>>DV.type=dvTypeFile
let lNam=(nam>>STRING.length+2) rshift 1
dv>>DV.length=lDV+lNam
MoveBlock(lv dv>>DV.fp, fp, lFP)
WriteBlock(dirStream, dv, lDV)
WriteBlock(dirStream, nam, lNam)
// return stream
resultis s
]
//---------------------------------------------------------------------------
and ClearDisk(disk, buf, firstPage, lastPage) be
//---------------------------------------------------------------------------
// Makes pages firstPage, through lastPage appear free, except that page 0
// has an illegal label written in it. This is to prevent its ever being
// assigned, as it plays a crucial role in end-of-file detection.
// buf must contain a sorted list of virtual disk addresses to be
// marked permanently bad (zero ends list).
[
let checkErrors = 0
let action = DCwriteLD
let zone = vec CBzoneLength
TFSInitializeCbStorage(disk, zone, firstPage, CBzoneLength, CDretry)
CDretry:
[
if zone>>CBZ.errorCount ge disk>>DSK.retryCount rshift 1 then
[
//having trouble checking header, try writing it instead.
//if this occurs more than 25 times then write all remaining headers.
checkErrors = checkErrors+1
action = DCwriteHLD
]
let vda = zone>>CBZ.currentPage
let iBad = 0
[
let cb = TFSGetCb(disk, zone)
while buf!iBad ne 0 & vda ugr buf!iBad do iBad = iBad+1
let useFp = (vda eq 0? table [ 0; 0; 0 ], // page 0
(vda eq buf!iBad? table [ -2; -2; -2 ], // permanently bad
freePageFp)) // normal, make it free
TFSDoDiskCommand(disk, cb, buf, vda, useFp, vda, action)
if checkErrors ls 25 then action = DCwriteLD
if vda eq lastPage then break
vda = vda+1
] repeat
while zone>>CBZ.head ne 0 do TFSGetCb(disk, zone)
] // end of CDretry
]