.TITLE FDUnjam - VAX/VMS VIRT DISK Host Process (memory disk) .IDENT 'V01-001' ;$$xdt=1 ; ; FACILITY: ; ; Acts as storage and also host process for simplest case of ; virtual disk implemented with FDDRV: a memory disk, using this ; process' virtual memory to simulate a disk. ; This version of the "host" actually will ONLY attempt to "unjam" ; a stuck FD: drive. It will do this by trying to ; 1. Put the fd: unit online ; 2. Issue the "terminate-IO" call to it to complete the I/O ; 3. Issue a disconnect-fd qio to take the fd: unit offline again. ; ; ; Command format: ; FDHost/switches VDn: ; 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. ; FDHOST/CLEAR will zero the ref. count only...nothing more. ; Note deassign normally will NOT be via command (I don't see how a ; command could ever be read) but vie exit AST. ; ; Note: define VMS$V5 to build for Version 5.x of VMS. ; ; ; 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 $PCBDEF ;DEFINE PCB OFFSETS $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 ; ; No need for direct UCB access here; this is done via the driver ; itself. We just worry about the files, etc. ; $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 FDHostD_DATA,RD,WRT,NOEXE,LONG DEFAULT_DEVICE: .ASCID /SYS$DISK/ $ATRDEF $FABDEF $FATDEF $FIBDEF $IODEF $NAMDEF $RMSDEF $XABDEF .ALIGN LONG IOSTATUS: .BLKQ 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 ;^^^ mbx_BUF: ; Buffer to hold mbxice name. .BLKB 40 mbx_BUF_SIZ = . - mbx_BUF mbx_BUF_DESC: ; Descriptor pointing to mbxice name. .LONG mbx_BUF_SIZ .ADDRESS mbx_BUF mPID: ; Owner of mbxice (if any). .BLKL 1 mbx_ITEM_LIST: ; mbxice list for $GETDVI. .WORD mbx_BUF_SIZ ; Make sure we a have a physical device name. .WORD DVI$_DEVNAM .ADDRESS mbx_BUF .ADDRESS mbx_BUF_DESC .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS mPID .LONG 0 .WORD 4 .WORD DVI$_DEVCLASS ; Check for a terminal. .ADDRESS mbx_CLASS .LONG 0 .LONG 0 ; End if item list. mbx_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 ; 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. ; MBCHN: .long 0 ; channel for mailbox MBUCB: .long 0 ; UCB address for mailbox CLRDS: .ASCID /CLEAR/ ASDSC: .ASCID /ASSIGN/ DASDSC: .ASCID /DEASSIGN/ P1DSC: .ASCID /UNIT/ P2DSC: .ASCID /FNAM/ .EVEN ; ; Data area for "disk" ; For a simple and yet somewhat useful initial test, we make FD: as a ; memory disk. This will have a 1280 block disk, rather small, yet ; big enough to hold ODS2 and try some nontrivial sized transfers. ; It has the advantage of going away once the process exits, so it can ; be used for a small scratch disk. Just bump fd_cyl as needed when ; changing the capacity. ; .align long fd_cyl=5 ;make it 5 cyls of 64 blocks each fd_blocks=fd_cyl*64 ; blocks... fd_longs=fd_blocks*128 ; longwords needed fd_data:: .BLKL fd_longs .blkl 128 ;guard area for safety during debug... ; ucb data area HSTUCB: .LONG 0 ;HOST UCB ADDRESS ;OURPID: .LONG 0 ;PID OF THIS PROCESS iosb: .long 0,0,0,0 ;iosb ioprog: .long 0 ; i/o in progress flag if nonzero ; BUFFER FOR COPIES OF DRIVR DATA BUFHDR: .LONG 0,0,0,0,0 BUF: .BLKL 8192. ; DATA AREA .LONG 0,0 ;SAFETY BUFFERS SETFD: .LONG 0 ;DECLARE PROCESS .LONG 0 ;PID .LONG FD_BLOCKS ;DISK SIZE .LONG 0,0,0,0 ;EXTRA STUFF FOR OTHER CALLS SETFDL=.-SETFD .LONG 0,0,0,0,0 ;SAFETY ; .PSECT FDHostD_CODE,RD,WRT,EXE,LONG .ENTRY FDHostD,^M ; only fdn: name on command line 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 FDHostD_EXIT 290$: clrl clrcnt ;flag clear count if 1 PUSHAB clrds ; 'DEASSIGN' CALLS #1,G^CLI$PRESENT ; IS /DEASSIGN USED? CMPL R0,#CLI$_PRESENT ; IF EQ YES BEQL 293$ incl clrcnt 293$: ; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE. $ASSIGN_S - DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR $GETDVI_S - CHAN=vdchn,- ; Command line has device name. ITMLST=VDV_ITEM_LIST BLBS R0,140$ BRW FDHostd_EXIT 140$: $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARG ; Now we have the PID for our process in OURPID and are ready to tell ; the driver we're here! COMMON: ; NOW TERMINATE THE I/O AND AWAIT MORE WORK. MOVL #1,SETFD ;TERMINATE I/O PACKET movl #1,bufhdr ;set write (client sent data) ; do write to avoid trying to move data into client process' space at ; i/o completion time. ; This reduces chances of messup. clrl bufhdr+4 ;blk 0 movl #512,setfd+12 ;say 512 bytes was size. MOVL BUFHDR,SETFD+4 ;SAVE TRANSFER DIRECTION MOVL BUFHDR+4,SETFD+8 ; BLOCK # MOVL BUFHDR+8,SETFD+12 ; NO. BYTES IN BUFFER MOVZWL #8,SETFD+16 ; IOSB 1 major lossage!!! CLRL SETFD+20 ; IOSB 2 ; ALWAYS failure i/o movl #setfdl,r4 $qiow_s efn=#1,chan=vdchn, - iosb=#iosb,func=#,p1=setfd,p2=R4 ; MOVL OURPID,SETFD+4 ;STORE PID (IPID!!!) ; movl #fd_blocks,setfd+8 ;size of disk (preset also) clrl setfd+4 clrl setfd+8 ;0 blks...disconnect clrl setfd+12 ;no mb ; movl mbucb,setfd+12 ; Comm mailbox UCB address CLRL SETFD ; flag that this is the setup movl #setfdl,r4 ; length of buffer ; Note we must modified func code from io$_format to something with ; a modifier bit set so FDDRV will treat this as OUR special QIO. $qiow_s efn=#1,chan=vdchn, - iosb=#iosb,func=#,p1=setfd,p2=R4 ON_ERR FDHostD_EXIT ; SKIP OUT IF ERROR ; EITHER... $DASSGN_S CHAN=VDCHN RET FDHostd_exit: RET ; ; KERNEL ARG LIST K_ARG: .LONG 2 ;2 ARGS: fd device name, mb device name .ADDRESS VDV_BUF_DESC .address mbx_buf_desc ; 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 ; Obtains host's PID, and also sets up correct size in driver UCB ; both by cylinder and by block. .if df,$$xdt jsb g^ini$brk ;call xdt .endc .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) ;;; (gets it in internal form, just as needed) .endc ;;; NEED IPID FOR DRIVER'S CALL TO SCH$POSTEF TO THIS HOST!! MOVL PCB$L_PID(R4),OURPID ;;;SAVE OUR PID IN INTERNAL FORM JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASE CLRL HSTUCB ;;; ZERO "HOST" UCB tstl clrcnt ;;;just zeroing count? bneq 126$ clrl mbucb 126$: 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$: ; 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.) ; ; Set device size. Since this is true of any disk, just use the offsets. ; No need for duplicating the UCB defs here. tstl clrcnt ;;;just zeroing use count beql 127$ ;;;if eql, no, normal ops movw #1,ucb$w_refc(r1) ;;;zero ref count (in case it got set -1) ;;; (note we set it to 1 so it decrements to 0 on our exit.) BICW #UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG OFFLINE BICW #UCB$M_VALID,UCB$W_STS(R1) ;;; AND VOL INVALID brb 128$ ;;;exit, success 127$: ; MOVL #fd_blocks,UCB$L_MAXBLOCK(R1) ;;; (SAVE SIZE TWICE, FOR RMS MOVL #fd_cyl,R0 ;;; GET HOST SIZE IN CYLINDERS MOVW R0,UCB$W_CYLINDERS(R1) ;;; SAVE IN UCB FOR REST OF VMS ; This computation is redone in fddrv itself, but do it here also. ; It assumes in fddrv that there are 64 sectors/cylinder. BISW #UCB$M_ONLINE,UCB$W_STS(R1) ;;; FLAG ONLINE NOW BISW #UCB$M_VALID,UCB$W_STS(R1) ;;; AND VOL VALID ;;; THAT'S IT... SHOULD BE OK NOW. 128$: 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 ourpid: .long 0 ;;;store this locally CLRCNT: .long 0 ;1 if clearing ref cnt ucb$w_refc ;;;(avoid paging problems in kernel) .END FDHostD