// BFSTestCmd.bcpl -- CreateFile, Erase, and Certify commands // Copyright Xerox Corporation 1982 // Last modified May 6, 1982 5:55 PM by Boggs get "Altofilesys.d" get "AltoDefs.d" get "Streams.d" get "Disks.d" get "Bfs.d" external [ // outgoing procedures Certify; Erase; CreateFile XferError // incoming procedures OpenFile; GetCurrentFa; PositionPage; DeleteFile BFSInit; CloseDisk; BfsMakeFpFromLabel; BFSNewDisk InitializeDiskCBZ; GetDiskCb; DoDiskCommand AssignDiskPage; ReleaseDiskPage; VirtualDiskDA Gets; Puts; Endofs; Closes; Resets Zero; MoveBlock; SetBlock; Noop; Idle Allocate; Free; DefaultArgs; MyFrame; GotoLabel Ws; Confirm; Ding; GetNumber; GetString PutTemplate; Random; MyIdle // incoming statics keys; dsp; sysZone label; data; eng // outgoing statics sysDisk ] static [ maxVDA; sysDisk nDisks; nTracks; nSectors; et ] manifest [ maxETEntries = 1000 errorThreshold = 3 ] structure ET: //Error Table [ nEntries word entry^0,maxETEntries-1 [ da word; nErrors word ] ] manifest lenET = size ET/16 //---------------------------------------------------------------------------- let CreateFile() be //---------------------------------------------------------------------------- [ sysDisk = BFSInit(sysZone, true, 0) if sysDisk eq 0 then [ Ws("*NCan't init the disk. Is it on? Is it formatted (use ERASE)?") return ] let fileName = GetString(" named ") if fileName eq 0 then [ CloseDisk(sysDisk); return ] let nPages = GetNumber(", length in pages ") Idle = MyIdle DeleteFile(fileName) if nPages ugr sysDisk>>DSK.diskKd>>KDH.freePages then [ Ding(dsp) Ws("*NThere isn't enough space on your disk") nPages = 0 ] let stream = 0 maxVDA = sysDisk>>DSK.diskKd>>KDH.diskBTsize*16 -1 until nPages eq 0 do [ // Scan the entire bit table and find the biggest hole ReleaseDiskPage(sysDisk, AssignDiskPage(sysDisk, 0)) let vdaBiggestHole, sizeBiggestHole = 0, 0 let vdaThisHole, sizeThisHole = 0, 0 let vda = 0; while vda ule maxVDA do [ test AssignDiskPage(sysDisk, vda, nil) ifso test vdaThisHole eq 0 //vda+1 is free ifso [ vdaThisHole, sizeThisHole = vda +1, 1 ] //new Hole ifnot sizeThisHole = sizeThisHole +1 ifnot if vdaThisHole ne 0 then //vda+1 is allocated [ if sizeThisHole ugr sizeBiggestHole then [ vdaBiggestHole, sizeBiggestHole = vdaThisHole, sizeThisHole ] vdaThisHole = 0 ] vda = vda +1 ] if vdaBiggestHole eq 0 then [ if stream ne 0 then [ Closes(stream); stream = 0; DeleteFile(fileName) ] Ding(dsp) Ws("*NThere isn't enough space on your disk") break ] PutTemplate(dsp, "*NFound a group of $UOb pages starting at vda $UOb", sizeBiggestHole, vdaBiggestHole) ReleaseDiskPage(sysDisk, AssignDiskPage(sysDisk, vdaBiggestHole-1)) if stream eq 0 then stream = OpenFile(fileName, ksTypeWriteOnly) let fa = vec lFA; GetCurrentFa(stream, fa) if nPages uls sizeBiggestHole then sizeBiggestHole = nPages PositionPage(stream, fa>>FA.pageNumber+sizeBiggestHole) nPages = nPages - sizeBiggestHole ] if stream then Closes(stream) Free(sysZone, fileName) CloseDisk(sysDisk) Idle = Noop ] //---------------------------------------------------------------------------- and Certify() be //---------------------------------------------------------------------------- [ let nPasses = GetNumber(". How many passes? ", 100) unless GetDiskShape("CERTIFY") return sysDisk = BFSInit(sysZone, false, 0, 0, true) sysDisk>>BFSDSK.nDisks = nDisks sysDisk>>BFSDSK.nTracks = nTracks sysDisk>>BFSDSK.nSectors = nSectors maxVDA = nDisks * nTracks * 2 * nSectors -1 et = Allocate(sysZone, lenET); Zero(et, lenET) Idle = MyIdle // Set up read and write cursors let rCursor = table [ 0; 0; 0; 76000b; 41000b; 41000b; 41000b; 76000b 44000b; 42000b; 42000b; 41000b; 41000b; 0; 0; 0 ] let wCursor = table [ 0; 0; 0; 40400b; 44400b; 44400b; 44400b; 25000b 25000b; 25000b; 12000b; 12000b; 12000b; 0; 0; 0 ] let savedCursor = vec 16; MoveBlock(savedCursor, cursorBitMap, 16) // suck out a random number of random numbers let c = @realTimeClock & 7777b while c ne 0 do [ Random(); c = c-1 ] // certify the disk for i = 1 to nPasses do [ for w = 0 to 255 do data!w = Random() MoveBlock(cursorBitMap, wCursor, 16) sysDisk>>DSK.retryCount = 8 if SweepDisk(i eq 1? DCwriteHLD, DCwriteLD) break MoveBlock(cursorBitMap, rCursor, 16) sysDisk>>DSK.retryCount = 1 if SweepDisk(DCreadLD) break ] // mark bad spots incorrigable sysDisk>>DSK.retryCount = 8 let nBadPages = 0 SetBlock(lv label>>DL.fileId, -2, lFID) for i = 0 to et>>ET.nEntries-1 do if et>>ET.entry^i.nErrors uge errorThreshold then [ let vda = VirtualDiskDA(sysDisk, lv et>>ET.entry^i.da) XferPage(DCwriteHLD, vda, 0, label, 0, lv Noop) nBadPages = nBadPages +1 ] PutTemplate(dsp, "*N$D pages marked bad", nBadPages) MoveBlock(cursorBitMap, savedCursor, 16) Idle = Noop Free(sysZone, et) CloseDisk(sysDisk) until Endofs(keys) do Gets(keys) ] //---------------------------------------------------------------------------- and Erase() be //---------------------------------------------------------------------------- [ Idle = MyIdle if GetDiskShape("ERASE") then unless BFSNewDisk(sysZone, 0, nDisks, nTracks, 0, nSectors) do [ Ws("...failed"); Ding(dsp) ] Idle = Noop ] //---------------------------------------------------------------------------- and GetDiskShape(action) = valof //---------------------------------------------------------------------------- [ if TryDisk(0, 0, 0, 0)<>KCB.command = seekOnly kcb>>KCB.headerAddress = lv kcb>>KCB.header kcb>>KCB.labelAddress = label kcb>>KCB.dataAddress = data kcb>>KCB.diskAddress.disk = dsk kcb>>KCB.diskAddress.track = trk kcb>>KCB.diskAddress.head = hd kcb>>KCB.diskAddress.sector = sect @diskAddress = -1 until @diskCommand eq 0 loop for trys = 1 to 5 do [ kcb>>KCB.status = 0 @diskCommand = kcb while (kcb>>KCB.status & DSTdoneBits) eq 0 loop if (kcb>>KCB.status & DSTgoodStatusMask) eq DSTgoodStatus break ] resultis kcb>>KCB.status ] //---------------------------------------------------------------------------- and SweepDisk(action) = valof //---------------------------------------------------------------------------- [ let zoneLength = sysDisk>>DSK.lengthCBZ + 2*nSectors*sysDisk>>DSK.lengthCB let cbz = Allocate(sysZone, zoneLength) InitializeDiskCBZ(sysDisk, cbz, 0, zoneLength, SweepRetry, lv SweepError) cbz>>CBZ.cleanupRoutine = Noop cbz>>CBZ.errorDA = 0 cbz>>CBZ.client = MyFrame() SweepRetry: let sweepVDA = cbz>>CBZ.errorDA while sweepVDA le maxVDA do [ let cb = GetDiskCb(sysDisk, cbz) cb>>CB.labelAddress = data DoDiskCommand(sysDisk, cb, data, sweepVDA, data+5, data!4, action) sweepVDA = sweepVDA +1 if (sweepVDA & 77b) eq 0 then [ unless Endofs(keys) break; if eng eq 4 then Idle() ] ] while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(sysDisk, cbz) Free(sysZone, cbz) resultis not Endofs(keys) ] //---------------------------------------------------------------------------- and SweepError(nil, cb, nil) be //---------------------------------------------------------------------------- [ let dst = cb>>CB.status let da = cb>>CB.diskAddress if dst<>ET.nEntries do [ if da eq et>>ET.entry^i.da break; i = i +1 ] if i ls maxETEntries then [ if et>>ET.entry^i.nErrors eq 0 then [ et>>ET.nEntries = et>>ET.nEntries +1 et>>ET.entry^i.da = da ] et>>ET.entry^i.nErrors = et>>ET.entry^i.nErrors +1 PutTemplate(dsp, " Errors here = $UD.", et>>ET.entry^i.nErrors) ] if i eq maxETEntries then Ws(" Error table full!") ] // treat it sort of like a soft error let cbz = cb>>CB.cbz cbz>>CBZ.errorDA = VirtualDiskDA(sysDisk, lv da) +1 InitializeDiskCBZ(sysDisk, cbz) if sysDisk>>DSK.retryCount eq 1 & dst<>CBZ.client, cbz>>CBZ.retry) ] //---------------------------------------------------------------------------- and XferPage(action, vda, d, l, h, lvError; numargs na) = valof //---------------------------------------------------------------------------- [ let header = vec 1 DefaultArgs(lv na, -2, data, label, header, lv XferError) let cbz = vec CBzoneLength InitializeDiskCBZ(sysDisk, cbz, 0, CBzoneLength, XferRetry, lvError) cbz>>CBZ.cleanupRoutine = XferCleanup cbz>>CBZ.client = h XferRetry: let cb = GetDiskCb(sysDisk, cbz) cb>>CB.labelAddress = l let fp = vec lFP; BfsMakeFpFromLabel(fp, l) DoDiskCommand(sysDisk, cb, d, vda, fp, l>>DL.pageNumber, action) while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(sysDisk, cbz) resultis cbz>>CBZ.currentPage ] //---------------------------------------------------------------------------- and XferCleanup(disk, cb, cbz) be //---------------------------------------------------------------------------- [ MoveBlock(cbz>>CBZ.client, cb>>CB.headerAddress, 2) cbz>>CBZ.currentPage = cb>>CB.status ] //---------------------------------------------------------------------------- and XferError(nil, cb, nil) be //---------------------------------------------------------------------------- [ let disk = cb>>CB.cbz>>CBZ.disk let rda = cb>>CB.diskAddress let vda = VirtualDiskDA(disk, lv rda) PutTemplate(dsp, "*NHard error at VDA $UO = Unit $D Cylinder $D Head $D Sector $D", vda, rda<>CB.command.headerAction case 2: cb>>CB.command.labelAction case 3: cb>>CB.command.dataAction ] action = selecton action into [ case 0: "read" case 1: "check" case 2: case 3: "write" ] let record = selecton i into [ case 1: "header" case 2: "label" case 3: "data" ] PutTemplate(dsp, " $S $S", action, record) ] Ws("*NResulting status was") let dst = cb>>CB.status if dst<