.Title DVF -- Deassign Virtual Disk .Enabl LC .Ident /V03.00/ .Sbttl ** DVF Data Area ; ; ; DVF -- Deassign Virtual Device & Delete Data Structures ; ; 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 * ; * ; ************************************************************************ ; ; DVF performs the reverse operation of the AVF command: DVF deassigns ; a virtual device, releasing its container files and deleting the ; virtual device data structure. ; ; 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. ; ; DVF takes a single argument from the user: the device specification ; of a virtual device. DVF obtains all other information required to ; deassign the device from the existing data structures. ; ;- ; ; 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 TCB 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 ; ; 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 FSRSZ$ ; Define Fsr Region .MCALL FINIT$ ; Define FCS init routine .MCALL NBOFF$ ; Define filename block offsets NBOFF$ DEF$L ; ; 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 ; ; 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 ; ; Local Data: ; ; Directives. ; WATDPB: QIOW$ IO.WAT,FILLUN,EV.QIO,,IOSTAT,, ERRDPB: QIOW$ IO.WVB,TTYLUN,EV.QIO,,IOSTAT,,<0,0,0,0,0,0> ; PRVDPB: GIN$ GI.SPR,0 VECDPB: GIN$ GI.VEC,VECBUF,VECSIZ CONDPB: SPWN$ ...CON,,,,,EV.SPN,,ESB,CONCMD ; ; GCML Control Block ; MAXDEP = 3 ; Allow nesting level to 3 MAXCMD = 80. ; Allow up to 80. 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.HLP = 2 ; Give help ; ; CSI Switch Tables. ; OUTSWI: CSI$SW HE,FL.HLP,CSIMSK,SET CSI$ND ; ; Filename Block ; FNB: .BLKB S.FNB ; Allocate Filename Block .EVEN ; ; Write Attribute List. ; WATLST: .BYTE H.UCHA,01 ; Write user characteristics .WORD WATATT ; .BYTE 0,0 ; End-of-list WATATT: .BYTE UC.CON .EVEN .WORD 0 ; Safety margin (?) ; ; Executive Vector Buffer ; VECBUF: .WORD 0 ; Flags word DEVHD: .WORD $DEVHD ; Device listhead DESEC: .WORD $DESEC ; Deallocate secondary pool block SAHDB: .WORD $SAHDB ; Header bias location SAHPT: .WORD $SAHPT ; Header displacement KISA6: .WORD KISAR6 ; Kernel APR 6 HEADR: .WORD $HEADR ; Header pointer QACNT: .WORD $QACNT ; Queue accounting block SABPT: .WORD $SABPT ; Pointer to SAB EXRQN: .WORD $EXRQN ; Request task routine TKTCB: .WORD $TKTCB ; TCB pointer FMASK2: .WORD $FMSK2 ; Second feature mask word DRQRQ: .WORD $DRQRQ ; Queue I/O to driver routine VECSIZ = <.-VECBUF>/2 ; ; Other variables. ; EXISTS::.WORD 0 ; Task exit status word IOSTAT::.WORD 0,0 ; I/O status block 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 DVUNT:: .WORD 0 ; Device unit number ERRFLG::.WORD 0 ; System state error flag CSIMSK::.WORD 0 ; CSI Mask word NUMFIL::.WORD 0 ; Number of container files OURTCB::.WORD 0 ; TCB address of task 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 ; ; Define local task area for building secondary control blocks ; SECBLK::.BLKB MX$FIL * X.LEN ; Define space for secondary blocks .NLIST BEX CONCMD: .ASCII ^CONFIGURE/NOMSG OFFLINE ^ CONADD: .BLKB 8. .LIST BEX .EVEN ; ; FSR region ; FSRSZ$ 1 ; One buffer required for GCML$ .PAGE .SBTTL ** DVF Main Code .PSECT $CODE,RO,I ;+ ; $DVF -- Deassign Virtual Device ; ; Syntax: ; ; >DVF ddnn: ; ; ddnn: Specifies the name to be used for the Virtual Unit. ; ;- $DVF:: ; ; Perform one-time initialization ; CALL TKINIT ; Do task-level initialization BCS DVFEX ; If CC=1 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 DVFEX ; 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 is checked to make sure that it is a virtual unit. ; ; If the device is online, an attempt is made to take it offline. ; ; If the carry bit is returned clear, processing can proceed; ; otherwise, the device cannot be deassigned. ; CALL GETDEV ; Parse virtual device and validate it BCS RESTRT ; On error, start next command ; ; Copy the secondary pool control block into local memory, and delete ; the secondary pool structure. ; CALL GETBLK ; Copy and delete secondary pool block structure ; ; DEAFIL is called to deaccess all active container files ; CALL DEAFIL ; Deaccess all container files CALL DETACH ; Detach from the device BR RESTRT ; And attempt to process new command DVFEX:: 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 ; ; 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 DIR$ #PRVDPB ; Clear task privilege MOV #EX$SUC,EXISTS ; Assume successful status DIR$ #VECDPB ; Get executive vectors BCC 10$ ; If cc=0 then successful MOV #ER$GIN,R4 ; Get the error code CALL PRTERR ; Report the error SEC ; Return cc=1 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:: CLR CSIMSK ; Store default switch environment 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 10$ ; If carry clear then OK JMP 135$ ; Handle error ; ; Process help request ; 10$: BIT #FL.HLP,CSIMSK ; Was help requested? BEQ 20$ ; 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 JMP 140$ ; And go for next command ; ; Perform other checks ; 20$: MOV #ER$NDV,R4 ; Assume no device specified BITB #CS.DVF,C.STAT(R0) ; Device specified? BNE 30$ ; If ne yes JMP 135$ ; If eq no 30$: MOV #ER$EXT,R4 ; Assume extraneous input BITB #CS.EQU,C.STAT(R0) ; Both input and output specified? BNE 40$ ; If ne yes BITB #CS.NMF!CS.DIF!CS.WLD!CS.MOR,C.STAT(R0) ; Other garbage? BEQ 50$ ; If eq no 40$: CALL PRTWAR ; Print the warning ; ; Extract device name ; 50$: 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 ALUN$S #FILLUN,DVNAM,DVUNT ; Assign to the virtual unit MOV #ER$ILD,R4 ; Assume error CMP $DSW,#IS.SUC ; Successful? BEQ 55$ ; If eq yes JMP 135$ ; If ne device not in system 55$: ; Reference label ; ; Go to system state to perform further checks and create device structure ; CLR ERRFLG ; Clear system state error flag CALL $SWSTK,100$ ; Switch to the system stack ; Get UCB address out of the header .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),R5 ;; Grab virtual disk UCB address .IFT ; DF X$$HDR MOV (SP)+,@KISA6 ;; Restore mapping .ENDC ; DF X$$HDR MOV R5,NEWUCB ;; Save UCB address MOV U.DCB(R5),NEWDCB ;; Save the DCB address, too ; ; Find VF0: ; MOV #ER$NLD,R4 ;; Assume VF: not there MOV DEVHD,R1 ;; Get device listhead 60$: MOV (R1),R1 ;; Get next DCB BEQ 80$ ;; If eq then end of list CMP D.NAM(R1),#<"VF> ;; Right name? BNE 60$ ;; If ne no TST D.UNIT(R1) ;; Unit zero? BNE 60$ ;; If ne no TST D.PCB(R1) ;; Is the driver loaded? BEQ 80$ ;; If eq no MOV R1,VFDCB ;; Save VF0: DCB address ; ; Check that the device the user specified is in fact a virtual device ; MOV #ER$NVD,R4 ;; Assume not a virtual device MOV D.UCB(R1),R1 ;; Get VF0: UCB address 70$: MOV U.VLNK(R1),R1 ;; Get next virtual UCB address BEQ 80$ ;; If eq end of list CMP R1,R5 ;; Found our unit? BNE 70$ ;; If ne no, try next one ; ; Check that the virtual disk is currently assigned. ; MOV #ER$NAS,R4 ;; Assume the unit is unassigned TST U.CTLP(R5) ;; Is this unit assigned? BEQ 80$ ;; If eq no - return error ; ; Check that the unit is not attached or allocated by someone else ; MOV #ER$ATT,R4 ;; Assume problems with the device TST U.OWN(R5) ;; Is the device owned? BEQ 74$ ;; If eq no CMP U.OWN(R5),TIUCB ;; Is it owned by us? BNE 80$ ;; If ne no, that's an error 74$: TST U.ATT(R5) ;; Is the device attached by someone? BNE 80$ ;; If ne yes, that's an error ; ; Check that the unit is not busy ; MOV #ER$BSY,R4 ;; Assume the device is busy BITB #US.BSY,U.STS(R5) ;; Is the unit busy? BNE 80$ ;; If ne yes BITB #US.MNT,U.STS(R5) ;; Is the unit mounted? BEQ 80$ ;; If eq yes ; ; Check that we have sufficient privilege to monkey with the disk ; MOV #ER$PRV,R4 ;; Assume we ain't got it CMPB U.XGRP(R5),DEVGRP ;; Does our protection group match the unit's BEQ 76$ ;; If eq yes -- accept command CMPB #10,DEVGRP ;; Are we sufficiently privileged? BLO 80$ ;; If Lo no -- not privileged group 76$: MOV OURTCB,U.ATT(R5) ;; Attach to the unit ; ; Assign a LUN to the unit so that I/O rundown will detach us ; .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 BR 90$ ;; And return to user state 80$: MOV R4,ERRFLG ;; Set error code 90$: RETURN ;; Return to user state 100$: CLC ; Assume success MOV ERRFLG,R4 ; Get error flag BNE 135$ ; If ne, then leave now ; ; If the unit is still online, then take it offline now. ; MOV NEWUCB,R5 ; Get the device UCB BITB #US.OFL,U.ST2(R5) ; Is the unit already offline? BNE 150$ ; If ne yes, return with success MOV #CONADD,R0 ; Get address of command line MOVB DVNAM,(R0)+ ; Store device name MOVB DVNAM+1,(R0)+ ; MOV DVUNT,R1 ; Get unit number CLR R2 ; No leading zeros CALL $CBOMG ; Convert to binary MOVB #<':>,(R0)+ ; Finish with 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 ; Take the device offline BCS 110$ ; Branch on spawn error STSE$S #EV.SPN ; Wait for command completion CMP #EX$SUC,ESB ; Did it work? BNE 110$ ; If ne no CLC ; Indicate success BR 150$ ; And return ; ; CON could not take the unit offline, probably because the user is non- ; privileged. We will just manually do it now. Deallocate the UCB extension, ; if there is one, with a call to accounting. Then mark the UCB offline. ; ; ** NOTE WELL! The following code must reside in APR 5!! ; 110$: CLC ; Clear carry CALL $SWSTK,150$ ; Go on the system stack MOV NEWUCB,R5 ;; Get the UCB address MOV U.UCBX(R5),R0 ;; Get UCB extension BEQ 130$ ;; If eq there is none CLR U.UCBX(R5) ;; Clear UCB extension pointer BIT #F2.ACN,@FMASK2 ;; Accounting supported? BEQ 120$ ;; If eq no, just deallocate it TST @SABPT ;; Is accounting active? BEQ 120$ ;; If eq no, just deallocate it MOV R0,R1 ;; Copy the UCB extension bias MOV @KISA6,-(SP) ;; Save APR for mapping UCBX MOV R1,@KISA6 ;; Map UCBX MOV #140000,R0 ;; Get displacement MOVB #BT.DST,B.TYP(R0) ;; Insert type MOVB #X.LGTH,B.LEN(R0) ;; And length ; ; Get the device name and unit number ; MOV (R5),R4 ;; Get the DCB address MOV D.NAM(R4),X.DNAM(R0) ;; Store the device name MOV R5,R3 ;; Copy the UCB address SUB D.UCB(R4),R3 ;; Convert to a UCB offset CLR R2 ;; Prepare for the divide DIV D.UCBL(R4),R2 ;; Get UCB number on this DCB MOVB D.UNIT(R4),R3 ;; Get number of first unit on this DCB BIC #177400,R3 ;; Eliminate possible sign extend ADD R2,R3 ;; Make it the total unit number MOVB R3,X.UNIT(R0) ;; Store the unit number MOV (SP)+,@KISA6 ;; Restore mapping ; ; Arguments to $QACNT (Queue Accounting Transaction Block): ; ; R1 - Relocation bias to map accounting block ; ; R3, R4, and R5 preserved ; CALL @QACNT ;; Pass block to accounting BR 130$ ;; And proceed 120$: MOV #/100,R1 ;; Set length of block ; ; Arguments to $DESEC (Deallocate Secondary Pool Block): ; ; R0 - Relocation bias to map secondary pool block ; R1 - Size of block in 32K word blocks ; CALL @DESEC ;; Deallocate ucb extension 130$: BISB #US.OFL,U.ST2(R5) ;; Set the device offline RETURN ;; Return to user state and to caller 135$: CALL PRTERR ; Print the error code 140$: SEC ; Indicate failure 150$: RETURN ; Return to caller .SBTTL ** GETBLK -- Copy Secondary Block Structure ;+ ; GETBLK -- Copy the secondary block structure into local memory ; and release it to secondary pool. ; ; GETBLK performs the following: ; ; Copies the secondary block structure from secondary pool ; into the local task image buffer. ; ; Deallocates the secondary block buffer, and resets various ; offsets in the UCB. ; ;- GETBLK:: CALL $SWSTK,30$ ; Go on the system stack MOV NEWUCB,R5 ;; Get address of virtual UCB MOVB U.XFIL(R5),R3 ;; Get number of container files MOV R3,NUMFIL ;; Store for later use MUL #X.LEN,R3 ;; Calculate number of bytes used MOV R3,-(SP) ;; Save the count MOV @KISA6,-(SP) ;; Save APR MOV U.CTLP(R5),@KISA6 ;; Map the control block MOV #140000,R0 ;; Load displacement MOV #SECBLK,R1 ;; Point to local copy of secondary block ASR R3 ;; Convert number of bytes to words 10$: MOV (R0)+,(R1)+ ;; Copy out of secondary pool SOB R3,10$ ;; Loop until finished MOV (SP)+,@KISA6 ;; Restore APR CLR U.CW2(R5) ;; Clear high order disk size CLR U.CW3(R5) ;; Clear low order MOV U.CTLP(R5),R0 ;; Get address of the control block CLR U.CTLP(R5) ;; Clear out secondary block address MOV (SP),R1 ;; Get number of bytes back ASH #-6,R1 ;; Convert to 32 word blocks BIT #77,(SP)+ ;; Do we need an extra block? BEQ 20$ ;; No, we're OK INC R1 ;; Deallocate one more block 20$: CALL @DESEC ;; Deallocate the secondary pool block 30$: RETURN ;; Return to user state and to caller .SBTTL ** DEAFIL -- Deaccess Container Files ;+ ; DEAFIL -- Deaccess Container Files ; ; This routine is called to deaccess any container files for 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 10$: MOV X.FLAG(R4),R0 ; Get flags word for this container file BEQ 50$ ; 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 BEQ 20$ ;; What ??? DEC V.TRCT(R1) ;; Decrement transaction cout MOV U.ACP(R5),R0 ;; Pick up TCB of the ACP BEQ 20$ ;; What again ??? CALL @EXRQN ;; And kick it around a bit 20$: RETURN ;; Return to user state 30$: BIT #XF.LCK,R0 ; Did we set the write lock bit? BEQ 50$ ; If eq no - don't touch the file MOV #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 FNB+N.DVNM ; Indicate the device is assigned MOVB #UC.CON,WATATT ; Remove deaccess lock bit (leave contig) F11QIO WATDPB,40$ ; Write the attribute BR 50$ ; Get the next file 40$: MOV R4,-(SP) ; Save secondary block address MOV #ER$RCE,R4 ; Get error code CALL PRTWAR ; Print warning code MOV (SP)+,R4 ; Recover pointer 50$: DEC NUMFIL ; One less file to look at BEQ 60$ ; No more to look at ADD #X.LEN,R4 ; Bump to the next container block BR 10$ ; And process it 60$: RETURN ; Return to caller .SBTTL ** DETACH -- Detach from the Virtual Device ;+ ; ; DETACH -- Detach from the Virtual Device ; ; This routine assigns FILLUN to the Virtual Device and ; detaches from the unit. ; ; 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 ** 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 ; Output: Returns carry set ;- 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 SEC ; Return carry set RETURN ; Return to caller .END $DVF