home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / jgd / jgdriver.mar (.txt) < prev    next >
Microsoft Windows Help File Content  |  1994-04-07  |  55KB  |  1,302 lines

  1.     .TITLE    JGDRiver    ;skeleton driver implementing ucb linkage
  2.     .IDENT    'V01b'
  3. ; Author: Glenn C. Everhart
  4. ;evax = 1
  5. ;alpha=1
  6. ;bigpage=1
  7. ;addressbits=32
  8.     .if    ndf,evax
  9.     .macro    driver_data
  10.     .PSECT    $$$105_PROLOGUE
  11.     .endm
  12.     .macro driver_code
  13.     .PSECT    $$$115_DRIVER
  14.     .endm
  15.     .endc
  16. ; above for Alpha only.
  17. ; Function: Error-retry intercept driver for optical disks.
  18. ;x$$$dt=0
  19. ;vms$$v6=0    ;add forvms v6 def'n
  20. vms$v5=1(
  21. ; define v5$picky also for SMP operation
  22. v5$picky=1&
  23.     .SBTTL    EXTERNAL AND LOCAL DEFINITIONS
  24. ; EXTERNAL SYMBOLS
  25.     .library /SYS$SHARE:LIB/
  26. ;    $ADPDEF                ;DEFINE ADAPTER CONTROL BLOCK)
  27.     $CRBDEF                ;DEFINE CHANNEL REQUEST BLOCK
  28.     $DYNDEF ;define dynamic data types
  29.     $DCDEF                ;DEFINE DEVICE CLASS
  30.     $DDBDEF                ;DEFINE DEVICE DATA BLOCK
  31.     $DEVDEF                ;DEFINE DEVICE CHARACTERISTICS)
  32.     $DPTDEF                ;DEFINE DRIVER PROLOGUE TABLE
  33.     $EMBDEF                ;DEFINE ERROR MESSAGE BUFFER(
  34.     $IDBDEF                ;DEFINE INTERRUPT DATA BLOCK%
  35.     $IODEF                ;DEFINE I/O FUNCTION CODES
  36.     $DDTDEF                ; DEFINE DISPATCH TBL...
  37.     $ptedef
  38.     $vadef
  39.     $IRPDEF                ;DEFINE I/O REQUEST PACKET    
  40.     $irpedef
  41.     $PRDEF                ;DEFINE PROCESSOR REGISTERS&
  42.     $SSDEF                ;DEFINE SYSTEM STATUS CODES&
  43.     $UCBDEF                ;DEFINE UNIT CONTROL BLOCK
  44.     $psldef
  45.     $prdef
  46.     $acldef$
  47.     $rsndef                ;define resource numbers
  48.     $acedef*
  49.     $VECDEF                ;DEFINE INTERRUPT VECTOR BLOCK
  50.     $pcbdef
  51.     $statedef
  52.     $jibdef
  53.     $acbdef
  54.     $vcbdef
  55.     $arbdef
  56.     $wcbdef
  57.     $ccbdef
  58.     $fcbdef
  59.     $phddef<
  60.         $RABDEF                         ; RAB structure defs7
  61.         $RMSDEF                         ; RMS constants
  62. ; defs for acl hacking
  63.     $fibdef
  64.     $atrdef
  65. p1=0    ; first qio param
  66. p4=12
  67. p5=16
  68. p6=20    ;6th qio param offsets
  69.     .IF    DF,VMS$V5    ;VMS V5 + LATER ONLY
  70.     $SPLCODDEF
  71.     $cpudef
  72.     .ENDC
  73. ; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS
  74.     $DEFINI    UCB            ;START OF UCB DEFINITIONS
  75. ;.=UCB$W_BCR+2                ;BEGIN DEFINITIONS AT END OF UCB*
  76. .=UCB$K_LCL_DISK_LENGTH    ;v4 def end of ucb8
  77. ; USE THESE FIELDS TO HOLD OUR LOCAL DATA FOR VIRT DISK.K
  78. ; Add our stuff at the end to ensure we don't mess some fields up that some
  79. ; areas of VMS may want.C
  80. ; Leave thisfield first so we can know all diskswill have it at the
  81. ; same offset.5
  82. $def    ucb$l_oldfdt    .blkl    1    ;fdt tbl of prior fdt chain
  83. ; Add other fields here if desired.
  84. $def    ucb$l_ctlflgs    .blkl    1        ;flags to control modes
  85. $def    ucb$l_cbtctr    .blkl    1        ;how many extents,
  86. $def    ucb$l_cbtini    .blkl    1        ;init for counter@
  87. ; preceding 2 fields allow specifying of contig-best-try extentsA
  88. ; on every Nth extend, not every one. This should still help keep
  89. ; file extensions from preferentially picking up chaff
  90. $def    ucb$JGcontfil    .blkb    80
  91. $DEF    ucb$l_minxt    .blkl    1        ;min. extent%
  92. $def    ucb$l_maxxt    .blkl    1        ;max extent
  93. $def    ucb$l_frac    .blkl    1        ;fraction to extend by
  94. $def    ucb$l_slop    .blkl    1        ;slop blocks to leave free
  95. ; DDT intercept fields
  96. ; following must be contiguous.
  97. $def    ucb$s_ppdbgn            ;add any more prepended stuff after thisI
  98. $def    ucb$l_uniqid    .blkl   1       ;driver-unique ID, gets filled in
  99.                                         ; by DPT address for easy following
  100.                                         ; by SDAJ
  101. $def    ucb$l_intcddt   .blkl   1       ; Our interceptor's DDT address if<
  102.                                         ; we are intercepted>
  103. $def    ucb$l_prevddt   .blkl   1       ; previous DDT addressH
  104. $def    ucb$l_icsign    .blkl   1       ; unique pattern that identifiesG
  105.                                         ; this as a DDT intercept block
  106. ; NOTE: Jon Pinkley suggests that the DDT size should be encoded in part of thisI
  107. ; unique ID so that incompatible future versions will be guarded against.
  108. $def    ucb$s_ppdend,
  109. $def    ucb$a_vicddt    .blkb   ddt$k_length@
  110.                                         ; space for victim's DDT
  111.             .blkl    4    ;safety1
  112. $def    ucb$l_backlk    .blkl    1    ;backlink to victim ucb
  113. ; Make the "unique magic number" depend on the DDT length, and on the
  114. ; length of the prepended material. If anything new is added, be sure that"
  115. ; this magic number value changes.F
  116. magic=^xF024F000 + ddt$k_length + <256*<ucb$s_ppdend-ucb$s_ppdbgn-16>>H
  117. p.magic=^xF024F000 + ddt$k_length + <256*<ucb$s_ppdend-ucb$s_ppdbgn-16>>
  118.                 ;an ACE is there or not.0
  119. $DEF    UCB$L_JG_HOST_DESCR    .BLKL    2    ;host dvc desc.
  120. ; Set FDT table start mask for each unit by keeping it here.1
  121. ; We need just enough to get back to user's FDTs.
  122. $def    ucb$l_fdtlgl    .blkl    2    ;legal fcn msks
  123. $def    ucb$l_fdtbuf    .blkl    2    ;buffered fcn msks%
  124. $def    ucb$l_fdtmfy    .blkl    3    ;modify fcn
  125. $def    ucb$l_fdtbak    .blkl    3    ;"go back" fcn0
  126. $def    ucb$l_vict    .blkl    1    ;victim ucb for checking<
  127. ; The following lets us steal start-io and add error retries7
  128. $def    ucb$l_omedia    .blkl    1    ;storage of orig. irp$l_media
  129. $def    ucb$l_ppid    .blkl    1    ;store for irp$l_pid contents
  130. $def    ucb$l_retries    .blkl    1    ;counter for i/o retries
  131. $def    ucb$l_hstartio    .blkl    1    ;host driver start-io loc./
  132. $def    ucb$l_hstucb    .blkl    1    ;host ucb (quick ref)
  133. $DEF    UCB$K_JG_LEN    .BLKW    1    ;LENGTH OF UCB!
  134. ;UCB$K_JG_LEN=.                ;LENGTH OF UCB
  135.     $DEFEND    UCB            ;END OF UCB DEFINITONS
  136.     .SBTTL    STANDARD TABLES
  137. ; DRIVER PROLOGUE TABLE
  138. ;     THE DPT DESCRIBES DRIVER PARAMETERS AND I/O DATABASE FIELDSA
  139. ;     THAT ARE TO BE INITIALIZED DURING DRIVER LOADING AND RELOADING
  140.     driver_data
  141. JG_UNITS=100
  142. vd_units=jg_units
  143. VJG$DPT::
  144. .iif ndf,spt$m_xpamod,dpt$m_xpamod=0
  145.     .if    df,evax
  146.     DPTAB    -            ;DPT CREATION MACRO$
  147.         END=JG_END,-        ;END OF DRIVER LABEL0
  148.         ADAPTER=NULL,-        ;ADAPTER TYPE = NONE (VIRTUAL)F
  149.         FLAGS=DPT$M_SMPMOD!dpt$m_xpamod!DPT$M_NOUNLOAD, - ;SET TO USE SMP,xa'
  150.         DEFUNITS=2,-        ;UNITS 0 THRU 1 thru 31
  151.         step=1,-'
  152.         UCBSIZE=UCB$K_JG_LEN,-    ;LENGTH OF UCB
  153.         MAXUNITS=JG_UNITS,-    ;FOR SANITY...CAN CHANGE
  154.         NAME=JGDRIVER        ;DRIVER NAME
  155.     .iff
  156.     DPTAB    -            ;DPT CREATION MACRO$
  157.         END=JG_END,-        ;END OF DRIVER LABEL0
  158.         ADAPTER=NULL,-        ;ADAPTER TYPE = NONE (VIRTUAL)F
  159.         FLAGS=DPT$M_SMPMOD!dpt$m_xpamod!DPT$M_NOUNLOAD, - ;SET TO USE SMP,xa'
  160.         DEFUNITS=2,-        ;UNITS 0 THRU 1 thru 31
  161.         UCBSIZE=UCB$K_JG_LEN,-    ;LENGTH OF UCB
  162.         MAXUNITS=JG_UNITS,-    ;FOR SANITY...CAN CHANGE
  163.         NAME=JGDRIVER        ;DRIVER NAME
  164.     .endc
  165.     DPT_STORE INIT            ;START CONTROL BLOCK INIT VALUES8
  166.     DPT_STORE DDB,DDB$L_ACPD,L,<^A\F11\>  ;DEFAULT ACP NAME3
  167.     DPT_STORE DDB,DDB$L_ACPD+3,B,DDB$K_PACK    ;ACP CLASS
  168.     .IF    NDF,VMS$V5
  169.     DPT_STORE UCB,UCB$B_FIPL,B,8    ;FORK IPL (VMS V4.X)"
  170.     .IFF    ;DEFINE FOR VMS V5.X & LATERG
  171.     DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8  ;FORK IPL (VMS V5.X + LATER)
  172.     .ENDCC
  173. ; These characteristics for an intercept driver shouldn't look just
  174. ; like a real disk unless it is prepared to handle being mounted, etc.)
  175. ; Therefore comment a couple of them out.
  176.     DPT_STORE UCB,UCB$L_DEVCHAR,L,-    ;DEVICE CHARACTERISTICS
  177.         <DEV$M_SHR-        ; SHAREABLE
  178.         !DEV$M_AVL-        ; AVAILABLE
  179.         !DEV$M_IDV-        ; INPUT DEVICE
  180.         !DEV$M_ODV-        ; OUTPUT DEVICE
  181.         !DEV$M_RND>        ; RANDOM ACCESS9
  182.     DPT_STORE UCB,UCB$L_DEVCHAR2,L,- ;DEVICE CHARACTERISTICS
  183.         <DEV$M_NNM>        ; Prefix name with "node$" (like rp06)
  184.     DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_MISC  ;DEVICE CLASS
  185.     DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,512  ;DEFAULT BUFFER SIZEB
  186. ; FOLLOWING DEFINES OUR DEVICE "PHYSICAL LAYOUT". It's faked here.+
  187.     DPT_STORE UCB,UCB$B_TRACKS,B,1    ; 1 TRK/CYL
  188.     DPT_STORE UCB,UCB$B_SECTORS,B,64  ;NUMBER OF SECTORS PER TRACK
  189.     DPT_STORE UCB,UCB$W_CYLINDERS,W,16  ;NUMBER OF CYLINDERS
  190.     DPT_STORE UCB,UCB$B_DIPL,B,22    ;DEVICE IPL7
  191.     DPT_STORE UCB,UCB$B_ERTMAX,B,10    ;MAX ERROR RETRY COUNT
  192.     DPT_STORE UCB,UCB$W_DEVSTS,W,-    ;INHIBIT LOG TO PHYS CONVERSION IN FDT
  193.         <UCB$M_NOCNVRT>        ;...
  194. ; don't mess with LBN; leave alone so it's easier to hack on...
  195.     DPT_STORE REINIT        ;START CONTROL BLOCK RE-INIT VALUESQ
  196. ;    DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,VR_INT  ;INTERRUPT SERVICE ROUTINE ADDRESS
  197.     .if    ndf,evax
  198.     DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,-  ;CONTROLLER INIT ADDRESS
  199.               D,JG_ctrl_INIT          ;...=
  200.     DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS
  201.               D,JG_unit_INIT          ;...
  202.     .endc0
  203.     DPT_STORE DDB,DDB$L_DDT,D,JG$DDT      ;DDT ADDRESSB
  204.         DPT_STORE UCB,UCB$L_UNIQID,D,DPT$TAB    ;store DPT addressH
  205.                                                 ; (change "XX" to deviceJ
  206.                                                 ; mnemonic correct values)P
  207.         DPT_STORE UCB,UCB$L_ICSIGN,L,magic      ; Add unique pattern (that mightM
  208.                                                 ; bring back some memories in
  209.                                                 ; DOS-11 users)
  210. ; HISTORICAL NOTE: under DOS-11, one would get F012 and F024 errors
  211. ; on odd address and illegal instruction traps. If we don't have@
  212. ; this magic number HERE, on the other hand, we're likely to see=
  213. ; bugchecks in VMS due to uncontrolled bashing of UCB fields!
  214.     DPT_STORE END            ;END OF INITIALIZATION TABLE
  215. ; DRIVER DISPATCH TABLE
  216. ;     THE DDT LISTS ENTRY POINTS FOR DRIVER SUBROUTINES WHICH ARE"
  217. ;     CALLED BY THE OPERATING SYSTEM.
  218.     .if    df,evax
  219.     DDTAB    -            ;DDT CREATION MACRO
  220.         DEVNAM=JG,-        ;NAME OF DEVICE'
  221.         START=JG_STARTIO,-    ;START I/O ROUTINE
  222.         FUNCTB=JG_FUNCTABLE,-    ;FUNCTION DECISION TABLE
  223.         CTRLINIT=JG_CTRL_INIT,-
  224.         UNITINIT=JG_UNIT_INIT,-
  225. ;        CANCEL=0,-        ;CANCEL=NO-OP FOR FILES DEVICE
  226. ;        REGDMP=0,-    ;REGISTER DUMP ROUTINE$
  227. ;        DIAGBF=0,-  ;BYTES IN DIAG BUFFER
  228.         ERLGBF=0    ;BYTES IN
  229.                 ;ERRLOG BUFFER
  230.     .iff
  231.     DDTAB    -            ;DDT CREATION MACRO
  232.         DEVNAM=JG,-        ;NAME OF DEVICE'
  233.         START=JG_STARTIO,-    ;START I/O ROUTINE
  234.         FUNCTB=JG_FUNCTABLE,-    ;FUNCTION DECISION TABLE-
  235. ;        CANCEL=0,-        ;CANCEL=NO-OP FOR FILES DEVICE
  236. ;        REGDMP=0,-    ;REGISTER DUMP ROUTINE$
  237. ;        DIAGBF=0,-  ;BYTES IN DIAG BUFFER
  238.         ERLGBF=0    ;BYTES IN
  239.                 ;ERRLOG BUFFER
  240.     .endc
  241. ; FUNCTION DECISION TABLE
  242. ;     THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4
  243. ;     CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2
  244. ;     PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.
  245. ; code chaining data:
  246. chnflg:    .long    1    ;chain or use our FDT chain flag...use ours if 0
  247. myonoff:3
  248. fdtonoff: .long 0    ;switch my fdt stuff off if non-0
  249.     .ascii    /flag/    ;define your own unique flag here; just leave it 4 bytes long!
  250.     .long 0        ;fdt tbl from before patch
  251. fdt_chn  = -12
  252. fdt_prev = -4
  253. fdt_idnt = -8
  254. JG_FUNCTABLE:
  255. newfdt:
  256.     FUNCTAB    ,-            ;LIST LEGAL FUNCTIONS
  257.         <NOP,-            ; NO-OP,
  258.         FORMAT,-        ; We use format to point to file
  259.         UNLOAD,-        ; UNLOAD
  260.         PACKACK,-        ; PACK ACKNOWLEDGE
  261.         AVAILABLE,-        ; AVAILABLE&
  262.         SENSECHAR,-        ; SENSE CHARACTERISTICS"
  263.         SETCHAR,-        ; SET CHARACTERISTICS
  264.         SENSEMODE,-        ; SENSE MODE
  265.         SETMODE,-        ; SET MODE
  266.         READLBLK,-        ; READ LOGICAL BLOCK$
  267.         WRITELBLK,-        ; WRITE LOGICAL BLOCK$
  268.         READPBLK,-        ; READ PHYSICAL BLOCK %
  269.         WRITEPBLK,-        ; WRITE PHYSICAL BLOCK
  270.         READVBLK,-        ; READ VIRTUAL BLOCK$
  271.         WRITEVBLK,-        ; WRITE VIRTUAL BLOCK0
  272.         ACCESS,-        ; ACCESS FILE / FIND DIRECTORY ENTRY&
  273.         ACPCONTROL,-        ; ACP CONTROL FUNCTION0
  274.         CREATE,-        ; CREATE FILE AND/OR DIRECTORY ENTRY
  275.         DEACCESS,-        ; DEACCESS FILE
  276.         DELETE,-        ; DELETE FILE AND/OR DIRECTORY ENTRY$
  277.         MODIFY,-        ; MODIFY FILE ATTRIBUTES
  278.         MOUNT>            ; MOUNT VOLUME
  279. ; no-op phys I/O for a test here...
  280.     FUNCTAB    ,-            ;BUFFERED FUNCTIONS
  281.         <NOP,-
  282.         FORMAT,-        ; FORMAT
  283.         UNLOAD,-        ; UNLOAD
  284.         PACKACK,-        ; PACK ACKNOWLEDGE
  285.         AVAILABLE,-        ; AVAILABLE&
  286.         SENSECHAR,-        ; SENSE CHARACTERISTICS"
  287.         SETCHAR,-        ; SET CHARACTERISTICS
  288.         SENSEMODE,-        ; SENSE MODE
  289.         SETMODE,-        ; SET MODE
  290.         ACCESS,-        ; ACCESS FILE / FIND DIRECTORY ENTRY&
  291.         ACPCONTROL,-        ; ACP CONTROL FUNCTION0
  292.         CREATE,-        ; CREATE FILE AND/OR DIRECTORY ENTRY
  293.         DEACCESS,-        ; DEACCESS FILE
  294.         DELETE,-        ; DELETE FILE AND/OR DIRECTORY ENTRY$
  295.         MODIFY,-        ; MODIFY FILE ATTRIBUTES
  296.         MOUNT>            ; MOUNT VOLUME
  297. ; io$_format + modifiers (e.g. io$_format+128) as function code
  298. ; allows one to associate a JG unit and some other device; seeE
  299. ; the JG_format code comments for description of buffer to be passed.
  300.     functab JG_format,-        ;point to host disk
  301.         <FORMAT>
  302. ; First our very own filter routines
  303. ; Following FDT function should cover every function in the local
  304. ; FDT entries between "myfdtbgn" and "myfdtend", in this case just@
  305. ; mount and modify. Its function is to switch these off or on at
  306. ; need.
  307.     Functab fdtswitch,-'
  308.         <mount,modify,create,deaccess,access>
  309. myfdtbgn=.J
  310. ; Leave a couple of these in place as an illustration. You would of courseM
  311. ; need to insert your own if you're messing with FDT code, or remove these if
  312. ; you don't want to. The FDT switch logic is a waste of time and space if
  313. ; you do nothing with them...
  314. ; They don't actually do anything here, but could be added to. Throw in one
  315. ; to call some daemon at various points and it can act as a second ACPG
  316. ; when control is inserted at FDT time (ahead of the DEC ACP/XQP code!)
  317. mymfy:
  318.     FuncTab MFYFilt,-(
  319.         <MODIFY>        ;modify filter (e.g. extend)
  320. myfdtend=.C
  321. ; Note that if we want to allow numerous disk drivers to be patched
  322. ; by this one there is not a unique path to the original fdt=
  323. ; routine. Therefore use a UCB cell for the patch, not a cell
  324. ; ahead of the FDT. That way each unit gets a good return
  325. ; path. That's why there's an "oldfdt" cell in the UCB here.
  326. ; Following contains all legal functions in mask...
  327. ; That way it can transfer all control to a "previous" FDT chain.
  328. mybak:
  329.     FuncTab fdttoorig,-
  330.         <NOP,-            ; NO-OP,
  331.         FORMAT,-        ; We use format to point to file
  332.         UNLOAD,-        ; UNLOAD
  333.         PACKACK,-        ; PACK ACKNOWLEDGE
  334.         AVAILABLE,-        ; AVAILABLE&
  335.         SENSECHAR,-        ; SENSE CHARACTERISTICS"
  336.         SETCHAR,-        ; SET CHARACTERISTICS
  337.         SENSEMODE,-        ; SENSE MODE
  338.         SETMODE,-        ; SET MODE
  339.         READLBLK,-        ; READ LOGICAL BLOCK$
  340.         WRITELBLK,-        ; WRITE LOGICAL BLOCK$
  341.         READPBLK,-        ; READ PHYSICAL BLOCK %
  342.         WRITEPBLK,-        ; WRITE PHYSICAL BLOCK
  343.         READVBLK,-        ; READ VIRTUAL BLOCK$
  344.         WRITEVBLK,-        ; WRITE VIRTUAL BLOCK0
  345.         ACCESS,-        ; ACCESS FILE / FIND DIRECTORY ENTRY&
  346.         ACPCONTROL,-        ; ACP CONTROL FUNCTION0
  347.         CREATE,-        ; CREATE FILE AND/OR DIRECTORY ENTRY
  348.         DEACCESS,-        ; DEACCESS FILE
  349.         DELETE,-        ; DELETE FILE AND/OR DIRECTORY ENTRYP
  350.                 CRESHAD,-                       ; Create a shadow set virtual u$O
  351.                 DIAGNOSE,-                      ; Special pass-through function
  352.                 REMSHAD,-                       ; Remove a shadow set member
  353.         DSE,-            ;data security erase=
  354.                 SETPRFPATH,-            ;  Set preferred path
  355.                 READRCT,-              ;  Read RCT blockA
  356.                 ADDSHAD,-              ;  Add a shadow set member
  357.                 SHADMV,-                ;  Invoke shadow set mount verification
  358.                  SEEK,-                 ;SEEK CYLINDER4
  359.                  RECAL,-                ;RECALIBRATE4
  360.                  DRVCLR,-               ;DRIVE CLEAR5
  361.                  RELEASE,-              ;RELEASE PORT
  362.                  OFFSET,-               ;OFFSET HEADS
  363.                  RETCENTER,-            ;RETURN HEADS TO CENTERLINE
  364.                  SEARCH,-               ;SEARCH FOR SECTOR7
  365.                  READPRESET,-           ;READ IN PRESET
  366.                  WRITEHEAD,-            ;WRITE HEADER AND DATA=
  367.                  READHEAD,-             ;READ HEADER AND DATA
  368.                  WRITECHECKH,-          ;WRITE CHECK HEADER AND DATA6
  369.                  STARTSPNDL,-           ;START SPINDLE?
  370.                 WRITETRACKD,-           ;WRITE TRACK DESCRIPTOR
  371.                 READTRACKD,-            ;READ TRACK DESCRIPTOR>
  372.                 COPYSHAD,-             ;  Do shadow set copies$
  373.         MODIFY,-        ; MODIFY FILE ATTRIBUTES
  374.         MOUNT>            ; MOUNT VOLUME
  375. ; Now the "standard" disk FDT routines needed to let ODS-2 work (or ods-1 !)I
  376. ; (Where we are doing read - or possibly write- virtual by hand ourselves
  377. ;  we may never get to these BTW...)(
  378.     FUNCTAB    +ACP$READBLK,-        ;READ FUNCTIONS#
  379.         <READLBLK,-        ; READ LOGICAL BLOCK
  380.         READPBLK,-!
  381.         READVBLK-        ; READ VIRTUAL BLOCK
  382.     FUNCTAB    +ACP$WRITEBLK,-        ;WRITE FUNCTIONS%
  383.         <WRITELBLK,-        ; WRITE LOGICAL BLOCK
  384.         WRITEPBLK,-
  385.         WRITEVBLK-        ; WRITE VIRTUAL BLOCK
  386.     FUNCTAB    +ACP$ACCESS,-        ;ACCESS FUNCTIONS
  387.         <ACCESS,-        ; ACCEESS FILE / FIND DIRECTORY ENTRY0
  388.         CREATE-            ; CREATE FILE AND/OR DIRECTORY ENTRY
  389.     FUNCTAB    +ACP$DEACCESS,-        ;DEACCESS FUNCTION
  390.         <DEACCESS-        ; DEACCESS FILE
  391.     FUNCTAB    +ACP$MODIFY,-        ;MODIFY FUNCTIONS
  392.         <ACPCONTROL,-        ; ACP CONTROL FUNCTIONm0
  393.         DELETE,-        ; DELETE FILE AND/OR DIRECTORY ENTRY$
  394.         MODIFY-            ; MODIFY FILE ATTRIBUTES
  395.         >p&
  396.     FUNCTAB    +ACP$MOUNT,-        ;MOUNT FUNCTION
  397.         <MOUNT>            ; MOUNT VOLUMEC
  398.         FUNCTAB +EXE$LCLDSKVALID,-      ;LOCAL DISK VALID FUNCTIONS    6
  399.                 <UNLOAD,-               ;UNLOAD VOLUME7
  400.                  AVAILABLE,-            ;UNIT AVAILABLEl9
  401.                  PACKACK>               ;PACK ACKNOWLEDGE
  402.     FUNCTAB    +EXE$ZEROPARM,-        ;ZERO PARAMETER FUNCTIONS5
  403.         <UNLOAD,-        ; UNLOADN
  404.         PACKACK,-        ; PACK ACKNOWLEDGE 
  405.         AVAILABLE>        ; AVAILABLEr0
  406.     FUNCTAB    +EXE$ONEPARM,-        ;ONE PARAMETER FUNCTION
  407.         <FORMAT-        ; FORMAT
  408.         >    *
  409.     FUNCTAB    +EXE$SENSEMODE,-    ;SENSE FUNCTIONS'
  410.         <SENSECHAR,-        ; SENSE CHARACTERISTICSE
  411.         SENSEMODE-        ; SENSE MODE
  412.         >D'
  413.     FUNCTAB    +EXE$SETCHAR,-        ;SET FUNCTIONSF#
  414.         <SETCHAR,-        ; SET CHARACTERISTICS    
  415.         SETMODE-        ; SET MODE
  416.     .long    -1,-1        ; catch-all mask%
  417. fcnca:    .long    0        ;fill in in unit initR
  418. VD_UCBTBL::O
  419.     .BLKL    VD_UNITSO
  420.     .LONG 0,0    ;SAFETY3
  421.     .long    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0    ;more safety
  422. ; offset address table
  423. v_unm=0 E
  424. ; Note: code elsewhere assumes that the xxvc macro generates 8 bytes.;?
  425. ; If .address generates more than 4, it breaks as coded here!!!K
  426.     .macro xxvc lblct
  427.     .address    vd_fxs'lblct
  428.     .globl    vd_fxs'lblct
  429.     .long    0
  430.     .endm
  431. VD_VOADT::
  432.     .rept    <vd_units+4>B
  433.     xxvc    \v_unm
  434. v_unm = <v_unm+1>d
  435.     .endr
  436.     driver_code
  437.     .if    df,evax
  438. fcae:    .jsb_entry
  439.     .iff
  440. fcae:f
  441.     .endc+
  442.     movzwl    #SS$_BADPARAM,r0    ;illegal parametert
  443.     clrl    r1
  444.     jmp    g^exe$abortio
  445. ; fdtswitch - A
  446. ;   Based on state of "myonoff" variable either enable or disable1D
  447. ; my FDT processing, allowing the FDT chain to remain always intact.C
  448. ; This needs to be the first of a chain of FDT entries added to thed
  449. ; FDT processing of a driver.H
  450.     .if    df,evax
  451. fdtswitch: .jsb_entry
  452.     .iffI
  453. fdtswitch:
  454.     .endc
  455.     tstl    fdtonoff        ;global on/off
  456.     bneq    1$
  457.     rsb                ;go to next FDT if null_5
  458. 1$:    addl2    #<myfdtend-myfdtbgn>,r8    ;pass our fdt codesT
  459.     rsb                ;return to std
  460. ; fdttoorig - A
  461. ;  This entry continues FDT processing at the point after the newtC
  462. ; entries by returning to the original FDT chain at the point wherenD
  463. ; that chain begins. (It is presumed that FDT entries will always be@
  464. ; added ahead of existing ones due to the nonreturning nature ofA
  465. ; FDT processing.) This is done instead of simply duplicating the
  466. ; DEC FDT entries because in this way multiple FDT patches canA
  467. ; coexist, as would be impossible if this trick were not used. As '
  468. ; can be seen, its overhead is minimal.hA
  469. ;  The old FDT location is kept in the UCB for our device becauseiD
  470. ; that allows us to get back to different FDTs when several drivers'$
  471. ; FDT chains are pointed here first.
  472.     .if    df,evax!
  473. fdttoorig: .jsb_entry,output=<r8>d
  474.     .iffl
  475. fdttoorig:
  476.     .endc?
  477. ; As a performance feature, use a switch to let us just use theeA
  478. ; FDT chain here rather than continuing an old one. This needs tod@
  479. ; be settable externally since there is no need to return down a.
  480. ; chain unless something else is IN the chain.
  481. ; Control this with chnflg
  482. ;    tstl    chnflg )
  483. ;    beql    2$            ;just continue if chnflg is 0e    
  484.     pushl    r0 =
  485. ; (this routine gets called a fair bit and if GETJGUCB can bed!
  486. ;  called less, things speed up.) /
  487.     jsb    getJGucb        ;get UCB for JG unit from stolen     
  488.                     ;one 
  489.     tstl    r0            ;r0 is return UCB&
  490.     bgeq    1$            ;if not negative, not a UCB*
  491.     tstl    ucb$l_oldfdt(r0)    ;a prior fdt exist?
  492.     beql    1$E
  493.         movl    ucb$l_oldfdt(r0),r8      ;point to original FDT point 8
  494.         addl2   #<16-12>,r8      ;pass the 2 entry masksD
  495. 1$:                                 ;back up since sysqioreq adds 12
  496.     popl    r0F
  497. 2$:        rsb                      ;off to the previous FDT routines.
  498. ; GETJGUCB - Find JG: UCB address, given r5 points to UCB of the patchedF
  499. ; device. Return the UCB in R0, which should return 0 if we can't find
  500. ; it.dB
  501. ;   This routine is called a lot and therefore is made as quick as0
  502. ; it well can be, especially for the usual case.
  503.     .if    df,evax
  504. getJGucb: .jsb_entry
  505.     .iffa    
  506. getJGucb: 
  507.     .endc!
  508. ;    clrl    r0    ;no UCB initially found 
  509.     pushl    r10(
  510.     pushl    r11    ;faster than pushr supposedly
  511. ;    pushr    #^m<r10,r11>D
  512. ; Assumes that R5 is the UCB address of the device that has had someA
  513. ; code intercepted and that we are in some bit of code that knowsS?
  514. ; it is in an intercept driver. Also assumes R11 may be used ascD
  515. ; scratch registers (as is true in FDT routines). Control returns at:
  516. ; label "err" if the DDT appears to have been clobbered byA
  517. ; something not following this standard, if conditional "chk.err"m
  518. ; is defined.f-
  519. ;       Entry: R5 - victim device UCB addressl0
  520. ;       Exit: R11 - intercept driver UCB address    
  521. chk.err=0uF
  522.         movl    ucb$l_ddt(r5),r10       ;get the DDT we currently have2
  523. ; note we know our virtual driver's DPT address!!!D
  524.         movab   VJG$dpt,r11              ;magic pattern is DPT addr.9
  525. ; lock this section with forklock so we can safely removet3
  526. ; entries at fork also. Use victim device forklock.r1
  527. ; (don't preserve r0 since we clobber it anyway.)B=
  528.         forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NOF4
  529. 2$:     cmpl    <ucb$l_uniqid-ucb$a_vicddt>(r10),R11=
  530.                                         ;this our own driver?D@
  531. ;        beql    1$                      ;if eql yes, end search
  532. ; The somewhat odd layout here removes extra branches in the@
  533. ; most common case, i.e., finding our driver the very first time<
  534. ; through. The "bneq" branch next time is usually NOT taken.
  535.     bneq    5$            ;check next in chain if not us A
  536. ; At this point R10 contains the DDT address within the intercept F
  537. ; driver's UCB. Return the address of the intercept driver's UCB next.O
  538.         movab   <0-ucb$a_vicddt>(r10),r11       ;point R11 at the intercept UCB.7
  539. ;    brb    4$    ; note in this layout we can comment this out.B
  540. 4$:;?
  541.         forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOE%
  542. ; NOW clobber r0 and put things back.)
  543.     movl    r11,r0
  544. ;    popr    #^m<r10,r11>!    
  545.     popl    r11O&
  546.     popl    r10    ;supposedly faster than popr
  547.     rsbA
  548. ; Make very sure this DDT is inside a UCB bashed according to ourA=
  549. ; specs. The "p.magic" number reflects some version info too.R3
  550. ; If this is not so, not much sense searching more.L9
  551. 5$:     cmpl    <ucb$l_icsign-ucb$a_vicddt>(r10),#p.magic;C
  552.         bneq    3$                     ;exit if this is nonstd bash
  553. ; follow DDT block chain to next saved DDT.,5
  554.         movl    <ucb$l_prevddt-ucb$a_vicddt>(r10),r10LI
  555.                                         ;point R10 at the next DDT in theR
  556.                     ;chain F
  557.         bgeq    3$                     ; (error check if not negative)9
  558.         brb     2$                      ;then check againd
  559. 3$:h$
  560.     clrl    r11    ;return 0 if nothing found
  561.     brb    4$O
  562. ; Few macros for long distance branches...
  563.     .macro    beqlw    lbl,?lbl2
  564.     bneq    lbl2
  565.     brw    lbl
  566. lbl2:    
  567.     .endm
  568.     .macro    bneqw    lbl,?lbl2D
  569.     beql    lbl2
  570.     brw    lbl
  571. lbl2:    
  572.     .endm
  573.     .macro    bleqw    lbl,?lbl2T
  574.     bgtr    lbl2
  575.     brw    lbl
  576. lbl2: 
  577.     .endm
  578.     .macro    bgeqw    lbl,?lbl2M
  579.     blss    lbl2
  580.     brw    lbl
  581. lbl2:d
  582.     .endm)
  583. ; allocate does not zero its result area.CE
  584. ; This macro makes it easy to zero an allocated area before using it.B@
  585. ; Leaves no side effects...just zeroes the area for "size" bytes
  586. ; starting at "addr".E
  587.     .macro    zapz    addr,size3
  588.     pushr    #^m<r0,r1,r2,r3,r4,r5>    ;save regs from movc5R
  589.     movc5    #0,addr,#0,size,addrS2
  590.     popr    #^m<r0,r1,r2,r3,r4,r5>    ;save regs from movc5
  591.     .endm
  592.     .SBTTL Our FDT Filter Routines
  593.     .if    df,evax<
  594. mfyfilt: .jsb_entry    ;filter on MODIFY requests (e.g. extend)
  595.     .iffT1
  596. mfyfilt:    ;filter on MODIFY requests (e.g. extend)B
  597.     .endc
  598. ; JG_format - bash host disk tables to point at ours.c
  599. ; With no function modifiers, this routine takes as arguments the nameE
  600. ; of the host disk (the real disk where the virtual disk will exist),RB
  601. ; the size of the virtual disk, and the LBN where the virtual diskE
  602. ; will start. After these are set up, the device is put online and isC
  603. ; software enabled.N
  604. ; This routine does virtually no checking, so the parameters must be
  605. ; correct.
  606. ; Inputs: >
  607. ;    p1 - pointer to buffer. The buffer has the following format:=
  608. ;         longword 0 - (was hlbn) - flag for function. 1 to bash .
  609. ;              the targetted disk, 2 to unbash it, else
  610. ;              illegal.@
  611. ;         longword 1 - virtual disk length, the number of blocks in,
  612. ;              the virtual disk. If negative disables&
  613. ;              FDT chaining; otherwise ignored.@
  614. ;         longword 2 through the end of the buffer, the name of the-
  615. ;              virtual disk. This buffer must be blank
  616. ;              padded if padding is necessary
  617. ;    p2 - size of the above buffero
  618.     .if    df,evax
  619. JG_format: .jsb_entryf
  620.     .iff'
  621. JG_format:
  622.     .endc<
  623.     bicw3    #io$m_fcode,irp$w_func(r3),r0    ;mask off function code)
  624.     bneq    20$            ;branch if modifiers, specialC)
  625. ;thus, normal io$_format will do nothing.L
  626.     rsb                ;regular processingR
  627. 100$:C0
  628.     popr    #^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
  629. 10$:+
  630.     movzwl    #SS$_BADPARAM,r0    ;illegal parameterI
  631.     clrl    r1
  632.     jmp    g^exe$abortio
  633. 20$: 
  634.     movl    p1(ap),r0        ;buffer address"
  635.     movl    p2(ap),r1        ;length of buffer:
  636.     jsb    g^exe$writechk        ;read access? doesn't return on error:
  637. ;    clrl    irp$l_bcnt(r3)        ;paranoia, don't need to do this...1
  638.     pushr    #^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>L$
  639.     movl    p1(ap),r0        ;get buffer address 
  640.     movl    (r0)+,r7        ;get option code#
  641.     bleq    100$            ;0 or negative illegal
  642.     cmpl    r7,#2            ;3 and up illegal too    
  643.     bgtr    100$
  644.     incl    chnflg/
  645.     movl    (r0)+,r6        ;size of virtual disk (ignored);    
  646.     bleq    70$O0
  647.     clrl    chnflg            ;if 0 or neg. size don't chain...
  648. 70$:$
  649.     movab    (r0),-            ;name of "real" disk
  650.         ucb$l_JG_host_descr+4(r5)G5
  651.     subl3    #8,p2(ap),-        ;set length of name in descriptorR
  652.         ucb$l_JG_host_descr(r5)    
  653.     bleq    100$            ;bad length4
  654.     movab    ucb$l_JG_host_descr(r5),r1    ;descriptor for...-
  655.     jsb    g^ioc$searchdev        ;search for host deviceE!
  656.     blbs    r0,30$            ;branch on successE
  657. ; fail the associate...S0
  658.     popr    #^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>=
  659.     movzwl    #ss$_nosuchdev+2,r0    ;make an error, usually a warninge
  660.     clrl    r1$
  661.     jmp    g^exe$abortio        ;exit with error
  662. 30$:    ;found the device
  663. ; r1 is target ucb address... $
  664. ; move it to r11 to be less volatile
  665.     movl    r1,r11%
  666.     cmpl    r7,#1        ;bashing the target UCB?d
  667.     bneq    31$        ;if neq it's unmung
  668.     jsb    mung        ;go mung target...e
  669.     brb    32$
  670. 31$:H
  671. ; Be sure we unmung the correct disk or we can really screw up a system.-
  672.     cmpl    r11,ucb$l_vict(r5)    ;undoing right disk?A)
  673.     bneq    32$            ;if not skip out, do nothing.    
  674.     jsb    umung        ;unmung target
  675. 32$:3
  676. ;    bisw    #ucb$m_valid,ucb$w_sts(r5)    ;set volume validS3
  677. ;    bisw    #ucb$m_online,ucb$w_sts(r5)    ;set unit onlineD5
  678. ;    movl    ucb$l_irp(r5),r3        ;restore r3, neatness counts;0
  679.     popr    #^m<r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>!
  680.     movzwl    #ss$_normal,r0            ;successY'
  681.     jmp    g^exe$finishioc            ;wrap things up.L
  682.     .if    df,evax
  683. mung: .jsb_entry
  684.     .iffB
  685. mung:    
  686.     .endc=
  687. ; steal DDT from host. Assumes that the intercept UCB addressOB
  688. ; is in R5 (that is, the UCB in which we will place the DDT copy),=
  689. ; and that the UCB of the device whose DDT we are stealing isDC
  690. ; pointed to by R11. All registers are preserved explicitly so thatUB
  691. ; surrounding code cannot be clobbered. R0 is returned as a statusC
  692. ; code so that if it returns with low bit clear, it means somethingDG
  693. ; went wrong so the bash did NOT occur. This generally means some otherAF
  694. ; code that does not follow this standard has grabbed the DDT already.A
  695. ; The following example assumes the code lives in a driver so theE3
  696. ; unique ID field and magic number are set already. 6
  697.     movab    fcae,fcnca    ;ensure final FDT entry is filled in7
  698.         pushr   #^m<r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11> 5
  699. ; Acquire victim's fork lock to synchronize all this.Y7
  700.         movl    #ss$_normal,r0          ;assume successt"
  701.         forklock ucb$b_flck(r11),-
  702.     savipl=-(sp),preserve=YES@
  703. ; find the current DDT address from the UCB (leaving the copy in
  704. ; the DDB alone)>
  705.         movl    ucb$l_ddt(r11),r10      ;point at victim's DDB-
  706. ; see if this DDT is the same as the originaluF
  707.         movl    ucb$l_ddb(r11),r9       ;the ddb$l_ddt is the originalG
  708.         cmpl    ddb$l_ddt(r9),r10       ;bashing driver the first time?d3
  709.         beql    1$                      ;if eql yesnG
  710. ; driver was bashed already. Check that the current basher followed thet)
  711. ; standard. Then continue if it looks OK..9
  712.         cmpl    <ucb$l_icsign-ucb$a_vicddt>(r10),#p.magicuF
  713.                                         ;does the magic pattern exist?6
  714. ; if magic pattern is missing things are badly messed.E
  715.         beql    2$                      ;if eql looks like all's wellm:
  716.         movl    #2,r0                   ;say things failed=
  717.         brw     100$                    ;(brb might work too) 
  718. 2$:t<
  719. ; set our new ddt address in the previous interceptor's slotB
  720.         movab   ucb$a_vicddt(r5),<ucb$l_intcddt-ucb$a_vicddt>(r10)H
  721.                                         ;store next-DDT address relativeC
  722.                                         ;to the original victim ones
  723. 1$:aD
  724.         movl    r10,ucb$l_prevddt(r5)   ;set previous DDT address upI
  725.         clrl    ucb$l_intcddt(r5)       ;clear intercepting DDT initiallyo
  726.         pushl   r5&
  727. ; copy a little extra for good luck...J
  728.         movc3   #<ddt$k_length+12>,(r10),ucb$a_vicddt(r5)    ;copy the DDTO
  729.         popl    r5                      ;get UCB pointer back (movc3 bashes it)r
  730. ; Here make whatever mods to the DDT you need to.o
  731. ; FOR EXAMPLE make the following mods to the FDT pointer7
  732. ; (These assume the standard proposed for FDT pointers)NH
  733.         movab   ucb$a_vicddt(r5),r8     ;get a base register for the DDTE
  734.         movl    r5,JG_functable+fdt_prev    ;save old FDT ucb addressK:
  735.     movl    ddt$l_fdt(r10),ucb$l_oldfdt(r5) ;save orig. fdt addrK
  736.         movl    ucb$l_uniqid(r5),JG_functable+fdt_idnt ;save unique ID alsoD9
  737. ; copy legal and buffered entry masks of original driver.EA
  738. ; HOWEVER, set mask for format entry to be nonbuffered here sinceO
  739. ; we deal with it.
  740.     pushr    #^m<r6,r7,r8,r9>/;
  741.     movab    ucb$l_fdtlgl(r5),r9    ;our function table dummy in UCB-+
  742.     movl    ddt$l_fdt(r10),r7    ;victim's FDT table C
  743. ; We want all functions legal in the victim's FDT table to be legala
  744. ; here. &
  745.     movl    (r7),(r9)+        ;1st half legal mask'
  746.     movl    4(r7),(r9)+        ;2nd half legal mask *
  747.     movl    8(r7),(r9)+        ;1st half buffered mask+
  748.     movl    12(r7),(r9)+        ;2nd half buffered mask 6
  749. ; Now copy in our modify & back-to-original FDT cells.B
  750. ; Thus every unit has its own legal & buffered masks, then goes to0
  751. ; original FDT, and we don't mess with OUR FDTs.2
  752. ; (Also original FDT tables aren't messed either.)&
  753.     movl    mymfy,(r9)+        ; modify template 1
  754.     movl    mymfy+4,(r9)+        ; & 2!
  755.     movl    mymfy+8,(r9)+        ;and addressS@
  756. ; Set -1 to set ALL possible function bits so we always go back.*
  757.     movl    #-1,(r9)+        ;then catch-all "go back""
  758.     movl    #-1,(r9)+        ; to original fdt*
  759.     movl    mybak+8,(r9)        ; and address of same.
  760.     popr    #^m<r6,r7,r8,r9>D
  761.         movab    ucb$l_fdtlgl(r5),ddt$l_fdt(r8) ;point at our FDT table<
  762.     movl    ddt$l_start(r8),ucb$l_hstartio(r5)    ;save host start-io0
  763.     movl    r11,ucb$l_hstucb(r5)    ;save backpointer too7
  764.     movab    stealstart,ddt$l_start(r8)    ;point at our startio 8
  765.         clrl    myonoff                 ;turn my FDTs on
  766. ; Finally clobber the victim device's DDT pointer to point to our new 
  767. ; one./
  768.         movab   ucb$a_vicddt(r5),ucb$l_ddt(r11)D@
  769. ; Now the DDT used for the victim device unit is that of our UCBI
  770. ; and will invoke whatever special processing we need. This processing in C
  771. ; the example here causes the intercept driver's FDT routines to be C
  772. ; used ahead of whatever was in the original driver's FDTs. BecauseVE
  773. ; the DDT is modified using the UCB pointer only, target device units B
  774. ; that have not been patched in this way continue to use their old
  775. ; DDTs and FDTs unaltered.
  776. ; Processing complete; release victim's fork lock    
  777. 100$:F6
  778.         forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,-
  779.          preserve=YESA7
  780.         popr    #^m<r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>F
  781.     .if    df,evax
  782. umung: .jsb_entryA
  783.     .iff
  784. umung:
  785.     .endc
  786. ; Entry: R11 points at victim device UCB and current driver is the oneK
  787. ; desiring to remove its entry from the DDT chain. Thus its xx$dpt: address    E
  788. ; is the one being sought. ("Current driver" here means the interceptD
  789. ; driver.)F
  790. ;   It is assumed that the driver knows that the DDT chain was patched4
  791. ; so that its UCB contains an entry in the DDT chain.
  792.         pushr   #^m<r0,r1,r2,r3,r4,r5,r10,r11>0
  793.     movl    r11,r5            ;hereafter use r5 as victim's UCBF
  794.         movl    ucb$l_ddt(r5),r10       ;get the DDT we currently have:
  795.         movl    ucb$l_ddb(r5),r1        ;get ddb of victim>
  796.         movl    ddb$l_ddt(r1),r1        ;and real original DDTF
  797.         movl    r10,r0                  ;save ucb$l_ddt addr for laterC
  798.         movab   DPT$TAB,r11             ;magic pattern is DPT addr.    9
  799. ; lock this section with forklock so we can safely removeC3
  800. ; entries at fork also. Use victim device forklock.
  801.         forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=YES4
  802. 2$:     cmpl    <ucb$l_uniqid-ucb$a_vicddt>(r10),R11=
  803.                                         ;this our own driver?E?
  804.         beql    1$                      ;if eql yes, end searchH
  805.         .if     df,chk.err9
  806.         cmpl    <ucb$l_icsign-ucb$a_vicddt>(r10),#p.magicaD
  807.         bneqw    4$                     ;exit if this is nonstd bash
  808.         .endc   ;chk.err+
  809. ; follow DDT block chain to next saved DDT.;5
  810.         movl    <ucb$l_prevddt-ucb$a_vicddt>(r10),r10 I
  811.                                         ;point R10 at the next DDT in thes.
  812.                                         ;chain
  813.         .if     df,chk.errF
  814.         bgeqw   4$                     ; (error check if not negative)
  815.         .endc   ;chk.err9
  816.         brb     2$                      ;then check againf
  817. 1$:vA
  818. ; At this point R10 contains the DDT address within the intercept,F
  819. ; driver's UCB. Return the address of the intercept driver's UCB next.M
  820.         tstl    <ucb$l_intcddt-ucb$a_vicddt>(r10)       ;were we intercepted?eC
  821.         bgeq    3$                      ;if geq no, skip back-fixupt/
  822. ; we were intercepted. Fix up next guy in line. L
  823.         movl    <ucb$l_intcddt-ucb$a_vicddt>(r10),r11  ;point at interceptorS
  824.         movl    <ucb$l_prevddt-ucb$a_vicddt>(r10),<ucb$l_prevddt-ucb$a_vicddt>(r11)n
  825. 3$:DE
  826. ; if we intercepted someone, fix up our intercepted victim to skip byb
  827. ; us also.I
  828.         movl    <ucb$l_prevddt-ucb$a_vicddt>(r10),r2    ;did we intercept 9
  829.                                         ;original driver?cA
  830.         cmpl    r2,r1                   ;test if this is original <
  831.         beql    5$                      ;if eql yes, no bashB
  832. ; replace previous intercept address by ours (which might be zero)R
  833.         movl    <ucb$l_intcddt-ucb$a_vicddt>(r10),<ucb$l_intcddt-ucb$a_vicddt>(r2)
  834. 5$:s>
  835. ; Here remove FDT entries from the list if they were modified.=
  836. ; This needs a scan of the FDT chain starting at the victim'sFB
  837. ; ddt$l_fdt pointer and skipping around any entry that has address
  838. ; JG_functable:tB
  839. ;  The FDT chain is singly linked. The code here assumes everybody
  840. ; plays by the same rules!G
  841. ; NOTE: Omit this code if we didn't insert our FDT code in the chain!!!m;
  842.         movl    ddt$l_fdt(r0),r1        ;start of FDT chainiA
  843.         movab   JG_functable,r2         ;address of our FDT tablea
  844.         clrl    r3;
  845.     movab    <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucbeD
  846. ; Also set the JG device offline when we unbash it. This is a simple@
  847. ; flag that ctl prog. can use to tell if it's been used already.
  848.     .if    df,evax/
  849.     bicl    #<ucb$m_valid!ucb$m_online>,ucb$l_sts(r4)s
  850.     .iffs/
  851.     bicw    #<ucb$m_valid!ucb$m_online>,ucb$w_sts(r4) 
  852.     .endcA
  853. 6$:     cmpl    r1,r2                   ;current fdt point at us?nA
  854.         beql    7$                      ;if eql yes, fix up chainq@
  855.         movl    r1,r3                   ;else store last pointer:
  856.         movl    fdt_prev(r1),r4         ;and point at next
  857.     bgeq    8$?
  858.     movl    ucb$l_oldfdt(r4),r1    ;where last FDT pointer is in the ucb A
  859. ;;;BUT not all UCBs will have the fdt offset at the same place!!!oF
  860. ;;;HOWEVER we will leave this in, putting the oldfdt field first after
  861. ;;;the regular UCB things.D
  862.         bgeq    8$                      ;if not sys addr, no messin'?
  863.         brb     6$                      ;look till we find one.u
  864. 7$:s*
  865. ;r3 is 0 or fdt pointing to our block next
  866. ;r1 points at our fdt blockbD
  867.         tstl    r3                      ;if r3=0 nobody points at us9
  868.         bgeq    8$                      ;so nothing to doy
  869.     movl    fdt_prev(r1),r4
  870.     bgeq    17$h.
  871.     movl    ucb$l_oldfdt(r4),-(sp)    ;save old fdt loc
  872.     movl    fdt_prev(r3),r4e    
  873.     blss    18$a
  874.     tstl    (sp)+o
  875.     brb    17$ 
  876. 18$:    movl    (sp)+,ucb$l_oldfdt(r4)N
  877. 17$:    movl    fdt_prev(r1),fdt_prev(r3)  ;else point our next-fdt pointer at7
  878.                                         ;last fdt addr.t
  879. ; Finally if the victim UCB DDT entry points at ours, make it point atF
  880. ; our predecessor. If it points at a successor, we can leave it alone.J
  881.         cmpl    r10,r0                  ;does victim ucb point at our DDT?A
  882.         bneq    4$                      ;if not cannot replace itn?
  883.         movl    <ucb$l_prevddt-ucb$a_vicddt>(r10),ucb$l_ddt(r5) 
  884. 4$:o@
  885.         forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES-
  886.        popr    #^m<r0,r1,r2,r3,r4,r5,r10,r11>mK
  887.                                         ;copy our prior DDT ptr to next one 
  888. ; stealstart - start-io entry '
  889. ; Must eventually call host's start-io.,
  890. ; entry: r3=IRP, r5=host UCB
  891. toorgj:    brw    toorgd
  892. awab:    brw    away
  893.     .if    df,evax
  894. stealstart: .jsb_entry
  895.     .iffu
  896. stealstart:D
  897.     .endc    
  898.     pushl    r51%
  899.     jsb    getjgucb    ;find intercept UCB now 
  900.     tstl    r0        ;did we find it?*
  901.     bgeq    awab        ;no, scram, but probably hang.&
  902.     cmpl    ucb$l_hstucb(r0),r5    ;right host?
  903.     beql    70$        ;if ok, leave-
  904.     movl    r5,ucb$l_hstucb(r0)    ;else put it in nowa
  905. 70$:(
  906.     movl    r0,r5        ;point at intercept ucb now<
  907.     bitl    #1048576,ucb$l_ctlflgs(r5)    ;user want error reduction?
  908.     beql    toorgj        ;if not skip out9
  909. ; besure this is read or write, else just start orig. one.<
  910.     EXTZV   #IRP$V_FCODE,-          ; Extract I/O function code)
  911.                 #IRP$S_FCODE,-          ;i!
  912.                 IRP$W_FUNC(R3),R0
  913.         ASSUME  IRP$S_FCODE LE 7        ; Allow byte mode dispatch!
  914.     cmpl    r0,#io$_writepblk    ;too low? 
  915.     blss    toorgj
  916.     cmpl    r0,#io$_readpblk
  917.     bgtr    toorgjC
  918. ; gotta arrange to get back after done the I/O and to reissue it ifi/
  919. ; errors happened and we're not out of count... 
  920.     .iif ndf,maxtries,maxtries=128cG
  921. ;We'll keep the info in the UCB for debugging, but when the host driver J
  922. ; that we're intercepting does a request completion, it will unbusy itselfN
  923. ; and dequeue anything else that was in the device queue. As a result, we needG
  924. ; to track when an IRP has already been modified in this pass, and mustrF
  925. ; also just go directly to the original code where that should happen.)
  926. ; To accomplish this we need storage for: 
  927. ;  1. Original irp$l_pid
  928. ;  2. Original irp$l_mediaL
  929. ;  3. Current retry count (and maybe use hi word as a flag that we have this
  930. ;            IRP)
  931. ; Since I don't want to mess anything up in the regular IRP, just allocateF
  932. ; a buffer and use the keydesc slot to point at it. If user has a key,J
  933. ; we let the i/o by and he takes his chances with device errors. Advertise-
  934. ; that opticals don't support dec encryption.m
  935. ; If user has something in the key field leave this IRP alone.$
  936.     bbs    #irp$v_key,irp$w_sts(r3),toorgj?
  937. ; key field should be free. Grab a bit of pool & point at it ifs
  938. ; nothing's there.
  939. vv.magic=0
  940. val.magic=^x76543210
  941. vv.retries=4
  942. vv.media=8    
  943. vv.pid=12a?
  944. ; Set the key bit and go grab an area of mem. to hold our info.v"
  945.     bbss    #irp$v_key,irp$w_sts(r3),16$-
  946. 16$:    clrl    irp$l_keydesc(r3)    ; zero initially.e
  947.     pushr    #^m<r0,r1,r2,r3,r4,r5>.$
  948.     movl    #32,r1            ;get 8 longwords area,
  949.     jsb    g^exe$alonpagvar    ;get the space or fail.
  950.     blbc    r0,55$        ; br if no space & just give up.    
  951. ; got it.r-
  952.     movl    r2,irp$l_keydesc(r3)    ;save area address
  953. vv.magic=0
  954. val.magic=^x76543210
  955. vv.retries=4
  956. vv.media=8    
  957. vv.pid=12u
  958. vv.bash=16-
  959.     movl    #val.magic,vv.magic(r2)    ;flag we got it
  960.     movl    i^#maxtries,vv.retries(r2)    ;save retry count?
  961.     movl    irp$l_media(r3),vv.media(r2)    ;save original media addressh;
  962.     movl    irp$l_pid(r3),vv.pid(r2)    ;save original pid addr too.h
  963.     popr    #^m<r0,r1,r2,r3,r4,r5>
  964.     brb    56$
  965. 55$:?
  966.     bbcc    #irp$v_key,irp$w_sts(r3),17$    ;clr key bit if we have nonea
  967.     popr    #^m<r0,r1,r2,r3,r4,r5>.
  968.     brw    toorg            ;can't find pool, just let irp by
  969. 56$:@
  970.     movl    I^#maxtries,ucb$l_retries(r5)    ;set initial retry count up.6
  971.     movl    irp$l_media(r3),ucb$l_omedia(r5) ;save lbn stuff5
  972.     movl    irp$l_pid(r3),ucb$l_ppid(r5)    ;save pid info tookD
  973.     movl    r3,ucb$l_irp(r5)    ;for debug keep irp addr in intercept ucb too:
  974. ; now set up IRP, then call the previous start-io point at<
  975. ; ucb$l_hstartio(r5) to do the work with registers put back.E
  976. ; For Alpha, the stack manipulation here is messy to track in machinec
  977. ; code, so do it in a register.e6
  978.     movl    r11,-(sp)        ; Free up ol' reliable R11 as scratch 
  979.     movl    r10,-(sp)        ; Free R10 also.
  980.     movzwl    ucb$w_unit(r5),r11    ; Need address cellI
  981. ; following assumes that addresses are 32 bits long so shift by 2 gets uso
  982. ; to an address offset.r7
  983.     ashl    #2,r11,r11        ; to get ucb address back at i/o done,6
  984.     movab    vd_ucbtbl,r10        ; Base of table of UCB addresses6
  985.     addl2    r11,r10            ; Make R10 point to cell for THIS UCB0
  986.     movl    r5,(r10)        ; Now save our UCB address there$
  987. ; (THIS ALLOWS US TO GET IT BACK...):
  988. ; This trick allows us to leave the rest of the IRP alone.
  989. ; Now the tricky bit.'C
  990. ; We must fill the appropriate address into IRP$L_PID for a call at1@
  991. ; I/O completion. We use a table of such routines, one per unit,=
  992. ; all of the same size so we can calculate the address of the3>
  993. ; routines. However, since the routine addresses can be almost9
  994. ; anywhere when the compiler gets done with them, we will    E
  995. ; use a table constructed BY the compiler of pointers to them all andlI
  996. ; access via that instead of just forming the address directly. The tablem,
  997. ; entries will be left 2 longs in size each.J
  998. ; Table VD_VOADT is what we need. Note however that the .address operatorsH
  999. ; there probably need to change to some more general .linkage directive.0
  1000.     movzwl    ucb$w_unit(r5),r11    ; get our unit number&
  1001. ; Each linkage pair is 8 bytes long...6
  1002.     ashl    #3,r11,r11        ; Make an offset to the linkage area)
  1003.     movab    vd_voadt,r10        ; get the table base 2
  1004.     addl2    r10,r11            ; r11 now points at the link addr;
  1005.     movl    (r11),irp$l_pid(r3)    ; Now point irp$l_pid at a proper1
  1006.     .if    ndf,evax#"
  1007. ; must add vjg$dpt address to this#
  1008.     movab    vjg$dpt,r10    ;start of driver;4
  1009.     addl2    r10,irp$l_pid(r3)    ;now pid should get back ok
  1010.     .endc    
  1011.     pushl    r0o
  1012.     movl    irp$l_keydesc(r3),r07
  1013.     movl    irp$l_pid(r3),vv.bash(r0)    ;save pid field we needb
  1014.     popl    r0'
  1015.                     ; pointer to the desired procedureg0
  1016. ;                ; GET BACK CONTROL AT VD_FIXSPLIT (VIA JSB)
  1017. ;                ; WHEN HOST'S I/O IS DONE.w
  1018.     movl    (sp)+,r10        ; Restore R101
  1019.     movl    (sp)+,r11        ; get r11 back & clean stack now30
  1020.     tstl    irp$l_ioqfl(r3)        ;i/o queue look sensible?#
  1021.     blss    19$        ;if negative it might bea>
  1022.     clrl    irp$l_ioqfl(r3)        ;else preemptively zero it for requeues0
  1023. 19$:    cmpl    irp$l_ioqfl(r3),#^xff000000    ;too high?/
  1024.     blssu    20$        ;if not real obvious leave it alonep
  1025.     clrl    irp$l_ioqfl(r3) 
  1026. 20$:7
  1027. ; Now restore registers and go to the original routine.n*
  1028. ; This is also where we come to try again.L
  1029. ; Assumes host ucb address on stack, JG ucb address in R5, IRP address in R3
  1030. steal2: >
  1031. toorg:    movl    ucb$l_hstartio(r5),r0    ;address of original routine(
  1032.     bgeq    away        ; if none, things are messed
  1033.     .iif df,x$$$dt, jsb g^ini$brk!
  1034.     popl    r5        ; get back original UCBr!
  1035.     movl    r0,-(sp)    ; save where to go
  1036.     movl    #1,r0        ; set ok status for now"
  1037.     jmp    @(sp)+        ; go to original code%
  1038. ;    jmp    (r0)            ;go to the original codel
  1039. away: 
  1040.     popl    r5
  1041.     .SBTTL    CONTROLLER INITIALIZATION ROUTINEa
  1042. ; JG_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE
  1043. ; FUNCTIONAL DESCRIPTION:3
  1044. ; noop    
  1045. ; INPUTS:r
  1046. ; R4 - CSR ADDRESS
  1047. ; R5 - IDB ADDRESS
  1048. ; R6 - DDB ADDRESS
  1049. ; R8 - CRB ADDRESS
  1050. ;     THE OPERATING SYSTEM CALLS THIS ROUTINE: 
  1051. ;         - AT SYSTEM STARTUP)
  1052. ;         - DURING DRIVER LOADINGS(
  1053. ;         - DURING RECOVERY FROM POWER FAILURE<
  1054. ;     THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.
  1055.     .if    df,evax7
  1056. JG_ctrl_INIT: .jsb_entry        ;JG CONTROLLER INITIALIZATIONs
  1057.     .iffi,
  1058. JG_ctrl_INIT:        ;JG CONTROLLER INITIALIZATION
  1059.     .endc*
  1060. ;    CLRL    CRB$L_AUXSTRUC(R8)    ; SAY NO AUX MEM
  1061.     movl    #1,r01
  1062.     RSB                ;RETURNd-
  1063.     .SBTTL    INTERNAL CONTROLLER RE-INITIALIZATION 
  1064. ; INPUTS: 
  1065. ;    R4 => controller CSR (dummy)
  1066. ;    R5 => UCBe
  1067. ctrl_REINIT:
  1068.     RSB        ; RETURN TO CALLER#
  1069.     .SBTTL    UNIT INITIALIZATION ROUTINEK
  1070. ; JG_unit_INIT - UNIT INITIALIZATION ROUTINE
  1071. ; FUNCTIONAL DESCRIPTION: 
  1072. ;     THIS ROUTINE SETS THE JG: ONLINE.
  1073. ;     THE OPERATING SYSTEM CALLS THIS ROUTINE:d
  1074. ;         - AT SYSTEM STARTUP 
  1075. ;         - DURING DRIVER LOADING (
  1076. ;         - DURING RECOVERY FROM POWER FAILURE
  1077. ; INPUTS: 
  1078. ;     R4    - CSR ADDRESS (CONTROLLER STATUS REGISTER)(
  1079. ;     R5    - UCB ADDRESS (UNIT CONTROL BLOCK)
  1080. ;    R8    - CRB ADDRESS
  1081. ; OUTPUTS:
  1082. ;     THE UNIT IS SET ONLINE.0
  1083. ;     ALL GENERAL REGISTERS (R0-R15) ARE PRESERVED.
  1084.     .if    df,evax2
  1085. JG_unit_INIT: .jsb_entry            ;JG UNIT INITIALIZATION
  1086.     .iffa3
  1087. JG_unit_INIT:; .jsb_entry            ;JG UNIT INITIALIZATION 
  1088.     .endc.
  1089.     movab    fcae,fcnca    ; set up catch-all final FDT>
  1090. ; Don't set unit online here. Priv'd task that assigns JG unit<
  1091. ; to a file does this to ensure only assigned JGn: get used.:
  1092. ;    BISW    #UCB$M_ONLINE,UCB$W_STS(R5)  ;SET UCB STATUS ONLINE
  1093. ;limit size of JG: data buffers(
  1094. JG_bufsiz=81929
  1095.     movl    #JG_bufsiz,ucb$l_maxbcnt(r5)    ;limit transfers to 8k 9
  1096.     MOVB    #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET MISC DEVICE CLASSk
  1097. ; NOTE: we may want to set this as something other than an RX classl>
  1098. ; disk if MSCP is to use it. MSCP explicitly will NOT serve an<
  1099. ; RX type device. For now leave it in, but others can alter.7
  1100. ; (There's no GOOD reason to disable MSCP, but care!!!)J9
  1101.     movl    #^Xb22d4001,ucb$l_media_id(r5)    ; set media id as JGdG
  1102. ; (note the id might be wrong but is attempt to get it.) (used only for_
  1103. ; MSCP serving.)>
  1104.     MOVB    #DT$_FD1,UCB$B_DEVTYPE(R5)  ;Make it foreign disk type 1/
  1105. ; (dt$_rp06 works but may confuse analyze/disk)mG
  1106. ;;; NOTE: changed from fd1 type so MSCP will know it's a local disk andp8
  1107. ;;; attempt no weird jiggery-pokery with the JG: device.G
  1108. ; MSCP may still refuse to do a foreign drive too; jiggery-pokery later
  1109. ; to test if there's occasion to do so.i
  1110. ; Set up crc polynomiala6
  1111. ;    clrl    chnflg        ;initially set to use our chain of FDTs
  1112.     movl    #1,chnflgn
  1113.     movl    #1,r0m
  1114.     RSB                ;RETURN 
  1115.     .SBTTL    START I/O ROUTINEk
  1116. ; JG_STARTIO - START I/O ROUTINE
  1117. ; FUNCTIONAL DESCRIPTION:b
  1118. ;     THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTs
  1119. ;     PACKET HAS BEEN DEQUEUED.
  1120. ; INPUTS:t
  1121. ;     R3        - IRP ADDRESS (I/O REQUEST PACKET)e)
  1122. ;     R5        - UCB ADDRESS (UNIT CONTROL BLOCK)    :
  1123. ;     IRP$L_MEDIA    - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER)
  1124. ; OUTPUTS:
  1125. ;     R0    - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFEREDo/
  1126. ;     R1    - SECOND I/O STATUS LONGWORD: 0 FOR DISKS"
  1127. ;     THE I/O FUNCTION IS EXECUTED.
  1128. ;     ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.
  1129.     .if    df,evax.
  1130. JG_STARTIO: .jsb_entry                ;START I/O OPERATION
  1131.     .iffT#
  1132. JG_STARTIO:                ;START I/O OPERATIONs
  1133.     .endc
  1134. ;     PREPROCESS UCB FIELDS
  1135. ;    ASSUME    RY_EXTENDED_STATUS_LENGTH  EQ  8vD
  1136. ;    CLRQ    UCB$Q_JG_EXTENDED_STATUS(R5)    ; Zero READ ERROR REGISTER area.
  1137. ;     BRANCH TO FUNCTION EXECUTION 3
  1138.     bbs    #ucb$v_online,-    ; if online set software validn
  1139.         ucb$w_sts(r5),210$5
  1140. 216$:    movzwl    #ss$_volinv,r0    ; else set volume invalidr'
  1141.     brw    resetxfr    ; reset byte count & exite
  1142. 210$:i;
  1143. ; Unless we use this entry, we want to junk any calls here.e+
  1144.     brb    216$        ;just always say invalid volume.m
  1145. ; Get here for other start-io entries if the virtual disk code ise$
  1146. ; commented out also, as it must be.!
  1147. FATALERR:                ;UNRECOVERABLE ERRORm2
  1148.     MOVZWL    #SS$_DRVERR,R0        ;ASSUME DRIVE ERROR STATUS
  1149. RESETXFR:    ; dummy entry ... should never really get here#
  1150.     MOVL    UCB$L_IRP(R5),R3    ;GET I/O PKTe5
  1151.     MNEGW    IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNTc
  1152. ;    BRW    FUNCXT
  1153. FUNCXT:                    ;FUNCTION EXIT&
  1154.     CLRL    R1            ;CLEAR 2ND LONGWORD OF IOSB
  1155.     REQCOM                ; COMPLETE REQUEST1
  1156. PWRFAIL:                ;POWER FAILURE:
  1157.     BICW    #UCB$M_POWER,UCB$W_STS(R5)  ;CLEAR POWER FAILURE BIT1
  1158.     MOVL    UCB$L_IRP(R5),R3    ;GET ADDRESS OF I/O PACKETB5
  1159.     MOVQ    IRP$L_SVAPTE(R3),-    ;RESTORE TRANSFER PARAMETERSs
  1160.         UCB$L_SVAPTE(R5)    ;....$
  1161.     BRW    JG_STARTIO        ;START REQUEST OVER
  1162. JG_INT::
  1163. JG_UNSOLNT::
  1164.     POPR    #^M<R0,R1,R2,R3,R4,R5>%
  1165.     REI    ;DUMMY RETURN FROM ANY INTERRUPTh
  1166. V_UNIT=0
  1167. V_UNM=1t
  1168.     .if    df,evax
  1169. VD_FXS0:: .jsb_entry input=<r5>t
  1170.     .iff     
  1171. VD_FXS0::e
  1172.     .endc
  1173.     MOVL    I^#V_UNIT,R4
  1174.     BSBW    VD_FIXSPLIT    ;GO HANDLE
  1175.     RSBA
  1176. VD_FXPL==<.-VD_FXS0>    ;LENGTH IN BYTES OF THIS LITTLE CODE SEGMENT_#
  1177. V_UNIT=V_UNIT+4        ;PASS TO NEXT UNITr
  1178.     .MACRO    XVEC LBLC 
  1179.     .if    df,evax"
  1180. VD_FXS'LBLC: .jsb_entry input=<r5>
  1181.     .iff 
  1182. VD_FXS'LBLC:
  1183.     .endc
  1184.     MOVL    I^#V_UNIT,R4
  1185.     BSBW    VD_FIXSPLIT 
  1186.     .ENDM-
  1187.     .REPEAT    <VD_UNITS+4>    ; some extra for safetyl
  1188.     XVEC    \V_UNM#
  1189. V_UNIT=V_UNIT+4        ;PASS TO NEXT UNITc
  1190. V_UNM=V_UNM+1 
  1191.     .ENDR
  1192.     .if    df,evax
  1193. VD_FIXSPLIT: .jsb_entrya
  1194.     .iffy
  1195. VD_FIXSPLIT:
  1196.     .endc
  1197. ; GET OLD PID..i
  1198. ; IN OUR UCB$PPID LONGWORD... G
  1199. ;some cleanup for host needed here. Note that r5 enters as IRP address.u/
  1200. ; Use initial R5 to help reset host's system... 
  1201. ;    .iif df,x$$$dt, jsb g^ini$brku)
  1202.     PUSHL    R4        ;r4 enters with JG unit number 0
  1203.     movl    r5,r3        ;put entering IRP addr in std place
  1204.     MOVAB    VD_UCBTBL,R5 -
  1205.     ADDL2    (SP)+,R5    ;R5 NOW POINTS AT UCB ADDRESSa-
  1206.     MOVL    (R5),R5        ;NOW HAVE JG UCB ADDRESS IN R5e 
  1207. ; notice stack is now clean too..
  1208.     movl    r5,r4        ;we need the jg ucb at fork levelD
  1209. ;Now we either restart the i/o if an error occurred, or go ahead and@
  1210. ; complete it. In either case we must fork. Also we must fork on!
  1211. ; the HOST'S UCB, not the JG UCB. 0
  1212. ; Therefore get host ucb again and fork on that.2
  1213.     movl    ucb$l_hstucb(r5),r5    ;note jg ucb still in r4)
  1214.     FORK            ;go fork on our UCB now (vd: ucb)k9
  1215. ; Now see if we need to reissue the I/O. If so, go do it.g0
  1216. ; r4 should still be jg ucb, r5=host ucb, r3=irp
  1217.     .if    df,x$$$dt
  1218.     jsb g^ini$brk2
  1219.     cmpl    r3,r3    ;irp. (look at @r3 at this point too.)
  1220.     cmpl    r4,r4    ;jg ucb addr
  1221.     cmpl    r5,r5    ;host ucb addr
  1222.     .endcG
  1223. ; Somehow we seem to get irp$l_ioqfl screwed up. Zero it if it is clear 
  1224. ; it's senseless.b5
  1225.     tstl    irp$l_ioqfl(r3)        ;ioq should always be negativei
  1226.     blss    19$            ;if + or 0 zero it
  1227.     clrl    irp$l_ioqfl(r3),?
  1228. 19$:    cmpl    irp$l_ioqfl(r3),#^XFF000000    ;too high to be sensible?v
  1229.     blssu    20$
  1230.     clrl    irp$l_ioqfl(r3)c
  1231. 20$:(
  1232.     movq    irp$l_media(r3),r0    ;get i/o status5
  1233.     blbs    r0,40$            ;if status is OK, just finish up here. /
  1234.     movl    irp$l_keydesc(r3),r0    ;get buffer area loc2    
  1235.     bgeq    40$ )
  1236.     decl    vv.retries(r0)        ;count retries down "
  1237.     bleq    40$            ;if so also finish now4
  1238. ;looks like we need to continue. Therefore go do so.J
  1239. ; Note that at this point the stack is clean and r3 and r5 are irp and ucb&
  1240. ; of host as his start-io will expect.K
  1241. ; (This will nead some tweaks for axp procedure nesting. OK on Vax though.)i
  1242. ; r5 points at host UCB now.:
  1243. ; Now reset the media field so the IRP will work next time"
  1244.     movl    vv.media(r0),irp$l_media(r3)E
  1245. ; If the host driver clobbered this field, we must ensure we get backnN
  1246. ; here as soon as we hit the next start-io for this driver. Actually it shouldC
  1247. ; be fixed like so now or we wouldn't be here...but be safe anyway.E7
  1248.     movl    vv.bash(r0),irp$l_pid(r3)    ;arrange us to get backcE
  1249. ; can't just call the original code since the driver may be busy with
  1250. ; something else. Our fork synch doesn't completely prevent this, since M
  1251. ; the relevant test is whether the driver is busy. Therefore call exe$insioqcl@
  1252. ; to do it instead, relying on our tests in stealstart to detect(
  1253. ; that this IRP has already been set up.I
  1254. ; Note that we have left the irp$l_pid address still unchanged so that it$F
  1255. ; still will get back here next time around, so again we can check it.:
  1256. ; For this we insert in the original device queue so leave@
  1257. ; r5 pointing at it. Note that steal2 entry wants original R5 on9
  1258. ; the stack but no longer requires R5 pointing at JG UCB.s-
  1259.     clrl    irp$l_ioqfl(r3)    ;be sure the irp is clrr
  1260.     jsb    g^exe$insioqc!
  1261.     movl    #1,r0        ;flag all seems well_
  1262.     rsb            ;return when done.D
  1263. ;;;    brw    steal2
  1264. 40$:+
  1265. ; Reset the IRP to have the original returna=
  1266. ; Thus the IRP will really complete next, not come back here. 
  1267. 1501$:6
  1268. ; GRAB R0 AND R1 AS REQCOM IN HOST DRIVER LEFT THEM...%
  1269.     MOVL    IRP$L_MEDIA(R3),R0    ;GET BACK R0o"
  1270.     MOVL    IRP$L_MEDIA+4(R3),R1    ;AND R1@
  1271. ; R0, R1 ARE AS HOST DRIVER LEFT THEM. R5 POINTS TO CORRECT UCB.
  1272. ; Now restore the original IRP$L_MEDIA field of the IRP in case error F
  1273. ; paths in IOC$REQCOM ever need it. Some very low XQP cache situationsD
  1274. ; may occasionally need this, though in reasonable sysgen configs itE
  1275. ; should never be needed. This is the one area that got bashed duringd;
  1276. ; the earlier I/O completion processing in the host driver.    
  1277. ; This will then appear to be coming from the original driver.
  1278.     pushr    #^m<r0,r1,r2,r3,r4,r5> >
  1279. ; Restore media and pid fields and deallocate the extra field.*
  1280.     movl    irp$l_keydesc(r3),r4    ;get our buffer:
  1281. ;    movl    vv.media(r4),irp$l_media(r3)    ;restore media address+
  1282. ; for com$post use must leave status in IRP.0
  1283.     movl    vv.pid(r4),irp$l_pid(r3)    ;restore pid alsoH
  1284. ; now deallocate the buffer. We never get here unless one was allocated.
  1285.     movl    r4,r0        ;address to freeo
  1286.     movl    #32,r1        ;length to freed,
  1287.     jsb    g^exe$deanonpgdsiz    ;free the pool againA
  1288.     clrl    irp$l_keydesc(r3)    ;zero the key descriptor too for neatnessmG
  1289.     bbcc    #irp$v_key,irp$w_sts(r3),42$ ;if using encryption, never get herep
  1290.     popr    #^m<r0,r1,r2,r3,r4,r5>E
  1291. ;(this may be the problem area; what unbusies the host driver & when?tD
  1292. ; Host driver called reqcom to get here which cleared his unit busy.I
  1293. ; If his unit is not busy now, this isn't really a problem. If it IS busycD
  1294. ; however, this IS a problem, as we really have no business touchingE
  1295. ; the host's UCB busy bit from here. Let's try using com$post insteadu
  1296. ; to finish things up.)b2
  1297. ;;;    JSB    G^IOC$REQCOM    ; GO COMPLETE THE I/O REQUEST;
  1298.     jsb    g^com$post    ; complete the request but leave busy ALONEb 
  1299.     RSB    ; GET BACK TO HOST SOMETIME
  1300. JG_END:                    ;ADDRESS OF LAST LOCATION IN DRIVER 
  1301.     .ENDp
  1302.