.Title AVF -- Assign Virtual Disk .Enabl LC .Ident /V03.00/ .Sbttl ** AVF Data Area ; ; AVF -- Assign and Create Virtual Device Unit ; ; Version: V03.00 ; Operating Systems: RSX-11M-PLUS V3.0 ; MICRO/RSX V3.0 ; (has NOT been tested under P/OS) ; ; Originally written by Ralph Stamerjohn ; ; Previously modified by: ; ; R.S. Mearns ; G. Everhart ; ; Updated by: G. L. Maxwell ; U.S. Geological Survey ; 27-AUG-86 ; ; ************************************************************************ ; * ; Although this program has been tested by the Geological Survey, * ; United States Department of the Interior, no warranty, expressed or * ; implied, is made by the Geological Survey as to the accuracy and * ; functioning of the program and related program material nor shall * ; the fact of distribution constitute any such warranty, and no respon- * ; sibility is assumed by the Geological Survey in connection therewith. * ; * ; Full permission and consent is hereby given to DECUS and to the DECUS * ; Special Interest Groups to reproduce, distribute, and publish and * ; permit others to reproduce in whole or in part, in any form and * ; without restriction, this program and any information relating thereto * ; * ; ************************************************************************ ; ; AVF creates the data structures and environment necessary for the ; functioning of a Virtual Disk. ; ; A Virtual Disk is composed of one or more contiguous container files ; on mounted Files-11 volumes (which may themselves be virtual disks), ; along with a virtual disk driver which maps I/O requests onto the ; container files. ; ; AVF accepts as input from the user the following information: ; ; - The name and unit number to use for the virtual disk device. ; Any valid RSX device name and unit number may be used. An ; existing device may be specified only if it is a previously ; existing virtual device which is unassigned. (The RSX Executive ; also treats some devices as special cases, such as VT:.) ; ; - The names of one or more container files, which may be ; created by AVF, which will compose the virtual disk. ; ; AVF attempts to create a new (or use an existing) device database ; structure from the VF0: prototype database and link the database into ; the device list. ; ; AVF processes all container file specifications, accesses each file and ; retrieves the statistics block for each, and build the secondary control ; block which will reside in secondary pool. ; ; AVF completes the linkages, increments the volume transaction counts ; (a command switch option), and marks the device online. ; ;- ; ; Macro Library Calls: ; ; Symbolic Definitions. ; .MCALL HDRDF$ ; Define Task Header Offsets HDRDF$ .MCALL UCBDF$ ; Define UCB Offsets UCBDF$ .MCALL F11DF$ ; Define Files-11 Offsets F11DF$ .MCALL TCBDF$ ; Define Task Control Block Offsets TCBDF$ ; ; Directive Macros. ; .MCALL DIR$ ; Issue Directive .MCALL ALUN$S ; Assign Lun .MCALL EXST$S ; Exit System .MCALL QIOW$ ; Issue QIO And Wait .MCALL GTSK$S ; Get Task Parameters .MCALL SPWN$ ; Spawn Task .MCALL STSE$S ; Stop For Single Event Flag .MCALL GIN$ ; Get information directive ; ; GCML, CSI Macros. ; .MCALL GCMLB$ ; Define GCML block .MCALL GCML$ ; Define GCML routine .MCALL RCML$ ; Define RCML routine .MCALL CSI$ ; Define CSI Offsets CSI$ .MCALL CSI$SW,CSI$SV,CSI$ND ; Switch Table Macros .MCALL CSI$1,CSI$4 ; Parse Command Line ; ; FCS Macros. ; .MCALL FDOF$L ; Define FCS Offsets FDOF$L .MCALL NBOF$L ; Define FNB Offsets NBOF$L .MCALL FCSBT$ ; Define FCS Bit Masks. FCSBT$ .MCALL FDBDF$ ; Define FDB .MCALL FDAT$R ; Define File Attributes .MCALL FDRC$R ; Define Record Access .MCALL FDBK$R ; Define Block Access .MCALL FDOP$R ; Define Open Characteristics .MCALL FSRSZ$ ; Define Fsr Region .MCALL NMBLK$ ; Define Default Filename Block .MCALL FINIT$ ; Define FCS init routine ; ; Define Files-11 QIO Macro. ; .MACRO F11QIO DPB,ADR DIR$ #DPB .IF NB ADR BCS ADR CMPB #IS.SUC,IOSTAT BNE ADR .ENDC .ENDM F11QIO .PSECT $WDATA,RW,D ; ; Local Symbols: ; ; Logical Units/event Flags. ; CMDLUN == 1 ; AVF command LUN TTYLUN == 2 ; Terminal I/O LUN FILLUN == 3 ; File I/O LUN VDLUN == 4 ; Virtual disk LUN EV.QIO == 1 ; QIO Wait Event Flag EV.SPN == 2 ; Spawn Event Flag DEFPRO == 176314 ; File protection [RW,RW,RW,] ; ; Files-11 Bit Masks. ; ; File attributes ; H.FOWN = 1 ; File owner H.FPRO = 2 ; File protection H.UCHA = 3 ; File characteristics U.UFAT = 4 ; Record I/O area I.FNAM = 5 ; Filename, filetype, version no. I.FTYP = 6 ; Filetype I.FVER = 7 ; Version no. I.EXDT = 10 ; Expiration date I.STAT = 11 ; Statistics block I.FHDR = 12 ; Entire file header I.RVNO = 13 ; Revision number, cr, rv, ex dates I.PLCM = 14 ; Placement control ; ; File characteristics ; UC.CON = 200 ; Logically contiguous file UC.DLK = 100 ; File improperly closed ; ; Size and extend control ; EX.AC1 = 1 ; Extend contiguously EX.AC2 = 2 ; Extend by largest contiguous hole EX.FCO = 4 ; File must end up contiguous EX.ADF = 10 ; Use default extend size EX.ALL = 20 ; Placement control EX.ENA = 200 ; Enable extend ; ; Access control ; AC.LCK = 1 ; Lock out further writes or extends AC.DLK = 2 ; Enable deaccess lock AC.LKL = 4 ; Enable block locking AC.EXL = 10 ; Enable explicit block unlocking AC.WCK = 40 ; Enable write-checking AC.ENB = 200 ; Enable access EXTCTL = * 400 ; Allocate contiguously ACWCTL = * 400 ; Write access - lock out further write ; accesses. ACRCTL = * 400 ; Read access - enable only ; ; Local Data: ; ; Directives. ; CREDPB: QIOW$ IO.CRE,FILLUN,EV.QIO,,IOSTAT,, ENADPB: QIOW$ IO.ENA,FILLUN,EV.QIO,,IOSTAT,,<0,0,0,0,0,FILFDB+F.FNB> DELDPB: QIOW$ IO.DEL,FILLUN,EV.QIO,,IOSTAT,, FNADPB: QIOW$ IO.FNA,FILLUN,EV.QIO,,IOSTAT,,<0,0,0,0,0,FILFDB+F.FNB> ACRDPB: QIOW$ IO.ACR,FILLUN,EV.QIO,,IOSTAT,, ACWDPB: QIOW$ IO.ACW,FILLUN,EV.QIO,,IOSTAT,, DACDPB: QIOW$ IO.DAC,FILLUN,EV.QIO,,IOSTAT,, WATDPB: QIOW$ IO.WAT,FILLUN,EV.QIO,,IOSTAT,, ERRDPB: QIOW$ IO.WVB,TTYLUN,EV.QIO,,IOSTAT,,<0,0,0,0,0,0> ; CONDPB: SPWN$ ...CON,,,,,EV.SPN,,ESB,CONCMD PRVDPB: GIN$ GI.SPR,0 VECDPB: GIN$ GI.VEC,VECBUF,VECSIZ ; Get system offsets ; ; GCML Control Block ; MAXDEP = 3 ; Allow nesting level to 3 MAXCMD = 255. ; Allow up to 255. char commands GCML: GCMLB$ MAXDEP,,,CMDLUN,,MAXCMD+2 .EVEN ; ; CSI Control Blocks. ; DSCBLK: .WORD C.EXPS ; Expanded command line descriptor .WORD .+2 ; Pointer to buffer (follows) .BLKB C.EXPS ; Expanded command line buffer .EVEN CSIBLK: .BLKB C.SIZE ; CSI Control Block .EVEN ; ; Switch Bit Masks. ; FL.CRE = 1 ; Create File FL.HLP = 2 ; Give help FL.RON = 4 ; Read-only Access to container file FL.LCK = 10 ; Lock container file FL.INC = 40 ; Increment volume transaction FL.WPR = 100 ; Device "hardware write-protected" FL.ONL = 200 ; Bring device online CSWDEF = FL.LCK ! FL.INC ! FL.ONL ; Default switches CSWNEW = FL.CRE ; Clear bit after each file ; ; CSI Switch Tables. ; OUTSWI: CSI$SW HE,FL.HLP,CSIMSK,SET ; Output switch table CSI$SW WP,FL.WPR,CSIMSK,SET,NEG CSI$SW ONL,FL.ONL,CSIMSK,SET,NEG CSI$ND INPSWI: CSI$SW CR,FL.CRE,CSIMSK,SET,,CREVAL ; Input switches CSI$SW RO,FL.RON,CSIMSK,SET,NEG CSI$SW LO,FL.LCK,CSIMSK,SET,NEG CSI$SW IN,FL.INC,CSIMSK,SET,NEG CSI$ND CREVAL: CSI$SV ASCII,STRING,8. CSI$ND ; ; Fake File FDB (for parsing purposes). ; FILFDB: FDBDF$ ; Define FDB block. ; ; Default Filename Block. ; FILDFB: NMBLK$ ,DSK,,SY,0 ; Default filename ; ; Create Write Attribute List. ; CRELST: .BYTE H.FPRO,02 ; Write protection code .WORD PROATT ; .BYTE U.UFAT,16 ; Write FCS attributes .WORD FILFDB ; .BYTE I.FNAM,12 ; Write filename attributes .WORD FILFDB+F.FNB+N.FNAM ; .BYTE H.UCHA,01 ; Write file characteristics .WORD WATATT ; .BYTE 0,0 ; End-of-list PROATT: .WORD DEFPRO ; Created file file protection ; ; Read Attribute List. ; ACWLST: .BYTE -I.STAT,12 ; Read statistics block .WORD STAATT ; .BYTE -H.UCHA,01 ; Read user characteristics .WORD WATATT ; .BYTE 0,0 ; End-of-list STAATT: .BLKB 12 ; Statistics block ; ; Write Attribute List. ; WATLST: .BYTE H.UCHA,01 ; Write user characteristics .WORD WATATT ; .BYTE 0,0 ; End-of-list WATATT: .BYTE 0 ; To be read or filled in .EVEN .WORD 0 ; Safety margin (?) ; ; System vector offsets ; VECBUF: .WORD 0 ; Flags word DEVHD: .WORD $DEVHD ; Device listhead ALOCB: .WORD $ALOCB ; Pool allocation routine DRQRQ: .WORD $DRQRQ ; Queue I/O to driver routine SAHDB: .WORD $SAHDB ; Header bias location SAHPT: .WORD $SAHPT ; Header displacement KISA6: .WORD KISAR6 ; Kernel APR 6 HEADR: .WORD $HEADR ; Header pointer ALSEC: .WORD $ALSEC ; Allocate secondary pool block DEACB: .WORD $DEACB ; Pool deallocation routine TKTCB: .WORD $TKTCB ; Pointer to TCB .S.LHD: .WORD S.LHD ; SCB listhead .S.STS: .WORD S.STS ; SCB status byte .S.PKT: .WORD S.PKT ; SCB packet holder VECSIZ = <.-VECBUF>/2 ; Size of buffer in words ; ; Other variables. ; EXISTS::.WORD 0 ; Task exit status word IOSTAT::.WORD 0,0 ; I/O status block STRING::.BLKB 8. ; Disk block string BLKNUM::.BLKW 2 ; Disk block number NEWFLG::.WORD 0 ; A data structure was created (0 = no) NEWUCB::.WORD 0 ; Address of new disk UCB VFDCB:: .WORD 0 ; VF0: DCB address NEWDCB::.WORD 0 ; DCB of new device DVNAM:: .BLKB 2 ; Name of device to create DVUNT:: .WORD 0 ; Device unit number DVBCK:: .WORD 0 ; DCB address of preceding unit ERRFLG::.WORD 0 ; System state error flag CSIMSK::.WORD 0 ; CSI Mask word OURTCB::.WORD 0 ; Pointer to this task's TCB TIUCB:: .WORD 0 ; TI: UCB address PROUIC::.BYTE 0 ; Protection UIC (Group code here) DEVGRP::.BYTE 0 ; Protection group for created device ESB:: .BLKW 8. ; Exit status block BASLBN::.WORD 0,0 ; Working base LBN for container files ; ; Define local task area for building secondary control blocks ; CURBLK::.WORD 0 ; Address of next available block location NUMFIL::.WORD 0 ; Number of container files currently defined SECBLK::.BLKB MX$FIL * X.LEN ; Define space for secondary blocks .NLIST BEX CONCMD: .ASCII ^CONFIGURE/NOMSG ONLINE ^ CONADD: .BLKB 8. .LIST BEX .EVEN ; ; FSR region ; FSRSZ$ 1 ; One buffer required for GCML$ .PAGE .SBTTL ** AVF Main Code .PSECT $CODE,RO,I ;+ ; $AVF -- Assign (Create) Virtual Disk Unit ; ; Syntax: ; ; >AVF ddnn:/out_switch = infile1/in_switch { , infile2 ...} ; ; ddnn: Specifies the name to be used for the Virtual Unit. ; infile Specifies one or more container file to be assigned. ; /out_switch Include: ; /WP - Create a write-protected device ; /ONL - Bring created device online ; /HE - Provide help message ; /in_switch Include: ; /LO - Set lock bit on file (write access required) ; /RO - Allow only read access to the file ; /CR:n - Create container file with n decimal blocks ; /NOINC - Do not increment volume transaction count ; for this device. ; ;- $AVF:: ; ; Perform one-time initialization ; CALL TKINIT ; Do task-level initialization BCS AVFEX ; If we can't init, then we can't run ; ; Top of command processing pass loop ; ; Perform pass initialization ; RESTRT: CALL PSINIT ; Perform pass intialization ; ; GETCMD returns: ; ; A new command line is read into the GCML buffer, and ; preliminary parsing has been done (CSI$1). ; ; R0 contains the address of the CSI control block ; ; If carry is set, end-of-file or an error has occurred while ; fetching the command line. ; CALL GETCMD ; Get next command line BCS AVFEX ; Exit with status to parent ; ; GETDEV performs the following: ; ; The output specification is parsed for the name and unit number ; of the virtual device, along with any device switches. ; ; The device control block is allocated, initialized, and linked ; into the system device list. ; ; Carry is set on one of the following conditions (error message ; has already been printed): Syntax error, illegal switch, invalid ; or duplicate device name, insufficient pool to allocate ; device structure, device already attached, device allocated to ; another terminal, or user requested help ; CALL GETDEV ; Parse virtual device and allocate it BCS RESTRT ; On error, start next command ; ; *** From this point on, any fatal error condition requires a call to ; DEADEV to unlink and deallocate the newly created Virtual unit *** ; ; Process next file specification ; ; GETFIL returns the following: ; ; The next container file specification is scanned. The file is ; created or accessed, and necessary control information is ; stored in our local copy of the secondary block which will be ; created later. ; ; Carry set indicates loop termination, a fatal error occurred: ; File not found, privilege violation, creation failure, ; syntax error, or illegal switch. ; MOV #PRVDPB,R0 ; Get GIN$ set privilege DPB CLR G.IP01(R0) ; Set to turn off privilege DIR$ R0 ; Non-privileged for file access NXTFIL:: CALL GETFIL ; Get next container file specification BCS UNDO ; If cs, handle exception return BITB #CS.MOR,CSIBLK+C.STAT ; Are there more files on the line? BNE NXTFIL ; Get the next one if we have more to do ; ; Create the secondary pool control block, and finish creation of ; the virtual unit. ; ; CREBLK performs the following: ; ; Allocates secondary pool space and copies the local secondary ; control block into secondary pool. ; ; Calculates the total size of the virtual device and stores ; these values in the UCB ; ; Establishes final links and bitmasks to set the unit online. ; ; If carry is set upon return, then insufficient secondary pool was ; available to create the secondary control block. ; CALL CREBLK ; Create secondary pool block structure BCS UNDO ; On failure, undo what we have done ; ; Try to bring the created unit online, if so desired by the user. ; If this fails, we print a warning message, but we leave things stand ; as they are. ; MOV #PRVDPB,R0 ; Get GIN$ set privilege DPB MOV #1,G.IP01(R0) ; Set to turn on privilege DIR$ R0 ; Privileged for online transition CALL ONLINE ; Optionally bring unit online CALL DETACH ; Detach from the virtual unit BR RESTRT ; Get next command ; ; At this point, something has failed in our secondary processing. ; The following actions are performed: ; ; DEAFIL is called to deaccess all active container files ; ; DEADEV is called to deallocate the virtual device database. ; UNDO:: CALL DEAFIL ; Deaccess all container files CALL DETACH ; Detach from the virtual disk MOV #PRVDPB,R0 ; Get GIN$ set privilege DPB MOV #1,G.IP01(R0) ; Set to turn on privilege DIR$ R0 ; Privileged until next file access CALL DEADEV ; Deallocate virtual device database BR RESTRT ; And attempt to process new command AVFEX:: EXST$S EXISTS ; Exit with status .SBTTL ** TKINIT -- Task Initialization ;+ ; ** TKINIT -- One-time task initialization ; ; This routine performs the following functions: ; ; - Retrieves the taskname for use in prompts and error messages ; - Initializes the FCS buffers ; - Retrieves the TCB for our task ; - Retrieves the TI: UCB address and the Protection Group code ; - Fills in the vector table with Executive routine entry points ; ; All registers are available to this routine ;- TKINIT:: SUB #18.*2.,SP ; Allocate buffer on stack MOV SP,R5 ; Point to it GTSK$S R5 ; Get task info MOV G.TSTN(R5),R1 ; Get task name MOV #TSKNAM,R0 ; Point to the output buffer MOV R0,R4 ; Save the buffer address CALL $C5TA ; Convert to ASCII for error routines ADD #18.*2.,SP ; Release the stack space MOV #PRMSTR+2,R3 ; Get command line prompt string MOVB (R4)+,(R3)+ ; Copy it over MOVB (R4)+,(R3)+ ; ... MOVB (R4)+,(R3)+ ; ... FINIT$ ; Initialize the FSR region MOV #EX$SUC,EXISTS ; Assume successful status DIR$ #VECDPB ; Get Executive vectors filled BCC 10$ ; If CC=0 then successful completion MOV #ER$GIN,R4 ; Get error code CALL PRTERR ; Print error message SEC ; Set error return BR 20$ ; And return 10$: MOV @TKTCB,R0 ; Get our TCB address MOV R0,OURTCB ; And save it MOV T.UCB(R0),R1 ; Get TI: UCB address MOV R1,TIUCB ; And save it MOV U.LUIC(R1),PROUIC ; Save protection group code 20$: RETURN ; Return to caller .SBTTL ** PSINIT -- Pass Initialization ;+ ; PSINIT -- Perform pass initialization ; ; This routine is executed prior to the scanning of a new command line. ; It resets variables which will be used to construct the Virtual Device. ; ; Inputs: None. ; Outputs: None. ;- PSINIT:: MOV #FILFDB,R0 ; Get FDB address FDAT$R ,#R.FIX,,#512. ; Define file attributes FDRC$R ,#FD.RWM ; Define record access FDBK$R ; Define block access FDOP$R ,#FILLUN ; Define open access MOV #SECBLK,R0 ; Point to secondary block build area MOV R0,CURBLK ; Initialize pointer MOV #,R1 ; Get number of words 10$: CLR (R0)+ ; Clear out the block SOB R1,10$ ; Loop until complete CLR NUMFIL ; No container files defined MOV #CSWDEF,CSIMSK ; Store default switch environment CLR BASLBN ; Clear base LBN counter CLR BASLBN+2 ; CLR NEWFLG ; No new device created yet RETURN ; Return to caller .SBTTL ** GETCMD -- Get next command ;+ ; ** GETCMD -- Get next command for processing ; ; Inputs: None. ; Outputs: Carry clear - A command has been successfully retrieved ; R0 points to the CSI control block ; Carry set - End of file or command I/O error ; ;- GETCMD:: GCML$ #GCML,#PRMSTR,#PRMSTL ; Get next command line BCS 10$ ; If cs then check error MOV R0,R1 ; Copy GCML block address MOV #CSIBLK,R0 ; Point to CSI control block MOV G.CMLD(R1),C.CMLD(R0) ; Copy command line descriptor BEQ GETCMD ; If eq then null command line MOV G.CMLD+2(R1),C.CMLD+2(R0) CSI$1 ; Perform syntax preprocessing BCC 30$ ; OK, exit to caller MOV #ER$SYN,R4 ; Get the error code BR 20$ ; And proceed 10$: CMPB #GE.EOF,G.ERR(R0) ; End of file on outer level? SEC ; Assume it is BEQ 30$ ; If eq yes MOV #ER$GCM,R4 ; Get the error code RCML$ #GCML ; On GCML errors, reset the context 20$: CALL PRTERR ; Print error code BR GETCMD ; Try to do it again 30$: RETURN ; Return to caller .SBTTL ** GETDEV -- Process Device Specification ; ; ** GETDEV -- Process virtual device specification ; ; Inputs: R0 points to CSI control block ; ; Outputs: Carry set: One of many errors has happened ; Carry clear: Device data structure created. ; GETDEV: CSI$4 ,OUTPUT,#OUTSWI,#DSCBLK ; Process output specification MOV #ER$SYN,R4 ; Assume an error occurred BCC 5$ ; If cc=0 then OK JMP 2050$ ; Illegal switch or invalid spec ; ; Process help request ; 5$: BIT #FL.HLP,CSIMSK ; Was help requested? BEQ 10$ ; If eq no MOV #ERRDPB,R0 ; Point to the QIO DPB MOV #HLPMSG,Q.IOPL(R0) ; Point to help message MOV #HLPLEN,Q.IOPL+2(R0) ; Store length MOV #<' >,Q.IOPL+4(R0) ; Store VFC DIR$ R0 ; Write it out BR 2080$ ; And go for next command ; ; Perform other checks ; 10$: MOV #ER$NEQ,R4 ; Assume no equals sign BITB #CS.EQU,C.STAT(R0) ; Both input and output specified? BEQ 2050$ ; If eq no MOV #ER$NDV,R4 ; Assume no device specified BITB #CS.DVF,C.STAT(R0) ; Device specified? BEQ 2050$ ; If eq no MOV #ER$NAM,R4 ; Assume filename, etc. specified BITB #CS.NMF!CS.DIF!CS.WLD!CS.MOR,C.STAT(R0) ; Other garbage? BEQ 15$ ; If eq no CALL PRTWAR ; Print the warning ; ; Extract device name ; 15$: MOV C.DEVD(R0),R3 ; Get length of device string MOV C.DEVD+2(R0),R0 ; Get address of device string MOVB (R0)+,DVNAM ; Store first char MOVB (R0)+,DVNAM+1 ; Store second char CALL $COTB ; Convert unit number MOV R1,DVUNT ; Store the unit number ; ; Go to system state to perform further checks and create device structure ; CLR ERRFLG ; Clear system state error flag CALL $SWSTK,2000$ ; Switch to the system stack CALL DSCAN ;; Scan for VF0:, check our device name MOV R5,VFDCB ;; Store DCB for VF0: BEQ 1002$ ;; If eq then VF: not loaded BCS 1001$ ;; If CC=1 then invalid device name MOV NEWUCB,R5 ;; Device data structure exist? BNE 20$ ;; If ne yes - bypass creation CALL CRDEV ;; Create new Virtual unit BCS 1003$ ;; If cs then insufficient pool MOV R4,NEWDCB ;; Save the new device DCB MOV DVBCK,R0 ;; Get preceding device MOV (R0),(R4) ;; Link forward from new one MOV R4,(R0) ;; And link ourselves in MOV R5,NEWUCB ;; Store it for later reference MOV VFDCB,R1 ;; Get VF0: DCB MOV D.UCB(R1),R1 ;; Get the UCB address MOV U.VLNK(R1),U.VLNK(R5) ;; Link to next virtual unit MOV R5,U.VLNK(R1) ;; Make ours the first virtual unit COM NEWFLG ;; Show we have created a device ; The following check will fail only for devices already in existence. 20$: TST U.OWN(R5) ;; Does someone own the unit? BEQ 30$ ;; If eq no CMP U.OWN(R5),TIUCB ;; Yes, do we own it? BNE 1004$ ;; If ne no -- reject the command 30$: TST U.ATT(R5) ;; Is a task attached to the device? BNE 1004$ ;; If ne yes -- reject the command MOV OURTCB,U.ATT(R5) ;; Attach to the device ; ; Assign LUN to the virtual disk so that in case we die a horrible death, ; I/O rundown will detach us from the unit ; .IF DF X$$HDR MOV @KISA6,-(SP) ;; Save APR MOV @SAHDB,@KISA6 ;; Map external header (if necessary) MOV @SAHPT,R0 ;; Get the header bias .IFF ; DF X$$HDR MOV @HEADR,R0 ;; Get task header address .IFTF ; DF X$$HDR MOV R5,H.LUN+<*4>(R0) ;; Assign LUN to Virtual Unit .IFT ; DF X$$HDR MOV (SP)+,@KISA6 ;; Restore mapping .ENDC ; DF X$$HDR MOVB DEVGRP,U.XGRP(R5) ;; Set the protection group code CLRB U.XFLG(R5) ;; Clear flags byte BIT #FL.WPR,CSIMSK ;; User want write-protected disk? BEQ 40$ ;; If eq no BISB #XF.WPR,U.XFLG(R5) ;; Set the bit 40$: BR 1900$ ;; Return successfully 1004$: INC ERRFLG ;; Device allocated or attached 1003$: INC ERRFLG ;; Insufficient pool 1002$: INC ERRFLG ;; VF: not loaded 1001$: INC ERRFLG ;; Duplicate device name 1900$: RETURN ;; Return to user state 2000$: CLC ; Assume success MOV ERRFLG,R4 ; Get error flag BEQ 2100$ ; If eq, then OK 2050$: CALL PRTERR ; Handle error, no undoing required. 2080$: SEC ; Indicate failure 2100$: RETURN ; Return to caller .SBTTL ** DSCAN -- Find Prototype Unit ;+ ; DSCAN -- Search for the prototype unit database and perform checks ; (System state routine) ; ; Inputs: DVNAM contains the ASCII device name to be created ; DVUNT contains the binary unit number to be created ; ; Outputs: Carry clear - Device duplication check passed ; R4 and DVBCK contain DCB address of preceding device ; R5 contains DCB address of VF0: (0 if not found) ; ;- DSCAN:: CLR R5 ;; Clear VF0: DCB CLR R4 ;; Clear preceding DCB pointer MOV DEVHD,R1 ;; Get address of device listhead 10$: MOV R1,R0 ;; Copy previous DCB MOV (R0),R1 ;; Get next DCB BEQ 70$ ;; If eq then VF0: not found - return error CMP D.NAM(R1),#<"VF> ;; Right name? BNE 10$ ;; If ne no - try next TST D.UNIT(R1) ;; Unit zero? BNE 10$ ;; If ne no - try next TST D.PCB(R1) ;; Is the driver loaded? BEQ 70$ ;; If eq no - fatal error MOV D.UCB(R1),R2 ;; Get the first UCB address BITB #US.OFL,U.ST2(R2) ;; Unit offline? BNE 70$ ;; If ne yes - fatal error MOV R1,R5 ;; Save VF0: DCB address ; ; Look for existing device or spot in device list where we will place this one ; MOV DEVHD,R1 ;; Get device listhead again 20$: MOV R1,R0 ;; Copy previous device MOV (R0),R1 ;; Get next device BEQ 50$ ;; If eq then break out of loop MOV D.UCB(R1),R2 ;; Get first UCB BIT #DV.PSE,U.CW1(R2) ;; Is this a pseudo-device? BNE 30$ ;; If ne yes, we go before it CMP D.NAM(R1),DVNAM ;; Names match? BNE 20$ ;; If ne no, keep looking CMPB D.UNIT(R1),DVUNT ;; Check lowest unit on DCB BEQ 22$ ;; If eq then duplicate check it out BHI 30$ ;; If hi then this is the one CMPB D.UNIT+1(R1),DVUNT ;; Check highest unit on DCB BLO 20$ ;; If lo then keep looking ; ; This device data structure contains the device specified by the user. ; We will accept it if: ; ; - It has the right structure (single unit on the DCB) ; - It is linked into the Virtual Device List (U.VLNK) ; - It is currently unassigned (U.CTLP is zero) ; 22$: CMPB D.UNIT(R1),D.UNIT+1(R1) ;; Single unit device? BNE 70$ ;; If ne no - cannot be this device MOV D.UCB(R5),R0 ;; Get VF0: UCB 24$: MOV U.VLNK(R0),R0 ;; Get next virtual device BEQ 70$ ;; If eq then this is not virtual device CMP R0,R2 ;; Is it this device? BNE 24$ ;; No, try next virtual device TST U.CTLP(R0) ;; Is the device currently assigned? BNE 70$ ;; Yes, that's an error MOV R0,NEWUCB ;; Mark it up as our baby MOV U.DCB(R0),NEWDCB ;; Save the DCB address BR 65$ ;; And return 30$: MOV R0,R4 ;; Save previous DCB address BR 60$ ;; And return 50$: TST R4 ;; Did we find preceding unit? BNE 60$ ;; If ne then all's fine MOV R0,R4 ;; Make the last device preceding 60$: MOV R4,DVBCK ;; Store the DCB address 65$: CLC ;; Indicate success RETURN ;; Return carry clear 70$: SEC ;; Return error status RETURN ;; Return to caller .SBTTL ** CRDEV -- Create Device Database ;+ ; CRDEV -- Allocate and initialize device database ; ; Inputs: VFDCB contains the DCB address of the prototype device ; DVNAM contains the two character device name ; DVUNT contains the binary unit number of the device ; ; Outputs: Carry set -- Insufficient pool to create structure ; Carry clear: ; R2 contains the SCB address of the new data structure. ; R4 contains the DCB address of the new data structure. ; R5 contains the UCB address of the new data structure. ; ; This routine is entered and exited at system state level ;- CRDEV:: MOV #$VFSIZ,R1 ;; Get size of VF: data structure CALL @ALOCB ;; Allocate device database BCS 40$ ;; If cs then insufficient pool MOV VFDCB,R5 ;; Get prototype DCB address MOV R0,R4 ;; Save address of the data structure MOV #<$VFSIZ/2>,R2 ;; Get the size of the database 10$: MOV (R5)+,(R0)+ ;; Copy the database SOB R2,10$ ;; Loop until done ; ; Now initialize the data structure. Setup R4 as the DCB, R5 as the UCB ; and R2 as the SCB pointers ; MOV R4,R5 ;; Copy DCB address ADD #$VFUOF,R5 ;; Point to the UCB MOV R5,R2 ;; Copy the UCB address ADD #$VFSOF,R2 ;; Point to the SCB ; ; Initialize the DCB ; MOV R5,D.UCB(R4) ;; Setup UCB pointer MOVB DVUNT,D.UNIT(R4) ;; Store low unit number MOVB DVUNT,D.UNIT+1(R4) ;; Store high unit number MOV DVNAM,D.NAM(R4) ;; Save device name ; ; Initialize the UCB ; CLR U.OWN(R5) ;; No one can own it yet MOV R4,U.DCB(R5) ;; Back pointer to DCB MOV R5,U.RED(R5) ;; No redirect MOVB #US.MNT!US.VV,U.STS(R5) ;; Not mounted MOVB #US.OFL,U.ST2(R5) ;; Unit offline MOV #DV.DIR!DV.MSD!DV.F11!DV.MNT,U.CW1(R5) ;; Preset chars CLR U.CW2(R5) ;; Clear device size words (redundant) CLR U.CW3(R5) ;; MOV #512.,U.CW4(R5) ;; Buffer size (redundant) MOV R2,U.SCB(R5) ;; Store SCB pointer CLR U.ATT(R5) ;; No one is attached CLR U.UCBX(R5) ;; No UCB extension CLR U.ACP(R5) ;; No ACP is attached (redundant) CLR U.VCB(R5) ;; No VCB associated (redundant) CLR U.UMB(R5) ;; No UMB node (redundant) CLR U.PRM(R5) ;; Preset geometry (may be changed later) CLR U.PRM+2(R5) ;; CLR U.CTLP(R5) ;; Clear secondary block bias CLR U.VLNK(R5) ;; Clear virtual UCB link ; ; Initialize the SCB ; MOV .S.LHD,R0 ;; Get SCB listhead offset ADD R2,R0 ;; Form pointer to I/O queue listhead CLR (R0) ;; Clear I/O queue listhead MOV R0,2(R0) ;; Empty the queue MOV .S.STS,R0 ;; Get SCB status offset ADD R2,R0 ;; Form pointer to it CLRB (R0) ;; Unit is not busy MOV .S.PKT,R0 ;; Get SCB packet address pointer ADD R2,R0 ;; Point to it CLR (R0) ;; No active packet 40$: RETURN ;; Return to caller .SBTTL ** GETFIL -- Access Next Container File ;+ ; ** GETFIL -- Access the next container file for use ; ; The next container file specification is scanned. The file is ; created or accessed, and necessary control information is ; stored in our local copy of the secondary block which will be ; created later. ; ; GETFIL returns the CSI control block address in R0. ; ; Carry set indicates loop termination: ; If Z-bit clear, then a fatal error occurred: ; File not found, privilege violation, creation failure, ; syntax error, or illegal switch. ; If Z-bit set, then no more container files remain. ;- GETFIL:: MOV #ER$TMF,R4 ; Assume too many files CMP #MX$FIL,NUMFIL ; How many container files do we have now? BHI 10$ ; If hi then we can have more JMP 250$ ; Too many files 10$: BIC #CSWNEW,CSIMSK ; Clear non-propagating switches MOV #ER$SYN,R4 ; Assume a syntax error will occur CSI$4 #CSIBLK,INPUT,#INPSWI,#DSCBLK ; Parse the next input file BCS 30$ ; Syntax error BITB #CS.WLD,C.STAT(R0) ; Any wild specifiers? BNE 30$ ; If ne yes, that's illegal 20$: MOV #FILFDB,R0 ; Get FDB address MOV #FILFDB+F.FNB,R1 ; Get filename block address MOV #CSIBLK+C.DSDS,R2 ; Get dataset descriptor MOV #FILDFB,R3 ; Get default filename block CALL .PARSE ; Create filename block BCC 40$ ; Branch if successful MOV #ER$PAR,R4 ; Get error code 30$: JMP 250$ ; Syntax error, go handle it 40$: MOV CSIMSK,R4 ; Get the switch mask BIC #^C,R4 ; Mask off bits CMP #,R4 ; Both /LO and /RO specified? BNE 50$ ; If ne no BIC #FL.LCK,CSIMSK ; Clear the switch mask BIT #FL.LCK,CSIBLK+C.MKW1 ; Was /LO actually specified? BEQ 50$ ; If eq no - no error MOV #ER$LOR,R4 ; Get error code CALL PRTWAR ; Print the warning 50$: BIT #FL.CRE,CSIMSK ; Was /CR specified? BEQ 120$ ; If eq no MOV #STRING,R4 ; Get start of the size string MOV R4,R5 ; Copy it MOV #8.,R3 ; Set maximum size 60$: TSTB (R4)+ ; Look for terminating null BEQ 70$ ; Found it SOB R3,60$ ; Search rest of string BR 80$ ; If loop dropped out, value is too large 70$: SUB #STRING+1,R4 ; Calculate length of number MOV #BLKNUM,R3 ; Get result area CALL .DD2CT ; Convert decimal to double binary BCS 80$ ; If cs, conversion error MOV (R3)+,R1 ; Get high order size of file TSTB -1(R3) ; Inspect high byte of high word BEQ 90$ ; If eq, then valid size 80$: MOV #ER$SIZ,R4 ; Illegal file length JMP 250$ ; Go handle the error 90$: MOV (R3)+,R0 ; Get low order block size MOV R0,CREDPB+Q.IOPL+6 ; Set size of file to create MOVB R1,CREDPB+Q.IOPL+4 MOV R0,FILFDB+F.HIBK+2 ; Set size of file in attribute block MOVB R1,FILFDB+F.EFBK+0 MOV R0,FILFDB+F.EFBK+2 ; Set EOF block in attribute block MOVB R1,FILFDB+F.EFBK+0 MOV #1000,FILFDB+F.FFBY ; Mark EOF at end of last block F11QIO CREDPB,110$ ; Attempt to create the file F11QIO ENADPB,100$ ; Attempt to create directory entry BR 140$ ; Continue if everything worked 100$: F11QIO DELDPB ; On create error, delete the file MOV #ER$ENT,R4 ; Error entering filename JMP 250$ ; Go print the error 110$: MOV #ER$SIZ,R4 ; Get error code JMP 250$ ; Go print the error ; ; Perform directory lookup operation on an existing container file ; 120$: F11QIO FNADPB,130$ ; Lookup existing file BR 140$ ; Continue on successful lookup 130$: MOV #ER$FNF,R4 ; Get error code JMP 250$ ; Go print the error ; ; Access, then deaccess file, obtaining necessary statistics ; 140$: BIT #FL.RON,CSIMSK ; Is the container file read-only? BNE 150$ ; If ne yes F11QIO ACWDPB,170$ ; Issue write access request BIT #FL.LCK,CSIMSK ; Is the file to be locked? BEQ 160$ ; If eq no BISB #UC.DLK,WATATT ; Set the deaccess lock bit F11QIO WATDPB,170$ ; Write the attribute BR 160$ ; And proceed 150$: F11QIO ACRDPB,170$ ; Issue read access request 160$: F11QIO DACDPB,170$ ; And deaccess the file BR 175$ ; Continue on success 170$: F11QIO DACDPB ; Make sure the file is deaccessed MOV #ER$ACC,R4 ; Get error code JMP 250$ ; And handle the error ; ; Get the next space in the local secondary pool block, and fill in ; the details ; 175$: MOV CURBLK,R4 ; Get address of next slot MOV #STAATT,R0 ; Point to the statistics block ; ; Format of the Files-11 statistics block as returned by the ACP: ; ; Words 0 and 1: High and low logical block no. (zero if non-contiguous) ; Words 2 and 3: High and low block size ; Word 4: Access count and Lock count ; MOV (R0)+,X.BASE(R4) ; Store LBN base for this file MOV (R0)+,X.BASE+2(R4) ; BNE 180$ ; If ne then file is contiguous MOV #ER$NCT,R4 ; Get error code JMP 250$ ; File not contiguous ; ; Store the offset into the virtual device that the container file ; represents, store the container size, and update the offset in case ; another container file is coming later. ; 180$: MOV BASLBN,X.OFF(R4) ; Store current offset into virtual device MOV BASLBN+2,X.OFF+2(R4) MOV (R0),X.SIZE(R4) ; Store high order size of container file ADD (R0)+,BASLBN ; Update offset for next container file MOV (R0),X.SIZE+2(R4) ; Store low order size of container file ADD (R0),BASLBN+2 ; Update low order offset for next file ADC BASLBN ; Propagate carry to high order ; ; Store the file ID of the container file in the block ; MOV #FILFDB+F.FNB+N.FID,R0 ; Point to the file ID MOV (R0)+,X.FID(R4) ; Copy it into the block MOV (R0)+,X.FID+2(R4) MOV (R0),X.FID+4(R4) ; ; Now get the UCB address of the device which holds the container file, ; and increment the volume transaction count, if that is called for ; CALL $SWSTK,210$ ; Go on the system stack .IF DF X$$HDR MOV @KISA6,-(SP) ;; Save APR MOV @SAHDB,@KISA6 ;; Map external header (if necessary) MOV @SAHPT,R0 ;; Get the header bias .IFF ; DF X$$HDR MOV @HEADR,R0 ;; Get task header address .IFTF ; DF X$$HDR MOV H.LUN+<*4>(R0),R1 ;; Grab container file UCB address .IFT ; DF X$$HDR MOV (SP)+,@KISA6 ;; Restore mapping .ENDC ; DF X$$HDR 190$: MOV U.RED(R1),R1 ;; Follow redirect chain CMP U.RED(R1),R1 ;; End of chain? BNE 190$ ;; If ne no MOV R1,X.UCB(R4) ;; Store UCB address in control block BIT #FL.INC,CSIMSK ;; Increment volume transaction? BEQ 200$ ;; If eq no MOV U.VCB(R1),R0 ;; Get the Volume Control Block INC V.TRCT(R0) ;; And increment the count 200$: RETURN ;; Return to user state at 210$ 210$: CLR R0 ; Preset flag word MOV CSIMSK,R1 ; Get the switch mask word BIT #FL.LCK,R1 ; Have we set the lock bit? BEQ 220$ ; If eq no BIS #XF.LCK,R0 ; Set the bit 220$: BIT #FL.INC,R1 ; Have we incremented the transaction count? BEQ 230$ ; If eq no BIS #XF.TRN,R0 ; Set the bit 230$: BIT #FL.RON,R1 ; Is the file readonly? BEQ 240$ ; If eq no BIS #XF.RON,R0 ; Set the bit 240$: MOV R0,X.FLAG(R4) ; Store the flags word INC NUMFIL ; Bump the number of active files ADD #X.LEN,R4 ; Bump to the next container block MOV R4,CURBLK ; And store the pointer CLC ; Indicate success BR 260$ ; And return 250$: CALL PRTERR ; Print an error message SEC ; Indicate failure 260$: RETURN ; Return to caller .SBTTL ** CREBLK -- Create Secondary Block Structure ;+ ; CREBLK - Create the secondary pool control block, and finish creation of ; the virtual unit. ; ; CREBLK performs the following: ; ; Allocates secondary pool space and copies the local secondary ; control block into secondary pool. ; ; Calculates the total size of the virtual device and stores ; these values in the UCB ; ; Establishes final links and bitmasks to set the unit online. ; ; If carry is set upon return, then insufficient secondary pool was ; available to create the secondary control block. ; ;- CREBLK:: CLR ERRFLG ; Assume no errors CALL $SWSTK,100$ ; Go on the system stack MOV NEWUCB,R5 ;; Get address of virtual UCB MOV NUMFIL,R1 ;; Get number of container files MOVB R1,U.XFIL(R5) ;; Store number in the UCB MUL #X.LEN,R1 ;; Calculate number of bytes needed MOV R1,R3 ;; Save for later use ASH #-6,R1 ;; Convert to 32 word blocks BIT #77,R3 ;; Do we need an extra block? BEQ 10$ ;; No, we're OK INC R1 ;; Allocate one more block 10$: CALL @ALSEC ;; Allocate secondary block BCS 95$ ;; If carry set, insufficient pool MOV R0,U.CTLP(R5) ;; Save address of control block MOV @KISA6,-(SP) ;; Save APR MOV R0,@KISA6 ;; Map the control block MOV #140000,R0 ;; Load displacement MOV #SECBLK,R1 ;; Point to local copy of secondary block ASR R3 ;; Calculate number of words to move 20$: MOV (R1)+,(R0)+ ;; Copy into secondary pool SOB R3,20$ ;; Loop until finished MOV (SP)+,@KISA6 ;; Restore APR MOV BASLBN,U.CW2(R5) ;; Store high order disk size MOV BASLBN+2,U.CW3(R5) ;; Store low order BR 99$ ;; All done! 95$: MOV #ER$UPS,ERRFLG ;; Store error code 99$: RETURN ;; Return to user state 100$: CLC ; Assume no problems MOV ERRFLG,R4 ; Any errors? BEQ 120$ ; If eq no CALL PRTERR ; Print error message SEC ; Indicate failure 120$: RETURN ; Return to caller .SBTTL ** ONLINE -- Bring New Device Online ;+ ; ; ONLINE -- Bring New Device Online, per User Request ; ; Inputs: DVNAM and DVUNT are used to generate the device name ; Outputs: None. ; ; The Online Reconfiguration Task, HRC, is notified that a new device ; database exists in the system. ; ; The CON command is spawned with an ONLINE command to bring the new ; device online. If this fails, then we manually place the device by ; allocating (if necessary) and initializing a UCB extension and clearing ; the US.OFL bit in the UCB. ; ;- ONLINE:: ; NOTE WELL!!! ; ; The following code may require changes if the RD:/HRC interface ; changes substantially. If it does, one should be able to revive ; the code by building AVF against OLR.OLB to bring in the HRCIN ; module, and using the following code: ; ; MOV #FILLUN,R0 ; Get LUN to use for RD: ; CALL $HRCIN ; Tell HRC about the new device ; ; End of optional code. The following code replaces the call to $HRCIN ; ALUN$S #FILLUN,#"RD,#0 ; Assing to RD0: BCS 40$ ; Print error on failure F11QIO HRCDPB,40$ ; Request HRC to reinitialize ; ; ** End of possibly future incompatible code ** ; BIT #FL.ONL,CSIMSK ; Bring the new unit online? BEQ 60$ ; If eq no, return now MOV #CONADD,R0 ; Get address for device string MOVB DVNAM,(R0)+ ; Store device name MOVB DVNAM+1,(R0)+ ; MOV DVUNT,R1 ; Get unit number CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert binary to octal MOVB #<':>,(R0)+ ; Finish with a colon SUB #CONCMD,R0 ; Calculate length of the command MOV #CONDPB,R1 ; Get the DPB MOV R0,S.PWCL(R1) ; Store command length DIR$ R1 ; Bring the device online BCS 10$ ; Branch on spawn error STSE$S #EV.SPN ; Wait for command completion CMP #EX$SUC,ESB ; Did it work? BEQ 60$ ; If eq yes ; ; We could not bring the device online with CON, probably because the ; user is not privileged. At this point, handle the UCB extension and ; clear the US.OFL bit in the UCB. ; 10$: CALL $SWSTK,60$ ; Go on the system stack MOV NEWUCB,R5 ;; Get the UCB address TST U.UCBX(R5) ;; Do we already have a UCBX? BNE 30$ ;; If ne yes, one is enough ; ; *** NOTE WELL! The following code must reside in APR 5 mapping! ; MOV #/100,R1 ;; Set number of secondary pool blocks CALL @ALSEC ;; Allocate it BCS 30$ ;; If CC=1, no room for UCBX MOV @KISA6,-(SP) ;; Save APR mapping MOV R0,@KISA6 ;; Map to the UCBX MOV R0,U.UCBX(R5) ;; And store in the UCB MOV #X.LGTH/2,R1 ;; Get length in words MOV #140000,R0 ;; Get displacement into the block MOV R0,R2 ;; Save it 20$: CLR (R0)+ ;; Clear the UCBX SOB R1,20$ ;; Loop until done MOVB #X.DFHL,X.ERHL(R2) ;; Initialize hard error limit MOVB #X.DFSL,X.ERSL(R2) ;; Initialize soft error limit MOVB #X.DFFL,X.FLIM(R2) ;; Initialize fairness count MOV #<^RUNK>,X.NAME(R2) ;; Set unknown drive name MOV #<^RN >,X.NAME+2(R2) ;; ... MOV (SP)+,@KISA6 ;; Restore previous mapping 30$: BICB #US.OFL,U.ST2(R5) ;; Set the device online RETURN ;; Back to user state and return 40$: MOV #ER$HRC,R4 ; Get error code...HRC not alive 50$: CALL PRTWAR ; Print the warning 60$: RETURN ; Return to caller .SBTTL ** DETACH -- Detach from the Virtual Device ;+ ; ; DETACH -- Detach from the Virtual Device ; ; Inputs: None ; Outputs: None ; ;- DETACH:: MOV NEWUCB,R5 ; Get the UCB address CALL $SWSTK,10$ ; Go on the system stack CMP U.ATT(R5),OURTCB ;; We are still attached, aren't we? BNE 10$ ;; No? Ask no questions, hear no lies CLR U.ATT(R5) ;; Release the device CLR R1 ;; No I/O packet CALL @DRQRQ ;; Kick the driver in case someone is waiting 10$: RETURN ;; Return to user state and to caller .SBTTL ** DEADEV -- Deallocate New Virtual Device Database ;+ ; ; DEADEV -- Deallocate newly created virtual device data structure ; ; This routine is called when an error occurs subsequent to the device ; creation which forces us to deallocate the data structure ; ; Inputs: None ; Outputs: None ;- DEADEV:: TST NEWFLG ; New device created? BEQ 50$ ; If eq no - don't delete CALL $SWSTK,50$ ; Go on the system stack ; ; Scan the device list for our database ; MOV DEVHD,R0 ;; Get address of device listhead 10$: MOV R0,R1 ;; Make current one the previous MOV (R1),R0 ;; Get next device BNE 20$ ;; Proceed BPT ;; Could not find it? That's fatal! 20$: CMP R0,NEWDCB ;; Is this the device? BNE 10$ ;; If ne no, keep looking ; ; Unlink from the device list ; MOV (R0),(R1) ;; Unlink our DCB from the list ; ; Unlink from the virtual device list that begins with VF0: ; MOV D.UCB(R0),R1 ;; Get new UCB address MOV VFDCB,R2 ;; Get VF0: DCB address MOV D.UCB(R2),R2 ;; Get its UCB address 30$: CMP U.VLNK(R2),R1 ;; Found the virtual link to this device? BEQ 40$ ;; If eq then we have MOV U.VLNK(R2),R2 ;; Get next virtual UCB BNE 30$ ;; Keep looking BPT ;; Virtual link not found? That's fatal! 40$: MOV U.VLNK(R1),U.VLNK(R2) ;; Unlink us from the list ; ; Deallocate the data structure ; MOV #$VFSIZ,R1 ;; Get size of the database CALL @DEACB ;; And deallocate the data structure 50$: RETURN ;; Return to user state and to caller .SBTTL ** DEAFIL -- Deaccess Container Files ;+ ; DEAFIL -- Deaccess Container Files (Error Recovery) ; ; This routine is called when an error has occurred in the creation ; of the virtual unit. Any file which was accessed must be examined ; to undo the operation. This may involve: ; ; - Re-writing attributes to disable the deaccess lock bit ; - Decrementing the volume transaction count of the ACP ;- DEAFIL:: MOV #SECBLK,R4 ; Point to secondary block area TST NUMFIL ; Any files there to check? BEQ 100$ ; If eq no - all done 10$: MOV X.FLAG(R4),R0 ; Get flags word for this container file BEQ 80$ ; Nothing to do -- get next one MOV X.UCB(R4),R5 ; Get the UCB address of the device CALL $SWSTK,30$ ; Go on the system stack .IF DF X$$HDR MOV @KISA6,-(SP) ;; Save APR6 MOV @SAHDB,@KISA6 ;; Map external header MOV @SAHPT,R1 ;; Point to the header .IFF ; DF X$$HDR MOV @HEADR,R1 ;; Point to task header .IFTF ; DF X$$HDR MOV R5,H.LUN+<*4>(R1) ;; Assign to the device .IFT ; DF X$$HDR MOV (SP)+,@KISA6 ;; Restore APR 6 .ENDC ; DF X$$HDR BIT #XF.TRN,R0 ;; Did we increment the volume transaction? BEQ 20$ ;; If eq no MOV U.VCB(R5),R1 ;; Get Volume Control Block DEC V.TRCT(R1) ;; Decrement transaction cout 20$: RETURN ;; Return to user state 30$: BIT #XF.LCK,R0 ; Did we set the write lock bit? BEQ 80$ ; If eq no - don't touch the file MOV #FILFDB+F.FNB+N.FID,R1 ; Point to file ID in filename block MOV X.FID(R4),(R1)+ ; Copy the file ID MOV X.FID+2(R4),(R1)+ MOV X.FID+4(R4),(R1) CLR FILFDB+F.FNB+N.DVNM ; Indicate the device is assigned MOVB #UC.CON,WATATT ; Remove deaccess lock bit (leave contig) F11QIO WATDPB,70$ ; Write the attribute BR 80$ ; Get the next file 70$: MOV R4,-(SP) ; Save secondary block address MOV #ER$RCE,R4 ; Get error code CALL PRTWAR ; Print warning code MOV (SP)+,R4 ; Recover pointer 80$: DEC NUMFIL ; One less file to look at BEQ 100$ ; No more to look at ADD #X.LEN,R4 ; Bump to the next container block BR 10$ ; And process it 100$: RETURN ; Return to caller .SBTTL ** PRTWAR/PRTERR -- Print error messages ;+ ; PRTERR -- Print error message and set error status for task ; PRTWAR -- Print error message and set warning status for task ; ; Input: R4 contains the index of the error message ;- PRTWAR::CMP #EX$ERR,EXISTS ; Already at error status? BEQ WARERR ; If eq yes, don't supercede MOV #EX$WAR,EXISTS ; Set exit status BR WARERR ; And proceed PRTERR::MOV #EX$ERR,EXISTS ; Set exit status WARERR: MOV R0,-(SP) ; Save a register MOV #ERRDPB,R0 ; Point to the QIO DPB MOV #TSKNAM,Q.IOPL(R0) ; Point to task name MOV #TSKLEN,Q.IOPL+2(R0) ; Store length MOV #<'$>,Q.IOPL+4(R0) ; Store VFC DIR$ R0 ; Write it out ASL R4 ; Make error code a word index MOV ERRTAB-2(R4),Q.IOPL(R0) ; Store address of error string MOV ERRLEN-2(R4),Q.IOPL+2(R0) ; Store length of error string MOV #<'+>,Q.IOPL+4(R0) ; Store VFC DIR$ R0 ; Write it out MOV (SP)+,R0 ; Restore register RETURN ; Return to caller .END $AVF