EVAX = 1 ALPHA = 1 BIGPAGE = 1 ADDRESSBITS = 32 .TITLE ASNVD - 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. Checks that this IS a VD unit. ; ; 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. ; ; 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 ; $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 ;v4 def end of ucb ; USE THESE FIELDS TO HOLD OUR LOCAL DATA FOR VIRT DISK. $DEF UCB$W_VD_WPS .BLKW 1 ;Words per sector. $DEF UCB$W_VD_CS .BLKW 1 ;CONTROL STATUS REGISTER $DEF UCB$W_VD_DB .BLKW 1 ;UCB ADDRESS OF HOST DRIVER $DEF UCB$W_VD_DPN .BLKW 1 ;(LONGWORD) $DEF UCB$L_VD_DPR .BLKL 1 ;START LBN OF HOST CONTIG FILE $DEF UCB$L_VD_FMPR .BLKL 1 ; $DEF UCB$L_VD_PMPR .BLKL 1 ;PREVIOUS MAP REGISTER $DEF UCB$B_VD_ER .BLKB 1 ;SPECIAL ERROR REGISTER .BLKB 1 ;Reserved. $DEF UCB$B_VD_LCT .BLKB 1 ;LOOP COUNTER $DEF UCB$B_VD_XBA .BLKB 1 ;BUS ADDRESS EXTENSION BITS $DEF UCB$W_VD_PWC .BLKW 1 ;PARTIAL WORD COUNT $DEF UCB$W_VD_SBA .BLKW 1 ;SAVED BUFFER ADDRESS $DEF UCB$L_VD_XFER .BLKL 1 ;TRANSFER FUNCTION CSR BITS $DEF UCB$L_VD_LMEDIA .BLKL 1 ;LOGICAL MEDIA ADDRESS $DEF UCB$Q_VD_EXTENDED_STATUS ; Area into which we do READ ERROR .BLKQ 1 ; REGISTER command. $DEF UCB$Q_VD_SVAPTETMP ; Area in which we save UCB fields - .BLKQ 1 ; SVAPTE, BOFF, and BCNT. $DEF UCB$L_VD_MAPREGTMP ; Area in which we save CRB fields - .BLKL 1 ; MAPREG, NUMREG, and DATAPATH. $DEF UCB$L_VD_SAVECS .BLKL 1 ; Area in which we save CS and DB regs. ; Add our stuff at the end to ensure we don't mess some fields up that some ; areas of VMS may want. $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 OF ORIGINAL PROCESS FROM IRQ BLK ; NOTE: It is important to ENSURE that we never clobber IRP$L_PID twice! ; therefore, adopt convention that UCB$PPID is cleared whenever we put ; back the old PID value in the IRP. Only clobber the PID where ; UCB$PPID is zero!!! $DEF UCB$stats .BLKL 1 ;STATUS CODE SAVE AREA $DEF UCB$OBCT .BLKL 1 ;STORE FOR IRP$L_OBCNT too $def ucb$lmedia .blkl 1 ;storage for IRP$L_MEDIA $def ucb$owind .blkl 1 ; store irp$l_wind... $def ucb$osegv .blkl 1 ; and irp$l_segvbn ; 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 ; we send to the host driver to look like logical I/O is being ; done and save the real function 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. ; define extra fork blks to try to avoid double forking possibilities $def ucb$l_vd_host_descr .blkl 2 ; char string descr $def ucb$vdcontfil .blkb 80 ; $def ucb$l_sanity .blkl 1 ;sanity chk /GCEF/ ascii if vddriver $DEF UCB$K_VD_LEN .BLKW 1 ;LENGTH OF UCB $def ucb$k_vd_leng ;UCB$K_VD_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/ .globl k_arg,dev_buf_desc,vdv_buf_desc .globl iostatus,dev_buf,vdv_buf,pid,dev_item_list .globl dev_class .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 DFAB_BLK: $FAB FNM=,XAB=FNXAB,FAC=,DNM= RDFAB_BLK: $FAB FNM=,XAB=FNXAB,FAC=,DNM= sanasc: .ascii /GCEF/ ;sanity check value if VDdriver ; 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 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 = . - 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" .globl vpid,vdv_item_list,vdv_class,wrk,vdfnm,vdfnmd .globl wrkdat,wrkstr,ddfnm,ddfnmd .globl ddchn,vdchn .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 .align long 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 .align long .globl repwrk 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/ geodsc: .ascid /GEOM/ ; hex geometry override starting at longword ;ucb$b_sectors (sect, trk, cyl) rodsc: .ascid /READONLY/ dvcdsc: .ascid /DEVICE/ .EVEN .align long geoflg: .long 0 ;flag saw /geom geoval: .long 0 ;geometry value roflg: .long 0 ;read-only flag dvcflg: .long 0 ;/device seen if 1 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 dcl_cmd: .ASCID /ASNVDM6 / cmdbuff: .BLKB 256 ;This buffer must be contig with dcl_cmd .ALIGN LONG cmdline: .WORD 0 .BYTE DSC$K_DTYPE_T .BYTE DSC$K_CLASS_D .ADDRESS 0 .EXTRN ASNVD_CLD .EVEN ; ; 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 .globl vducb,vdprog,vdsts,vdsts2,bashucb,hstucb,hstlbn,hstfsz .globl vdcyl,asdas,repwrk,repflg,geoms 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 (no typedef'd) 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 311200, 311220, 311200, 1221, 15, 17 dt$_rd54;rd54 GeoTbl 340670, 340720, 340670, 815, 19, 22 dt$_rp06;RP06 GeoTbl 400176, 400200, 400176, 2382, 4, 42 dt$_ra60;ra60 GeoTbl 409792, 409850, 409792,1348, 8, 38 dt$_rz24;RZ24 GeoTbl 500384, 500420, 500384, 823, 19, 32 dt$_rm05;RM05 GeoTbl 832527, 832550, 832527,1492, 9, 62 dt$_rz25;rz25 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 1241848,1241860,1241848,51744, 6, 4 dt$_rrd42;RRD42 GeoTbl 1954050,1954100,1954050,1835, 15, 71 dt$_rz57;RZ57 GeoTbl 2050860,2050890,2050860,2570, 14, 57 dt$_fd1;rz26 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= ; .CALL_ENTRY Home_Args=True,Preserve= .iff .ENTRY ADVDD,^M .endc ; ; Allow foreign command calling now PUSHAQ CMDLINE ;Get the foreign command line CALLS #1,G^LIB$GET_FOREIGN ON_ERR ADVDD_EXIT PUSHAQ CMDLINE PUSHAQ DCL_CMD PUSHAQ CMDLINE CALLS #3,G^STR$CONCAT PUSHAL ASNVD_CLD PUSHAQ CMDLINE CALLS #2,G^CLI$DCL_PARSE ON_ERR ADVDD_EXIT clrl geoflg ;initially no /geom seen clrl repflg ;say not reporting initially clrl roflg movab repwrk,r0 ;clear work string initially movl #80,r1 1$: clrb (r0)+ sobgtr r1,1$ ;zero the array out pushab geodsc ;/geom:nnn seen? calls #1,g^cli$present cmpl r0,#cli$_present ;see it? bneq 2$ ;if neq no incl geodsc pushab wrk ;area for ret len pushab wrkstr ;scratch string pushab geodsc ;/geom:nnnn val calls #3,g^cli$get_value ;get value as string on_err advdd_exit pushl #17 ;ignore blanks pushl #4 ;4 bytes pushab geoval ;geom value pushab wrkstr ;where string is calls #4,g^ots$cvt_tu_l ;convert to binary on_err advdd_exit 2$: pushab rodsc ;/readonly? calls #1,g^cli$present cmpl r0,#cli$_present bneq 42$ ;if neq no incl roflg 42$: clrl dvcflg ;no /device yet. 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 dvcdsc ;check for /device calls #1,g^cli$present ;see if /sec64 specified cmpl r0,#cli$_present bneq 525$ incl dvcflg ;say /device seen. ; (note /device overrides lots of stuff!) 525$: 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$: clrl lbnn ;initially set lbn=0 tstl dvcflg ; /device spec'd? beql 1525$ ; if not check /lbn movl #10000,lenn ; (dummy length initially) ; (fixed up in bashucb) brw 2525$ ; then set len, lbn initially 1525$: 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 2525$: ; 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. 9525$: brw 296$ 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 9525$ tstl repflg bneq 9525$ ;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 MOVL DDFNA,RDFAB_BLK+FAB$L_FNA ;SET UP FILENAME ADDR MOVB DDFNM,RDFAB_BLK+FAB$B_FNS ;AND LENGTH tstl roflg ;read-only mode? bneq 3521$ ;if yes branch $OPEN FAB=DFAB_BLK brb 3522$ 3521$: $open fab=rdfab_blk 3522$: 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 $CLOSE FAB=DFAB_BLK 300$: ; 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= .iff .ENTRY BASHUCB,^M .endc ; 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 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 .if ndf,evax JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 .iff call_searchdev .endc 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,r11 ; keep a copy of host ucb in r11 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 .if ndf,evax JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 .iff call_searchdev .endc BLBS R0,160$ 159$: BRW BSH_XIT 160$: movl r1,vducb ;;; store vd ucb cmpl sanasc,ucb$l_sanity(r1) ;is this VDdriver? bneq 165$ ; if not leave before we do damage 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$: .if ndf,evax movzwl ucb$w_refc(r1),vdsts2 ;;; save status for debug CMPW UCB$W_REFC(R1),#1 ;;; CHECK COUNT VS 1 FOR THIS BGTRU 165$ .iff movl ucb$l_refc(r1),vdsts2 ;;; save status for debug CMPL UCB$l_REFC(R1),#1 ;;; CHECK COUNT VS 1 FOR THIS BGTRU 165$ .endc ; TSTW UCB$W_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 .if ndf,evax BICW #UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG OFFLINE BICW #UCB$M_VALID,UCB$W_STS(R1) ;;; AND INVALID .iff BICL #UCB$M_ONLINE,UCB$L_STS(R1) ;;; FLAG OFFLINE BICL #UCB$M_VALID,UCB$L_STS(R1) ;;; AND INVALID .endc clrb ucb$vdcontfil(r1) ;;;clr container file name BRW 200$ ; /device switch gives an exact copy of the host device geometry ; and size, and also device type, fork level IPL (which for disks is ; always 8 anyhow), and maxbcnt (which can vary). 184$: tstl dvcflg ; See /device?? bneq 5525$ brw 3525$ ;if eql no... 5525$: movl ucb$l_maxblock(r11),lenn movl lenn,hstfsz ;store size movl ucb$l_maxblock(r11),ucb$l_maxblock(r1) ;copy size clrl ucb$hlbn(r1) ;start lbn=0 ;copy geom next movw ucb$w_cylinders(r11),ucb$w_cylinders(r1) movb ucb$b_tracks(r11),ucb$b_tracks(r1) movb ucb$b_sectors(r11),ucb$b_sectors(r1) movb ucb$b_devtype(r11),ucb$b_devtype(r1) ;set type too. movl ucb$l_maxbcnt(r11),ucb$l_maxbcnt(r1) ;;;store max bytes as a word .if ndf,evax movb ucb$b_fipl(r11),ucb$b_fipl(r1) ;;;ensure fork levels match .endc brw 4525$ 3525$: tstl geoflg ;/geom:nnn there? beql 7526$ ;if 0, no movl geoval,ucb$b_sectors(r1) ;fill in long with sec/trk/cyl 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 ;;;must make maxbcnt and fipl match!!! .if ndf,evax movb ucb$b_fipl(r11),ucb$b_fipl(r1) ;;;ensure fork levels match .endc movl ucb$l_maxbcnt(r11),ucb$l_maxbcnt(r1) ;;;store max bytes as a word brw 4525$ 7526$: 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 ;;;must make maxbcnt and fipl match!!! .if ndf,evax movb ucb$b_fipl(r11),ucb$b_fipl(r1) ;;;ensure fork levels match .endc movl ucb$l_maxbcnt(r11),ucb$l_maxbcnt(r1) ;;;store max bytes as a word 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 ; The geotbl table in this file contains a set of known device ; geometries sorted by device size. Use device size to pick the closest ; geometry (so that, for instance, a container file/device of ; 1008000 blocks, up to 1008500 blocks in this case, is treated as ; the 1008000 block RP07 device. This table is not exhaustive unfortunately ; even of DEC devices, but covers many of them and can be extended as desired ; to handle more. If the geometry is not found in the geotbl table, ; and if the disk has <65530 blocks, it is given a "small disk" geometry ; of 1 trk by 1 sector by n cylinders (n=#blks). Otherwise it is given ; a geometry of either 64 sectors, 1 track, n cylinders, or 32 ; sectors, 32 tracks, n cylinders, where n is set to be such that the ; total size is less than or equal to the container file/device. The /sec32 ; and /sec64 switches control this; default is /sec64 if the disk is small ; enough, /sec32 otherwise. ; ; GEOTBL FORMAT: ; (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 4525$: 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 tstl roflg ;user say readonly?? beql 5455$ bisl #dev$m_swl,ucb$l_devchar(r1) ;set readonly 5455$: .if ndf,evax 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 .iff 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 .endc ;;; 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