.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=,XAB=FNXAB,FAC=,DNM= ; 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=,XAB=EFNXAB,FAC=,DNM= ; 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 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 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 ; 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