.TITLE VDDRIVER - VAX/VMS VIRT DISK DRIVER .IDENT 'V03-000' ; ; FACILITY: ; ; VAX/VMS VIRTUAL DISK DRIVER USING CONTIGUOUS FILES. ; ; AUTHOR: ; ; G. EVERHART ; ; ; ABSTRACT: ; ; THIS MODULE CONTAINS THE TABLES AND ROUTINES NECESSARY TO ; PERFORM ALL DEVICE-DEPENDENT PROCESSING OF AN I/O REQUEST ; FOR VMS VIRTUAL DISKS ON CONTIG FILES. ; ; Note: ; This driver will be for logical I/O and will inhibit physical ; block I/O as makes sense. ; It will have an FDT table that will look just like other ; disks for everything, but will NOT do buffered I/O. ; In its' FDT routines, which will be dummies, it will just ; modify logical block numbers in the I/O packets, set or ; clear the buffered bit in irp$w_STS according as the real ; driver's bit is set or clear, do a range check to make sure ; the LBN used is in the legal range for this particular unit ; ov VD:, and reset things to call the real driver's FDT ; routines and let IT do the work. It will unbusy itself ; before losing control. ; The idea is that only I/O "gets at the physical ; storage", so only that need be munged. Since this happens ; only for read/write logical/physical, we just leave OUR ; FDT routines in there for everything else. In just changing ; the buffered bit in the I/O we MAY mess up some quotas (this ; will eventually get cleaned up), but won't lose buffers or ; otherwise mess up things. Since most drivers have nonbuffered ; I/O, we'll usually be just fine. (Disk drivers, that is.) ; To call the "real" FDT routines we'll just reset the ; registers (and the IORP) to the real device and return. The ; exec routines that handle FDT routines will take it from there ; and do the FDT processing in the real driver. We just have to ; let them work... ; The FDT routines are called from SYSQIOREQ.MAR for ; future reference. ; We don't need to get control back, really; the real ; driver will finish off the I/O. We just need a few checks to ; ensure that a "real" driver exists and has been associated ; with this unit. ; ;-- .PAGE .SBTTL EXTERNAL AND LOCAL DEFINITIONS ; ; 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 $SSDEF ;DEFINE SYSTEM STATUS CODES $UCBDEF ;DEFINE UNIT CONTROL BLOCK $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK ; ; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS ; $DEFINI UCB ;START OF UCB DEFINITIONS .=UCB$W_BCR+2 ;BEGIN DEFINITIONS AT END OF UCB ; 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. UCB$K_DY_LEN=. ;LENGTH OF UCB $DEFEND UCB ;END OF UCB DEFINITONS .SBTTL STANDARD TABLES ; ; DRIVER PROLOGUE TABLE ; ; THE DPT DESCRIBES DRIVER PARAMETERS AND I/O DATABASE FIELDS ; THAT ARE TO BE INITIALIZED DURING DRIVER LOADING AND RELOADING ; DPTAB - ;DPT CREATION MACRO END=DY_END,- ;END OF DRIVER LABEL ADAPTER=UBA,- ;ADAPTER TYPE = NONE (VIRTUAL) DEFUNITS=10,- ;UNITS 0 THRU 10 UCBSIZE=UCB$K_DY_LEN,- ;LENGTH OF UCB NAME=VDDRIVER ;DRIVER NAME DPT_STORE INIT ;START CONTROL BLOCK INIT VALUES DPT_STORE DDB,DDB$L_ACPD,L,<^A\F11\> ;DEFAULT ACP NAME DPT_STORE DDB,DDB$L_ACPD+3,B,DDB$K_SLOW ;ACP CLASS DPT_STORE UCB,UCB$B_FIPL,B,8 ;FORK IPL DPT_STORE UCB,UCB$L_DEVCHAR,L,- ;DEVICE CHARACTERISTICS ; RANDOM ACCESS DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_DISK ;DEVICE CLASS DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,512 ;DEFAULT BUFFER SIZE DPT_STORE UCB,UCB$B_SECTORS,B,64 ;NUMBER OF SECTORS PER TRACK DPT_STORE UCB,UCB$W_CYLINDERS,W,1 ;NUMBER OF TRACKS PER CYLINDER ; FAKE GEOMETRY TO MAKE TRANSLATION EASIER. HAVE PRIV'D IMAGE LATER ; RESET THE UCB$W_CYLINDERS TO WHATEVER'S DESIRED. JUST MAKE SURE IT'S ; A MULTIPLE OF 64 BLOCKS IN SIZE, WHICH OUGHT TO BE GOOD ENOUGH. DPT_STORE UCB,UCB$B_DIPL,B,21 ;DEVICE IPL DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNT DPT_STORE UCB,UCB$W_DEVSTS,W,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;... ; ; CONVERT TO PHYS IN FDT SO WE NEEDN'T MESS WITH IT... ; DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUES ; DPT_STORE CRB,CRB$L_INTD+4,D,DY_INT ;INTERRUPT SERVICE ROUTINE ADDRESS DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,- ;CONTROLLER INIT ADDRESS D,DY_RX211_INIT ;... DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS D,DY_RX02_INIT ;... DPT_STORE DDB,DDB$L_DDT,D,DY$DDT ;DDT ADDRESS DPT_STORE END ;END OF INITIALIZATION TABLE ; ; DRIVER DISPATCH TABLE ; ; THE DDT LISTS ENTRY POINTS FOR DRIVER SUBROUTINES WHICH ARE ; CALLED BY THE OPERATING SYSTEM. ; DDTAB - ;DDT CREATION MACRO DEVNAM=VD,- ;NAME OF DEVICE START=DY_STARTIO,- ;START I/O ROUTINE UNSOLIC=0,- ;UNSOLICITED INTERRUPT FUNCTB=DY_FUNCTABLE,- ;FUNCTION DECISION TABLE CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICE REGDMP=0,- ;REGISTER DUMP ROUTINE DIAGBF=0,- ;BYTES IN DIAG BUFFER ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER ; ; FUNCTION DECISION TABLE ; ; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH ; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO ; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS. ; DY_FUNCTABLE: FUNCTAB ,- ;LIST LEGAL FUNCTIONS FUNCTAB ,- ;BUFFERED FUNCTIONS FUNCTAB DY_ALIGN,- ;TEST ALIGNMENT FUNCTIONS FINCTAB VD_FAKEOUT,- ; FAKEOUT FOR LOGICAL OR PHYSICAL I/O ; ; LEAVE NORMAL ACP CALLS IN SO FILE STRUCTURED STUFF ON OUR VD: UNIT ; WILL WORK OK. ; FUNCTAB +ACP$READBLK,- ;READ FUNCTIONS FUNCTAB +ACP$WRITEBLK,- ;WRITE FUNCTIONS FUNCTAB +ACP$ACCESS,- ;ACCESS FUNCTIONS FUNCTAB +ACP$DEACCESS,- ;DEACCESS FUNCTION FUNCTAB +ACP$MODIFY,- ;MODIFY FUNCTIONS FUNCTAB +ACP$MOUNT,- ;MOUNT FUNCTION FUNCTAB +EXE$ZEROPARM,- ;ZERO PARAMETER FUNCTIONS FUNCTAB +EXE$ONEPARM,- ;ONE PARAMETER FUNCTION FUNCTAB +EXE$SENSEMODE,- ;SENSE FUNCTIONS FUNCTAB +EXE$SETCHAR,- ;SET FUNCTIONS .PAGE .SBTTL CONTROLLER INITIALIZATION ROUTINE ; ++ ; ; DY_RX211_INIT - CONTROLLER INITIALIZATION ROUTINE ; ; FUNCTIONAL DESCRIPTION: ; noop ; ; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUP ; - DURING DRIVER LOADING ; - DURING RECOVERY FROM POWER FAILURE ; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR. ;-- DY_RX211_INIT: ;RX211 CONTROLLER INITIALIZATION RSB ;RETURN .PAGE .SBTTL INTERNAL CONTROLLER RE-INITIALIZATION ; ; INPUTS: ; R4 => RX211 CSR ; R5 => UCB ; RX211_REINIT: RSB ; RETURN TO CALLER .PAGE .SBTTL UNIT INITIALIZATION ROUTINE ;++ ; ; DY_RX02_INIT - UNIT INITIALIZATION ROUTINE ; ; FUNCTIONAL DESCRIPTION: ; ; THIS ROUTINE SETS THE VD: ONLINE. ; ; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUP ; - DURING DRIVER LOADING ; - DURING RECOVERY FROM POWER FAILURE ; ; INPUTS: ; ; R4 - CSR ADDRESS (CONTROLLER STATUS REGISTER) ; R5 - UCB ADDRESS (UNIT CONTROL BLOCK) ; ; OUTPUTS: ; ; THE UNIT IS SET ONLINE. ; ALL GENERAL REGISTERS (R0-R15) ARE PRESERVED. ; ;-- DY_RX02_INIT: ;RX02 UNIT INITIALIZATION ; Don't set unit online here. Priv'd task that assigns VD unit ; to a file does this to ensure only assigned VDn: get used. ; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE MOVB #DC$_DISK,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASS MOVB #DT$_RX04,UCB$B_DEVTYPE(R5) ;ASSUME RX04 DEVICE TYPE RSB ;RETURN .PAGE .SBTTL FDT ROUTINES ;++ ; ; DY_ALIGN - FDT ROUTINE TO TEST XFER BYTE COUNT ; ; FUNCTIONAL DESCRIPTION: ; ; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER ; TO CHECK THE BYTE COUNT PARAMETER SPECIFIED BY THE USER PROCESS ; FOR AN EVEN NUMBER OF BYTES (WORD BOUNDARY). ; ; INPUTS: ; ; R3 - IRP ADDRESS (I/O REQUEST PACKET) ; R4 - PCB ADDRESS (PROCESS CONTROL BLOCK) ; R5 - UCB ADDRESS (UNIT CONTROL BLOCK) ; R6 - CCB ADDRESS (CHANNEL CONTROL BLOCK) ; R7 - BIT NUMBER OF THE I/O FUNCTION CODE ; R8 - ADDRESS OF FDT TABLE ENTRY FOR THIS ROUTINE ; 4(AP) - ADDRESS OF FIRST FUNCTION DEPENDENT QIO PARAMETER ; ; OUTPUTS: ; ; IF THE QIO BYTE COUNT PARAMETER IS ODD, THE I/O OPERATION IS ; TERMINATED WITH AN ERROR. IF IT IS EVEN, CONTROL IS RETURNED ; TO THE FDT DISPATCHER. ; ;-- DY_ALIGN: ;CHECK BYTE COUNT AT P1(AP) BLBS 4(AP),10$ ;IF LBS - ODD BYTE COUNT RSB ;EVEN - RETURN TO CALLER 10$: MOVZWL #SS$_IVBUFLEN,R0 ;SET BUFFER ALIGNMENT STATUS JMP G^EXE$ABORTIO ;ABORT I/O .PAGE .SBTTL START I/O ROUTINE ; VD_FAKEOUT ; CALLED TO DO MOST OF THE REAL WORK... ; ; This entry does the work of making a contiguous file look like the ; real storage of the VD: unit. It is assumed that the UCB has been ; stuffed with the starting LBN, the size in blocks, and the UCB of ; the physical disk on which a contiguous file is to be used. This ; entry validates the transfer and changes the I/O packet to look like ; it was meant for the equivlent LBN within the file on the "host" disk. ; ; ; ENTRY: ; R0= FDT ENTRY (OURS ON ENTRY; HOST'S ON EXIT) ; R1, R2 SCRATCH ; R3= I/O PKT ADDRESS ; R4= PCB ADDRESS ; R5= UCB ADDRESS (OURS ON ENTRY; HOST'S ON EXIT) ; R6 = CCB ADDRESS ; R7= I/O FCT CODE BIT NUMBER ; R8= FDT DISPATCH ADDRESS (ADD 12. TO IT EVERY PASS THRU INCLUDINBG FIRST) ; (OURS ON ENTRY; HOST'S ON EXIT) ; R9, R10, R11 = SCRATCH ; AP = ADDRESS OF 1ST FUNCT DEPENDENT PARAMETER VD_FAKEOUT: ; FIRST ENSURE ALL'S WELL FOR LBN RANGE CMPL UCB$HFSZ(R5),8(AP) ;LBN OF FILE > REQ LBN? BGTRU 1$ ; IF GT THEN OK MOVL #SS$_BADPARAM,R0 ;IF NOT, BAD PARAMS JMP G^EXE$ABORTIO ;ABORT I/O 1$: ; NOW ADJUST LBN REQUEST AND FAKE THINGS SO IT APPEARS LBN REQUEST ; IS FOR REAL DEVICE. ; ADDL UCB$HLBN(R5),8(AP) ; ADD THE LBN ON STACK BEFORE STORED ; NOW FIND HOST UCB TSTL UCB$HUCB(R5) ; BE SURE WE HAVE SOMETHING IN UCB ADDR BNEQ 2$ MOVL #SS$_OFFLINE,R0 JMP G^EXE$ABORTIO ;ABORT I/O 2$: MOVL UCB$HUCB(R5),R5 ; R5 NOW IS HOST'S UCB ADDRESS MOVL UCB$L_DDT(R5),R0 MOVL DDT$L_FDT(R0),R8 ; POINT AT HOST'S FDT AREA ; ; NOW FILL IN HOST UCB IN I/O PKT MOVL R5,IRP$L_UCB(R3) ; PACKET MOVES TO HOST... ; NOTE WE DON'T WORRY ABOUT IT GETTING INTO THE WRONG QUEUE HERE ; BECAUSE IN THE FDT ROUTINES, IT ISN'T YET QUEUED TO THE DEVICE ; CCB$W_IOC HAS BEEN INCREMENTED, BUT HOST DRIVER WILL EVENTUALLY ; FINISH I/O ON THE PACKET AND DECREMENT THIS. THE DECREMENT OPERATION ; IS INDEXED BY CHANNEL NUMBER, NOT UNIT, SO THE CCB'S I/O PENDING ; COUNT WILL BE HANDLED OK. ; ; PASS FIRST 2 QUADWORDS OF MASKS ADDL #4,R8 ; WHEN WE RETURN WE GO TO 1ST FDT ; ROUTINE OF REAL DRIVER. SEE ; SYSQIOREQ.MAR FOR DETAILS. ; NOW ALL SET. ONLY LOGICAL I/O GETS HERE AND IT'LL NOW BE DISPATCHED ; FOR THE HOST DRIVER WITH THE MODIFIED I/O PACKET PARAMETERS. ; SINCE FDT PROCESSING JUST GOES MERRILY ALONG FOR ALL FDT ROUTINES, ; IT WILL NOW DO SO IN THE HOST DRIVER USING THE HOST DRIVER'S FDT ; ROUTINES, BUT WITH LBN CORRECTED TO POINT TO OUR ASSOCIATED FILE. ; THIS WILL GET US, WITH LITTLE OVERHEAD, TO A VIRTUAL DISK ON A CONTIGUOUS ; FILE. NOTE ONLY LOGICAL I/O IS TRANSFORMED; THE REST IS FILE-STRUCTURED ; STUFF AND WILL GO ON AS IF WE HAD REAL INDEPENDENT STORAGE ON THIS ; "DEVICE". RSB ; "BACK" TO SYSTEM TO GET TO HOST'S FDT'S NEXT. ;++ ; ; DY_STARTIO - START I/O ROUTINE ; ; FUNCTIONAL DESCRIPTION: ; ; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUEST ; PACKET HAS BEEN DEQUEUED. ; ; SELDOM IF EVER CALLED DUE TO FDT THAT REROUTES MOST EVERYTHING TO ; HOST DRIVER. ; ; INPUTS: ; ; R3 - IRP ADDRESS (I/O REQUEST PACKET) ; R5 - UCB ADDRESS (UNIT CONTROL BLOCK) ; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER) ; ; OUTPUTS: ; ; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFERED ; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKS ; ; THE I/O FUNCTION IS EXECUTED. ; ; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED. ; ;-- DY_STARTIO: ;START I/O OPERATION ; ; PREPROCESS UCB FIELDS ; ; ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8 ; CLRQ UCB$Q_DY_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area. ; ; BRANCH TO FUNCTION EXECUTION ; 10$:; BBS #IRP$V_PHYSIO,- ;IF SET - PHYSICAL I/O FUNCTION ; IRP$W_STS(R3),20$ ;... BBS #UCB$V_VALID,- ;IF SET - VOLUME SOFTWARE VALID UCB$W_STS(R5),20$ ;... MOVZWL #SS$_VOLINV,R0 ;SET VOLUME INVALID STATUS BRW RESETXFR ;RESET BYTE COUNT AND EXIT 20$: CMPB #IO$_UNLOAD, R1 ;Unload function? BEQL UNLOAD ;Branch if yes. CMPB #IO$_AVAILABLE, R1 ;Available function? BEQL AVAILABLE ;Branch if yes. BRW FEXL ;Else, branch to execute function. ; ; UNLOAD and AVAILABLE Functions ; Clear UCB$V_VALID in UCB$W_STS ; UNLOAD: AVAILABLE: ; BICW #UCB$M_VALID, - ;Clear sofware volume valid bit. ; UCB$W_STS(R5) ; BRB NORMAL ;Then complete the operation. ; ; OPERATON COMPLETION ; NORMAL: ;SUCCESSFUL OPERATION COMPLETE MOVZWL #SS$_NORMAL,R0 ;ASSUME NORMAL COMPLETION STATUS BRB FUNCXT ;FUNCTION EXIT FATALERR: ;UNRECOVERABLE ERROR MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUS FUNCXT: ;FUNCTION EXIT CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB REQCOM ;COMPLETE REQUEST .PAGE ; PWRFAIL: ;POWER FAILURE BICW #UCB$M_POWER,UCB$W_STS(R5) ;CLEAR POWER FAILURE BIT MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKET MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERS UCB$L_SVAPTE(R5) ;... BRW DY_STARTIO ;START REQUEST OVER DY_END: ;ADDRESS OF LAST LOCATION IN DRIVER .END