.MCALL .MODULE .MODULE DUPZRO,VERSION=21,COMMENT=,IDENT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion 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 Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ; Edit History: ; ; 001 28-Jan-80 11:01 Guldenschuh, Chuck cpg [240,148] ; Correct "Volume not RT-11 format" problem ; (001) ; 002 30-Jan-80 01:54 Guldenschuh, Chuck cpg [240,148] ; Correct BBRT overflow bug and add NT .GTLIN ; (002) ; 003 11-Nov-80 11:34 AM Fingerhut, David [240,134] ; Init of former RSX disk fails ; (003) ; 004 02-Dec-80 11:32 AM David Fingerhut [240,134] ; Account for RK07 Status Word during bad block scan ; (004) ; 005 20-Mar-81 03:01 PM David Fingerhut [240,134] ; INIT/BAD does /REPLACE rather than create FILE.BAD's ; (005) ; 006 02-Apr-81 09:41 AM David Fingerhut [240,134] ; Change system id (IBM) from ASCII to EBCDIC ; (006) ; 007 21-Dec-81 01:31 PM David Fingerhut [40,134] ; Insert RESET in dummy bootstrap ; (007) ; 008 19-Jan-82 09:30 AM David Fingerhut [40,134] ; Make No Boot on Volume a -U- type error, not -F- ; (008) ; 009 02-Feb-82 11:20 AM David Fingerhut [40,134] ; Clear BUP area in homeblock ; (009) ; ; V05.08 MBG 11-Sep-84 Check for odd count of extra bytes in directory ; 02 header when saving portion of directory in home ; block. ; ; 020 06-Nov-1990 JFW ; bracket error messages in ;+/;ERROR/.../;- ; ; (021) 23-Jun-91 MBG Corrected problem with count of free blocks ; when there are replacable bad blocks .SBTTL Edit History ; CG03 Fix error in MDUP assembly DUPZRO EL33 DUP V04.00 ; CG05 Fix MDUP INITIALIZE code DUPZRO EL34 DUP V04.00 ; CG10 Code bumming DUPZRO EL35 DUP V04.00 ; CG12 INIT replacement table forcing DUPZRO EL36 DUP V04.00 .ENABL LC,GBL .SBTTL PSECT definitions .IIF NDF MDUP, MDUP = 0 ;Default to no MDUP .IIF NDF M$UPD, M$UPD = 0 ;Default to no MDUP Update .IIF NDF SDC, SDC = 0 ;Default to no SDCOPY BELL = 07 CR = 15 LF = 12 PSECT ...ERS ; ;001 PSECT USERP ;User patchable data psect PSECT IMPURE ;Impure data PSECT .LIBD. ;Library data (error messages) PSECT .LIBP. ;Library pointers (error messages) PSECT PURE ;Pure data PSECT PUREB ;[byte] Pure data PSECT ZERO ;Code psect PSECT PATCH ;Patch psect .BLKW 32. PSECT USERP SEGTBL::.WORD 512. , 1 ;1 segment for 512 blocks or smaller .WORD 1024.*02., 4 ;4 segments for 2k blocks or smaller .WORD 1024.*12., 16. ;16 segments for 12k blocks or smaller .WORD 177777 , 31. ;31 segments for > 12k blocks .BLKW 10. ;Allow for the range to be modified .WORD 0 ;Stopper. PSECT PURE BAD.: .WORD R50AST ;RAD50 '*' .RAD50 \ BAD\ ;'*.BAD' .SBTTL Home block information PSECT PURE .NLIST BEX HOME0: .WORD HOME1-HOME0-4,351*2 .WORD 1 ;Word 351 ;Pack cluster size .WORD 6 ;Word 352 ;Start block number of directories .RAD50 \V05\ ;Word 353 ;System version number HOME1: .WORD HOME2-HOME1-4,354*2 .ASCII \RT11A \ ;Word 354-361 ;Default Vol ID .ASCII \ \ ;Word 362-367 ;Owner name HOME2: .WORD HOME3-HOME2-4,370*2 .ASCII \DECRT11A \ ;Word 370-375 ;Pack format type HOME3: .SBTTL Prototype directory PROTO: .WORD 0 ;Number of available segments .WORD 0 ;Link to next segment .WORD 1 ;Highest segment open .WORD 0 ;Number of extra bytes .WORD 0 ;Starting block for files in this segment .WORD DS.EMP ;First file always an empty .RAD50 \ EMPTYFIL\ ;Give it a filename .WORD 0 ;File length .WORD 0 ;Job number and channel number .WORD 0 ;File creation date PROTOS = <. - PROTO> / 2 ;Size of the prototype in words .WORD DS.EOS ;End-of-segment flag for 2nd entry .SBTTL Dummy bootstrap TTPS = 177564 TTPB = 177566 DBOOT: NOP ;Type 1 boot block RESET ;Data volume BR 3$ ;Go to executable code .=DBOOT+ ;Start of identification area .BYTE 20 ;PDP-11 instruction set (for checksum) .BYTE 103 ;Controller type (NON-MSCP) (for checksum) .BYTE 20 ;RT-11 file structure (for checksum) .BYTE 0 ;Checksum (calculated dynamically) 3$: BR 4$ ;Version 1 of boot standard 4$: JSR R0,1$ ;Call the print routine ;+ ;ERROR .ASCII <0><0><0><0>\?BOOT-U-No boot on volume\<200>;008 ;- .EVEN 1$: TSTB @#TTPS ;Is the printer ready? BPL 1$ ;Branch if not MOVB (R0)+,@#TTPB ;Output a character BPL 1$ ;Branch if more to come 2$: BR 2$ ;Done DBOOTS = <. - DBOOT> / 2 ;Size in words of the dummy boot CONTYP = 13 ;Offset from DBOOT to controller type MSCPBT = 130 ;Value for controller if MSCP .LIST BEX .SBTTL Bad Block Replacement Table Information REPTBL: .WORD DMID, 32. ;RK06/7's can have 32. replaceable blocks .WORD DLID, 10. ;RL01/2's can have 10. replaceable blocks .BLKW 10. ;Leave room for 5 more devices .WORD 0 ;Stopper. Must be 0 PSECT PUREB .IF EQ MDUP .NLIST BEX MSGINI: .ASCII \/Initialize\<200> MSGPRO: .ASCII \Volume contains protected files\<200> REALLY: .ASCII \Initializing \\SYSTEM\\ volume!\ .ASCII \SY:/Initialize\<200> PRMPT1:.ASCII \Type , 0, or nnnnnn ()\ PRMPT2:.ASCII \Replace block # \<200> .LIST BEX .SBTTL Error Messages .MACRO ERRMSG NAME,TEXT DS NAME,BYTE .PSECT .LIBD. EM.'NAME: .ASCII \TEXT\<200> .PSECT .LIBP. .WORD EM.'NAME .ENDM ERRMSG .MACRO MSGLST NAME .DSECT ...ERS,GLOBAL=NO .PSECT .LIBP. NAME: .WORD ..MAX. .ENDM MSGLST .MACRO MSGEND DS ..MAX.,BYTE .ENDM MSGEND ;+ ;ERROR MSGLST OERTAB ERRMSG BSA, ERRMSG RTO, ERRMSG VNR, MSGEND ;- .SBTTL Impure data PSECT IMPURE ;Error message area block OEAREA: .BYTE 0 ; Error code byte .BYTE 0 ; Error level/return flag .WORD ERRPRE ; -> Error message prefix .WORD ERRLEV ; -> Error level byte .WORD OERTAB ; -> Error message offset table .WORD 0 ; -> File name block .WORD ABORT ; -> Abort return SAVREP: .WORD 0 ;Save area for max # of replacement blocks .ENDC ;EQ MDUP PSECT IMPURE ;CG03 LSTBLK: .WORD 0 ;Size of the device SYS: .RAD50 \SY \ ;Device name for system volume check SYS1: .WORD 0 ;Filename and real device name (eventually) DXBUFF: .WORD 0 ;System ID buffer for sector 7 track 0 ; .ASCII \RT11A\ ; of a floppy (RX01) (EBCDIC) ;006 .BYTE 331 ;R ;006 .BYTE 343 ;T ;006 .BYTE 361 ;1 ;006 .BYTE 361 ;1 ;006 .BYTE 301 ;A ;006 .BYTE 100 ; ;006 .EVEN ;Only 1st 5 bytes are significant! FUDGE: .WORD 0 ;Fudge factor for .SPFUN reads to DM, DL REPBLK: .BLKW ; : Block to use for replacement .SBTTL ZERO - Zero a device ;+ ; ZERO ; ; /BADBLOCKS ; Scan is done. All bad blocks become .BAD files. Replacement table is ; zeroed ; /BADBLOCKS:RETAIN ; No scan is done. All current .BAD files retained. Replacement table ; is zeroed. ; /REPLACE ; Scan is done. All replaceable bad blocks go into replacement table. ; Non-replaceable bad blocks become .BAD files ; /REPLACE:RETAIN ; No scan is done. Replacement table is retained. ; /BADBLOCKS/REPLACE ; Scan is done. All replaceable bad blocks go into replacement table. ; Non-replaceable bad blocks become .BAD files ; /BADBLOCKS:RETAIN/REPLACE ; Scan is done. All replaceable bad blocks that are not already .BAD ; files go into replacement table. Non-replaceable bad blocks become ; .BAD files. All current .BAD files are retained. ; /BADBLOCKS/REPLACE:RETAIN ; Scan is done. All bad blocks that are not already in replacement ; table become .BAD files. Replacement table is retained. ; /BADBLOCKS:RETAIN/REPLACE:RETAIN ; No scan is done. All current .BAD files are retained. Replacement ; table is retained. ; ; Volume ID and owner name will not be modified unless FL.VOL in $MFLAG ; ; NOTE: The fudge factor introduced when a disk is scanned with .SPFUN ; is needed because that request returns a status word in the first ; word of the buffer. This is generally uncouthful as far as this ; part of the code is concerned. The .SPFUN is used because the ; volume may not currently contain a reasonable bad block replacement ; table, and we don't want the home block or directory sent to some ; random block on the disk. ;- ORIGIN ZERO ZERO:: .IF EQ MDUP ;+ ; Test for magtape or cassette ;- BIT #,$ISFLG ; Input device a magtape or cassette? BNE 10$ ; Branch if so BIT #DEV.MT,$OSFLG ; Zeroing a magtape? BEQ CHKSY ; Branch if not 10$: JMP ZEROMC ; Go do it, otherwise .PAGE ;+ ; Test for initializing system device if /WAIT option not specified ; Request confirmation with bell warning it attempting to init SY: ; If not attempting to init SY:, request confirmation if /NOQUERY ; option was not specified. ;- CHKSY: BIT #FL.WAT,$MFLAG ; Was /WAIT given? SYCHK:: BNE 20$ ; Branch if so ; Check for initializing system device!!!!! .LOOKUP #IOAREA,#16,#SYS ; Lookup the system device BCC 10$ ; Branch if no error ;+ ;ERROR MOV #FE.SYS,R0 ; Oops! Shouldn't happen JMP PRTERR ; <-F-System error> ;- 10$: MOV #16,R0 ; R0 = channel number MOV #SYS1,R1 ; R1 -> location to store real device name CALL REALDV ; Convert logical to physical .PURGE #16 ; Purge the channel CMP @R1,INFILE ; Same device we're supposed to init? BNE 20$ ; Branch if not. Do normal message MOV #REALLY,RUSPRM ; Do the attention getter instead CALL RSURE1 ; Prompt with no check for /NOQUERY BR 30$ ; Continue normal checking ; Ask user for confirmation 20$: SURE #INFILE,#MSGINI,FG ; See if he really wants to zero it ; SURE checks /NOQUERY option 30$: BEQ NWTPRO ; He really wants to. RETURN .PAGE ;+ ; Check for protected files if /WAIT option not specified ;- NWTPRO: BIT #FL.WAT,$MFLAG ; Was /WAIT given? BNE CHKSCN ; Branch if so - check just before destruction ; Get buffer for directory operation .GTCOR # ; Request block for directory buffer BCS NSFMEM ; Unable to allocate block TST (R0)+ ; Leave room for fudge factor MOV R0,$DIRBF ; Save the directory buffer pointer MOV #ICHAN,$DIRCH ;Set up the directory channel MOV #1,$NXTSG ; Start at the beginning of the directory CLR $NXTFL ; Force the first segment to be read ; Check for protected files CALL FNDPRO ; See if there are any protected files BCC 10$ ; Branch if no error CLR RETAIN ; No retension - not RT-11 directory structure BR 20$ ; 10$: TST R0 ; Were any found? BEQ 20$ ; Branch if not ; Tell user about protected files and ask for confirmation CLR R0 ; Flag no filename to print SURE ,#MSGPRO ; Make sure we can init it. BEQ 20$ ; Branch if so. RETURN ; Release buffer used for directory operation 20$: MOV #FREMLH,R0 ; R0 -> free memory list head ; R1 = size of the block to be released ; from .GTCOR request MOV $DIRBF,R2 ; R2 = address of the block to be released + 2 TST -(R2) ; R2 = address of the block to be released CALL $RLCB ; Release the block CLR $DIRBF ; Clear pointer to directory buffer released .PAGE ;+ ; Determine if bad block scan should be done ; If scan is to be done, jump to S1LINK in root. ; S1LINK returns to ZERO1L. ; ; If scan done and bad blocks were found, BADLHD will point to the start ; of the bad block table. ;- CHKSCN: TSTB RETBAD ; Retaining .BAD files? BNE 10$ ; Branch if so. No scan for that .IFTF ;EQ MDUP BIT #FL.BAD,$MFLAG ; Do the scan? (/BAD specified) .IFT ;EQ MDUP BNE 20$ ; Branch if so 10$: TSTB RETREP ; Retaining replacement table? BNE ZERO1L ; Branch if so. No scan BIT #FL.REP,$MFLAG ; Do the scan? (/REPLACE specified .IFTF ;EQ MDUP BEQ ZERO1L ; Branch if not 20$: JMP S1LINK ; Go do the bad block scan .PAGE ;+ ; If the bad block scan was done an bad blocks found, BADLHD points to ; the start of the bad block list. ; ; Get memory for buffers that will be needed. ;- ZERO1L:: .GTCOR # ; Get a directory, home block, and ; replacement block buffers BCC SETBUF ; Branch if no error ;+ ;ERROR NSFMEM: .ERR #ERAREA,#FE.NOM,LEVEL=FATAL,RETURN=NO ; <-F-Insufficient memory> ;- ;+ ; Setup pointers to directory buffer, home block buffer, and replacement ; buffer. The replacement buffer is used the check that the replacement ; block is good. ;- SETBUF: TST (R0)+ ; Leave room for fudge factor MOV R0,$DIRBF ; Save the directory buffer pointer ADD #,R0 ; Homeblock will be read here MOV R0,IBFBEG ; Save homeblock buffer address ADD #<512.>,R0 ; Replacement block will be read in here ; Contains an extra word for devices which ; return an xtra word on .SPFUN requests (DM:) MOV R0,REPBUF ; Save replacement buffer address MOV #ICHAN,$DIRCH ; Set up the directory channel .IFT ;EQ MDUP ;CG05 .PAGE ;+ ; Check for protected files if /WAIT option specified ;- WATPRO: BIT #FL.WAT,$MFLAG ; Was /WAIT given BEQ DEVSIZ ; Branch if not - directory already checked MOV #1,$NXTSG ; Start at the beginning of the directory CLR $NXTFL ; Force the first segment to be read WAIT #WAITIN,#INFILE ; Wait for the volume to be mounted ; Check for protected files CALL FNDPRO ; See if there are any protected files BCC 10$ ; Branch if no error CLR RETAIN ; No retension - not RT-11 directory structure BR DEVSIZ ; 10$: TST R0 ; Were any found? BEQ DEVSIZ ; Branch if not ; Tell user about protected files and ask for confirmation CLR R0 ; Flag no filename to print SURE ,#MSGPRO ; Make sure we can init it. BEQ DEVSIZ ; Branch if so. RETURN .IFTF ;EQ MDUP ;+ ; Get device size ;- DEVSIZ: MOV #1,$NXTSG ; Start at the beginning of the directory CLR $NXTFL ; Force the first segment to be read MOV #INST,R0 ; R0 -> input .DSTATUS block MOV #$ISFLG,R1 ; R1 -> input file/device flag word MOV #ICHAN,R2 ; R2 = input channel number CALL GTDVSZ ; Get the device size MOV R1,LSTBLK ; Save the size of the device for MERGE MOV R1,SAVSIZ ; Save the size of the device for ZERO part II .PAGE ;+ ; Get number of directory segments ;- GETSEG: MOV #SEGTBL,R0 ; R0 -> device size/directory segment table .IFT ;EQ MDUP MOV SEGMNT,R5 ; R5 = /N value BNE BADBUF ; Branch if specified .IFTF ;EQ MDUP 10$: CMP R1,(R0)+ ; This entry give # of directory segments? BLOS 20$ ; Branch if so. ;CG10 TST (R0)+ ; Skip # of directory segments TST @R0 ; Any more entries? BNE 10$ ; Branch if so. Check again TST -(R0) ; Back up to the number of segments ;CG10 20$: MOV @R0,SEGMNT ; Save # of directory segments ;CG10 MOV @R0,R5 ; Copy it .IFT ;EQ MDUP ;+ ; Setup buffer to hold bad blocks if doing a retain or device supports BBR ;- BADBUF: TST BADLHD ; Was a scan done AND bad blocks found? BNE BADRET ; Branch if so TST RETAIN ; Retaining anything? BNE 10$ ; Branch if so BIT #,$ISFLG ; Support bad block replacement? BEQ REDHOM ; Branch if not ;CG12 10$: .GTCOR # ; Get the area for the bad block table ;+ ;ERROR BCS NSFMEM ; Branch if no memory ; <-F-Insufficient memory> ;- MOV R0,BADLHD ; Save the start of the table MOV R0,R1 ; Copy it CLR (R1)+ ; Zero # of bad blocks and skip header .PAGE ;+ ; Retain .BADs if /BAD:RET ;- .ENABL LSB BADRET: TSTB RETBAD ; Retaining .BAD entries? BEQ REDHOM ; Branch if not 10$: MOV #BAD.,R0 ; R0 -> "*.BAD" filename CALL FNDPRM ; Find one BCC 20$ ; Branch if no error ;+ ;ERROR CMP R0,#ILD ; "Illegal directory"? BNE PRTERR ; Branch if not. Give error ;- CLR RETAIN ; Can't retain anything BR REDHOM ; ;+ ;ERROR PRTERR: MOV R0,R1 ; Copy the error code .ERR #ERAREA,R1,LEVEL=FATAL,RETURN=NO,FILE=#INFILE ;- 20$: TST R0 ; Was one found? BEQ REDHOM ; Branch if not. Done MOV R0,R1 ; R1 -> directory entry MOV #BAD.NR,(R1)+ ; Non-replaceable bad block MOV $STBLK,(R1)+ ; Save the start address MOV DE.LEN(R0),(R1)+ ; Save the size CALL MERGE ; Merge it in with the current list BR 10$ ; Go get next one .DSABL LSB .PAGE ;+ ; If /BAD/RET:REP was specified in the command line then ; check replaced blocks and if bad make original block as bad ;- REPCHK: TSTB RETREP ; Retaining replacement table? BEQ 20$ ; Branch if not TSTB RETBAD ; Retaining .BAD files? BNE 20$ ; Branch if so, no scan done BIT #FL.BAD,$MFLAG ; Was scan for bad blocks done? BEQ 20$ ; Branch if not ; /BAD/RET:REP was specified in command line MOV IBFBEG,R1 ; Point to replacement table in home block 10$: TST (R1)+ ; Is there an entry here? BEQ 20$ ; Branch if not READ #IOAREA,#ICHAN,REPBUF,#256.,(R1)+ ; Read replacement block BCC 10$ ; Branch if successful MOV REPBUF,R0 ; R0 -> Area to build bad block entry MOV #BAD.NR,(R0)+ ; - Non-replaceable bad block MOV -4(R1),(R0)+ ; - Block number MOV #1,(R0)+ ; - One block MOV REPBUF,R0 ; R0 -> Bad block entry for MERGE CALL MERGE ; Merge bad block in with current list BR 10$ ; Loop till done 20$: .IFTF ;EQ MDUP .PAGE ;+ ; Read home block ;- REDHOM: CLR FUDGE ; Assume a zero fudge factor BIT #,$ISFLG ; Input device support bad block rep? BEQ 10$ ; Branch if not MOVB #1,SPFUNI ; Do .SPFUN reads MOVB #1,SPFUNO ; and writes BIT #DEV.SR,$ISFLG ; Input device sometimes replaceable (RK06/7)? BEQ 10$ ; Branch if not MOV #2,FUDGE ; Fudge factor is 2 bytes 10$: .IFT ;EQ MDUP ;CG10 SUB FUDGE,IBFBEG ; Fudge the buffer pointer BIT #,$ISFLG ; Support bad block replacement? BEQ 20$ ; Branch if not BIT #DEV.DU,$ISFLG ; Is this MSCP? BNE 20$ ; Branch if so MOV IBFBEG,R2 ; R2 -> input buffer CALL GTMBS1 ; Get and merge man. bad sector file ;CG12- 20$: READ #IOAREA,#ICHAN,IBFBEG,#256.,#HOMBLK ; Read in the home block BCC 30$ ; Branch if no error ;+ ;ERROR MOV #ERT,R0 ; Set up the error code ; <-F-Error reading replacement table> BIT #,$ISFLG ; Support bad blk replacement? BNE PRTERR ; Branch if so MOV #FE.INE,R0 ; Set up error code ; <-F-Input error> BR PRTERR ; Go give the error ;- 30$: ADD FUDGE,IBFBEG ; Fix buffer pointer .IFTF ;EQ MDUP ;CG10 .PAGE ;+ ; Test for bad blocks in system area ;- SYSBAD: MOV #-1,R1 ; Set up default bad block # MOV BADLHD,R0 ; R0 -> scanned or saved bad blocks BEQ 20$ ; Branch if none. Done TST (R0)+ ; R0 -> 1st one BEQ 10$ ; Branch if none TST (R0)+ ; Skip the type CMP @R0,R1 ; Is this one lower than the other one? BHIS 10$ ; Branch if not MOV @R0,R1 ; Save it 10$: ASL R5 ; Get the highest block we'll use ADD #6,R5 ; Offset by 6 blocks CMP R5,R1 ; Is there a bad block in the system area? BLOS 20$ ; Branch if not ;+ ;ERROR .ERR #OEAREA,#BSA,LEVEL=FATAL,RETURN=NO,FILE=#INFILE ; <-F-Bad block in system area> ;- 20$: .IFT ;EQ MDUP ;CG05 ;+ ; Read 1st segment of directory ;- REDDIR: SUB FUDGE,$DIRBF ; Account for .SPFUN READ #IOAREA,#ICHAN,$DIRBF,#SEGSIZ,#6 ; Read in the first segment BCC 10$ ; Branch if no error ;+ ;ERROR MOV #DIE,R0 ; Set the error code JMP PRTERR ; Go give it ;- 10$: ADD FUDGE,$DIRBF ; .IFTF ;EQ MDUP ;CG05 .PAGE ;+ ; Setup volume ID and owner name ;- SETVOL: MOV IBFBEG,R5 ; R5 -> home block buffer .IFT ;EQ MDUP BIT #FL.VOL,$MFLAG ; Want to set the vol ID? BEQ 10$ ; Branch if not JMP V1LINK ; Go do vol id stuff 10$: CMP DK.VRN(R5),#<^RV3A> ; Is it already a V3 format disk? BEQ 20$ ; Branch if so CMP DK.VRN(R5),#<^RV4A> ; How about V4? BEQ 20$ ; Branch if so CMP DK.VRN(R5),#<^RV05> ; How about V5? BEQ 20$ ; Branch if so .ENDC ;EQ MDUP MOV #HOME1,R0 ; R0 -> dummy vol ID and owner name CALL SETHOM ; Go set it up 20$: .BR ZERO2 .SBTTL ZERO2L - Zero a device (part II) ;+ ; ZERO2L ; This part of the ZERO code is entered with the following condition set ; ; R5 -> home block buffer ; $DIRBF -> directory buffer containing the 1st directory segment ; IBFBEG -> home block buffer ; REPBUF -> replacement buffer ; Bad block scan (if any) has been done ; Volume ID has been set up ;- .ENABL LSB ZERO2: BR 10$ ; If we get entered here, input volume is up ZERO2L:: WAIT #WAITIN,#INFILE ; Wait for the volume to be mounted .IF EQ MDUP ; Call to DUPVOL (V1LINK) causes value of FUDGE to be lost due to overlay ; - recalculate FUDGE CLR FUDGE ; Assume zero fudge factor BIT #DEV.SR,$ISFLG ; Input device sometimes replaceable (RK06/7)? BEQ 10$ ; Branch if not MOV #2,FUDGE ; Fudge factor is 2 bytes .IFTF ;EQ MDUP 10$: CLR -(SP) ; Assume the disk is V3 or V4 format .IFT ;EQ MDUP ;CG05 CMP #<^RV3A>,DK.VRN(R5) ; Is it V3? BEQ CHKDW ; Branch if so CMP #<^RV4A>,DK.VRN(R5) ; How about V4? BEQ CHKDW ; Branch if so CMP #<^RV05>,DK.VRN(R5) ; How about V5? BEQ CHKDW ; Branch if so .ENDC ;EQ MDUP ;CG05 DEC @SP ; Say that it isn't BR SETRSX .DSABL LSB .IF EQ MDUP ;+ ; Check for DW (RD52) geometry change ;- CHKDW: CMP #BAD$ID,DK.RX1(R5) ; Failed attempt to convert pre-V5.3 ; DW disk to V5.3 geometry? BNE SETRSX ; Branch if not INC @SP ; Make flag positive to indicate no restore .ENDC ;EQ MDUP .PAGE ;+ ; Setup RT/RSX words in home block ;- SETRSX: MOV #GOD$ID,DK.RX1(R5) ; Init RT/RSX word 1 CLR DK.RX2(R5) ; Clear RT/RSX word 2 ; ; Setup home block pack cluster size, block number of 1st directory segment, ; and system version. ; MOV #HOME0,R0 ; R0 -> home block info part I CALL SETHOM ; Set it up ; ; Part II of the home block info is the volume ID and owner name, which is ; set up by VOLID or ZERO. ; ; Setup system identification in home block ; MOV #HOME2,R0 ; R0 -> home block info part III CALL SETHOM ; Set it up ;+ ; Save data for INIT/RESTORE ;- CALL CLRRST ; Assume we don't have any data to store .IF EQ MDUP ;CG05 SETRST: TST @SP ; Can we restore disk? BNE CLRSOM ; Branch if not MOV R5,R1 ; R1 -> homeblock buffer ADD #DK.SAV,R1 ; R1 -> INIT/RESTORE save area MOV #PROTOS,R0 ; R0 = header size + 1 directory entry MOV $DIRBF,R2 ; R2 -> directory buffer MOV DH.EXB(R2),R3 ; R3 = number of extra bytes BIT #1,R3 ; Is count valid? BNE CLRSOM ; Not if it's odd 10$: MOV (R2)+,(R1)+ ; Save header and 1st entry SOB R0,10$ ; Loop ADD R3,R2 ; R2 -> second entry MOV #DE.SIZ/2,R0 ; R0 = size of a directory entry 20$: MOV (R2)+,(R1)+ ; Save the 2nd entry SOB R0,20$ ; Loop .ENDC ;EQ MDUP .PAGE ;+ ; Clear BUP information area and unused area ;- CLRSOM: MOV R5,R1 ; R1 -> Homeblock buffer ADD #DK.BUP,R1 ; R1 -> BUP info area MOV #/2,R0 ; R0 = word size of BUP info area ; plus unused area up to DK.RX1 10$: CLR (R1)+ ; Clear area SOB R0,10$ ; Loop MOV R5,R1 ; R1 -> Homeblock buffer ADD #DK.UN2,R1 ; R1 -> Second unused area MOV #7.,R0 ; R0 = word size of second unused area 20$: CLR (R1)+ ; Clear area SOB R0,20$ ; Loop CLR DK.UN3(R5) ; Clear third unused area CLR DK.CSM(R5) ; Clear check sum (for now) MOV R5,R3 ; R3 -> homeblock buffer .IF EQ MDUP ;+ ; Check to see if /REP:RET was specified in the command line. ; If so, check to see if V3, V4, or V5 disk. ; If not, check to see if scan was done for replacement. ;- REPRET: TSTB RETREP ; Retaining bad block replacement table? BEQ REPLAC ; Branch if not. See if scan was done TST @SP ; Was this a V3 or V4 disk? BPL WRTHOM ; Branch if so. Retain table BR CLRREP ; Finish up .PAGE ;+ ; Bad block replacement table setup ;- REPLAC: BIT #FL.REP,$MFLAG ; Bad block scan for replacement done? BEQ CLRREP ; Branch if not ; Look for device ID in list of replacable devices MOV #REPTBL,R0 ; R0 -> table of replaceable devices MOV INST,R1 ; R1 -> input device status word BIC #^C377,R1 ; Leave only device id 10$: TST @R0 ; Is there one? BEQ CLRREP ; Branch if not. No replacement for you! CMP R1,(R0)+ ; Is this the device? BEQ 20$ ; Branch if so TST (R0)+ ; Point to next one BR 10$ ; Try for next one ; Bad block replacement table overflowed or ; ran out of good replacement blocks. ; ; Get list of blocks to be replaced from the user ;+ ;ERROR 60$: .ERR #OEAREA,#RTO,LEVEL=WARNING,RETURN=YES,FILE=#INFILE ; <-W-Replacement table overflow> ;- CALL GTUSER ; Get user input on which blocks to replace MOV R5,R3 ; Reset -> homeblock replacement table ;002 BR REPLAC ; Try again ; Device ID found - start bad block replacement process 20$: MOV (R0)+,R4 ; Save the maximum block number MOV R4,SAVREP ; Save it for possible table overflow MOV SAVSIZ,REPBLK ; Initialize replacement block number DEC REPBLK ; (pre-decrement for later INC) ADD SAVSIZ,R4 ; R4 -> Past replacement block area MOV BADLHD,R0 ; R0 -> scan bad block list head BEQ CLRREP ; None. MOV (R0)+,R1 ; R1 = number of bad blocks found BEQ CLRREP ; Branch if none CALL CLRRST ; No restore for you! 30$: BIT #BAD.RP,@R0 ; Is it replaceble? BEQ 50$ ; Branch if not BIT #BAD.NR,@R0 ; Do we really want it bad? ;CG12 BNE 50$ ; Branch if so ;CG12 40$: INC REPBLK ; Bump replacement block to use CMP REPBLK,R4 ; Have we gone past replacement area? BHIS 60$ ; Branch if so MOV R0,-(SP) ; Save R0 from READ READ #IOAREA,#ICHAN,REPBUF,#256.,REPBLK ; See if replacement ; block is readable MOV (SP)+,R0 ; Restore R0 BCS 40$ ; Can't read it. Try next one MOV BT.BLK(R0),(R3)+ ; Copy the block number MOV REPBLK,(R3)+ ; Copy the replacement block 50$: ADD #BT.SIZ,R0 ; Point to the next one SOB R1,30$ ; Loop 'til done .ENDC ;EQ MDUP ;+ ; Clear rest of BBR table in home block and calculate the checksum ;- CLRREP: MOV R5,R0 ; Calculate the size of the area to be cleared ADD #DK.SAV,R0 ; - R0 -> Start of BUP information area SUB R3,R0 ; - R0 = Number of bytes to clear 10$: CLRB (R3)+ ; Zero next entry in replacement table SOB R0,10$ ; - Loop till done MOV R5,R3 ; R3 -> Start of bad block replacement table TST (R3)+ ; Does disk have a BBR table? BNE 20$ ; Branch if yes MOV #DW.CD1,(R3)+ ; Move in special code words MOV #DW.CD2,(R3)+ ; for DW in case this is a DW volume 20$: ;+ ; Write the home block out to the disk ;- WRTHOM: TST (SP)+ ; Clean off the stack ;005 CALL CKSMHB ; Calculate the checksum for the home block SUB FUDGE,IBFBEG ; Fudge the buffer pointer WRITE #IOAREA,#ICHAN,IBFBEG,#256.,#HOMBLK ; Write out the homeblock BCS OUTERR ; Branch on error ADD FUDGE,IBFBEG ; Fix buffer pointer ;+ ; Force a re-read of the software BBR table by the handler ;- USEBBR: BIT #,$ISFLG ; Device support BBR? BEQ WRTBOT ; Branch if not .SPFUN #IOAREA,#ICHAN,#SF.IRT,#0,#0,#0,#0 ; Force re-read of table CLR SPFUN ; .READ/.WRIT requests can now be done safely ; ** Do NOT use .READ/.WRIT requests before this point. ; ** The BBR table must be setup first. ; ** If directory is re-vectored, it will probably be bad anyway. ;+ ;Calculate boot checksum, and set controller type if MSCP ;- WRTBOT: MOV #,R4 ; R4 -> DBOOT CMPB #DUID,INST ; Is it a DU (MSCP)? BNE 10$ ; Branch if not MOVB #MSCPBT,(R4) ; Fill in MSCP controller value 10$: DEC R4 ; Point to start of information area CLR R1 ; Clear accumulator MOVB (R4)+,R2 ; Get N*2 byte ADD R2,R1 ; Add to accumulator MOVB (R4)+,R2 ; Get N*2+1 byte ADD R2,R1 ; Add to accumulator MOVB (R4)+,R2 ; Get N*2+2 byte ADD R2,R1 ; Add to accumulator COM R1 ; Complement accumulator MOVB R1,(R4) ; Put the checksum in the boot MOV #DBOOT,R4 ;007 WRITE #IOAREA,#ICHAN,R4,#DBOOTS,#0 ; Write out dummy bootstrap BCC SETDIR ; Branch if no error ;+ ;ERROR OUTERR: MOV #FE.OPE,R1 ; Set the error code ; <-F-Output error dev:> DIRERR: .ERR #ERAREA,R1,LEVEL=FATAL,RETURN=NO,FILE=#INFILE ;- ;+ ; Set up the directory header ;- SETDIR: MOV #PROTO,R0 ; R0 -> prototype directory MOV SEGMNT,DH.AVL(R0) ; Save the number of available segments MOV XTRBYT,R1 ; R1 = number of extra bytes/entry MOV R1,DH.EXB(R0) ; Save it MOV SAVSIZ,R2 ; R2 = device size in blocks MOV R2,DH.SIZ+DE.LEN(R0) ; Save it in the file size MOV SEGMNT,R2 ; R2 = # of directory segments ASL R2 ; Compute size of the boot blocks ADD #6,R2 ; plus the directory size SUB R2,DH.SIZ+DE.LEN(R0) ; Fix the size of the empty MOV R2,DH.STB(R0) ; Save it as the start block for files MOV DATE,DH.SIZ+DE.DAT(R0) ; Save today's date MOV $DIRBF,R2 ; R2 -> directory buffer MOV #PROTOS,R3 ; R3 = size of prototype directory 10$: MOV (R0)+,(R2)+ ; Store the directory header & 1st file entry SOB R3,10$ ; Loop 'til done 20$: TST R1 ; Any extra bytes? BEQ 30$ ; Branch if not CLRB (R2)+ ; Clear out extra bytes SOB R1,20$ ; Loop 'til done 30$: MOV #DS.EOS,@R2 ; Mark the end of the directory MOV #6,$DIRSG ; Write out segment 1 CALL WRTDIR ; Do it BCC CREBAD ; Branch if no error ;+ ;ERROR MOV #DOE,R1 ; Set the error code JMP DIRERR ; Give it ; <-F-Directory output error dev:> ;- ;+ ; Do .BAD file creation ;- CREBAD: CLR R2 ; Clear non-replaceable bad block found flag MOV BADLHD,R0 ; R0 -> bad block list head from scan BEQ ZERO3L ; Branch if none MOV (R0)+,R1 ; R1 = # of bad blocks ;Are there any? BEQ ZERO3L ; Branch if not .IF EQ MDUP TSTB RETREP ; Retaining replacement table? BEQ 20$ ; NO MOV R5,R3 ; R3 -> Start of bad block replacement table 20$: BIT #BAD.NR,(R0)+ ; Is this a .BAD? BNE 60$ ; Branch if so. TSTB RETREP ; Retaining replacement table? BEQ 70$ ; NO 30$: TST (R3) ; Is there a replaced block here? BEQ 50$ ; NO CMP (R0),(R3) ; Is this block <= BBR block? BLOS 40$ ; YES CMP (R3)+,(R3)+ ; R3 -> Next replaced block in BBR table BR 30$ ; Loop till end of table or block found 40$: BEQ 60$ ; Branch if block in BBR table 50$: BIS #BAD.NR,-2(R0) ; Set non-replaceable flag so .BAD is created 60$: MOV (R0),R2 ; Set non-replacable bad block found flag 70$: CMP (R0)+,(R0)+ ; Skip the block number and size SOB R1,20$ ; Check them all TST R2 ; Any non-replacable bad blocks found? BEQ ZERO3L ; NO, Go finish up CALL CLRRST ; Can't save data for /RESTORE in that case CALL CKSMHB ; Calculate the checksum for the home block WRITE #IOAREA,#ICHAN,IBFBEG,#256.,#HOMBLK ; Write out the homeblock .ENDC ;EQ MDUP JMP C1LINK ; Go create the files ZERO3L:: CMPB #DXID,INST ; Is it a floppy? BNE 10$ ; Branch if not .SPFUN #IOAREA,#ICHAN,#SF.WPS,#DXBUFF,#0,#7,#0 ; Write system id in ; sector 7, track 0 10$: RETURN ; Clear the /RESTORE area in the home block. ; CLRRST: SAVE02 ; Save R0 - R2 MOV R5,R1 ; R1 -> homeblock buffer ADD #DK.SAV,R1 ; R1 -> INIT/RESTORE save area MOV #>,R0 ; R0 = word size of INIT/RESTORE area 10$: CLR (R1)+ ; Clear INIT/RESTORE save area SOB R0,10$ ; Loop RETURN .SBTTL SETHOM - Set Up Home Block Buffer ;+ ; SETHOM ; This routine sets up data in the home block buffer. ; ; R0 -> .WORD size of data in bytes ; .WORD offset into home block for data ; .BLKB data ; R5 -> home block buffer ; ; CALL SETHOM ;- SETHOM: SAVE02 ;Save volatile registers MOV (R0)+,R1 ;R1 = size of data to move MOV (R0)+,R2 ;R2 = offset from start of home block ADD R5,R2 ;Make it absolute 1$: MOVB (R0)+,(R2)+ ;Move a byte SOB R1,1$ ;Loop RETURN .SBTTL GTMBSF - Get and merge manufacturer's bad sector file ;CG12+ .IF EQ MDUP ;+ ; This routine reads in the manufacturer's bad sector file and merges it with ; the bad block list. ; ; * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * ; This routine is duplicated in DUPSCN. If you modify one, modify them both!! ; * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * ; ; R2 -> input buffer ; ; CALL GTMBS1 ;- .MACRO MBSF DEV,SLUFF,NUMSEC,TPC,SPT,HACK .WORD DEV'ID ;Data for DEV .WORD SLUFF ;Bad sector file starts at last block + SLUFF .WORD NUMSEC ;NUMSEC sectors containing file .WORD TPC ;TPC tracks/cylinder .WORD SPT ;SPT sectors/track .WORD HACK ;Computed block is divided by 2^HACK .ENDM MBSF PSECT PURE .LIST MEB MBSFT1:: MBSF DM,44.,5,3,22.,0 MBT.SZ == . - MBSFT1 MBSF DL,10.,5,2,40.,1 .NLIST MEB .BLKW MBT.SZ*2 ;Leave room for 2 more devices .WORD 0 ;End of table PSECT IMPURE LISTMB: .BLKW 3 ;Temp bad block element PSECT * GTMBS1:: SAVE05 ;Save all registers MOV #MBSFT1,R3 ;R3 -> table of device data 1$: TST @R3 ;Any more devices to check? BEQ 11$ ;Branch if not. Done CMPB @R3,INST ;Is this the device BEQ 2$ ;Branch if so. ADD #MBT.SZ,R3 ;R3 -> data for next device BR 1$ ;Go try again 2$: MOV R2,R4 ;R4 -> start of input buffer TST (R3)+ ;Get rid of device id MOV (R3)+,R1 ;R1 = number of blocks to add to last block ADD LSTBLK,R1 ;R1 = block number of bad sector file 3$: MOV R4,R2 ;Restore R2 to point to start of input buffer READ #IOAREA,#ICHAN,R2,#256.,R1 ;Read in a block of the file BCC 5$ ;Branch if no error 4$: ADD #2,R1 ;R1 -> next block of file DEC @R3 ;Decrement the number of blocks left in file BEQ 11$ ;Branch if none left BR 3$ ;Try to read this one 5$: BIT #DEV.SR,$ISFLG ;Input device sometimes replaceable (RK06/7)? BEQ 6$ ;Branch if not TST (R2)+ ;Skip status return 6$: TST (R3)+ ;Skip number of blocks CMP (R2)+,(R2)+ ;Skip pack serial number TST @R2 ;Is the word 0? BEQ 7$ ;Branch if so TST -(R3) ;Back up -> block counter ;003 BR 4$ ;Try read the next one 7$: CMP (R2)+,(R2)+ ;Skip leading 0 words 8$: CMP @R2,#-1 ;At the end of file? BEQ 11$ ;Branch if so. BIS #FL.REP,$MFLAG ;Say that we did a bad block scan MOV R3,-(SP) ;Save R3 for next element in file MOV (R2)+,R1 ;R1 = cylinder of bad sector MOV (R3)+,R0 ;R0 = # tracks/cylinder CALL $MUL ;R1 = CYL * TRK/CYL MOV (R2)+,R4 ;R4 = .BYTE SECTOR,TRACK MOV R4,-(SP) ;Save it CLRB R4 ;Get rid of sector SWAB R4 ;Get track in low byte ADD R4,R1 ;R1 = CYL * TRK/CYL + TRK MOV (R3)+,R0 ;R0 = sectors/track CALL $MUL ;R1 = (CYL * TRK/CYL + TRK) * SEC/TRK MOV (SP)+,R4 ;Get track,sector back BIC #^C<377>,R4 ;Leave only sector ADD R4,R1 ;R1 = (CYL * TRK/CYL + TRK) * SEC/TRK + SEC MOV (R3)+,R0 ;R0 = Divisor BEQ 10$ ;Branch if none 9$: CLC ;Clear C-bit ROR R1 ;Divide by 2 SOB R0,9$ ;Loop 10$: MOV #LISTMB,R0 ;R0 -> bad block list element MOV R0,R5 ;R5 -> bad block list element MOV #BAD.RP,(R5)+ ;Say that block is replacable MOV R1,(R5)+ ;Store the block number of the block MOV #1,@R5 ;Always 1 block CALL MERGE ;Merge it into our list MOV (SP)+,R3 ;R3 -> device data BR 8$ ;Try for another one 11$: RETURN ;CG12- .SBTTL GTUSER - Ask user which blocks to replace ;+ ; GTUSER ; This routine is entered when the replacement table overflows. ; ; CALL GTUSER ;- GTUSER:: JSR PC,$SAVAL ;Save all registers BIS #JS.NTG,@#S$JSW ;Set non-terminating .GTLIN mode ;002 MOV SAVREP,R3 ;R3 = number of replacement slots available MOV BADLHD,R4 ;R4 -> bad block list MOV #CMDBUF,R5 ;R5 -> handy input buffer MOV R4,R0 ;Copy it BEQ 11$ ;Branch if done MOV (R0)+,R1 ;R1 = number of bad blocks BEQ 11$ ;Branch if done 1$: BIS #BAD.NR,@R0 ;Say that it's not replaceable ADD #BT.SIZ,R0 ;R0 -> next block SOB R1,1$ ;Loop till all done BIT #FL.YES,$MFLAG ;/NOQUERY specified? BNE 6$ ;Branch if so. Same as user typing .GTLIN R5,#PRMPT1 ;Do the first prompt 2$: TSTB @R5 ;All done? BEQ 6$ ;Branch if so. Put the rest back. CALL GETNUM ;Get the block number TST R0 ;Did he say "no more"? BEQ 11$ ;Branch if so MOV R4,R2 ;R2 -> bad block list MOV (R2)+,R1 ;R1 = number of bad blocks 3$: CMP R0,BT.BLK(R2) ;Does it match this block? BNE 4$ ;Branch if not. Get the next one BIT #BAD.RP,@R2 ;Is it replaceable? BNE 10$ ;Branch if so BR 5$ ;Else ignore the input 4$: ADD #BT.SIZ,R2 ;R2 -> next block SOB R1,3$ ;Try again ; ; If we fall through, it didn't match. Get another block. ; 5$: .GTLIN R5,#PRMPT2 ;Get a block number BR 2$ ;Check it out ; ; If we get here, either user typed a , or /NOQUERY was specified. ; 6$: MOV R4,R0 ;R0 -> bad block list MOV (R0)+,R1 ;R1 = number of bad blocks 7$: BIT #BAD.NR,@R0 ;Is this one set non-replaceable? BNE 8$ ;Branch if so ADD #BT.SIZ,R0 ;R0 -> next block SOB R1,7$ ;Count down the number of bad blocks 8$: BIT #BAD.RP,@R0 ;Is it really replaceable? BEQ 9$ ;Branch if not BIC #BAD.NR,@R0 ;Make it replaceable 9$: ADD #BT.SIZ,R0 ;R0 -> next block DEC R1 ;Count down the number of bad blocks BEQ 11$ ;Branch if done SOB R3,7$ ;Loop on number of slots left BR 11$ ;Done ; ; If we get to here, the block is to be replaced ; 10$: BIT #BAD.NR,@R2 ;Did we already include this one? BEQ 5$ ;Branch if so. Ignore input BIC #BAD.NR,@R2 ;It's now replacable SOB R3,5$ ;Loop if there are more available 11$: MOV R4,R0 ;R0 -> bad block list MOV (R0)+,R1 ;R1 = number of bad blocks 12$: BIT #BAD.NR,@R0 ;Is this one non-replaceable? BEQ 13$ ;Branch if not BIC #BAD.RP,@R0 ;Else make sure it's non-replaceable 13$: ADD #BT.SIZ,R0 ;R0 -> next list element SOB R1,12$ ;Loop BIC #JS.NTG,@#S$JSW ;Clear non-terminating .GTLIN mode ;002 RETURN .SBTTL GETNUM - Accumulate a number ;+ ; GETNUM ; ; R5 -> input buffer ; ; CALL GETNUM ; ; R0 = number ;- GETNUM: JSR R5,$SAVRG ;Save R3 - R5 MOV R5,R4 ;Save -> in case '.' found ;002 CLR R0 ;Initialize accumulator 1$: TSTB @R5 ;Anything left? BEQ 2$ ;Branch if done ASL R0 ;Acc * 2 ASL R0 ;Acc * 4 ASL R0 ;Acc * 8 MOVB (R5)+,R3 ;R3 = new character BIC #^C177,R3 ;Get rid of garbage CMPB #'.,R3 ;Decimal point? ;002 BEQ 25$ ;Branch if so ;002 SUB #'0,R3 ;Make it binary ADD R3,R0 ;Add in low order digit BR 1$ ;Try again 25$: CLRB -(R5) ;Make it the end of the string ;002 MOV R4,R5 ;Restore -> input string ;002 CLR R0 ;Clear accumulator ;002 26$: TSTB @R5 ;End of string? ;002 BEQ 2$ ;Branch if so ;002 MOV R0,-(SP) ;Save old value ;002 ASL R0 ;*2 ;002 ASL R0 ;*4 ;002 ADD (SP)+,R0 ;*5 ;002 ASL R0 ;*10 ;002 MOVB (R5)+,R3 ;Get next digit ;002 BIC #^C177,R3 ;Clear ugly bits ;002 SUB #'0,R3 ;Make it binary ;002 ADD R3,R0 ;Add it into acc ;002 BR 26$ ;Loop 'til done ;002 ;002 2$: RETURN .ENDC ;EQ MDUP .IIF NE MDUP, .END ;CG03