.TITLE ADDBAD -- Add bad block to BADBLK.SYS file .ENABL LC .SBTTL Title page .IDENT -010100- ;+ ; Abstract: ADDBAD ; ; This task will add a bad block to the BADBLK.SYS file. ; Often, bad blocks will be encountered during system operation ; and it will be necessary to add bad blocks to the system bad ; block file. This task will allow that to be done without ; re-initializing the pack and doing a DSC on it. ; ; The task will not touch the bad block descriptor ; block. That block is for the use of BAD, INI, and DSC to ; remember which blocks were bad from initialization to ; initialization without requiring the user to type in all ; the bad blocks every time a pack is initialized. Since ; the use of the bad block descriptor block is predicated on ; re-writing the volume anyway, the use of BAD with the /MAN ; switch is a better way of adding bad blocks to the bad ; block descriptor block. This task will only update the ; BADBLK.SYS file to include the bad block(s) specified. ; ; Operating procedures: ; ; This task must be run from a privileged account. In ; addition, the victim disk pack must be mounted with the /UNL ; switch, and there must not be any activity on the volume ; (this can be accomplished by using the /PRO= and /UIC= ; switches in the command line). The task will prompt for the ; disk name and block name; only one block at a time may be ; entered in the bad block file. ; ; This task can be run either as an MCR or PDS command or by ; saying RUN $ADDBAD. It prompts with ; ; ADD> ; ; and expects a command string of the form: ; ; dev:/switches ; ; where dev: is the victim device name and defaults to SY0:. ; ; The disk should be dismounted and remounted IMMEDIATELY ; before this task is run; also, the disk should be dismounted ; IMMEDIATELY after this task is run, to synchronize the bitmap ; file on disk with the bitmap file which the operating system ; keeps in memory. ; ; Switches: ; ; /BL:nnnn:mmmm - The block number which is to be removed. ; nnnn and mmmm are the high order and ; low order words of the block number, ; respectively. ; /RA:nnnn - Indicates that the range of blocks ; beginning from the above /BL: switch ; is to be marked as bad. The default ; value for the range if this switch is ; not specified is 1. ; ; Task: ADDBAD ; ; Limitations: ; ; This task will probably not work on disk packs larger ; than 516096. blocks in size, since the bitmap file format ; changes for disks of that size. The larger disks have an ; extension to the bitmap header block, and the current ; task may not properly take this into account. The code ; looks like it matches what FILES-11 wants, but I'm not ; entirely sure. ; ; This task will currently only work on IAS/RSX-11D ; systems. It will not work for RSX-11M, RSX-11M+, RSTS, or ; VAX/VMS. RSX-11M and RSX-11M+ should require only a slight ; modification to adjust for slight differences in the Executive ; data structures; RSTS and VAX/VMS haven't a prayer because ; the internal file structures are completely different. ; ; Nonstandard features: ; ; Written in MACRO-11. This is necessary to bypass a ; number of things which would get in the way in a higher-level ; language, and also, alas, to do bit twiddling. ; ; Does not use the FCS READ$/WRITE$ macro's to do I/O ; to the files!! It uses some "similar" macros which expand ; to QIO's; the problem with the FCS macro's is that the ; INDEXF.SYS and BITMAP.SYS files don't have a complete FCS ; context, and setting up one manually will mess up the files ; when they are closed. ; ; Written: 30-Jan-1981, -1.0.0-, Bruce C. Wright ; Modified: 05-Aug-1981, -1.1.0-, Bruce C. Wright ; Added /RA switch. ; Verified: 05-Aug-1981, -1.1.0-, Bruce C. Wright ;- .SBTTL MACRO CALLS .MCALL QIOW$,WSIG$S,EXIT$S,QIOW$S .MCALL OPNS$M,CLOSE$ .MCALL CSI$,CSI$1,CSI$2,CSI$SW,CSI$SV,CSI$ND .MCALL GCML$,GCMLB$ .MCALL FDBDF$,FSRSZ$,FDRC$A,FDBK$A,FDOP$A .MCALL FDOF$L,FCSBT$,FHDOF$,HMBOF$ FDOF$L FCSBT$ FHDOF$ DEF$L HMBOF$ DEF$L CMDLUN=1 CMDEVF=1 INDLUN=2 INDEVF=2 BITLUN=3 BITEVF=3 MSGLUN=4 MSGEVF=4 .SBTTL MACRO DEFINITIONS .MACRO MSG ARG .NCHR $$$, .WORD $$$ .ASCII "ARG" .EVEN .ENDM .MACRO TYPE STR,LEN MOV STR,-(SP) MOV LEN,-(SP) CALL TYPE CMP (SP)+,(SP)+ .ENDM .MACRO TYPMSG ARG TYPE #ARG+2,ARG .ENDM .MACRO ONERR ARG BCC .+6 JMP ARG .ENDM .MACRO READ FDB,BUFFER,SIZE MOV FDB,R0 .IIF NB BUFFER MOV BUFFER,F.BKDS+2(R0) .IIF NB SIZE MOV SIZE,F.BKDS(R0) JSR PC,READ .ENDM READ .MACRO WRITE FDB,BUFFER,SIZE MOV FDB,R0 .IIF NB BUFFER MOV BUFFER,F.BKDS+2(R0) .IIF NB SIZE MOV SIZE,F.BKDS(R0) JSR PC,WRITE .ENDM WRITE .SBTTL MAIN LINE CODE BEGIN:: MOV SP,SPSAVE MOV .CRTSK,R0 ; Get our ATL node. MOV A.TI(R0),R0 ; Get the PUD address where we're running BITB #UT.PR,U.TF(R0) ; Are we on a privileged terminal? BNE RSTART ; J if so. TYPMSG M.PRI ; Type privilege message. EXIT$S ; And get out. RSTART: MOV SPSAVE,SP ; Restore SP CLOSE$ #IDXFDB ; Close INDEXF.SYS (if open) CLOSE$ #BITFDB ; Close BITMAP.SYS (if open) GCML$ #CMLBLK ; BCC GETOK ;GOT A LINE CMPB CMLBLK+G.ERR,#GE.EOF ;EOF? BNE 10$ ;NO EXIT$S ;YES 10$: CMPB CMLBLK+G.ERR,#GE.IOR ;I/O ERROR? BNE 20$ ;NO TYPMSG M.IOR EXIT$S ;THIS IS FATAL 20$: CMPB CMLBLK+G.ERR,#GE.OPR ;OPEN ERROR? BNE 30$ TYPMSG M.OPR BR RSTART 30$: CMPB CMLBLK+G.ERR,#GE.BIF ;SYNTAX ERROR? BNE 40$ ;NO TYPMSG M.BIF BR RSTART 40$: CMPB CMLBLK+G.ERR,#GE.MDE ;MAX @ DEPTH? BNE 50$ TYPMSG M.MDE BR RSTART 50$: TYPMSG M.UNK ;UNKNOWN ERROR EXIT$S ;AND LEAVE GETOK: TST CMLBLK+G.CMLD ;INPUT? BEQ RSTART ;NO MOV #1,RANGE ; Assume range of 1 block. CLR SWORD ; Default to no switches CSI$1 #CSIBLK,CMLBLK+G.CMLD+2,CMLBLK+G.CMLD ; BCC 10$ TYPMSG M.PS1 BR RSTART 10$: CSI$2 #CSIBLK,OUTPUT,#SWTAB ; BCC 20$ ;OK? TYPMSG M.PS2 ;NO JMP RSTART ;RESTART 20$: MOV #IDXDVL,IDXNAM ; Set up dataset descriptor for INDEXF MOV #IDXDVS,IDXNAM+2 ; ... MOV #BITDVL,BITNAM ; For BITMAP.SYS as well. MOV #BITDVS,BITNAM+2 ; ... BITB #CS.EQU!CS.NMF!CS.DIF!CS.WLD!CS.MOR,CSIBLK+C.STAT BEQ 30$ ;ANY ILLEGAL BITS SET? TYPMSG M.BAD ;YES -- BAD PARAMETERS JMP RSTART ; 30$: BITB #CS.DVF,CSIBLK+C.STAT ;DEV STRING? BEQ OPEN ;NO MOV CSIBLK+C.DEVD,IDXNAM ; Move in device spec for INDEXF MOV CSIBLK+C.DEVD+2,IDXNAM+2 ; ... MOV CSIBLK+C.DEVD,BITNAM ; For BITMAP.SYS as well MOV CSIBLK+C.DEVD+2,BITNAM+2 ; ... OPEN: BIT #SW.BLK,SWORD ; /BL switch specified? BNE 10$ ; J if so. TYPMSG M.BLK ; /BL switch must be specified. JMP RSTART ; Skip if not. ; ; Get the INDEXF.SYS file open. ; 10$: CLOSE$ #IDXFDB ; Close index file if necessary. OPNS$M #IDXFDB,,#IDXNAM ; Open the index file. ONERR ERROR ; ; Check that the block number is within range. ; MOV .PUDBA,R1 ; Get the PUD address. 12$: CMP U.DN(R1),IDXFDB+F.FNB+N.DVNM ; Right device name? BNE 14$ ; J if not. CMPB U.UN(R1),IDXFDB+F.FNB+N.UNIT ; Right unit number? BEQ 15$ ; J if so. 14$: ADD #U.SZ,R1 ; Get to next device. CMP R1,.PUDEA ; To end of PUD? BLO 12$ ; J if not. TYPMSG M.DEV ; Illegal device message. JMP RSTART ; And restart program. 15$: MOV BLKNUM,BLKHI ; Compute high block number. MOV BLKNUM+2,BLKHI+2 ; ... ADD RANGE,BLKHI+2 ; Add in the range. ADC BLKHI ; Propagate carry. CMP BLKHI,U.LBH(R1) ; Is the block number too high? BLO 18$ ; J if not. BHI 16$ ; Is it really too high? CMP BLKHI+2,U.LBN(R1) ; Is the low order out? BLO 18$ ; J if not. 16$: TYPMSG M.SIZ ; Message about size of device. JMP RSTART ; Restart task. ; ; Get the home block for various info about the device. ; 18$: CLR IDXFDB+F.BKVB ; Clear hi order block # MOV #2,IDXFDB+F.BKVB+2 ; Init low order block # READ R0,#HOME,#1000 ; Read home block. ONERR ERROR ; Print message on any error. ; ; Get the BITMAP.SYS file open. ; CLOSE$ #BITFDB ; Close the BITMAP.SYS file if necessary OPNS$M #BITFDB,,#BITNAM ; Open the bitmap file. ONERR ERROR ; ; Call the low level subroutines to allocate each bit. ; 20$: CALL ALLBIT ; Allocate a bit in the bitmap. ADD #1,BLKNUM+2 ; Increment block number. ADC BLKNUM ; ... DEC RANGE ; Decrement range. BGT 20$ ; And loop if still more blocks. 30$: JMP RSTART ; And start over. ; ; Subroutine to allocate a bit. ; ALLBIT: CLR BITFDB+F.BKVB ; Clear high order block # MOV #1,BITFDB+F.BKVB+2 ; Set low order block # = 1 READ #BITFDB,#BITMAP,#1000 ; Get the bitmap header block ONERR ERROR ; On error, leave. CLR R2 ; Clear out R2 for number of blocks. BISB BITMAP+3,R2 ; Get number of blocks in the bitmap. MOV #1+1,R5 ; Get the default offset from the ; start of the file (=1 for 1-origin ; + 1 for the header block). 20$: CMP R2,#126. ; Too many for one header block? BLOS 22$ ; J if not. INC R5 ; Account for another header block. SUB #128.,R2 ; Count the number of pointers. BR 20$ ; And loop until computed number of headers. ; ; Read in the appropriate block of the bitmap. ; 22$: MOV BLKNUM,R2 ; Get high order block # MOV BLKNUM+2,R3 ; Get low order block # ASHC #-12.,R2 ; Compute block # in bitmap. ADD R5,R3 ; Get block number in file. ADC R2 ; Carry to high order. MOV R2,BITFDB+F.BKVB ; Set the high order block # MOV R3,BITFDB+F.BKVB+2 ; Set the low order block # READ #BITFDB,#BITMAP,#1000 ; Read the appropriate block # ONERR ERROR ; J if error MOV R2,BITFDB+F.BKVB ; Reset the block # in the file. MOV R3,BITFDB+F.BKVB+2 ; ... MOV BLKNUM+2,R3 ; Get low order block # ASH #-3,R3 ; Shift to get byte within buffer. BIC #^C777,R3 ; Clean out unused bits. MOV BLKNUM+2,R1 ; Get the block number again. BIC #^C7,R1 ; Get bit number within byte. MOV #1,R2 ; Get a roving bit. ASH R1,R2 ; Get the bit mask. BITB R2,BITMAP(R3) ; Is it allocated? BNE 25$ ; J if not. TYPMSG M.ALL ; Type allocated message. RETURN ; And return to the caller. 25$: BICB R2,BITMAP(R3) ; Set the bit in the bitmap. ; ; Read in the file header for BADBLK.SYS. This is a block in ; INDEXF.SYS; we can't use the normal READ/WRITE ATTRIBUTES ; functions in the ACP because we must diddle the retrieval ; pointers mapping information. ; MOV HOME+H.IBSZ,R1 ; Get size of index file bitmap ADD #3+2,R1 ; Compute block # of BADBLK.SYS header MOV R1,IDXFDB+F.BKVB+2 ; Set in low order block # of index file CLR IDXFDB+F.BKVB ; Clear high order block # READ #IDXFDB,#HEADER,#1000 ; Read the BADBLK.SYS header. ONERR ERROR MOV R1,IDXFDB+F.BKVB+2 ; Set in low order block # of index file CLR IDXFDB+F.BKVB ; Clear high order block # CLR R5 ; Get R5 clear for next operation. BISB HEADER+H.MPOF,R5 ; Get map area offset in words ASL R5 ; Make it into bytes. ADD #HEADER,R5 ; Absolutize the map area pointer. MOV R5,R4 ; Point to ... ADD #M.RTRV,R4 ; ... The retrieval pointer area. CLR R3 ; Get ready to get another byte. BISB M.USE(R5),R3 ; Get the number of words in use. ASR R3 ; Make into the number of pointers. ; ; Loop through the retrieval pointers looking for a retrieval pointer ; which matches the retiring block on either its low or its high end. ; 30$: TST R3 ; Any more retrievel pointers? BEQ 50$ ; J if not. CLR R0 ; Clear high order block # BISB (R4),R0 ; Set in the high order retrieval pointer MOV 2(R4),R1 ; Get the low order retrieval pointer. SUB #1,R1 ; Compute retrieval pointer - 1 SBC R0 ; ... CMP R0,BLKNUM ; Does it match our block? BNE 35$ ; J if not. CMP R1,BLKNUM+2 ; Well?? BEQ 60$ ; J if so. 35$: CLR R0 ; Clear high order block # again BISB (R4),R0 ; Set in the high order retrieval pointer MOV 2(R4),R1 ; Get the low order retrieval pointer. CLR R2 ; Clear a scratch register. BISB 1(R4),R2 ; Get the size of the retrieval pointer. INC R2 ; Get one past the last block in pointer. ADD R2,R1 ; Compute ending block # ADC R0 ; ... CMP R0,BLKNUM ; Does it match our block? BNE 40$ ; J if not. CMP R1,BLKNUM+2 ; Well?? BEQ 70$ ; J if so. 40$: DEC R3 ; Decrement number of retrieval pointers. ADD #4,R4 ; To next retrieval pointer. BR 30$ ; And continue searching for a match. ; ; The search of retrieval pointers terminated without a match. ; See if we can increment the number of retrieval pointers. ; 50$: CMPB M.USE(R5),M.MAX(R5) ; Already using the maximum? BLO 55$ ; J if not. TYPMSG M.FUL ; Type message about file header full. RETURN ; And return to the caller. 55$: INCB M.USE(R5) ; Increment the usage by 2. INCB M.USE(R5) ; ... MOV BLKNUM,(R4) ; High order block # MOV BLKNUM+2,2(R4) ; Low order block # BR 100$ ; And leave -- success. ; ; The search of retrieval pointers found a pointer which matches ; the desired block, at the beginning. Decrement the block number ; in the retrieval pointer and write back out. ; 60$: CMPB 1(R4),#255. ; Too many blocks already? BEQ 40$ ; Yes -- look for another retrieval pointer. SUB #1,2(R4) ; Point to block before current block. SBC (R4) ; ... INCB 1(R4) ; Adjust size of retrieval pointer. BR 100$ ; And leave -- success. ; ; The search of retrieval pointers found a pointer which matches ; the desired block, at the end. Increment the number of blocks ; handled by the retrieval pointer, and write back out. ; 70$: CMPB 1(R4),#255. ; Too many blocks already? BEQ 40$ ; Yes -- look for another retrieval pointer. INCB 1(R4) ; Adjust the size of the retrieval pointer. BR 100$ ; And leave -- success. ; ; Success. We must now do preparation and write out the ; header block. First, ; ; Compute checksum of the new header block. ; 100$: MOV #HEADER,R0 ; Point to file header block. MOV #255.,R1 ; Get number of words in header. CLR R2 ; Clear checksum word. 110$: ADD (R0)+,R2 ; Add up the header. SOB R1,110$ ; ... MOV R2,HEADER+H.CKSM ; Save the new checksum. ; ; Write out the new header block for BADBLK.SYS. ; WRITE #IDXFDB,#HEADER,#1000 ONERR ERROR ; ; Finally, write out the new bits in the BITMAP.SYS file. ; WRITE #BITFDB,#BITMAP,#1000 ; ONERR ERROR RETURN ; And return to the caller. .SBTTL TYPE MESSAGE TO THE TERMINAL ; ; THIS SUBROUTINE TYPES A MESSAGE TO THE TERMINAL ; TYPE: MOV 2(SP),QMSG+Q.IOPL+2 ;LENGTH MOV 4(SP),QMSG+Q.IOPL ;BUFFER ADDRESS MOV #QMSG,-(SP) ;DO I/O CALL .DIRDL ; BCS 10$ ; RETURN ;RETURN TO CALLER 10$: BPT ;ERROR? ; .SBTTL Print error message to the terminal. ; ERROR: MOV #BLKPR,R1 ; Get the message buffer MOV #BLKSZ,R2 ; Get the message length CALL .PRFCS ; Print the FCS error CLOSE$ R0 ; Close the file. JMP RSTART ; And start again. ; .SBTTL READ - Read from a file ; READ: MOV R1,-(SP) ; Save R1 MOV R2,-(SP) ; Save R2 MOV R3,-(SP) ; And R3 CLR -(SP) ; Room for IOST CLR -(SP) ; ... MOV SP,R3 ; Point to it. MOVB F.LUN(R0),R1 ; Get the LUN. MOVB F.BKEF(R0),R2 ; Get the event flat # BNE 10$ ; J if specified. MOV #32.,R2 ; Use 32. by default. 10$: QIOW$S #IO.RVB,R1,R2,,R3,, MOV F.BKDS(R0),R1 ; Get the buffer size. ADD #777,R1 ; Round up to next block. ASH #-9.,R1 ; Make it into blocks. ADD R1,F.BKVB+2(R0) ; Get to the next block. ADC F.BKVB+2(R0) ; ... MOV F.BKST(R0),R2 ; Any I/O Status blocks? BEQ 20$ ; J if not. MOV (SP),(R2)+ ; Return IOST MOV 2(SP),(R2)+ ; ... 20$: TST @#$DSW ; Any errors? BMI 30$ ; J if so. TST (SP) ; Well? BGE 40$ ; J if not. 30$: SEC ; Indicate error. 40$: MOV (SP)+,(SP)+ ; Pop IOST. MOV (SP)+,R3 ; Recover registers. MOV (SP)+,R2 ; ... MOV (SP)+,R1 ; ... RETURN ; And return to the caller. ; .SBTTL WRITE - Write to a file ; WRITE: MOV R1,-(SP) ; Save R1 MOV R2,-(SP) ; Save R2 MOV R3,-(SP) ; And R3 CLR -(SP) ; Room for IOST CLR -(SP) ; ... MOV SP,R3 ; Point to it. MOVB F.LUN(R0),R1 ; Get the LUN. MOVB F.BKEF(R0),R2 ; Get the event flat # BNE 10$ ; J if specified. MOV #32.,R2 ; Use 32. by default. 10$: QIOW$S #IO.WVB,R1,R2,,R3,, MOV F.BKDS(R0),R1 ; Get the buffer size. ADD #777,R1 ; Round up to next block. ASH #-9.,R1 ; Make it into blocks. ADD R1,F.BKVB+2(R0) ; Get to the next block. ADC F.BKVB+2(R0) ; ... MOV F.BKST(R0),R2 ; Any I/O Status blocks? BEQ 20$ ; J if not. MOV (SP),(R2)+ ; Return IOST MOV 2(SP),(R2)+ ; ... 20$: TST @#$DSW ; Any errors? BMI 30$ ; J if so. TST (SP) ; Well? BGE 40$ ; J if not. 30$: SEC ; Indicate error. 40$: MOV (SP)+,(SP)+ ; Pop IOST. MOV (SP)+,R3 ; Recover registers. MOV (SP)+,R2 ; ... MOV (SP)+,R1 ; ... RETURN ; And return to the caller. .SBTTL DATA AREA ; ; DATA AREA FOR THE INDEX FILE SCANNER PROGRAM. ; SPSAVE: .WORD 0 ;SAVE AREA FOR SP IOST: .WORD 0,0 ;IO STATUS BLOCK BLKNUM: .WORD 0,0 ; BLOCK NUMBER TO BE MARKED AS BAD BLKHI: .WORD 0,0 ; High block number in range. RANGE: .WORD 0 ; Range of block numbers. HEADER: .BLKB 1000 ; File header area. BITMAP: .BLKB 1000 ;BITMAP BUFFER AREA HOME: .BLKB 1000 ;HOME BLOCK AREA .ENABL LC M.PRI: MSG M.IOR: MSG M.OPR: MSG M.BIF: MSG M.MDE: MSG M.UNK: MSG M.PS1: MSG M.PS2: MSG M.BAD: MSG M.BLK: MSG M.ALL: MSG M.FUL: MSG M.SIZ: MSG M.DEV: MSG BLKPR: .ASCII /ADDBAD/ BLKSZ = .-BLKPR .EVEN IDXFDB: FDBDF$ ;FDB FOR INDEX FILE FDRC$A FD.RWM ;USE BLOCK IO FDBK$A ,1000,,INDEVF,IOST FDOP$A INDLUN BITFDB: FDBDF$ ; FDB for BITMAP.SYS file FDRC$A FD.RWM ; Use block I/O FDBK$A ,1000,,BITEVF,IOST FDOP$A BITLUN FSRSZ$ 1 ;NO BLOCKING BUFFERS NEEDED CMLBLK: GCMLB$ 2,ADD,USRBUF,CMDLUN USRBUF: .BLKB 82. .EVEN CSI$ CSIBLK: .BLKB C.SIZE .EVEN SWTAB: CSI$SW BL,SW.BLK,SWORD,SET,,BLKDSC CSI$SW RA,SW.RAN,SWORD,SET,,RANDSC CSI$ND BLKDSC: CSI$SV OCTAL,BLKNUM,2 CSI$SV OCTAL,BLKNUM+2,2 CSI$ND RANDSC: CSI$SV OCTAL,RANGE,2 CSI$ND SW.BLK = 000001 ;/BL: SWITCH SW.RAN = 000002 ;/RA: switch SWORD: .WORD QMSG: QIOW$ IO.WVB,MSGLUN,MSGEVF,,IOST,,<0,0,40> ; ; Index file Dataset Descriptor ; IDXNAM: .WORD IDXDVL,IDXDVS .WORD IDXUIL,IDXUIS .WORD IDXFIL,IDXFIS IDXDVS: .ASCII /SY0:/ IDXDVL = .-IDXDVS .EVEN IDXUIS: .ASCII /[0,0]/ IDXUIL = .-IDXUIS .EVEN IDXFIS: .ASCII /INDEXF.SYS/ IDXFIL = .-IDXFIS .EVEN ; ; Bitmap file Dataset Descriptor ; BITNAM: .WORD BITDVL,BITDVS .WORD BITUIL,BITUIS .WORD BITFIL,BITFIS BITDVS: .ASCII /SY0:/ BITDVL = .-BITDVS .EVEN BITUIS: .ASCII /[0,0]/ BITUIL = .-BITUIS .EVEN BITFIS: .ASCII /BITMAP.SYS/ BITFIL = .-BITFIS .EVEN .END BEGIN