;
; This is the ALPHA (previously called "EVAX") version of ARCH_DEFS.MAR,
; which contains architectural definitions for compiling VMS sources
; for VAX and ALPHA systems.
;
EVAX = 1
ALPHA = 1
BIGPAGE = 1
ADDRESSBITS = 32
	.TITLE	ADVD - VAX/VMS VIRT DISK DRIVER ASSIGN/DEASSIGN
	.IDENT	'V03-001'
;
; FACILITY:
; 
; ASSIGN/DEASSIGN VIRTUAL DISK TASK THAT WORKS WITH VDDRIVER
;  ESTABLISHES CONNECTION (OR BREAKS IT) BETWEEN A LUN OF
;  VD: AND A CONTIGUOUS FILE.
;
; 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 has an option to report the assigned
; file so associated. (/report)
;
; 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.
; Also added is RX50 recognition. The RX50 has an unusual physical
; structure (1 cylinder, 80 trks/cyl and 10 sect/trk) considering
; the actual layout. The geotbl entry reflects the structure as seen
; by show device/full on VMS. Other structures are added by GEOTBL
; macros in the table; most disk structures I could lay my hands
; on are included. The /sec32 structure is provided to give
; compatible handling with the Bear Systems virtual disk, which
; uses 32 tracks/cyl and 32 sector/track for large unrecognized
; disks. We used the Bear driver on our 750 and I needed to be
; able to get at the virtual disks compatibly using vddriver.
;
;
;With version 3 is added facility to use VD: 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 VD:
; 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 ASNVD
; 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 VD: driver, or permit partitioning of physical disks
; without the overhead of a Files-11 index structure on the disk.
; (the code added will probably be moved to ASNVQ also, where such
; disk assignment has other uses also.)
;
; Command format:
; ADVD/switches VDn: file
;  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...
;   Device geometry is needed by INIT and MOUNT, though vddriver
; doesn't care. Therefore a "sensible" geometry is always generated,
; and device size is always an integral number of cylinders. Vddriver
; doesn't support physical I/O really, but init and mount use the
; physical structure to figure where to put home blocks or look for
; them.
;
; 
; 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 /ALPHA$LIBRARY:LIB/
; 
; EXTERNAL SYMBOLS
; 

	$dyndef
	$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 VDDRIVER. Don't
; change one without changing the other to match it!!!
;	G. Everhart 9/5/1986
; 
; 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
$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
	.align long
DEFAULT_DEVICE:
	.ASCID	/SYS$DISK/
	.ALIGN LONG
;
; KERNEL ARG LIST
K_ARG:
	.LONG	2			;2 ARGS: HOST-DVC NAME, VD DVC NAME
	.ADDRESS	DEV_BUF_DESC
	.ADDRESS	VDV_BUF_DESC
;	.ADDRESS	DDFNM
;	.ADDRESS	VDFNM


	.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_SIZ = 40

DEV_BUF_DESC:			; Descriptor pointing to device name.
	.LONG	 DEV_BUF_SIZ
	.ADDRESS DEV_BUF

PID:				; Owner of device (if any).
	.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.

DEV_CLASS:
	.LONG	1
;**
VDV_BUF:			; Buffer to hold VDVice name.
	.BLKB	40
VDV_BUF_SIZ = 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
; 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
	.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 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
;
; 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/
LBNDSC:	.ASCID	/LBN/
LENDSC:	.ASCID	/LENGTH/
	.EVEN
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
; 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,typ
	.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
	.long	typ	;drive type (for ucb$b_devtype)
	.endm
; Geoms MUST be in increasing order of size.
Geoms:
;		losiz	hisiz	blks	cyl	trk	sect	typ	id
;	(can't do rx01...blks not 512 bytes long, but 128.)
;	GeoTbl	494,	494,	494,	77,	1,	26	dt$_rx01;rx01
	GeoTbl	512,	512,	512,	1,	4,	128	dt$_tu58;tu58
	GeoTbl	576,	576,	576,	1,	4,	144	dt$_tu56;tu56 (old DECtape)
	Geotbl  800,	805,	800,	1,	80,	10	dt$_rx50;rx50
	GeoTbl	1440,	1440,	1440,	80,	2,	9	dt$_rx23s;rx23s loden
	GeoTbl	1976,	1976,	1976,	76,	1,	26	dt$_rx04;rx04
	GeoTbl	2880,	2880,	2880,	80,	2,	18	dt$_rx23s;rx23s hidens 
	Geotbl	4800,	4810,	4800,	200,	2,	12	dt$_fd1;RK05
	Geotbl	10240,	10250,	10240,	256,	2,	40	dt$_rl01;RL01 (sect=256 bytes)
	GeoTbl	15000,	15002,	15000,	15000,	1,	1	dt$_rd51;my virt dsk
	Geotbl	20480,	20500,	20480,	512,	2,	40	dt$_rl02;RL02 (Sect=256 bytes)
	Geotbl	27126,	27150,	27126,	411,	3,	22	dt$_rk06;RK06
	GeoTbl	53790,	53830,	53790,	815,	3,	22	dt$_rk07;RK07
	GeoTbl	131680,	131700,	131680,	823,	5,	32	dt$_rm03;RM03
	GeoTbl	138672,	138690,	138672,	1024,	8,	17	dt$_rd53;RD53
	GeoTbl	171798,	171850,	171798,	411,	19,	22	dt$_rp04;RP04
	GeoTbl	242606,	242650,	242606,	559,	14,	31	dt$_rm80;RM80 (or RB80)
	GeoTbl	251328,	251330,	251328,	561,	14,	32	dt$_rb80;rb80
	GeoTbl	340670,	340720,	340670,	815,	19,	22	dt$_rp06;RP06
        GeoTbl  409792, 409850, 409792,1348,    8,      38      dt$_rz24;RZ24
	GeoTbl	500384,	500420,	500384,	823,	19,	32	dt$_rm05;RM05
	GeoTbl	891072,	891110,	891072,	1248,	14,	51	dt$_ra81;RA81
	GeoTbl	1008000,1008500,1008000,630,	32,	50	dt$_rp07;RP07
	GeoTbl	1216665,1216700,1216665,1423,	15,	57	dt$_ra82;RA82
        GeoTbl  1954050,1954100,1954050,1835,   15,     71      dt$_rz57;RZ57
        GeoTbl  2376153,2376200,2376153,2649,   13,     69      dt$_ra90;RA90
	.Long	0,0,0,0		;list terminator
;
;
;

	.PSECT	ADVDD_CODE,RD,NOWRT,EXE,LONG
.if	DF,EVAX
ADVDD::
	.CALL_ENTRY Preserve=<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
;	.CALL_ENTRY Home_Args=True,Preserve=<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
.iff
	.ENTRY	ADVDD,^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
.endc
	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

	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$:
	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	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

	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
	BRB	DAS2
DAS1:	CLRL	ASDAS			; FLAG /DEAS
DAS2:

	TSTL	ASDAS			; IF 0, DEASSIGNING SO NO CHNL FOR HOST
					; FILE
	BEQL	290$
	tstl	repflg
	bneq	290$			;/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$:
290$:
; 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$:
	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$:
;
; 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	ASDAS			; IF ZERO WE DEASSIGN
	BEQL	296$
	tstl	repflg
	bneq	296$			;forget file open if /report only
; 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
	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
	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$:
	.if	ndf,phy$io
	tstl	vsec64
	beql	784$
	BICL2	#63,HSTFSZ		;;;MAKE A MULTIPLE OF 64 BLKS
;;; As long as the driver doesn't do physical I/O we can omit this...
;;; except INIT seems unhappy then
	brb	785$
784$:
	cmpl	hstfsz,#65530		;big disk?
	blss	785$			;if not leave size alone.
;	bicl2	#31,hstfsz		;else make granular to 32 sectors anyhow
785$:
	.endc
;;;HAS TO BE A MULTIPLE OF 64 BLKS DUE TO FAKED-OUT PHYSICAL DRIVE
;;; STRUCTURE OF 64 SECTORS/TRACK, 1 TRACK/CYL, NNN CYLINDERS...
	TSTL	HSTFSZ			; HOST SIZE POSITIVE
	BLSS	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
300$:
	$CLOSE FAB=DFAB_BLK
; BE SURE WE DON'T LEAVE THE CHANNELS ASSIGNED TO THE DEVICES
; EITHER...
	$DASSGN_S CHAN=VDCHN
	tstl	repflg
	bneq	550$
	TSTL	ASDAS				; IF ZERO WE DEASSIGN
	beql	540$				; if zero, no file chnl to deass
	$DASSGN_S CHAN=DDCHN			;CLEAN UP I/O CHANNELS
540$:	; skip deassign file chnl on advd/deassign
	; to avoid final error msg
	movl	#1,r0
	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$:
	movl	#1,r0
	ret
advdd_exit:
	RET

; BASHUCB - AREA TO MESS UP UCB WITH OUR FILE DATA
; BEWARE BEWARE BEWARE
;  runs in KERNEL mode ... HAS to be right.

.if	Df, EVAX
BASHUCB::
	.Call_Entry Home_Args=True,Max_Args=2,Preserve=<R2,R3,R4,R5,R6,R7,R8>
.iff
	.ENTRY	BASHUCB,^M<R2,R3,R4,R5,R6,R7,R8>
.endc
; TAKEN LOOSELY FROM ZERO.MAR
	MOVL	G^CTL$GL_PCB,R4		;;; NEED OUR PCB (VMS V5)
	JSB	G^SCH$IOLOCKW		;;; LOCK I/O DATABASE
	CLRL	HSTUCB			;;; ZERO "HOST" UCB
	movl	#1,vdprog		;;; got to start
	tstl	repflg
	bneq	90$			;;;no host lookup on /report
	TSTL	ASDAS			;;; IF DEASSIGN, ZERO
	BEQL	90$			;;; SO IF EQUAL SKIP LOCATE HOST UCB
	MOVL	4(AP),R1		;;; ADDRESS DVC NAME DESCRIPTORS
	JSB	G^IOC$SEARCHDEV		;;; GET UCB ADDRESS INTO R1
	BLBS	R0,60$
	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	#2,vdprog		;;; got host ucb ok
	MOVL	R1,HSTUCB		;;; SAVE HOST UCB ADDRESS
	BEQL	167$			;;; ... BUT ZERO UCB ADDRESS LOOKS BAAAAD
90$:
	MOVL	8(AP),R1		;;; ADDRESS VDn NAME DESCRIPTORS
	movl	#3,vdprog		;;; got vdn: descriptor
	JSB	G^IOC$SEARCHDEV		;;; GET UCB ADDRESS INTO R1
	BLBS	R0,160$
	BRW	BSH_XIT
160$:
	movl	r1,vducb		;;; store vd ucb
	movl	#4,vdprog		;;; got vd ucb
	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$:
	movl	#5,vdprog		;;; not allocated yet
; 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$:
	movl  ucb$l_refc(r1),vdsts2	;;; save status for debug
	CMPL	UCB$L_REFC(R1),#1	;;; CHECK COUNT VS 1 FOR THIS
	BGTRU	165$
;	TSTW	UCB$L_REFC(R1)		;;; IF MOUNTED DON'T TOUCH
;	BNEQ	165$			;;; IF NEQ IT'S ACCESSED...
	movl	#6,vdprog		;;; not mounted either
	MOVL	HSTUCB,UCB$HUCB(R1)	;;; SAVE HOST UCB OR 0
	BNEQ	184$			;;; IF NE, OK NOW
;;; ZERO -- DEASSIGNING. FLAG VOLUME INVALID
	BICL	#UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG OFFLINE
	BICL	#UCB$M_VALID,UCB$L_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
	movl	#7,vdprog		;;; filled in stuff
					;;; AND QIO CHECKS, AND OUR SAFETY
					;;; ONES)
	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?
; get md: geometry if /sec32 spec'd.
; was bneq 685$
	bneq	3687$			;;;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
; 16(r2) = type
	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
	movb	16(r2),ucb$b_devtype(r1)	;set type too.
	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	#20,r2				;pass to next entry of geoms table
	cmpl	(r2)+,(r2)+
	cmpl	(r2)+,(r2)+
	tstl	(r2)+
	brb	686$				;go check for next device or end
687$:
	movl	(sp)+,r2		;;;restore reg
3687$:
; 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$:
	movl	#8,vdprog
	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
	BISL	#UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG ONLINE NOW
	BISL	#UCB$M_VALID,UCB$L_STS(R1) ;;; AND VOL VALID
	movl	ucb$l_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
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
