// Certify.bcpl -- BFS Certify program // Copyright Xerox Corporation 1986 // created November 23, 1986 7:18 PM by Putz // Last modified November 24, 1986 5:59 AM by Putz // To compile and load: // BCPL/O Certify.bcpl // Bldr/LV Certify BFSInit GP Template Random get "Altofilesys.d" get "AltoDefs.d" get "Streams.d" get "SysDefs.d" get "Disks.d" get "Bfs.d" external [ // incoming procedures BFSInit // from BFSInit.br PutTemplate // from Template.br Random // from Random.br ReadParam // from GP.br SetupReadParam // from OS VirtualDiskDA; CloseDisk; BfsMakeFpFromLabel InitializeDiskCBZ; GetDiskCb; DoDiskCommand Ws; dsp; keys; Endofs; Gets; Resets OpenFile; Closes; CleanupDiskStream Zero; MoveBlock; SetBlock; Noop; lvIdle; Idle Allocate; Free; DefaultArgs; MyFrame; GotoLabel sysZone; lvUserFinishProc; lvSysErr ] static [ label; data; machineType maxVDA; certDisk; eTable nDisks; nTracks; nSectors origPartition; savedUFP; savedIdle certPartition; currentPass; logFile abortFlag = false doPrompt = true nPasses = 100 // default ] manifest [ maxETEntries = 200 errorThreshold = 1 abortChar = 3 // abort with control-C ] structure String [ length byte; char↑1,1 byte ] structure ET: //Error Table [ nEntries word entry↑0,maxETEntries-1 [ da word; nErrors word ] ] manifest lenET = size ET/16 //---------------------------------------------------------------------------- let Certify() be //---------------------------------------------------------------------------- [ Ws("Certify.run of November 24, 1986.") // show "BFS" cursor MoveBlock(cursorBitMap, table [ 0; 0; 0; 0; 161706b; 111011b; 111010b; 161606b; 111001b; 111011b; 161006b; 0; 0; 0; 0; 0 ], 16) machineType = AltoVersion() if machineType ls 4 then [ Ws("No partitions on this machine.") abort ] origPartition = ChangePartition(0) savedIdle = @lvIdle savedUFP = @lvUserFinishProc @lvSysErr = MyErr @lvUserFinishProc = MyCleanUp // Allocate buffers // let spaceLeft = nil // Allocate(sysZone, 30000, lv spaceLeft) // PutTemplate(dsp, "*NSpace left = $D", spaceLeft) eTable = Allocate(sysZone, lenET) data = Allocate(sysZone, 256) label = Allocate(sysZone, 8) logFile = OpenFile("Certify.log", ksTypeWriteOnly, charItem) //get partition number and number of passes from command line let switches = vec 50 // unpacked string SetupReadParam(0, switches) doPrompt = not ((switches!0 ge 1) & ((switches!1 eq $y) % (switches!1 eq $Y))) let noArgs = true [ certPartition = ReadParam($D, -1) while (switches!0 eq 1) & ((switches!1 & 0337) eq $P) do [ // switch /P sets number of passes nPasses = certPartition certPartition = ReadParam($D, -1) ] if certPartition eq -1 break CertifyPartition() noArgs = false ] repeatuntil abortFlag if noArgs then Ws("*NUsage: Certify[/Yes] [nPasses/P] partNum ... partNum") Free(sysZone, eTable) Free(sysZone, data) Free(sysZone, label) ] and let CertifyPartition() be [ ChangePartition(certPartition) if ChangePartition(0) ne certPartition then abort Zero(eTable, lenET) unless GetDiskShape() abort let format = "*NCertify BFS$D Disks: $D, Cylinders: $D, Heads: 2, Sectors: $D" PutTemplate(dsp, format, certPartition, nDisks, nTracks, nSectors) if doPrompt then [ PutTemplate(dsp, "*NConfirm erase and certify BFS$D ($D passes)", certPartition, nPasses) if not Confirm("? ") then finish let now = @realTimeClock while now + 5*27 ugr @realTimeClock loop Resets(keys) if not Confirm("*NAre you still sure? ") then finish ] ChangePartition(origPartition) PutTemplate(logFile, format, certPartition, nDisks, nTracks, nSectors) ChangePartition(certPartition) certDisk = BFSInit(sysZone, false, 0, 0, true) certDisk>>BFSDSK.nDisks = nDisks certDisk>>BFSDSK.nTracks = nTracks certDisk>>BFSDSK.nSectors = nSectors maxVDA = nDisks * nTracks * 2 * nSectors -1 @lvIdle = 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 [ currentPass = i for w = 0 to 255 do data!w = Random() MoveBlock(cursorBitMap, wCursor, 16) certDisk>>DSK.retryCount = 8 if SweepDisk(i eq 1? DCwriteHLD, DCwriteLD) break MoveBlock(cursorBitMap, rCursor, 16) certDisk>>DSK.retryCount = 1 if SweepDisk(DCreadLD) break ] // mark bad spots incorrigable certDisk>>DSK.retryCount = 8 SetBlock(lv label>>DL.fileId, -2, lFID) for i = 0 to eTable>>ET.nEntries-1 do if eTable>>ET.entry↑i.nErrors uge errorThreshold then [ let da = eTable>>ET.entry↑i.da let vda = VirtualDiskDA(certDisk, lv da) XferPage(DCwriteHLD, vda, 0, label, 0, lv Noop) let format = "*N BFS$D Un $D, Cyl $3F0D, Hd $D, Sec $2F0D. Errors = $D" PutTemplate(dsp, format, certPartition, da<<DA.disk, da<<DA.track, da<<DA.head, da<<DA.sector, eTable>>ET.entry↑i.nErrors) ChangePartition(origPartition) PutTemplate(logFile, format, certPartition, da<<DA.disk, da<<DA.track, da<<DA.head, da<<DA.sector, eTable>>ET.entry↑i.nErrors) ChangePartition(certPartition) ] PutTemplate(dsp, "*N$D pages marked bad on BFS$D in $D passes.", eTable>>ET.nEntries, certPartition, currentPass) MoveBlock(cursorBitMap, savedCursor, 16) CloseDisk(certDisk) ChangePartition(origPartition) PutTemplate(logFile, "*N$D pages marked bad on BFS$D in $D passes.*N", eTable>>ET.nEntries, certPartition, currentPass) CleanupDiskStream(logFile) ] //---------------------------------------------------------------------------- and GetDiskShape(action) = valof //---------------------------------------------------------------------------- [ if TryDisk(0, 0, 0, 0)<<DST.notReady then [ Ws(". DP0 is not ready!"); resultis false ] nDisks, nTracks, nSectors = 1, 203, 12 unless TryDisk(1, 0, 0, 0)<<DST.notReady do nDisks = 2 unless TryDisk(0, 203, 0, 0)<<DST.seekFail do nTracks = 406 unless TryDisk(0, 0, 0, 13)<<DST.finalStatus eq badSector do nSectors = 14 resultis true ] //---------------------------------------------------------------------------- and TryDisk(dsk, trk, hd, sect) = valof //---------------------------------------------------------------------------- [ let kcb = vec lKCB; Zero(kcb, lKCB) kcb>>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 = certDisk>>DSK.lengthCBZ + 2*nSectors*certDisk>>DSK.lengthCB let cbz = Allocate(sysZone, zoneLength) InitializeDiskCBZ(certDisk, 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(certDisk, cbz) cb>>CB.labelAddress = data DoDiskCommand(certDisk, cb, data, sweepVDA, data+5, data!4, action) sweepVDA = sweepVDA +1 if (sweepVDA & 77b) eq 0 then [ if not Endofs(keys) then [ PutTemplate(dsp, "*NCurrent Pass = $D", currentPass) if Gets(keys) eq abortChar then [ abortFlag = true; break ] ] if machineType eq 4 then Idle() ] ] while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(certDisk, cbz) Free(sysZone, cbz) resultis abortFlag ] //---------------------------------------------------------------------------- and SweepError(nil, cb, nil) be //---------------------------------------------------------------------------- [ let dst = cb>>CB.status let da = cb>>CB.diskAddress if dst<<DST.checksumError ne 0 & dst<<DST.dataLate eq 0 then [ PutTemplate(dsp, "*NChecksum error at BFS$D Un $D, Cyl $3F0D, Hd $D, Sec $2F0D.", certPartition, da<<DA.disk, da<<DA.track, da<<DA.head, da<<DA.sector) let i = 0; while i ls eTable>>ET.nEntries do [ if da eq eTable>>ET.entry↑i.da break; i = i +1 ] if i ls maxETEntries then [ if eTable>>ET.entry↑i.nErrors eq 0 then [ eTable>>ET.nEntries = eTable>>ET.nEntries +1 eTable>>ET.entry↑i.da = da ] eTable>>ET.entry↑i.nErrors = eTable>>ET.entry↑i.nErrors +1 PutTemplate(dsp, " Errors here = $UD/$D", eTable>>ET.entry↑i.nErrors, currentPass) ] 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(certDisk, lv da) +1 InitializeDiskCBZ(certDisk, cbz) if certDisk>>DSK.retryCount eq 1 & dst<<DST.seekFail then [ //retry count of one bypasses GetCB's recal for pos errors @diskAddress = -1 DoDiskCommand(certDisk, GetDiskCb(certDisk, cbz), 0, 0, 0, 0, 525b) ] GotoLabel(cbz>>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(certDisk, cbz, 0, CBzoneLength, XferRetry, lvError) cbz>>CBZ.cleanupRoutine = XferCleanup cbz>>CBZ.client = h XferRetry: let cb = GetDiskCb(certDisk, cbz) cb>>CB.labelAddress = l let fp = vec lFP; BfsMakeFpFromLabel(fp, l) DoDiskCommand(certDisk, cb, d, vda, fp, l>>DL.pageNumber, action) while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(certDisk, 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 BFS$D VDA $UO = Unit $D Cylinder $3F0D Head $D Sector $2F0D", certPartition, vda, rda<<DA.disk, rda<<DA.track, rda<<DA.head, rda<<DA.sector) Ws("*NAttempted action was") for i = 1 to 3 do [ let action = selecton i into [ case 1: cb>>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<<DST.seekFail then Ws(" seek failed") if dst<<DST.seeking then Ws(" seeking") if dst<<DST.notReady then Ws(" disk not ready (on?)") if dst<<DST.dataLate then Ws(" data late") if dst<<DST.noTransfer then Ws(" no transfer") if dst<<DST.checksumError then Ws(" checksum error") if dst<<DST.finalStatus then Ws(selecton dst<<DST.finalStatus into [ case 1: (dst&360b)? "", " sector late" case 2: " check error" case 3: " illegal sector" ]) ] //---------------------------------------------------------------------------- and MyIdle() be //---------------------------------------------------------------------------- [ let MulDiv = table [ 055001B // sta 3 savedPC,2 155000B // mov 2 3 111000B // mov 0 2 102460B // mkzero 0 0 061020B // mul 031403B // lda 2 3 3 061021B // div 077400B // Swat 121000B // mov 1 0 171000B // mov 3 2 035001B // lda 3 savedPC,2 001401B // jmp 1,3 ] @mouseX = 200 + 200*diskAddress>>DA.disk @mouseY = diskAddress>>DA.track ls 0? 0, 20 + MulDiv(808-40-16, diskAddress>>DA.track, 406) ] //---------------------------------------------------------------------------- and Confirm(prompt) = valof //---------------------------------------------------------------------------- [ Ws(prompt) switchon Gets(keys) into [ case $Y: case $y: case $*N: [ Ws("Yes"); resultis true ] case $N: case $n: case $*177: [ Ws("No"); resultis false ] default: [ Ws("(Y or N) "); loop ] ] repeat ] and AltoVersion() = valof [ resultis (table [ 61014b; 1401b ])(origPartition) ] and ChangePartition(partNumber) = valof [ resultis (table [ 61037b; 1401b ])(partNumber) ] and MyErr(p1, errCode) be [ ChangePartition(origPartition) PutTemplate(dsp, "*NSystem error $D", errCode) abort ] and MyCleanUp(code) be [ ChangePartition(origPartition) Closes(logFile) @lvIdle = savedIdle @lvUserFinishProc = savedUFP ]