	.TITLE	ASNVQ - VAX/VMS VIRT DISK DRIVER ASSIGN/DEASSIGN
	.IDENT	'V00-01A'
;
; FACILITY:
; 
; ASSIGN/DEASSIGN VIRTUAL DISK TASK THAT WORKS WITH VDDRIVER
;  ESTABLISHES CONNECTION (OR BREAKS IT) BETWEEN A LUN OF
;  VQ: AND A CONTIGUOUS FILE.
; This version is set up to assign one or two files to
; the VQ: driver, allowing shadowing of VQ: units in
; software. If only one file is given, the VQ: unit will
; be run in vd: - compatibility mode; that is, ucb$shmd
; will be set to zero and only one file will be used by
; VQDRIVER. If two files are given, then ucb$shmd
; will be set to 1 so writes will be done to both. The
; size of the "combined" disk will be the minimum of the
; file sizes given.
; A qualifier /SHADOW will be needed in order to assign the
; second file. Without this it will simply assign the first
; file only.
;
; Also this version will save the container file spec in the
; UCB area ucb$vdcontfil as a null terminated string up to 79
; bytes long. Also it will have an option to report the assigned
; file so associated.
;
; ALSO, this version will recognize a couple container file sizes.
; Specifically: a file sized 500384 to 500400 blocks long will be
; treated as an RM05, with 823 cylinders, 19 tracks/cylinder,
; and 32 sectors per track. A file under 65530 blocks long will
; get geomtery n cylinders, 1 sector/track, 1 track/cyl, and
; a file of size 131680 to 131700 blocks long will be treated as
; an RM03 with 823 cylinders, 5 tracks/cylinder, and 32 sectors
; per track. This will facilitate use for some kinds of backups.
; Other disk types can be wedged in as needed. Note the physical
; structure for small disks thus generated is DIFFERENT from the
; "standard" driver set. A /sec64 switch will allow this to be
; overridden where we need compatibility.
;
;With version 3 is added facility to use VQ: with an arbitrary
; section of disk. The /LBN=number/LEN=number switches will
; allow one to force an LBN and length in blocks for a VQ:
; assignment even if the file assigned is NOT contiguous.
;  The motive for this is: I have noticed that my SYSDUMP.DMP file
; (after backup/restore) exists as one contiguous area, even though
; it is not marked contiguous. Addition of these commands to ASNVQ
; will allow use of such areas of disk for things like scratch
; space, where the volatility of scratch area is not an issue.
; This method will also allow entire physical disks to be assigned
; through the VQ: driver, or permit partitioning of physical disks
; without the overhead of a Files-11 index structure on the disk.
;
; Command format:
; ADVD/switches VQn: file1 file2
;  where a .CLD file is expected so that this can all be parsed by
;  the CLI. The legal switches will just be /ASSIGN or /DEASSIGN
;  to specify which operation is required. In the /DEASSIGN
;  case no filename is needed of course; the virtual disk must
;  however be dismounted before this utility will allow it to
;  be deassigned. The ucb$w_refc field must be zero before the
;  deassign is thus permitted.
;  We must set the UCB$L_MAXBLOCK longword to the size of the file
;  here also. This requires reading the statistics on the file to
;  discover the size if contiguous; the statistics block will
;  show zero if noncontig...
;    We also set the number of "cylinders" for a fakeout structure.
; I don't really think that physical I/O needs to even be legal, but
; for the sake of argument & trying to get SOMETHING that works,
; I've left it in for now. The driver world be simpler just
; removing readpblk and writepblk from the legal-function FDT masks
; but there's always the chance SOMETHING will need it...
;	Note that file1 is the "prime" file in that catchup is ALWAYS
; done from file1 to file2. Unless the /RWBOTH qualifier is given
; only file1 will be read, though both will be written. Unless the
; /SHADOW qualifier exists, file2 will be ignored even if given.
;
; Note: define VMS$V5 to build for Version 5.x of VMS.
;VMS$V5=1
;
; 
; AUTHOR:
; 
; G. EVERHART
;
; 04-Aug-1989	D. HITTNER	Cleaned up definitions, added messages
; 29-Aug-1989   G. Everhart	Added more flexible device geometry selection
;--
	.PAGE
	.SBTTL	EXTERNAL AND LOCAL DEFINITIONS

	.LIBRARY /SYS$SHARE:LIB/
; 
; EXTERNAL SYMBOLS
; 

	$ADPDEF				;DEFINE ADAPTER CONTROL BLOCK
	$ATRDEF
	$CRBDEF				;DEFINE CHANNEL REQUEST BLOCK
	$DCDEF				;DEFINE DEVICE CLASS
	$DDBDEF				;DEFINE DEVICE DATA BLOCK
	$DEVDEF				;DEFINE DEVICE CHARACTERISTICS
	$DPTDEF				;DEFINE DRIVER PROLOGUE TABLE
	$DVIDEF				;Symbols for $GETDVI service.
	$EMBDEF				;DEFINE ERROR MESSAGE BUFFER
	$FABDEF
	$FATDEF
	$FIBDEF				;Symbols for file information block.
	$IDBDEF				;DEFINE INTERRUPT DATA BLOCK
	$IODEF				;DEFINE I/O FUNCTION CODES
	$IRPDEF				;DEFINE I/O REQUEST PACKET
	$NAMDEF
	$PRDEF				;DEFINE PROCESSOR REGISTERS
	$RMSDEF
	$SBDEF
	$SCSDEF
	$SSDEF				;DEFINE SYSTEM STATUS CODES
	$STSDEF				;Symbols for returned status.
	$TPADEF				;Symbols for LIB$TPARSE calls.
	$UCBDEF				;DEFINE UNIT CONTROL BLOCK
	$VECDEF				;DEFINE INTERRUPT VECTOR BLOCK
	$XABDEF

; 
; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS
; DEFINE THESE SO WE KNOW WHERE IN THE UCB TO ACCESS. WE MUST
; SET THE ONLINE BIT OR CLEAR IT, AND ALSO SET
; UCB$HUCB (HOST UCB ADDRESS), UCB$HFSZ (HOST FILE SIZE),
; AND UCB$HLBN (HOST LOGICAL BLOCK NUMBER OF FILE START)
;
; Note: These MUST match the definitions in VQDRIVER. Don't
; change one without changing the other to match it!!!
;	G. Everhart 10/10/1989
; 
; Since I/O postprocessing on virtual or paging I/O makes lots of
; assumptions about location of window blocks, etc., which are
; not true here (wrong UCB mainly), we'll bash the function code status
; we send to the host driver to look like logical I/O is being
; done and save the real status code here. Later when VD: does
; I/O completion processing, we'll replace the original function
; from here back in the IRP. This will be saved/restored along with
; ucb$ppid (irp$l_pid field) and so synchronization will be detected
; with ucb$ppid usage.

	$DEFINI	UCB			;START OF UCB DEFINITIONS

;.=ucb$w_bcr+2				;BEGIN DEFINITIONS AT END OF UCB
.=ucb$k_lcl_disk_length			;vms v4, right out of the book...
					;LOCAL DATA FOR VIRT DISK.
$DEF	UCB$W_DY_WPS	.BLKW	1	;Words per sector.
$DEF	UCB$W_DY_CS	.BLKW	1	;CONTROL STATUS REGISTER
$DEF	UCB$W_DY_DB	.BLKW	1	;UCB ADDRESS OF HOST DRIVER
$DEF	UCB$W_DY_DPN	.BLKW	1	;(LONGWORD)
$DEF	UCB$L_DY_DPR	.BLKL	1	;START LBN OF HOST CONTIG FILE
$DEF	UCB$L_DY_FMPR	.BLKL	1	;
$DEF	UCB$L_DY_PMPR	.BLKL	1	;PREVIOUS MAP REGISTER
$DEF	UCB$B_DY_ER	.BLKB	1	;SPECIAL ERROR REGISTER
			.BLKB	1	;Reserved.
$DEF	UCB$B_DY_LCT	.BLKB	1	;LOOP COUNTER
$DEF	UCB$B_DY_XBA	.BLKB	1	;BUS ADDRESS EXTENSION BITS
$DEF	UCB$W_DY_PWC	.BLKW	1	;PARTIAL WORD COUNT
$DEF	UCB$W_DY_SBA	.BLKW	1	;SAVED BUFFER ADDRESS
$DEF	UCB$L_DY_XFER	.BLKL	1	;TRANSFER FUNCTION CSR BITS
$DEF	UCB$L_DY_LMEDIA	.BLKL	1	;LOGICAL MEDIA ADDRESS
$DEF	UCB$Q_DY_EXTENDED_STATUS	; Area into which we do READ ERROR
			.BLKQ	1	;  REGISTER command.
$DEF	UCB$Q_DY_SVAPTETMP		; Area in which we save UCB fields -
			.BLKQ	1	;  SVAPTE, BOFF, and BCNT.
$DEF	UCB$L_DY_MAPREGTMP		; Area in which we save CRB fields -
			.BLKL	1	;  MAPREG, NUMREG, and DATAPATH.
$DEF	UCB$L_DY_SAVECS	.BLKL	1	; Area in which we save CS and DB regs.
$DEF	UCB$HUCB	.BLKL	1	;ADDRESS OF HOST UCB
$DEF	UCB$HLBN	.BLKL	1	;LBN OF HOST FILE
$DEF	UCB$HFSZ	.BLKL	1	;SIZE OF HOST FILE, BLKS
$DEF	UCB$PPID	.BLKL	1	;PID save area for active requests
$DEF	UCB$STATS	.BLKL	1	;IRP STATUS CODE SAVE AREA
$DEF	UCB$OBCT	.BLKL	1	;STORE FOR IRP$L_OBCNT too
$DEF	UCB$LMEDIA	.BLKL	1	;irp$l_media store
$DEF	UCB$OWIND	.BLKL	1	; store irp$l_wind...
$DEF	UCB$OSEGV	.BLKL	1	; and irp$l_segvbn
$DEF	UCB$L_VD_HOST_DESCR
			.BLKL	2
$DEF	UCB$VDCONTFIL	.BLKB	80	;container file spec, 0 term'd
; new structures for shadow disk operation
$def	ucb$hucb2	.blkl	1	;host UCB of file 2
$def	ucb$hlbn2	.blkl	1	;LBN of file 2
$def	ucb$hfsz2	.blkl	1
$def	ucb$shmd	.blkl	1	;shadow mode. 0=use file 1 only
					; 1= read file 1 always; write both
					; 2= read both (select); write both
$def	ucb$rwlk	.blkl	1	; read/write interlock. Initialize to 1
					; on special read-logical, set to 44 on
					; normal write in area of block read,
					; return as i/o status and clear on
					; special write-logical.
$def	ucb$rwlbn	.blkl	1	; LBN of first block in special read/logical
$def	ucb$rwsz	.blkl	1	; size of special transfer
$def	ucb$llbn1	.blkl	1	; last LBN of file 1
$def	ucb$llbn2	.blkl	1	; last LBN of file 2
$def	ucb$ucbos	.blkl	1	; offset to ucb/lbn/fsz in ucb to use at fin-io
$def	ucb$rwdir	.blkl	1	;read (0) or write (1) I/O
$def	ucb$er1		.blkl	1	; store for error code of 1st write of 2
;
;end new structures for shadowing

$DEF	UCB$K_VD_LEN	.BLKW	1	;length
;ucb$k_dy_len=.				;LENGTH OF UCB

	$DEFEND	UCB			;END OF UCB DEFINITONS

; TO SET ONLINE:
;	BISW	#UCB$M_ONLINE,UCB$W_STS(R5)  ;SET UCB STATUS ONLINE

; Macro to check return status of system calls.
;
	.MACRO	ON_ERR	THERE,?HERE
	BLBS	R0,HERE
	BRW	THERE
HERE:	.ENDM	ON_ERR

;
;
;
	.PSECT	ADVDD_DATA,RD,WRT,NOEXE,LONG

DEFAULT_DEVICE:
	.ASCID	/SYS$DISK/

	.ALIGN LONG
DFAB_BLK: $FAB FNM=<VD0.DSK>,XAB=FNXAB,FAC=<GET,PUT>,DNM=<VDCONT.DSK>
;
FNXAB:	$XABFHC	; XAB STUFF TO GET LBN, SIZE
	.BLKL	20 ;SAFETY
IOSTATUS: .BLKQ 1
DEV_BUF:			; Buffer to hold device name.
	.BLKB	40
DEV_BUF_SIZ = . - DEV_BUF

DEV_BUF_DESC:			; Descriptor pointing to device name.
	.LONG	 DEV_BUF_SIZ
	.ADDRESS DEV_BUF
; SECOND FILE CONTROL BLOCKS
	.ALIGN LONG
EFAB_BLK: $FAB FNM=<VD0.DSK>,XAB=EFNXAB,FAC=<GET,PUT>,DNM=<VDCONT.DSK>
;
EFNXAB:	$XABFHC	; XAB STUFF TO GET LBN, SIZE
	.BLKL	20 ;SAFETY
EIOSTATUS: .BLKQ 1
EDEV_BUF:			; Buffer to hold device name.
	.BLKB	40
EDEV_BUF_SIZ = . - EDEV_BUF

EDEV_BUF_DESC:			; Descriptor pointing to device name.
	.LONG	 EDEV_BUF_SIZ
	.ADDRESS EDEV_BUF

PID:				; Owner of device (if any).
	.BLKL	1
EPID:	.BLKL	1
DEV_ITEM_LIST:			; Device list for $GETDVI.
	.WORD	 DEV_BUF_SIZ	; Make sure we a have a physical device name.
	.WORD	 DVI$_DEVNAM
	.ADDRESS DEV_BUF
	.ADDRESS DEV_BUF_DESC
	.WORD	 4		; See if someone has this device allocated.
	.WORD	 DVI$_PID
	.ADDRESS PID
	.LONG	 0
	.WORD	 4
	.WORD	 DVI$_DEVCLASS	; Check for a terminal.
	.ADDRESS DEV_CLASS
	.LONG	 0
	.LONG	 0		; End if item list.
; DUPLICATE ITEM LIST FOR 2ND FILE.
EEV_FLAG:	.LONG	0
EEV_ITEM_LIST:			; Device list for $GETDVI.
	.WORD	 EDEV_BUF_SIZ	; Make sure we a have a physical device name.
	.WORD	 DVI$_DEVNAM
	.ADDRESS EDEV_BUF
	.ADDRESS EDEV_BUF_DESC
	.WORD	 4		; See if someone has this device allocated.
	.WORD	 DVI$_PID
	.ADDRESS EPID
	.LONG	 0
	.WORD	 4
	.WORD	 DVI$_DEVCLASS	; Check for a terminal.
	.ADDRESS DEV_CLASS
	.LONG	 0
	.LONG	 0		; End if item list.

DEV_CLASS:
	.LONG	1
;**
VDV_BUF:			; Buffer to hold VDVice name.
	.BLKB	40
VDV_BUF_SIZ = . - VDV_BUF

VDV_BUF_DESC:			; Descriptor pointing to VDVice name.
	.LONG	 VDV_BUF_SIZ
	.ADDRESS VDV_BUF

VPID:				; Owner of VDVice (if any).
	.BLKL	1

VDV_ITEM_LIST:			; VDVice list for $GETDVI.
	.WORD	 VDV_BUF_SIZ	; Make sure we a have a physical device name.
	.WORD	 DVI$_DEVNAM
	.ADDRESS VDV_BUF
	.ADDRESS VDV_BUF_DESC
	.WORD	 4		; See if someone has this device allocated.
	.WORD	 DVI$_PID
	.ADDRESS VPID
	.LONG	 0
	.WORD	 4
	.WORD	 DVI$_DEVCLASS	; Check for a terminal.
	.ADDRESS VDV_CLASS
	.LONG	 0
	.LONG	 0		; End if item list.

VDV_CLASS:
	.LONG	1
;**
DEFNAM:

WRK:	.BLKL	1	;SCRATCH INTEGER
WRK2:	.BLKL	1
	.align long
wrkstr:	.word	20	;length
	.byte	dsc$k_dtype_t	;text
	.byte	1	;static
	.address	wrkdat
wrkdat:	.blkb	20
	.byte	0,0,0,0	;safety
; DESCRIPTOR FOR VDn: "FILENAME"
	.ALIGN LONG
VDFNM:	.WORD	 255.	;LENGTH
VDFTP:	.BYTE	DSC$K_DTYPE_T	;TEXT TYPE
	.BYTE	1	; STATIC STRING
	.ADDRESS	VDFNMD
VDFNMD:	.BLKB	256.	; DATA AREA
;
; DESCRIPTOR FOR DVn:DSKFIL "FILENAME"
	.ALIGN LONG
DDFNM:	.WORD	 255.	;LENGTH
DDFTP:	.BYTE	DSC$K_DTYPE_T	;TEXT TYPE
	.BYTE	1	; STATIC STRING
DDFNA:	.ADDRESS	DDFNMD
DDFNMD:	.BLKB	256.	; DATA AREA
DDCHN:	.LONG	0
VDCHN:	.LONG	0	;CHANNEL HOLDERS
; second file desc.
	.ALIGN LONG
EDFNM:	.WORD	 255.	;LENGTH
EDFTP:	.BYTE	DSC$K_DTYPE_T	;TEXT TYPE
	.BYTE	1	; STATIC STRING
EDFNA:	.ADDRESS	EDFNMD
EDFNMD:	.BLKB	256.	; DATA AREA
EDCHN:	.LONG	0
	.align	long
dbuf:	.blkl	2048
	.blkl	2 ;safety		;data buffer
; 16 blocks at a time
cupios:	.long	0,0			;io stat blk
cbks:	.long	0		;blocks left
csz:	.long	8192		;16 blocks at a time

;
; FOR initial use, don't bother allocating the file. Assume the
; user can somehow allocate a contiguous file of the size he wants
; for himself.
;
repdsc:	.ascid	/REPORT/	;report associated file
repflg:	.long	0		;1 if reporting, 0 otherwise
reptxt:	.word	80		;80 byte long
	.byte dsc$k_dtype_t	;static, fixed length string of text
	.byte 1
	.address	repwrk	;data pointer is repwrk's address
repwrk:	.blkb	80		;copy of filespec
s64dsc:	.ascid	/SEC64/		;flag this if 64 sectors/trk geometry needed
s32dsc:	.ascid	/SEC32/		;md: type 32 sector forcer
ASDSC:	.ASCID	/ASSIGN/
DASDSC:	.ASCID	/DEASSIGN/
P1DSC:	.ASCID	/UNIT/
P2DSC:	.ASCID	/FNAM/
P3DSC:	.ASCID	/FNAM2/
shddsc:	.ASCID	/SHADOW/
sh2dsc:	.ascid	/RWBOTH/
cupdsc:	.ascid	/CATCHUP/
LBNDSC:	.ASCID	/LBN/
LENDSC:	.ASCID	/LENGTH/
	.EVEN
cupf:	.long	0	;catchup flag
cupsz:	.long	0	;device size for catchup
cupcur:	.long	0	;current block for catch-up
shd2:	.long	0	;flag we start with r/w both
SHDF:	.LONG	0	;flag /shadow seen if nonzero
SHMD:	.LONG	0	;VQ: USAGE MODE 0=VD: COMPAT, 1=2 FILES THERE
ASDAS:	.LONG	0	;DEFAULT DEASSIGN
vSec64:	.long	0	;1 if using /sec64 geometry
vsec32:	.long	0	;1 if using /sec32 geometry
LBNn:	.long	0	;temp storage for /lbn=number
LENn:	.long	0	;temp storage for /len=number
;
; ucb data area
HSTUCB:	.LONG	0	;HOST UCB ADDRESS
HSTLBN:	.LONG	0	;LBN OF 1ST BLK OF HOST FILE
HSTFSZ:	.LONG	0	;LENGTH IN BLOCKS OF HOST FILE
HSTUC2:	.LONG	0	;HOST UCB ADDRESS FILE 2
HSTLB2:	.LONG	0	;LBN FILE 2
HSTFS2:	.LONG	0	;LENGTH OF SECOND FILE (IF ANY)
; debug words
vducb: .long 0
vdsts:	.long 0
vdsts2:	.long 0
vdsts3:	.long 0
vdcyl:	.long 0
vdprog:	.long 0	;counts where we've been
;
;
ERROR:	.LONG	2
MESS:	.LONG	SS$_ABORT
	.LONG	0

; Device geometry
; Use this table for "large" devices so that container files of
; sizes matching known geometry devices are made to appear to
; have exactly the known geometry. This will avoid a LOT of special
; case testing and allow insertion of more device geometries as we
; like
	.macro	Geotbl losz,hisz,blks,cyl,trk,sect
	.Long	losz	;low limit file size this geom
	.Long	hisz	;high limit file size this geom
	.long	blks	;Number of blks on device
	.word	cyl	;number cylinders
	.byte	trk	;number tracks/cyl
	.byte	sect	;number sectors/track
	.endm
; Geoms MUST be in increasing order of size.
Geoms:
;		losiz	hisiz	blks	cyl	trk	sect	id
	Geotbl	4800,	4810,	4800,	200,	2,	12	;RK05
	Geotbl	10240,	10250,	10240,	256,	2,	40	;RL01 (sect=256 bytes)
	Geotbl	20480,	20500,	20480,	512,	2,	40	;RL02 (Sect=256 bytes)
	Geotbl	27126,	27150,	27126,	411,	3,	22	;RK06
	GeoTbl	53790,	53830,	53790,	815,	3,	22	;RK07
	GeoTbl	131680,	131700,	131680,	823,	5,	32	;RM03
	GeoTbl	138672,	138690,	138672,	1024,	8,	17	;RD53
	GeoTbl	171798,	171850,	171798,	411,	19,	22	;RP04
	GeoTbl	242606,	242650,	242606,	559,	14,	31	;RM80 (or RB80)
	GeoTbl	340670,	340720,	340670,	815,	19,	22	;RP06
	GeoTbl	500384,	500420,	500384,	823,	19,	32	;RM05
	GeoTbl	891072,	891110,	891072,	1248,	14,	51	;RA81
	GeoTbl	1008000,1008500,1008000,630,	32,	50	;RP07
	GeoTbl	1216665,1216700,1216665,1423,	15,	57	;RA82
	.Long	0,0,0,0		;list terminator
;
;
;

	.PSECT	ADVDD_CODE,RD,NOWRT,EXE,LONG
	.ENTRY	ADVDD,^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
	clrl	cupf		;no catchup mode initially
	clrl	shdf		;no initial shadow flag
	clrl	repflg		;say not reporting initially
	movab	repwrk,r0	;clear work string initially
	movl	#80,r1
1$:	clrb	(r0)+
	sobgtr	r1,1$		;zero the array out
;	CLRL	eev_flag	;initially say no second file (for knl code)
	pushab	cupdsc		;/catchup flag being issued here?
	calls	#1,g^cli$present	;see if we find that
	cmpl	r0,#cli$_present
	bneq	12$		;if neq no /catchup
	incl	cupf		;catchup mode.
12$:
	MOVL	#1,ASDAS	;SET ASSIGN
	PUSHAB	WRK		;PUSH LONGWORD ADDR FOR RETLENGTH
	PUSHAB	VDFNM		;ADDRESS OF DESCRIPTOR TO RETURN
	PUSHAB	P1DSC		; GET P1 (VDn: UNIT)
	CALLS	#3,G^CLI$GET_VALUE	;GET VALUE OF NAME TO VDFNM
	ON_ERR	ADVDD_EXIT
	clrl	vsec64		;zero s64 flag
	clrl	vsec32		;ditto s32 flag
	pushab	s64dsc
	calls	#1,g^cli$present	;see if /sec64 specified
	cmpl	r0,#cli$_present
	bneq	503$			;if neq not there
	incl	vsec64
503$:
	tstl	cupf			;catchup mode? Can ignore most of the
					;args if so (only need vd:)
	beql	5031$			;if eql not catchup
	brw	l290$			;if neql go assign channel to vd:
5031$:
	pushab	s32dsc
	calls	#1,g^cli$present	;see if /sec32 specified
	cmpl	r0,#cli$_present
	bneq	1503$			;if neq not there
	incl	vsec32
1503$:
	pushab	shddsc			;was /SHADOW seen?
	clrl	shdf			;(assume no)
	calls	#1,g^cli$present
	cmpl	r0,#cli$_present
	bneq	603$			;if neql no /shadow seen
	incl	shdf			;if eql we saw /shadow
603$:
	pushab	sh2dsc			;was /RWBOTH seen?
	clrl	shd2			;(assume no)
	calls	#1,g^cli$present
	cmpl	r0,#cli$_present
	bneq	6031$			;if neql no /shadow seen
	incl	shd2			;if eql we saw /shadow
6031$:
	pushab	repdsc
	calls	#1,g^cli$present	;/report used?
	cmpl	r0,#cli$_present
	bneq	103$			;if not there, skip...
	movl	#1,repflg
	jmp	das1			;if there, no need for 2nd file either
;
; IF "DEASSIGN" WE DON'T NEED 2ND ARG... SEE...
;
103$:
	PUSHAB	DASDSC			; 'DEASSIGN'
	CALLS	#1,G^CLI$PRESENT	; IS /DEASSIGN USED?
	CMPL	R0,#CLI$_PRESENT	; IF EQ YES
	BEQL	DAS1
	CLRL	SHMD			; INITIALLY SET SHARE MODE 0 FOR ONE FILE MODE
	PUSHAB	WRK			; GET 2ND FILE (REAL FILE)
	PUSHAB	DDFNM			; & ITS DESCRIPTOR
	PUSHAB	P2DSC			; & PARAMETER NAME 'P2'
	CALLS	#3,G^CLI$GET_VALUE	; GET FNM
	ON_ERR	ADVDD_EXIT
	tstl	shdf			; see /shadow?
	beql	das2			;if eql no, skip getting 2nd file
	pushab	wrk2
	pushab	EDFNM			;get 2nd filename
	pushab	p3dsc
	calls	#3,g^cli$get_value	;get filename
	on_err advdd_exit
	BRB	DAS2
DAS1:	CLRL	ASDAS			; FLAG /DEAS
DAS2:

	TSTL	ASDAS			; IF 0, DEASSIGNING SO NO CHNL FOR HOST
					; FILE
	bneq	50$
52$:	brw	l290$
50$:
;	BEQL	l290$
	tstl	repflg
	bneq	52$			;/report doesn't need file either
	$ASSIGN_S -			; Get a channel to the 
		DEVNAM=DDFNM,-		; device for host file
		CHAN=DDCHN
	ON_ERR	ADVDD_EXIT
; LET ERRORS BY FOR THIS SINCE WE GET OUR INFO VIA OPEN ANYWAY SO
; CHANNEL REALLY DOESN'T HAVE TO BE THERE.
; Get the physical device name, and see if this device has an owner.
; (We must do this so we can get the host UCB address)
	$GETDVI_S -
		CHAN=ddchn,-		; Command line has device name.
		ITMLST=DEV_ITEM_LIST
	BLBS	R0,40$
	BRW	advdd_EXIT
40$:
	tstl	shdf			; /shadow flag set?
	beql	l290$			; if not, no info needed
	$assign_s devnam=EDFNM,chan=EDCHN
	on_err	advdd_Exit
	$getdvi_s chan=EDCHN,ITMLST=EEV_ITEM_LIST
	on_err	advdd_exit
l290$:
; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE.
	$ASSIGN_S -
		DEVNAM=VDFNM,-		; GET CHANNEL FOR VDn:
		CHAN=VDCHN
	ON_ERR	ADVDD_EXIT		; SKIP OUT IF ERROR
	$GETDVI_S -
		CHAN=vdchn,-		; Command line has device name.
		ITMLST=VDV_ITEM_LIST
	BLBS	R0,140$
	BRW	advdd_EXIT
140$:
;
; NOW LOCATE THE FILE AND VERIFY IT'S REALLY CONTIGUOUS, AND FIND
; OUT HOW BIG IT IS. STORE RESULTS IN HSTLBN AND HSTFSZ AND
; CALL KERNEL ROUTINE TO BASH THE VDn: UCB APPROPRIATELY.
;
; DON'T NEED TO DO THIS FOR DEASSIGN SO CHECK THAT FIRST...
	tstl	cupf			;catchup mode ignores this
	beql	230$
231$:	brw	296$
230$:
;	bneq	296$			;/catchup mode doesn't need to open files
	TSTL	ASDAS			; IF ZERO WE DEASSIGN
	BEQL	231$
	tstl	repflg
	bneq	231$			;forget file open if /report only
	clrl	lbnn
	clrl	lenn		;zero lbn and length flags.
	brb	1401$
1400$:	brw	1501$
1401$:
	PUSHAB	LBNDSC			; 'lbn='
	CALLS	#1,G^CLI$PRESENT	; IS /DEASSIGN USED?
	CMPL	R0,#CLI$_PRESENT	; IF EQ YES
	Bneq	1400$			; if neq no
	pushab	lendsc			; /len=nnnn
	calls	#1,g^cli$present	;see it too? (must have both)
	cmpl	r0,#cli$_present
	Bneq	1400$
; have both /len and /lbn specified. Get values for them. If they
; look OK, bypass file open and replace logic.
	PUSHAB	WRK		;PUSH LONGWORD ADDR FOR RETLENGTH
	pushab	wrkstr		;scratch string
	PUSHAB	lbndsc		; GET lbn
	CALLS	#3,G^CLI$GET_VALUE	;GET VALUE OF LBN
	ON_ERR	ADVDD_EXIT
; string in wrkdat
	pushl	#17		;mask...ignore blanks
	pushl	#4		;4 bytes
	pushab	lbnn		;where to store
	pushab	wrkstr		;string descriptor
	calls	#4,g^ots$cvt_tu_l ;convert to binary
	on_err advdd_exit
; lbnn now is start logical blk
	PUSHAB	WRK		;PUSH LONGWORD ADDR FOR RETLENGTH
	pushab	wrkstr		;scratch string
	PUSHAB	lendsc		; GET length
	CALLS	#3,G^CLI$GET_VALUE	;GET VALUE OF Length
	ON_ERR	ADVDD_EXIT
; string in wrkdat
	pushl	#17		;mask...ignore blanks
	pushl	#4		;4 bytes
	pushab	lenn		;where to store
	pushab	wrkstr		;string descriptor
	calls	#4,g^ots$cvt_tu_l ;convert to binary
	on_err advdd_exit
;len must be positive!
	tstl	lenn		;so IS it positive?
	blss	1501$		;if lss then no, it's negative so try and probably
				; fail to open file.
	movl	lbnn,hstlbn	;looks ok so save host LBN
	movl	lenn,hstfsz	;and start blk
	brw	1785$		;then merge common path in again.
1501$:
;
; OPEN THE FILE, CHECK ITS INITIAL LBN
; IF ERROR OR NOT CONTIG, EXIT...
; DO VIA OPENING FILE AND READING ITS' STATBLOCK VIA
; QIO...
; SET UP FOR FILENAME WE REALLY FOUND IN FAB...
	MOVL	DDFNA,DFAB_BLK+FAB$L_FNA	;SET UP FILENAME ADDR
	MOVB	DDFNM,DFAB_BLK+FAB$B_FNS	;AND LENGTH
	$OPEN	FAB=DFAB_BLK
	blbs	r0,235$
236$:	brw	300$
235$:
;	BLBC	R0,300$			; FAILURE IF FILE WON'T OPEN
; FNXAB HAS INFO ON LBN, SIZE
	MOVL	FNXAB+XAB$L_SBN,HSTLBN	; GET HOST'S LBN
	bneq	237$
238$:	brw	301$
237$:
;	BEQL	301$			;;; RESTRICTION FOR NOW ...
					;;; IF ZERO, FILE NONCONTIG
					;;; SO FORGET IT...
	MOVL	FNXAB+XAB$L_HBK,HSTFSZ	; GET FILE SIZE. (CHECK THAT BELOW)
1785$:
; Note that /lbn and /len switches pply to 1st file only, so far.
	tstl	shdf			;doing /shadow?
	beql	1603$			;if eql no
	MOVL	EDFNA,EFAB_BLK+FAB$L_FNA	;SET UP FILENAME ADDR
	MOVB	EDFNM,EFAB_BLK+FAB$B_FNS	;AND LENGTH
	$OPEN	FAB=EFAB_BLK
	BLBC	R0,236$			; FAILURE IF FILE WON'T OPEN
; FNXAB HAS INFO ON LBN, SIZE
	MOVL	EFNXAB+XAB$L_SBN,HSTLB2	; GET HOST'S LBN
	BEQL	238$			;;; RESTRICTION FOR NOW ...
					;;; IF ZERO, FILE NONCONTIG
					;;; SO FORGET IT...
	MOVL	EFNXAB+XAB$L_HBK,HSTFS2	; GET FILE SIZE. (CHECK THAT BELOW)
;NOW set hstfsz to min of the two sizes
;(needed to make shadowing make sense...)
	cmpl	hstfsz,hstfs2		;file 1 bigger
	bleq	1603$			;if file 1 smaller or equal use that size
; note we treat them as SIGNED.
	movl	hstfs2,hstfsz		;else use file 2 size
1603$:

	TSTL	HSTFSZ			; HOST SIZE POSITIVE
	BLEQ	301$			; IF <0 OR =0 THEN ILLEGAL; BUG OUT
					; ELSE ISSUE THE REQUESTS TO GET THE
					; DEVICES...
296$:

	$CMKRNL_S -
		ROUTIN=BASHUCB,ARGLST=K_ARG
	CMPL	R0,#SS$_NORMAL				;Any errors?
	BEQL	300$					;No, skip error routine
	MOVL	R0,MESS					;Move error to message
;;;	BRW	300$
301$:
; ERROR RETURN ... CLOSE FAB & LEAVE
	$PUTMSG_S	MSGVEC=ERROR			;Pump out error message
	$CLOSE FAB=DFAB_BLK
300$:
; BE SURE WE DON'T LEAVE THE CHANNELS ASSIGNED TO THE DEVICES
; EITHER...
	tstl	cupf				;/catchup mode?
	beql	305$				;if eql, just go exit
	jsb	catchup
305$:
	$DASSGN_S CHAN=VDCHN
	tstl	repflg
	bneq	550$
	tstl	cupf				;catchup flag nonzero => only vd: chnl
	bneq	540$
	TSTL	ASDAS				; IF ZERO WE DEASSIGN
	beql	540$				; if zero, no file chnl to deass
	$DASSGN_S CHAN=DDCHN			;CLEAN UP I/O CHANNELS
	tstl	shdf
	beql	540$
	$dassgn_s chan=edchn
540$:	; skip deassign file chnl on advd/deassign
	; to avoid final error msg
	RET
550$:
; print out the filespec
	tstb	repwrk				;got any file assigned?
	beql	552$				;if not, don't emit name
	pushab	reptxt				;text descr. of filename
	calls	#1,g^lib$put_output		;emit same
552$:
	ret
advdd_exit:
	RET
; catch up the disk.
; Inputs: cupsz - size of device being used.
catchup:
	clrl	cupcur			; current block
; go thru the disk reading, then writing a block. if we get an IOSB
; error on writing, go back and retry the read/write cycle.
; errors other than 44 in iosb mean do NOT turn on dual read
; shadowing.
;  Do the catchup 16 blocks at a time (until there are less than
;  16 left; then do the last bit). This will reduce the overhead
;  of catch-up to perhaps more or less acceptable levels.
	movl	cupsz,cbks		;set blks left = all
	movl	#8192,csz		;start off with 16 blks at a time
10$:	movl	csz,r4			;byte count
	movl	cupcur,r3		;blk number
; note we use function MODIFIERS to tell VQdriver that this is catchup
; I/O.
	$qiow_s efn=#1,chan=vdchn,iosb=cupios,func=<#io$_readlblk+128>,-
		p1=dbuf,p2=r4,p3=r3	;read special
	blbs	r0,1100$
1101$:	brw	1000$
1100$:
;	blbc	r0,1000$		;exit on error
	blbc	cupios,1101$
	$qiow_s efn=#1,chan=vdchn,iosb=cupios,func=<#io$_writelblk+128>,-
		p1=dbuf,p2=r4,p3=r3	;write special
	blbc	r0,1101$		;qio$ call should be ok
	blbc	cupios,20$		;if iosb is ok, go to next blk
	cmpw	cupios,#44		;special "conflict" error?
	bneq	20$
18$:	brw	10$
;	beql	10$			;if so, go retry read
20$:
	addl2	#16,cupcur		;go to next block group
	subl2	#16,cbks		;subtract off blocks-to-do
	cmpl	cbks,#16		;more than 16 blocks left (or =)?
	bgeq	30$			;if .ge. yes, leave alone
; less than 16 blocks remain. Adjust size of transfer to fit in
; the remaining part of the disk.
	movl	cbks,r4			;blocks left
	ashl	#9,r4,r4		;shift over 9 bits to get bytes
	movl	r4,csz			;store as new byte count
30$:
	cmpl	cupcur,cupsz		;see if we hit max block
	blss	18$			;if still below max block go do next
;not that when we hit max block, we have done ALL blocks since numbering
;starts from zero.
;
; Now when we fall through, the disk is fully caught-up and can be placed
; in full read-both mode. Therefore do so.
	$cmkrnl_s routin=ucbfin
1000$:
	rsb
; entry point to set ucb$shmd to 2 on finish of copy operation.
; assumes VDUCB set up already.
	.entry	ucbfin,^m<r2,r3,r4>
	movl	vducb,r2	;get vq: ucb address
	beql	90$
	movl	#2,ucb$shmd(r2)	;set shadow mode to 2 = read/write both
90$:
	movl	#ss$_normal,r0	;return an "ok" status
	ret

;
; KERNEL ARG LIST
K_ARG:
	.LONG	3			;2 ARGS: HOST-DVC NAME, VD DVC NAME
	.ADDRESS	DEV_BUF_DESC
	.ADDRESS	VDV_BUF_DESC
	.ADDRESS	EDEV_BUF_DESC	;2ND FILE (IF PRESENT)
; BASHUCB - AREA TO MESS UP UCB WITH OUR FILE DATA
; BEWARE BEWARE BEWARE
;  runs in KERNEL mode ... HAS to be right.

	.ENTRY	BASHUCB,^M<R2,R3,R4,R5,R6,R7,R8>
; TAKEN LOOSELY FROM ZERO.MAR
	.if	ndf,vms$v5
	MOVL	G^SCH$GL_CURPCB,R4	;;; NEED OUR PCB
	.iff
	MOVL	G^CTL$GL_PCB,R4		;;; NEED OUR PCB (VMS V5)
	.endc
	JSB	G^SCH$IOLOCKW		;;; LOCK I/O DATABASE
	CLRL	HSTUCB			;;; ZERO "HOST" UCB
	tstl	cupf			;;;catchup?
	bneq	90$			;;;if neq yes, only get vd: info
	tstl	repflg
	bneq	90$			;;;no host lookup on /report
	TSTL	ASDAS			;;; IF DEASSIGN, ZERO
	BEQL	90$			;;; SO IF EQUAL SKIP LOCATE HOST UCB
	tstl	shdf
	beql	58$			;if not shadowing skip
	movl	12(AP),r1		;get file 2 desc
	jsb	g^ioc$searchdev
	blbc	r0,59$			;if we fail, scram
	movl	r1,hstuc2		;if we succeed save host UCB address for file 2
58$:
	MOVL	4(AP),R1		;;; ADDRESS DVC NAME DESCRIPTORS
	JSB	G^IOC$SEARCHDEV		;;; GET UCB ADDRESS INTO R1
	BLBS	R0,60$
59$:	BRW	BSH_XIT
60$:
;	TSTL	UCB$L_PID(R1)		;;; ENSURE DVC NOT ALLOCATED
;	BEQL	80$
;	MOVL	#SS$_DEVALLOC,R0
;	BRW	BSH_XIT
; ALLOCATED OK SINCE IT COULD JUST BE PRIVATE MOUNT...
;
80$:
	MOVL	R1,HSTUCB		;;; SAVE HOST UCB ADDRESS
	BEQL	167$			;;; ... BUT ZERO UCB ADDRESS LOOKS BAAAAD
90$:
	MOVL	8(AP),R1		;;; ADDRESS VDn NAME DESCRIPTORS
	JSB	G^IOC$SEARCHDEV		;;; GET UCB ADDRESS INTO R1
	BLBS	R0,160$
	BRW	BSH_XIT
160$:
	movl	r1,vducb		;;; store vd ucb
	movl	ucb$l_maxblock(r1),cupsz ;;;save device size
	tstl	repflg
	bneq	168$			;;;on /report don't mess ucb up
	TSTL	UCB$L_PID(R1)		;;; ENSURE DVC NOT ALLOCATED
	BEQL	180$
165$:
	MOVL	#SS$_DEVALLOC,R0
167$:	BRW	BSH_XIT
168$:	brw	455$
180$:
; BUGGER THE UCB
; ASSUMES FILE LBN AND SIZE ALREADY RECORDED
; ALSO ASSUMES THAT ZERO LBN OR SIZE MEANS THIS ENTRY NEVER CALLED.
; (REALLY ONLY WORRY ABOUT ZERO SIZE; IF WE OVERMAP A REAL DEVICE
; THEN ZERO INITIAL LBN COULD BE OK.)
;
; CHECK REF COUNT FIRST... ONLY CAN GET AWAY WITH THIS ON DEVICE
; NOBODY'S USING...
; .. fake this since device may have count messed by advd somehow
; but will be allocated if mounted.
; ... for now ...
554$:
	tstl	cupf			;;;/catch-up mode?
	beql	1893$
	brw	1892$			;;;if neq yes
1893$:	movzwl  ucb$w_refc(r1),vdsts2	;;; save status for debug
	CMPW	UCB$W_REFC(R1),#1	;;; CHECK COUNT VS 1 FOR THIS
	BGTRU	165$
;	TSTW	UCB$W_REFC(R1)		;;; IF MOUNTED DON'T TOUCH
;	BNEQ	165$			;;; IF NEQ IT'S ACCESSED...
	MOVL	HSTUCB,UCB$HUCB(R1)	;;; SAVE HOST UCB OR 0
	BNEQ	184$			;;; IF NE, OK NOW
;;; ZERO -- DEASSIGNING. FLAG VOLUME INVALID
	BICW	#UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG OFFLINE
	BICW	#UCB$M_VALID,UCB$W_STS(R1) ;;; AND INVALID
	clrb	ucb$vdcontfil(r1)	;;;clr container file name
	BRW	200$
184$:	MOVL	HSTLBN,UCB$HLBN(R1)	;;; SAVE HOST'S LBN
	MOVL	HSTFSZ,UCB$HFSZ(R1)	;;; AND FILE SIZE
	MOVL	HSTFSZ,UCB$L_MAXBLOCK(R1) ;;; (SAVE SIZE TWICE, FOR RMS
	clrl	ucb$ppid(r1)		;;;zero original PID
	movl	r4,-(sp)
	movl	hstucb,r4		;;;get host UCB
	beql	189$			;;;forget it if none
;;;must make maxbcnt and fipl match!!!
	movb	ucb$b_fipl(r4),ucb$b_fipl(r1)	;;;ensure fork levels match
	movl	ucb$l_maxbcnt(r4),ucb$l_maxbcnt(r1) ;;;store max bytes as a word
189$:
	movl	(sp)+,r4
					;;; AND QIO CHECKS, AND OUR SAFETY
					;;; ONES)
	clrl	ucb$shmd(r1)		;;;shadow mode 0 - no shadowing initial
	clrl	ucb$llbn1(r1)
	clrl	ucb$llbn2(r1)		;zero some offsets
	tstl	shdf			;;;shadowing enabled?
	beql	191$			;;;if eql no
	movl	hstuc2,ucb$hucb2(r1)	;;;store host ucb file 2
	beql	191$			;;;zero is not valid...
	movl	hstfs2,ucb$hfsz2(r1)	;;;store file size
	movl	hstlb2,ucb$hlbn2(r1)	;;;and start LBN
; now set as shadow state 1, write to both, read first only
	movl	#1,ucb$shmd(r1)		;;;set shadow mode to write both
; assume the catchup program will set this to 2.
	tstl	shd2			;;;did he say set it to 2 at first?
	beql	191$
	movl	#2,ucb$shmd(r1)		;;;if so, do so. useful for initial setup.
191$:
	MOVL	HSTFSZ,R0		;;; GET HOST SIZE
	ASHL	#-6,R0,R0		;;; GET # CYLINDERS IN SIZE NOW
;Set default geometry as 1 track/cylinder, 64 sectors/track, and
; as many cylinders as needed for device size. We use this if the
; /SEC64 switch is given. Otherwise we check to see if the container
; file is size same as some known disk and adopt its' geometry, or
; if that fails use either a 1 sector/trk 1 trk/cyl n cylinder
; geometry for small disks (under 65000 blocks), or a 32 sect/trk
; 32 trk/cyl n cylinder geometry for large disks.
;
;  *** Where one gets over 2 billion blocks and sets the sign bit
;  *** in the blocks count, this code will break due to not
;  *** ensuring sign extension is avoided. Since this corresponds
;  *** to a single disk of 1 terabyte, it seems unlikely to cause
;  *** difficulties for a while. The 64 sector geometry breaks down
;  *** at 64*65536 blocks (2 GB) and the 32*32*n geometry breaks
;  *** down at 1024 * 65536 blocks. These seem high enough not to 
;  *** worry about for now. If they become a problem, play with
;  *** geometry!!!
;
	MOVW	R0,UCB$W_CYLINDERS(R1)	;;; SAVE IN UCB FOR REST OF VMS
	movl	r0,vdcyl		;;; store cylinders for debug
	movb	#64,ucb$b_sectors(r1)	;;;init sectors to 64 always
	movb	#1,ucb$b_tracks(r1)	;number of tracks/cyl=1
	tstl	vsec64		;;;did user say he needs 64 sector geometry?
	beql	6843$			;;;if eql no, do tests
	brw	6841$			;;;if neql leave geometry alone...
6843$:
	tstl	vsec32			;;;did he ask for 32 sect/32 trk geom?
	bneq	687$			;;; if sect32 asked for, do default md:
				;;; geometry, 1 by 1 by n for small disks, 32 by 32
				;;; by n for big ones.
;	bneq	685$			;;;if so (neq) skip geom table.
	movl	r2,-(sp)		;;;Need a register to point to geoms
	movab	geoms,r2		;;;so we can test sizes
; Check for file sizes of known disks and set geometry of those
; disks IF we match.
686$:	tstl	(r2)			;;;end of table?
	beql	687$			;;;if eql yes, skip out
	cmpl	hstfsz,(r2)		;;;above min size this disk type?
	blss	688$			;;;if too small, we're done so exit the loop
	cmpl	hstfsz,4(r2)		;;;see if too big
	bgtr	688$			;;;if too big, look at next
; got a match. Now fill in geometry
; (r2) = lo size (must be at LEAST as large as device)
; 4(r4) = hi size lim
; 8(r2) = # blks on device
; 12(r2) = cyl
; 14(r2) = trk
; 15(r2) = cyl
	movl	8(r2),ucb$l_maxblock(r1)	;Set up maximum block
	movw	12(r2),ucb$w_cylinders(r1)	;number of cylinders
	movb	14(r2),ucb$b_tracks(r1)		;number of tracks/cyl
	movb	15(r2),ucb$b_sectors(r1)	;number sectors/track
	movl	(sp)+,r2			;restore our register
	brb	684$				;exit, we got our device
; Notice we must pass the "small device" test since some devices have
; less than 65000 blocks. We won't emulate device TYPE exactly, but will
; emulate device GEOMETRY with this logic.
688$:;	addl2	#16,r2				;pass to next entry of geoms table
	cmpl	(r2)+,(r2)+
	cmpl	(r2)+,(r2)+
	brb	686$				;go check for next device or end
687$:
	movl	(sp)+,r2		;;;restore reg
; test for small files
	cmpl	hstfsz,#65530		;"small" disks?
	bgtr	685$
	movw	hstfsz,ucb$w_cylinders(r1)	;yep...save size in cyl
	movb	#1,ucb$b_sectors(r1)		;and set 1 sector/trk
	movb	#1,ucb$b_tracks(r1)		;and 1 track/cyl (should be ok already)
	brw	684$				;done with geometry
685$:
; Add other checks here
; Make geometry like mdan: disks, that is, 32 sectors and 32 tracks/cyl.
; unless /sec64 switch was set. This facilitates random use as a switch
; over from md: type disks. Note 32 * 32 = 1024
	MOVL	HSTFSZ,R0		;;; GET HOST SIZE
	ASHL	#-10,R0,R0		;;; GET # CYLINDERS IN SIZE NOW as #/1024
	MOVW	R0,UCB$W_CYLINDERS(R1)	;;; SAVE IN UCB FOR REST OF VMS
	bicl2	#1023,ucb$l_maxblock(r1)	;ensure even number of cylinders
	movb	#32,ucb$b_sectors(r1)	;set 32 sectors/track
	movb	#32,ucb$b_tracks(r1)	;and 32 tracks/cylinder
	brb	684$				;This is the "large disk" default
;						;unless /sec64 sets 64 sect geom.
6841$:
; If here, we are using the 64 sector/track geometry
	bicl2	#63,ucb$l_maxblock(r1)		;make disk size a multiple of sect/trk
684$:
	pushl	r0
	pushl	r1
	pushl	r2
; Fill in filename as 1st 79 chars of what user sent us
	movab	ddfnmd,r0		;data address
	movl	#79,r2			;copy 79 bytes
	addl	#ucb$vdcontfil,r1	;point at ucb offset
457$:	movb	(r0)+,(r1)+
	sobgtr	r2,457$			;copy the data
	clrb	(r0)+			;null terminate
	popl	r2
	popl	r1
	popl	r0
	BISW	#UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG ONLINE NOW
	BISW	#UCB$M_VALID,UCB$W_STS(R1) ;;; AND VOL VALID
	movzwl	ucb$w_sts(r1),vdsts	;;; save VD status
;;; THAT'S IT... SHOULD BE OK NOW.
	brb	200$
455$:
; copy vd: stored name into prog area
	pushl	r1
	pushl	r2
	movab	repwrk,r0		;;;get report area
	movl	#80,r2			;;;80 bytes max
	addl2	#ucb$vdcontfil,r1	;;;point at in area
456$:	movb	(r1)+,(r0)+
	beql	458$			;;;on null terminator stop copy
					;;;(keeps old name junk from reappearing)
	sobgtr	r2,456$			;;;copy the data
458$:
	popl	r2
	popl	r1
200$:
	MOVL	#SS$_NORMAL,R0
	brb	bsh_xit
1892$:	tstl	ucb$hucb2(r1)		;;;ensure 2nd ucb exists
	beql	1894$			;;;if eql clear cupf
	movl	#1,ucb$shmd(r1)		;;;set read 1 write both mode
	brb	200$			;;;set valid code and return
1894$:	clrl	cupf			;;;abort copy operation
	movl	#46,r0			;;;set error code
BSH_XIT:
	PUSHL	R0
	JSB	G^SCH$IOUNLOCK		;;; UNLOCK I/O DATABASE (DROP IPL)
	POPL	R0			;;; REMEMBER R0
	RET	;;; BACK TO USER MODE NOW
	.END ADVDD
