.TITLE ADVD - VAX/VMS VIRT DISK DRIVER ASSIGN/DEASSIGN .IDENT 'V01-000' ; ; FACILITY: ; ; ASSIGN/DEASSIGN VIRTUAL DISK TASK THAT WORKS WITH VDDRIVER ; ESTABLISHES CONNECTION (OR BREAKS IT) BETWEEN A LUN OF ; VD: AND A CONTIGUOUS FILE. ; ; N.B. UNTESTED!!! USE AT YOUR OWN RISK. ; ; Command format: ; VDCTL/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... ; 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... ; ; ; AUTHOR: ; ; G. EVERHART ;-- .PAGE .SBTTL EXTERNAL AND LOCAL DEFINITIONS .LIBRARY /SYS$SHARE:LIB/ ; ; EXTERNAL SYMBOLS ; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK $DCDEF ;DEFINE DEVICE CLASS $DDBDEF ;DEFINE DEVICE DATA BLOCK $DEVDEF ;DEFINE DEVICE CHARACTERISTICS $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE $EMBDEF ;DEFINE ERROR MESSAGE BUFFER $IDBDEF ;DEFINE INTERRUPT DATA BLOCK $IODEF ;DEFINE I/O FUNCTION CODES $IRPDEF ;DEFINE I/O REQUEST PACKET $PRDEF ;DEFINE PROCESSOR REGISTERS $SCSDEF $SBDEF $STSDEF $STSDEF ; Symbols for returned status. $DVIDEF ; Symbols for $GETDVI service. $DCDEF ; Symbols for device type. $SSDEF ;DEFINE SYSTEM STATUS CODES $UCBDEF ;DEFINE UNIT CONTROL BLOCK $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK ; ; 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 ; $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... ; USE THESE FIELDS TO HOLD OUR 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 ;UCB$HUCB=. $DEF UCB$W_DY_DB .BLKW 1 ;UCB ADDRESS OF HOST DRIVER $DEF UCB$W_DY_DPN .BLKW 1 ;(LONGWORD) ;UCB$HLBN=. $DEF UCB$L_DY_DPR .BLKL 1 ;START LBN OF HOST CONTIG FILE ;UCB$HFSZ=. ; HOST FILE SIZE IN BLKS (RANGE CHECK) $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. ; RY_EXTENDED_STATUS_LENGTH = .-UCB$Q_DY_EXTENDED_STATUS $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$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 $FIBDEF ; Symbols for file information block. $IODEF ; Symbols for QIO functions. $DVIDEF ; Symbols for $GETDVI calls. $TPADEF ; Symbols for LIB$TPARSE calls. ; 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/ $ATRDEF $FABDEF $FATDEF $FIBDEF $IODEF $NAMDEF $RMSDEF $XABDEF .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 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" .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 ; ; 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. ; ASDSC: .ASCID /ASSIGN/ DASDSC: .ASCID /DEASSIGN/ P1DSC: .ASCID /UNIT/ P2DSC: .ASCID /FNAM/ .EVEN ASDAS: .LONG 0 ;DEFAULT DEASSIGN ; ; 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 ; ; .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG .ENTRY ADVDD,^M 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 ; ; IF "DEASSIGN" WE DON'T NEED 2ND ARG... SEE... ; 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$ $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$: ; ; 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$ ; 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) .if ndf,phy$io 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 .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 BRW 300$ 301$: ; ERROR RETURN ... CLOSE FAB & LEAVE $CLOSE FAB=DFAB_BLK 300$: ; BE SURE WE DON'T LEAVE THE CHANNELS ASSIGNED TO THE DEVICES ; EITHER... $DASSGN_S CHAN=VDCHN TSTL ASDAS ; IF ZERO WE DEASSIGN beql 540$ ; if zero, no file chnl to deassign $DASSGN_S CHAN=DDCHN ;CLEAN UP I/O CHANNELS 540$: ; skip deassign file chnl on advd/deassign ; to avoid final error msg RET advdd_exit: RET ; ; 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 ; 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 MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASE CLRL HSTUCB ;;; ZERO "HOST" UCB movl #1,vdprog ;;; got to start 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 UCB$L_PID(R1) ;;; ENSURE DVC NOT ALLOCATED BEQL 180$ 165$: MOVL #SS$_DEVALLOC,R0 167$: BRW BSH_XIT 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 ... 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 #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 BICW #UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG OFFLINE BICW #UCB$M_VALID,UCB$W_STS(R1) ;;; AND INVALID 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 movl #65535,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 MOVW R0,UCB$W_CYLINDERS(R1) ;;; SAVE IN UCB FOR REST OF VMS movl r0,vdcyl ;;; store cylinders for debug movl #8,vdprog 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. 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