$BEGIN DSCBD,0021, ; ; COPYRIGHT (C) 1976 BY DIGITAL EQUIPMENT CORPORATION, ; MAYNARD, MASSACHUSETTS ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY ON A ; SINGLE COMPUTER SYSTEM AND MAY BE COPIED ONLY WITH THE IN- ; CLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE, OR ; ANY OTHER COPIES THEREOF, MAY NOT BE PROVIDED OR OTHERWISE ; MADE AVAILABLE TO ANY OTHER PERSON EXCEPT FOR USE ON SUCH ; SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE TERMS. TITLE ; TO AND OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES REMAIN ; IN DIGITAL. ; ; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITH- ; OUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ; DIGITAL EQUIPMENT CORPORATION. ; ; DIGITAL EQUIPMENT CORPORATION ASSUMES NO RESPONSIBILITY FOR ; THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS ; NOT SUPPLIED BY DIGITAL. ; ; ANDREW C. GOLDSTEIN 1-NOV-76 22:50 .SBTTL IMPURE DATA ; ; WORDS USED BY MANUAL BAD BLOCK INPUT ; BLOCK: .BLKW 2 ; LBN OF BAD AREA COUNT: .BLKW 2 ; COUNT OF BLOCKS FLAGS: .BLKW 1 ; FLAGS WORD, CONTAINING: BA.END = 1 ; EXIT FLAG .SBTTL PURE DATA ; ; PROMPT STRING TO ASK FOR MANUAL BAD BLOCK DATA ; PROMPT: .ASCII "DSC> BAD=" PROMPL = .-PROMPT .EVEN .SBTTL MAIN BAD BLOCK ROUTINE ;+ ; ; *** - $DSCBD DSC BAD BLOCK PROCESSING ; ; THIS ROUTINE CONSTRUCTS THE INTERNAL BAD BLOCK TABLE FROM THE ; BAD BLOCK MAP ON THE OUTPUT DISK. ; ; INPUTS: ; ; OUTLUN ASSIGNED TO DISK ; $OUDEV POINTING TO DEVICE TABLE ENTRY ; ; OUTPUTS: ; ; BAD BLOCK MAP IN $BADBK ; ;- $DSCBD:: LET $BADP := #$BADBK ; INIT BAD BLOCK POINTER $CALL AUTO ; DO NORMAL AUTOMATIC PROCESSING IF #KY.MAN SET.IN $OFLAG $CALL MANUAL ; DO MANUAL BAD BLOCK PROCESSING END ; ; IF THE LAST CLUSTER OF THE VOLUME IS PARTIALLY OFF THE END ; OF THE TRUE VOLUME, DUE TO ROUND UP, MARK IT BAD. ; LET R2 := $VOLSZ - #1 ; GET LAST LBN OF VOLUME, LET R1 := $VOLSZ+2 - CARRY ; ROUNDED UP TO NEXT CLUSTER DCOMP R1,R2 $CW2,$CW3 ; COMPARE TO TRUE SIZE IF RESULT IS HIS $CALL MAKBAD <,R1,R2,#1> ; MARK ONE CLUSTER BAD END RETURN .SBTTL AUTOMATIC BAD BLOCK HANDLING ; ; THIS ROUTINE READS THE BAD BLOCK DESCRIPTOR FROM THE END OF THE ; VOLUME, VERIFIES IT, AND FORMATS THE DATA INTO THE ALLOCATION MAP. ; IF THE DISK IS AN RK06 OR RK07, CONTROL PASSES TO THE RK06/7 BAD ; BLOCK ROUTINE. THE RK06/7 IS IDENTIFIED BY THE VOLUME SIZE. ONE OF ; THESE DAYS WHEN WE DEFINE DEVICE TYPE CODES WE WILL BE ABLE TO DO ; THIS A BIT MORE CLEANLY. ; ; FIRST SEARCH FROM THE BACK OF THE VOLUME FOR THE DESCRIPTOR. ; AUTO: IF #KY.NAU OFF.IN $OFLAG ; DO ONLY IF REQUESTED BEGIN AUTOB LET R2 := $CW2 ; GET END OF VOLUME LET R3 := $CW3 IF R2 EQ #0 AND R3 EQ #RK06SZ GOTO RK06 IF R2 EQ #0 AND R3 EQ #RK07SZ GOTO RK07 BEGIN FIND PUSH #256. FOR (SP) := (SP) DOWNTO #0 LET R3 := R3 - #01 ; BACK UP ONE BLOCK LET R2 := R2 - CARRY $CALL $RDWLN <#OUTLUN,,R2,R3,#$B1HD> ; READ A BLOCK ON.NOERROR $CALL $CKSUM ; CHECK THE CHECKSUM ON.NOERROR LET R4 := R5 IF (R4)+ EQ #1401 LEAVE FIND ; CHECK FOR FORMAT WORD END ELSE ; LOOP ONLY ON PARITY ERROR IFB (R4) NE #IE.VER THEN ERROR ER.IOR END LET $B1HD+B.STAT := #0 ; DISCARD THE BUFFER FOR RETRY END LOOP ERRP ER.NBD ; BAD BLOCK DATA NOT FOUND LEAVE AUTOB END FIND TST (SP)+ ; CLEAN THE STACK ; ; BAD BLOCK DESCRIPTOR IS FOUND. FIRST MAKE AN ENTRY FOR THE ; DESCRIPTOR ITSELF. ; $CALL MAKBAD <,R2,R3,#0> ; ; NOW ENTER EACH BAD CLUSTER INTO THE BAD BLOCK LIST. ; PUSH (R4)+ ; PUT COUNT ON STACK LET 1(SP) :B= #0 LET (SP) := (SP) R.SHIFT 1 IF RESULT IS NE ; IF MAP IS NOT EMPTY FOR (SP) := (SP) DOWNTO #0 LET R1 := #0 LET R1 :B= R1 SET.BY (R4)+ ; HIGH ORDER LBN LET R3 := #0 LET R3 :B= R3 SET.BY (R4)+ ; GET COUNT FIELD LET R2 := (R4)+ ; LOW ORDER LBN $CALL MAKBAD <,R1,R2,R3> ; ENTER CLUSTER IN BAD BLOCK LIST ON.ERROR THEN ERRP ER.BBD ; BAD DATA IN DESCRIPTOR END LOOP END END AUTOB TST (SP)+ ; CLEAN COUNT OFF STACK END RETURN .SBTTL RK06/7 BAD BLOCK HANDLING ; ; RANDOM CONSTANTS FOR THIS ROUTINE. ; RK06SZ = 27126. ; SIZE OF RK06 RK07SZ = 45210. ; SIZE OF RK07 CYL = 411. ; NUMBER OF CYLINDERS TRK6 = 3 ; 3 SURFACES FOR RK06 TRK7 = 5 ; 5 SURFACES FOR RK07 SECT = 22. ; 22 SECTORS PER TRACK UBDATA = 12. ; LAST 12 SECTORS ARE USER DATA TRK: .BLKW 1 ; NUMBER OF SURFACES OF THIS DISK ; ; THIS ROUTINE READS THE BAD BLOCK MAP FROM THE LAST TRACK OF THE RK06/7 ; AND ENTERS IT IN THE BAD BLOCK TABLE. 22 SECTOR MODE DATA IS FOUND IN ; THE FIRST EVEN NUMBERED SECTOR THAT READS WITHOUT A PARITY ERROR. ; RK06: LET TRK := #TRK6 ; SET UP NUMBER OF SURFACES GOTO RKCOM RK07: LET TRK := #TRK7 ; SET UP NUMBER OF SURFACES ; ; FIRST, MARK THE LAST TRACK OF THE DISK BAD ; RKCOM: PUSH R3 ; SAVE VOLUME SIZE LET R3 := R3 - #SECT ; BACK UP TO START OF LAST TRACK PUSH R3 ; SAVE DISK ADDR $CALL MAKBAD <,#0,R3,#SECT-1> POP R3 ; RECOVER START OF LAST TRACK IF #KY.NAU OFF.IN $OFLAG REPEAT ; LOOP FOR FACTORY & USER DATA BEGIN FIND REPEAT $CALL $RDWLN <#OUTLUN,,#0,R3,#$B1HD> ; READ A BLOCK ON.NOERROR LEAVE FIND IFB (R4) NE #IE.VER THEN ERROR ER.IOR LET $B1HD+B.STAT := #0 ; DISCARD THE BUFFER FOR RETRY LET R3 := R3 + #2 ; TRY THE NEXT SECTOR UNTIL R3 HIS (SP) ; UNTIL WHOLE TRACK HAS BEEN TRIED ERRP ER.NBD ; PRINT MESSAGE LEAVE LOOP END FIND ; ; NOW ENTER EACH BAD CLUSTER INTO THE BAD BLOCK LIST. ; PUSH R3 ; SAVE CURRENT BLOCK NUMBER LET R3 := - R3 + $CW3 ; SEE IF WE ARE INTO USER DATA IF R3 HI #UBDATA ; IF NOT.... LET R4 := R5 + #6. ; POINT TO START OF DATA IF (R4)+ NE #0 THEN ERROR ER.DGP ; NON-ZERO MEANS DO NOT USE END REPEAT LET R0 := (R4)+ ; GET NEXT CYLINDER NUMBER IF R0 EQ #-1 LEAVE LOOP ; -1 IS END OF DATA $CALL $MUL ; COMPUTE NUMBER OF TRACKS LET R2 := (R4)+ ; GET TRACK AND SECTOR LET R3 := R2 CLRB R3 ; ISOLATE TRACK SWAB R3 LET R2 := R2 OFF.BY #^C377 ; ISOLATE SECTOR LET R1 := R1 + R3 ; ADD IN TRACK NUMBER $CALL $MUL <#SECT,R1> ; COMPUTE NUMBER OF SECTORS LET R2 := R2 + R1 ; COMPUTE LBN LET R1 := #0 $CALL MAKBAD <,R1,R2,#0> ; MARK 1 SECTOR BAD ON.ERROR THEN ERRP ER.BBD ; BAD DATA IN DESCRIPTOR UNTIL R4 HIS #$BUF1+512. ; LOOP UNTIL END OF BUFFER LET $B1HD+B.STAT := #0 LET R0 := $CW3 - (SP)+ ; SEE HOW FAR WE WERE FOM THE END IF R0 LE #UBDATA LEAVE LOOP ; OUT IF USER DATA ALREADY SEEN LET R3 := $CW3 - #UBDATA ; POINT TO FIRST BLOCK OF USER DATA END LOOP END TST (SP)+ ; CLEAN THE STACK RETURN .SBTTL MANUAL BAD BLOCK ENTRY ; ; THIS ROUTINE ACCEPTS BAD BLOCK DATA TYPED IN BY THE USER ; AFTER THE MANUAL OPTION HAS BEEN SPECIFIED IN THE COMMAND LINE. ; ; IT PROMPTS WITH THE STRING "DSC> BAD=". THE REPLY IS IN THE ; FORM "NNNN,MMMM", WHERE NNNN IS THE STARTING LBN OF THE BAD AREA ; AND MMMM IS AN OPTIONAL COUNT. IF THE COUNT IS NOT PRESENT IT ; IS ASSUMED TO BE 1. THIS ROUTINE WILL LOOP AND PROMPT FOR ; ADDITIONAL DATA UNTIL TERMINATED BY A NULL LINE. ; MANUAL: PUSH GCLFLG ; SAVE MCR FLAG AND LET GCLFLG := #0 ; CLEAR IT TO FORCE INPUT REPEAT $CALL .GTCML <,,,#PROMPL,#PROMPT> ; GET INPUT LINE $CALL .TPARS <,#0,#BKYTB,R3,R4,#BSTRT> ; PARSE IT ON.ERROR ERRP ER.BSY ; SYNTAX ERROR ELSE IF #BA.END SET.IN FLAGS LEAVE LOOP IF COUNT+2 NE #0 ERRP ER.BCT ; COUNT MUST BE ONE WORD ELSE LET R3 := COUNT - #1 $CALL MAKBAD <,BLOCK+2,BLOCK,R3> ON.ERROR THEN ERRP ER.BRG ; BLOCK OUT OF RANGE END END END POP GCLFLG ; RESTORE MCR FLAG RETURN .SBTTL BAD BLOCK LIST SUBROUTINE ;+ ; ; THIS ROUTINE ENTERS THE DISK CLUSTERS CONTAINING THE INDICATED ; BLOCKS INTO THE BAD BLOCK LIST. IF ALL OR PART OF THE BLOCKS ; INDICATED ARE REDUNDANT, THEY ARE MERGED INTO THE APPROPRIATE ; CLUSTER. ; ; INPUTS: ; ; R1 = HIGH ORDER STARTING LBN ; R2 = LOW ORDER STARTING LBN ; R3 = BLOCK COUNT - 1 ; ; R4 IS PRESERVED ; ;- MAKBAD: LET R5 := $BADP ; GET BAD BLOCK TABLE POINTER PUSH R1,R2 ; SAVE LBN LET R2 := R2 + R3 ; COMPUTE LBN PLUS COUNT LET R1 := R1 + CARRY $CALL $DDIV <$CLF,R1,R2> ; COMPUTE UPPER CLUSTER BOUNDARY LET R3 := R2 + #01 ; INCLUDE WHOLE CLUSTER LET R2 := R1 + CARRY $CALL $DMUL <$CLF,,R2,R3> ; CONVERT BACK TO LBN LET (R5)+ := R1 ; STORE IN NEW TABLE ENTRY LET (R5)+ := R0 POP R2,R1 ; GET BACK STARTING LBN $CALL $DDIV <$CLF,R1,R2> ; COMPUTE LOW CLUSTER BOUNDARY LET R3 := R2 LET R2 := R1 $CALL $DMUL <$CLF,,R2,R3> ; AND CONVERT BACK TO LBN LET (R5)+ := R1 ; STORE STARTING LBN LET (R5)+ := R0 LET R5 := R5 - #8. ; BACK UP POINTER DCOMP 2(R5),(R5), $VOLSZ+2,$VOLSZ ; CHECK IF WITHIN VOLUME IF RESULT IS HI THEN RETURN ERROR ; BLOCKS OUT OF BOUNDS ; ; NOW SEARCH THE BAD BLOCK MAP FOR AN AREA THAT OVERLAPS OR IS ; ADJACENT TO THE NEW AREA. IF ONE IS FOUND, MERGE THEM. ; BEGIN TEST LET R3 := #$BADBK REPEAT IF R3 HIS $BADP LEAVE LOOP ; STOP AT END OF TABLE LET R1 := (R3)+ ; GET COUNT LET R0 := (R3)+ BEGIN MERGE PUSH 2(R3),(R3) ; MAKE TWO COPIES OF LBN PUSH 2(R3),(R3) LET (SP) := (SP) + R1 ; ADD COUNT TO COMPUTE LET 2(SP) := 2(SP) + CARRY + R0 ; END LBN DCOMP 2(R3),(R3), 6(R5),4(R5) ; COMPARE START LBN'S IF RESULT IS LO DCOMP 2(SP),(SP), 6(R5),4(R5) ; COMPARE END TO START IF RESULT IS LO LEAVE MERGE ; NO OVERLAP IF RESULT IS HI GOTO TESTE ; OVERLAP GOTO USE2 ; ADJACENT END IF RESULT IS HI ; (FROM FIRST COMPARE) LET 4(SP) := 4(R5) ; CONSIDER USING START LET 6(SP) := 6(R5) ; OF NEW AREA DCOMP 2(R3),(R3), 2(R5),(R5) ; COMPARE START TO END IF RESULT IS HI LEAVE MERGE ; NO OVERLAP IF RESULT IS LO GOTO TESTE ; OVERLAP ELSE ; FIRST COMPARE WAS EQUAL TESTE: DCOMP 2(SP),(SP), 2(R5),(R5) ; COMPARE END TO END IF RESULT IS LO USE2: LET (SP) := (R5) ; USE END OF NEW REGION LET 2(SP) := 2(R5) END END ; ; IF WE MAKE IT TO HERE WE HAVE FOUND AN OLD AREA THAT OVERLAPS ; OR IS ADJACENT TO THE NEW ONE. THE STACK CONTAINS END LBN, ; FOLLOWED BY START LBN, OF THE MERGED AREA. ; CMP -(R3),-(R3) ; BACK UP TO START OF POINTER LET (SP) := (SP) - 4(SP) ; COMPUTE COUNT FROM LET 2(SP) := 2(SP) - CARRY - 6(SP) ; LBN'S LET (R3)+ := POP ; AND FILL IN OLD POINTER LET (R3)+ := POP ; WITH NEW DATA LET (R3)+ := POP LET (R3)+ := POP LEAVE TEST ; END OF PROCEDURE END MERGE LET SP := SP + #8. ; END OF THIS TEST - CLEAN STACK CMP (R3)+,(R3)+ ; BUMP TO NEXT TABLE ENTRY END ; AND LOOP THRU TABLE ; ; THE ENTIRE TABLE HAS BEEN SEARCHED AND NO OVERLAPS HAVE BEEN ; FOUND. CONVERT THE NEW ENTRY INTO THE STANDARD COUNT, LBN FORMAT ; AND BUMP THE END OF TABLE POINTER. ; IF R5 HIS #$BADND THEN ERROR ER.BFU ; TABLE FULL LET (R5) := (R5) - 4(R5) LET 2(R5) := 2(R5) - CARRY - 6(R5) LET $BADP := R5 + #8. END TEST RETURN .SBTTL STATE TABLE TO PARSE MANUAL BAD BLOCK DATA .MCALL ISTAT$,STATE$,TRAN$ ISTAT$ BSTB,BKYTB STATE$ BSTRT TRAN$ $EOS,$EXIT,,BA.END,FLAGS ; EXIT ON NULL LINE TRAN$ $NUMBR,,SETN ; LBN STATE$ TRAN$ $EOS,$EXIT ; EXIT ON NO COUNT TRAN$ <',> STATE$ TRAN$ $NUMBR,,SETC ; COUNT STATE$ TRAN$ $EOS,$EXIT STATE$ .SBTTL ACTION ROUTINES FOR MANUAL BAD BLOCK PARSE ; ; SET LBN ; SETN: LET BLOCK := .PNUMB LET BLOCK+2 := .PNUMH LET COUNT := #1 LET COUNT+2 := #0 LET FLAGS := #0 RETURN ; ; SET COUNT ; SETC: LET COUNT := .PNUMB LET COUNT+2 := .PNUMH RETURN .END