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