*\f BDK010.A#BDK010.A)BACK/TRUNC/BLOCK=8192 *.* []BDK010.A/SAVE EVERHART `>ɗV5.5 _QUICK::  _$1$DKB700: V5.5-2  e*[EVERHART.BASHKIT]BASHDK.DOC;4+,./ 4P-B#+0123KPWO56`3ɗ7 3ɗ89GHJBASHDK ?BashDK is an in-memory driver patcher that is designed to patchADKDRIVER in memory so that DKDRIVER will properly control jukebox=disks as normal VMS disks. The patches are minimal and do not;interfere with normal operation on normal VMS disks on SCSIbusses.<The BASHDK program is VMS version specific, so that it worksCcorrectly only where DKDRIVER does not change. It does some testingAto ensure it has the correct DKDRIVER version and will do nothing*if it finds out it has the wrong version. Use::Suppose you have an HP jukebox connected to SCSI unit 0 ofbus A.1. Boot VMS normally.B2. Run BASHDK from a fully priv'd account (needs and uses $cmkrnl)%3. Issue SYSGEN connect commands like$ sysgen:==$sysgen&$ sysgen connect dka0:/driver=dkdriverANow the DKA0: device is connected and can be used as a normal VMSdisk. Internals:*Several locations in DKdriver are patched.In routine MODE_SENSE:The instructionL BITB #,- ; write relocation, automatic read< UCB$B_RECOV_PAR+2(R3) ; disable correctionEis patched so it is a bicb2 followed by changing the branch to always act as though the bits are zero,disabling these checks.*;In the early version,also the instruction;K; BICL2 #,- ; Assume FORMAT unsupported#; UCB$L_DK_FLAGS(R3);I;was edited so that it does NOT clear the ucb$m_noreassign flag (which is;set by the patch to INQUIRE).. This is not done in the production version.Also in mode_sense:M; If this is a read-only device such as a CDROM, it may not have real tracks,J; sectors, and cylinders. If this is the case, READ_CAPACITY will set up aD; dummy values for the geometry parameters. For now, assume success.P92$: BBS #DEV$V_SWL,- ; If this is a read-only device, it's n$M UCB$L_DEVCHAR(R3),75$ ; required to have non-zero values ofIThe above instruction is changed to test the DEV$V_IDV bit (input device)Iwhich is basically always set. This allows any device to get its geometry,later on instead of giving up with an error.1Other things called from io_packack: are patched.Subroutine INQUIRY:L BNEQ 40$ ; Branch if not, illegal device typeD BISL #UCB$M_CDROM,- ; Indicate CDROM-like device) UCB$L_DK_FLAGS(R3) ;H BISL2 #UCB$M_HWL,- ; This a read-only device so setE UCB$L_DK_FLAGS(R3) ; the hardware write-lock bitH BBSS #DEV$V_SWL,- ; This a read-only device so setE UCB$L_DEVCHAR(R3),10$ ; the software write-lock bit This has been changed to:/ blss 40$ ; if type < 5 (5=cdrom), not a disk.- ; leaves types 5, 6, and 7 treated as disks ; 5 = cdrom, 7 = jukebox. bisl #,-5 ucb$l_dk_flags(r3) ; Set cdrom type (in case true),7 ; don't support block reassign and say no host based. ; shadow support so no read-long gets tried3 bisl #0,ucb$l_dk_flags(r3) ; disable read-only set: bbss #dev$v_idv,ucb$l_devchar(r3),10$ ; set idv bit which6 ; basically is always set anyway; no-ops this inst.9Also we change the movb #3,(r5)=to a CVTFB #63, to change the retry=count from 3 to 120, and we clear the err_recov$m_rc but from:the error recovery ignore mask so that that bit IS cleared?during error recovery and treated as a don't care bit. This bit:is removed from a location in the mode_sense routine also.(The retry count patch is that we change: IO_RW_RETRY:K MOVB #RW_RETRY_CNT,- ; Initialize read/write retry count) UCB$B_RW_RETRY(R3) ;to IO_RW_RETRY:A CVTFB #63,- ; Initialize read/write retry count) UCB$B_RW_RETRY(R3) ;#The two err_recov$m_rc patches are:;One in MODE_SENSE_CHANGABLE where we add the err_recov$m_rcbit to the instruction:; BICB #,R2 ;and again in mode_select:'we remove the bit from the instruction:I BICB3 #^C,- ; don't cares or have already beenD UCB$B_RECOV_PAR+2(R3),- ; checked for zero values in5 R1 ; MODE_SENSE)BThese changes allow the optical disks to be tested for support for>revectoring, but greatly increase the error retry count beforeBthis happens and causes the driver not to treat the err_recov$m_rc@flag, common on opticals, as a fatal error condition. Should the=error result in no data being transferred in the first sector>however, the driver will still report an error. It is for thatBreason that the jgdriver intercept function exists, to reissue theAIRP to the DKdriver again when this happens to recover. Once this@happens, opticals will have some errors logged when ECC recoveryChappens, but this is essentially always recovered from. The opticalHdisk signal is noisy, so ECC errors on optical are common, but disablingAreporting of them for optical disk would interfere with reportingBthis class of errors for other SCSI disks, where they are serious.AAccordingly, customers need to understand that the error count on?their optical disks will be usually nonzero, but that it is notCmeaningful, and their applications will not see these errors. If we=had a hardware board, or a totally new driver, we could avoidEthese bogus error reports, but as we're using the DEC driver in order@not to mess up access to other SCSI devices, these error reports'will occur and just need to be ignored.GNote however that a second test in mode set will still set the readonlyAbits (dev$m_hwl and dev$m_swl) so long as the SCSI config readingCcommands return writelock. My tests show this happening for CDroms.CEven if this isn't done, one can still use mount/nowrite to preventGattempts at write access to CDs, though it will (obviously) do no harm.@These changes can obviously be made on future DKdriver versions.DWhile this change means dkdriver could attempt to access type 6 SCSI?devices, in fact this doesn't generally happen because one mustAuse the sysgen connect DKcnnn:/driver=dkdriver command to connectAdisks. So long as one doesn't do something stupid like command to>connect one's scanner as a disk, this latent (mis)feature willcause no harm.GAs things now appear, it isn't clear to me that an SA&o BDK010.AB#+[EVERHART.BASHKIT]BASHDK.DOC;4PQy further patches areAneeded. I could place a bit of code out of line in there, but theAfew error paths changed are basically operational errors, causingBno more problems because other errors a bit later will be seen (as@in the case of no geometry...mount will just fail a bit later if/no geometry is finally available, for example).Glenn C. Everhart 2/15/19943/2/1994*[EVERHART.BASHKIT]BASHDK.EXE;6+,"./ 4-B#+0123 KPWO 56ɗ7@ˠɗ89GHJ 0D`0205IhBASHDK1.1Xɗ05-13QPP  ? PID GDevice(Mu;3sP1ПXTp0<UUVfVVUiѦ%DKDRѦ)IVER䑏zMxEf=~xRzЏV_g?H BPPx0ЎP@DP @ BASHDK BSDK "BSHDK CDEV_DATA CDEV_CODE'*[EVERHART.BASHKIT]BASHDK.INSTRUCTIONS;5+,./ 4K,-B#+0123KPWO 56%<7@ɗ89GHJBASHDK ?BashDK is an in-memory driver patcher that is designed to patchADKDRIVER in memory so that DKDRIVER will properly control jukebox=disks as normal VMS disks. The patches are minimal and do not;interfere with normal operation on normal VMS disks on SCSIbusses.<The BASHDK program is VMS version specific, so that it worksCcorrectly only where DKDRIVER does not change. It does some testingAto ensure it has the correct DKDRIVER version and will do nothing?if it finds out it has the wrong version. The program currently?has no licensing code. Since it is VMS version specific, it may>be enough to have code that only writes the license owner nameCto opa0: when it runs. Alternatively the full license key code that$Branches uses could be incorporated.HThe current version of the DK driver patch system is built for VMS 5.5-x6and use should not be attempted on other VMS versions.Use::Suppose you have an HP jukebox connected to SCSI unit 0 ofKbus A. This would normally show up as DKA0: if it were a regular SCSI disk.1. Boot VMS normally.B2. Run BASHDK from a fully priv'd account (needs and uses $cmkrnl)%3. Issue SYSGEN connect commands like$ sysgen:==$sysgen&$ sysgen connect dka0:/driver=dkdriverANow the DKA0: device is connected and can be used as a normal VMSdisk.CHowever, optical disks have a fairly low signal level so that it isAnormal for the electronics to use error correction codes (ECC) toErecover errors that appear transiently. This is normal on optical andEnot significant, but DKdriver is not designed to handle large numbersof ECC errors. FTo avoid disabling ECC handling on normal SCSI disks, these errors areBhandled by an intercept system which is turned on for each opticalAdisk and which retries the ECC errors where needed, leaving error%handling for normal SCSI disks alone.CDo this by loading and turning on JGAn: units for each optical diskyou use.$ sysgen:==$sysgen-$ sysgen conn JGA0:/noadapter/driver=JGdriver$ set comm sys$system:jgctl$ jgctl/verify JGA0: DKA0:Thus, to use the package:@1. Copy JGCTL.CLD, BASHDK.EXE, and JGDRIVER.EXE into sys$system:G2. On the node where the optical disk is attached perform the following8 steps. Assume the optical disk is on SCSI bus B, unit 2> here for the example. If on bus A you'd use DKA, not DKB, and6 if it's on SCSI LUN n you use n00 as the unit number, where here we'll use "200".INote: Do this from the system account. You can insert these commands intosystartup_v5.com if you like.$ sysgen:==$sysgen$ run sys$system:bashdk($ sysgen connect dkb200:/driver=dkdriver0$ sysgen connect JGA0:/noadapter/driver=jgdriver$ set command sys$system:jgctl$ JGCTL/VERIFY JGA0: DKB200:C(connect other JGAn: units and use JGCTL to turn them on in similarGfashion. Thus if you have a second optical disk connected at SCSI bus A(and SCSI LUN 4 you would add after this:($ sysgen connect dka400:/driver=dkdriver,$ sysgen connect jga1:/noada/driver=jgdriver$ jgctl/verify JGA1: DKA400:KThis will cause the units DKB200: and DKA400: above to behave as normal VMSCdisks. You will see errors logged for them, owing to our not havingEdisabled ECC handling in DKdriver (as your other disks need it), but Gthe disks will act normally to your applications. They can be used, andEerror rates of up to a fraction of a percent of I/O operations on theFoptical disks as seen by SHOW ERRORS can be ignored; your applicationsKwill not see them, and the data on the opticals will be recorded correctly.} BDK010.AsB#+$[EVERHART.BASHKIT]BASHDK.INTERNALS;1K$*[EVERHART.BASHKIT]BASHDK.INTERNALS;1+,s./ 4K,-B#+0123 KPWO 56[e76ɗ89GHJBASHDK ?BashDK is an in-memory driver patcher that is designed to patchADKDRIVER in memory so that DKDRIVER will properly control jukebox=disks as normal VMS disks. The patches are minimal and do not;interfere with normal operation on normal VMS disks on SCSIbusses.<The BASHDK program is VMS version specific, so that it worksCcorrectly only where DKDRIVER does not change. It does some testingAto ensure it has the correct DKDRIVER version and will do nothing?if it finds out it has the wrong version. The program currently?has no licensing code. Since it is VMS version specific, it may>be enough to have code that only writes the license owner nameCto opa0: when it runs. Alternatively the full license key code that$Branches uses could be incorporated.HThe current version of the DK driver patch system is built for VMS 5.5-x6and use should not be attempted on other VMS versions.Use::Suppose you have an HP jukebox connected to SCSI unit 0 ofKbus A. This would normally show up as DKA0: if it were a regular SCSI disk.1. Boot VMS normally.B2. Run BASHDK from a fully priv'd account (needs and uses $cmkrnl)%3. Issue SYSGEN connect commands like$ sysgen:==$sysgen&$ sysgen connect dka0:/driver=dkdriverANow the DKA0: device is connected and can be used as a normal VMSdisk.CHowever, optical disks have a fairly low signal level so that it isAnormal for the electronics to use error correction codes (ECC) toErecover errors that appear transiently. This is normal on optical andEnot significant, but DKdriver is not designed to handle large numbersof ECC errors. FTo avoid disabling ECC handling on normal SCSI disks, these errors areBhandled by an intercept system which is turned on for each opticalAdisk and which retries the ECC errors where needed, leaving error%handling for normal SCSI disks alone.CDo this by loading and turning on JGAn: units for each optical diskyou use.$ sysgen:==$sysgen-$ sysgen conn JGA0:/noadapter/driver=JGdriver$ set comm sys$system:jgctl$ jgctl/verify JGA0: DKA0:Thus, to use the package:@1. Copy JGCTL.CLD, BASHDK.EXE, and JGDRIVER.EXE into sys$system:G2. On the node where the optical disk is attached perform the following8 steps. Assume the optical disk is on SCSI bus B, unit 2> here for the example. If on bus A you'd use DKA, not DKB, and6 if it's on SCSI LUN n you use n00 as the unit number, where here we'll use "200".INote: Do this from the system account. You can insert these commands intosystartup_v5.com if you like.$ sysgen:==$sysgen$ run sys$system:bashdk($ sysgen connect dkb200:/driver=dkdriver0$ sysgen connect JGA0:/noadapter/driver=jgdriver$ set command sys$system:jgctl$ JGCTL/VERIFY JGA0: DKB200:C(connect other JGAn: units and use JGCTL to turn them on in similarGfashion. Thus if you have a second optical disk connected at SCSI bus A(and SCSI LUN 4 you would add after this:($ sysgen connect dka400:/driver=dkdriver,$ sysgen connect jga1:/noada/driver=jgdriver$ jgctl/verify JGA1: DKA400:KThis will cause the units DKB200: and DKA400: above to behave as normal VMSCdisks. You will see errors logged for them, owing to our not havingEdisabled ECC handling in DKdriver (as your other disks need it), but Gthe disks will act normally to your applications. They can be used, andEerror rates of up to a fraction of a percent of I/O operations on theFoptical disks as seen by SHOW ERRORS can be ignored; your applicationsKwill not see them, and the data on the opticals will be recorded correctly.*[EVERHART.BASHKIT]BASHDK.MAR;8+,./ 4Q-B#+0123KPWO56`^\@ɗ7@ɗ89GHJ  .TITLE bashdk .IDENT /1.1x/; experimental bashdk...$; does not try to avoid writel test.<; Seems to be needed to avoid bad blocks that don't clear on ; opticals...;dgr$=0vms$v5=1;++;; Title:; bashdk; ; Action:7; patches dkdriver to allow opticals. Set for vms 5.5-2C; (needs more tests to check dkdriver is ok, really. experimental.);; Environment:=; CMKRNL privilege required, I/O data base is locked, program; executed at elevated IPL.; ; Author:>; Glenn Everhart. Uses some code from ZDEC.MAR by Mark Oakley.;--  .SBTTL Symbols, Macros, Data .LIBRARY /SYS$LIBRARY:LIB.MLB/# $TPADEF ; Symbols for LIB$TPARSE.% $SSDEF ; Symbols for return status.# $UCBDEF ; Symbols for device ucb.( $STSDEF ; Symbols for returned status.( $DVIDEF ; Symbols for $GETDVI service.# $DCDEF ; Symbols for device type. $dptdef% $DEVDEF ; SYM. FOR SDI TYPE DEVICE. $brkdef $opcdef $pcbdef ; pcb symbols+ .PSECT CDEV_DATA,RD,WRT,NOEXE,LONG,SHR,PICwrk: .long 0 ; scratch"PIDDS: .ASCID /PID/ ; /PID switch#PIDVL: .word 32 ; length of buffer .byte dsc$k_dtype_t ;text type .byte 1 ;fixed static .address pidtx=pidtx: .blkl 8 ;text area for /pid:nnnnnnnn "nnnnnnnn" valuepidwk: .long 0 ;work storage'newpid: .long 0 ;pid to move device toP1DSC: .ascid /Device/; in .cld have a lineI; parameter p1,prompt="Device:",value(required,type=$device),label=Device(DEV_BUF: ; Buffer to hold device name. .BLKB 40DEV_BUF_SIZ = . - DEV_BUF5DEV_BUF_DESC: ; Descriptor pointing to device name. .LONG DEV_BUF_SIZ .ADDRESS DEV_BUF#PID: ; Owner of device (if any). .BLKL 12K_ARG: ; Argument list for kernel-mode routine. .LONG 2 ; 2 args9 .ADDRESS DEV_BUF_DESC ; Pass descriptor for device name., .address newpid ; PID to "give" device to.7 ; Note: pid field must be nonzero or this is a no-op. ; UCB$L_PID is set... .SBTTL Main program+ .PSECT CDEV_CODE,RD,NOWRT,EXE,LONG,SHR,PIC0 .ENTRY BSDK,^M; Get the args. clrl newpid30$:5 $CMKRNL_S - ; Enter k-mode to claim device for pid ROUTIN=Bshdk,- ARGLST=K_ARG BLBS R0,80$ BRW EXIT80$:; leave ret code in r0EXIT: RET .SBTTL Bshdk Routine;++;; Functional Description:8; This routine Bshdks out the error count in the UCB for; a specified device.;; Calling Sequence:%; $CMKRNL_S ROUTIN=Bshdk,ARGLST=K_ARG;&; bash dkdriver in memory for opticals; Formal Parameters:"; Descriptor for name of a device.;; Implicit Inputs:; I/O database.;; Implicit Outputs:%; Device error count is set to Bshdk.;; Completion Status:; Returned in R0.;; Side Effects:A; I/O database is locked (routine runs in kernel mode at elevated; IPL).;;--1 .ENTRY Bshdk,^M .if ndf,vms$v5; MOVL G^SCH$GL_CURPCB,R4 ;; Our PCB address is input to SCH .iff9 MOVL G^CTL$GL_PCB,R4 ;; Our PCB address is input to SCH .endc ;„@ BDK010.AB#+[EVERHART.BASHKIT]BASHDK.MAR;8Q9 ; routines.- JSB G^SCH$IOLOCKW ;; Lock the I/O database.;find dkdriver% movl ioc$gl_dptlist,r5 ;dpt listhead movl r5,r6-1$: movl dpt$l_flink(r6),r6 ;get next elem. cmpl r6,r5 ;done? beql 77$ cmpl dpt$t_name+1(r6),#^a/DKDR/ bneq 1$ cmpl dpt$t_name+5(r6),#^a/IVER/ BNEQ 1$ ;GOT IT?;if here r6 points at dkdriver;bmsk=1a7a ;v5.5-2; =d0 hex;icmpb=1a78 ;cmpb = 93 hexbmsk=6778 ;hex 1a7aicmpb=6776 ;hex 1a78boadr=6226 ;hex 1852boval=25 ;hex 19 (bneq -> blss) boclr1=^x1856 boclr2=^x185f2slval=^x1A ;bit 26 = input device (instead of swl)"sladr=^x1867 ;address in bbss inst slcmp=^xe2;:; don't let mode sense clear the 800 bit in ucb$l_dk_flags2; (ucb$v_noreassign) and set it in inspect routine cnorea=^x199e mdsense=^x800;!; avoid errs if no geom is there. geobsh=^x1b7a;:; Also patch instruction that checks drivetype cdrom to do5; bneq to default to disk instead of default illegal.* cmpb #^xD0,bmsk(r6) ;check value to bash bneq 177$ ;if neq leave) cmpb #^x93,icmpb(r6) ;is it a cmpb inst? bneq 177$* cmpb #slcmp,sladr-1(r6) ;ensure bbss inst bneq 177$;patch dkdriver=bmbc=^x1a78 ;addr of bitb instr we change to bicb2 (93 to 8a)5bmts=^x1a7e ;addr of beql we change to brb (13 to 11); movb #00,bmsk(r6) ;bash it.+ movb #^x11,bmts(r6) ;accept bits as clr'd% movb #^x8a,bmbc(r6) ;clr extra bits .if df,dgr$177$: .endcF; this patch will allow dkdriver to access other device types but willJ; inhibit it from knowing that CDROM is automatically read/only. Note thatD; CDRom can still be mounted /nowrite manually in this case however.C; Other SCSI types that are known will be treated OK, but if we getA; a SCSI type of 6 or 7 it will get treated like a disk. The CLRL>; instructions just prevent the read-only bits from being set.;D; Note one uses disassembly of dkdriver, comparison of listings, and>; SDA poking to ensure one has the right addresses and values.1 movb #boval,boadr(r6) ;change the bneq to a blss* ; so types less than 4 are treated as ;non disks%; fix so we don't need geom instantly movb #slval,geobsh(r6)/; clrl boclr1(r6) ; don't set any readonly bits;bit 13 = hbs checked;cdrom bit is 10000 bit;noreass bit is 800"; total = 2000 + 10000 = 12000 hex ;boo1=^x12800 boo1=^x10000; movl #boo1,boclr1(r6) ;set HBS check bit set and CDrom bit; movl #0,boclr2(r6) ;leave nofe bit in, do not set hwl bit+; movl #dev$m_nofe,boclr2(r6) ;set nofe bit boof2=^x1864.; movw #ucb$l_devchar2,boof2(r6) ;set nofe bit<; bicl #mdsense,cnorea(r6) ; don't clear noreassign bit from ; earlier set; However leave cdrom bit set; clrl boclr2(r6)7; fix not to set writelock for type 5,6, or 7 devs here? movb #slval,sladr(r6) ;instead of setting swl bit, set idv bit ; which disks have anyway.Q; we might be better ignoring "rc" bit errors...don't know so make it conditional; to do so or not.; increase retry count to 63 rci=^x100d rcu=^x100e@ movb #63,rcu(r6) ;c hange retry count from 3 to 63G ;(far as we can go in a 1 byte literal), movb #^x48,rci(r6) ;make it cvtfb, not movb ;so the count is 120, not 63 btmk=^x1cf3(;clr out err_recov$m_rc from ignore mask bicb #^x10,btmk(r6)ig$rc=0 ;rec$eok=0 .if df,ig$rc rcmsk=^x1c42C movb #^x1b,rcmsk(r6) ;ignore err_recov$m_rc bits in mode sense too .endc .if df,rec$eokO; Also treat SCSI recovered errors as flags that we do nothing...if conditionedsensetbr=^x08caB movb #1,sensetbr(r6) ;set recovered errs as normal status returns .endc .if ndf,dgr$177$: .endc77$: MOVL #SS$_NORMAL,R0 Bshdk_EXIT: PUSHL R0 ;;; Remember status.8 JSB G^SCH$IOUNLOCK ;;; Unlock I/O database (drop IPL). POPL R0 RET .END BSDK*[EVERHART.BASHKIT]BASHDK.OBJ;5+, ./ 4-B#+0123KPWO56Kɗ75ɗ89GHJ3BASHDK1.1X 7-APR-1994 21:49 VAX MACRO V5.4-3MACRO BASHDK  BASHDKe CTL$GL_PCB DSC$K_DTYPE_TIOC$GL_DPTLIST SCH$IOLOCKW SCH$IOUNLOCK SYS$CMKRNL . ABS .P$ABS$-PPPPPPPPPPP CDEV_DATAP3PIDQ&Q DSC$K_DTYPE_T%Q C3DeviceQ&Q Q((MQu; CDEV_CODEP BSDK&5;" SYS$CMKRNLP1 "BSHDK& CTL$GL_PCBT SCH$IOLOCKWIOC$GL_DPTLISTUUVfVVUiѦ%DKDRѦ)IVER䑏zMxEf=~xRzЏV_g?H BPP SCH$IOUNLOCKЎP# BSDK "BSHDK0 CDEV_DATA CDEV_CODE(*[EVERHART.BASHKIT]BASHDK_INTERNALS.DOC;2+,. / 4K B-B#+0123KPWO 56ldɗ7dɗ89GHJBASHDK 2Written by Glenn Everhart for Acorn Software, 19946Released April 1994 by Acorn Software for general use.?BashDK is an in-memory driver patcher that is designed to patchADKDRIVER in memory so that DKDRIVER will properly control jukebox=disks as normal VMS disks. The patches are minimal and do not;interfere with normal operation on normal VMS disks on SCSIbusses.<The BASHDK program is VMS version specific, so that it worksCcorrectly only where DKDRIVER does not change. It does some testingAto ensure it has the correct DKDRIVER version and will do nothing?if it finds out it has the wrong version. The program currently?has no licensing code. Since it is VMS version specific, it may>be enough to have code that only writes the license owner nameCto opa0: when it runs. Alternatively the full license key code that$Branches uses could be incorporated.HThe current version of the DK driver patch system is built for VMS 5.5-x6and use should not be attempted on other VMS versions.ANormally one should run the package by using the BASHDK_SETUP.COM>script. This document describes how to use it by hand however.DNote that it is expected you know the SCSI bus and unit your optical>disk or jukebox is connected to, so that if it's on SCSI bus A@the disk name starts with "DKA" and if on bus B, with "DKB", andCthe VMS unit number is 100 times the SCSI unit number, so a disk onASCSI bus B connected to SCSI unit 3 would be called DKB300: as anexample.Use::Suppose you have an HP jukebox connected to SCSI unit 0 ofKbus A. This would normally show up as DKA0: if it were a regular SCSI disk.1. Boot VMS normally.B2. Run BASHDK from a fully priv'd account (needs and uses $cmkrnl)%3. Issue SYSGEN connect commands like$ sysgen:==$sysgen&$ sysgen connect dka0:/driver=dkdriverANow the DKA0: device is connected and can be used as a normal VMSdisk.CHowever, optical disks have a fairly low signal level so that it isAnormal for the electronics to use error q BDK010.AB#+([EVERHART.BASHKIT]BASHDK_INTERNALS.DOC;2K  correction codes (ECC) toErecover errors that appear transiently. This is normal on optical andEnot significant, but DKdriver is not designed to handle large numbersof ECC errors. FTo avoid disabling ECC handling on normal SCSI disks, these errors areBhandled by an intercept system which is turned on for each opticalAdisk and which retries the ECC errors where needed, leaving error%handling for normal SCSI disks alone.CDo this by loading and turning on JGAn: units for each optical diskyou use.$ sysgen:==$sysgen-$ sysgen conn JGA0:/noadapter/driver=JGdriver$ set comm sys$system:jgctl$ jgctl/verify JGA0: DKA0:Thus, to use the package:@1. Copy JGCTL.CLD, BASHDK.EXE, and JGDRIVER.EXE into sys$system:G2. On the node where the optical disk is attached perform the following8 steps. Assume the optical disk is on SCSI bus B, unit 2> here for the example. If on bus A you'd use DKA, not DKB, and6 if it's on SCSI LUN n you use n00 as the unit number, where here we'll use "200".INote: Do this from the system account. You can insert these commands intosystartup_v5.com if you like.$ sysgen:==$sysgen$ run sys$system:bashdk($ sysgen connect dkb200:/driver=dkdriver0$ sysgen connect JGA0:/noadapter/driver=jgdriver$ set command sys$system:jgctl$ JGCTL/VERIFY JGA0: DKB200:C(connect other JGAn: units and use JGCTL to turn them on in similarGfashion. Thus if you have a second optical disk connected at SCSI bus A(and SCSI LUN 4 you would add after this:($ sysgen connect dka400:/driver=dkdriver,$ sysgen connect jga1:/noada/driver=jgdriver$ jgctl/verify JGA1: DKA400:KThis will cause the units DKB200: and DKA400: above to behave as normal VMSCdisks. You will see errors logged for them, owing to our not havingEdisabled ECC handling in DKdriver (as your other disks need it), but Gthe disks will act normally to your applications. They can be used, andEerror rates of up to a fraction of a percent of I/O operations on theFoptical disks as seen by SHOW ERRORS can be ignored; your applicationsKwill not see them, and the data on the opticals will be recorded correctly.Note:GThe patches are described by documents supplied here. If you use BashDKHit should work on at least some optical disks in VMS 5.5-x. It will needFto be reissued for other versions. This is at present a Vax-only patchK(though some axp support in the pseudo driver exists). Be aware though thatEif you use this, you're on your own for support. Nobody is committingAto support for this, though it worked nicely in some tests we ranon it.$*[EVERHART.BASHKIT]BASHDK_SETUP.COM;2+, }./ 4OR-B#+0123 KPWO 56v7J[ɗ89GHJ !$!Setup generator for DK patcher.G$! Generates script to be run at startup time from the startup process.$ask:==inquire$emit:==write sys$outputD$oldprv=f$setprv("cmkrnl,sysprv,log_io,phy_io,tmpmbx,volpro,detach")E$tprv=f$privilege("cmkrnl,sysprv,log_io,phy_io,tmpmbx,volpro,detach")$if (tprv) then goto gotprv*$write sys$output "Not enough privileges."$exit$gotprv:$emit ""D$if (f$search("sys$system:JGdriver.exe") .nes. "") then goto seedrvr$$emit "Cannot find driver. Exiting."$ exit $seedrvr: $goto tstdo$nocomp:#$emit "Component missing. Exiting."=$emit "Be sure all the component pieces exist in sys$system."$exit$tstdo:"$! Be sure all pieces are present.?$if f$search("sys$system:bashdk.exe") .eqs. "" then goto nocomp>$if f$search("sys$system:jgctl.cld") .eqs. "" then goto nocomp>$if f$search("sys$system:jgctl.exe") .eqs. "" then goto nocomp$jgnum=0F$if f$search("sys$manager:dkpatch_Start.com") .eqs. "" then goto gocfgH$emit "SYS$MANAGER:DKPATCH_START.COM already exists. Delete if you wish"9$emit "to create a new one with this procedure. Exiting."$exit$gocfg: $ccmd=" "$ndsk=0-$open/write cfg sys$manager:dkpatch_start.com#$write cfg "$run sys$system:bashdk"$write cfg "$sysgen:==$sysgen"*$write cfg "$set command sys$system:jgctl"$getdsk:O$ask dsk "Enter name of optical disk [e.g. DKB200:], or just return if no more"!$if dsk .eqs. "" then goto wrapup$$! allow a few explicit commands too%$if dsk .eqs. "EXIT" then goto wrapup%$if dsk .eqs. "exit" then goto wrapup%$if dsk .eqs. "quit" then goto wrapup%$if dsk .eqs. "QUIT" then goto wrapup$jgnm="JGA"+f$string(ndsk)+":"/$ccmd="$sysgen connect "+dsk+"/driver=DKdriver"$write cfg ccmd6$ccmd="$sysgen connect "+jgnm+"/noada/driver=jgdriver"$write cfg ccmd#$ccmd="$jgctl/verify "+jgnm+" "+dsk$write cfg ccmd $ndsk=ndsk+1 $goto getdsk$wrapup: $close cfg$emit "Add the line"'$emit "$@sys$manager:dkpatch_start.com"H$emit " to your SYSTARTUP_V5.COM file now. The script can be run from"6$emit " a fully privileged account now if you wish."$exit*[EVERHART.BASHKIT]JGCTL.CLD;4+,./ 4H-B#+0123KPWO56`ɗ7+ɗ89GHJDEFINE VERB JGCTL IMAGE sys$system:JGCTL.EXEH parameter p1,prompt="JGAn:",value(required,type=$device),label=UNIT> parameter p2,label=FNAM,prompt="Disk",value(type=$infile) qualifier DEASSIGN qualifier VERIFY! Usage: JFCTL JFAn: disk:?! Where JFAn: is a unit of JF: that is not otherwise in use and/! disk: is some disk to fragmentation-avoid on.! ! switches:#! /DEASSIGN Turns off dk err fixups%! /VERIFY turns on read/write retries*[EVERHART.BASHKIT]JGCTL.EXE;8+,./ 4-B#+0123 KPWO56yĐɗ7@ɗ89GHJ0D`0205%I$ JGCTLV001o%ɗ05-13QPP  ? BDK010.AB#+[EVERHART.BASHKIT]JGCTL.EXE;8SYS$DISK((( (PX(( $4UNIT@FNAMLFRACTION\MINIMUMkMAXIMUM zALDEFONLYDEASSIGNCBTVERIFY ,<`^,n䐏PHݬA^|)VX^,n䐏Qݬf^PRݬ@l$լ ݬf  RP|VD^,nȐSȞ؞|ܕlլݬfЬ̑lլ  lլ,n䞭l լ Ь l լЬlլ ݬf^<`^,n䐏Tel լЬ^<`^,n䐏U$ݬ^ ЏSPj`LPDP1gcP1H|~tfPP1+|~(n2V'РTVTQV4ɏ@VdPV(TQK(`PPR1nDSP@PРTVV4РQɏ@VdPV(T(mTV 42P¢$VPVPSlЬ P`P1ePSмT4L,m£(TˏdUUTP͏@dQȠQQdURT PPT$ЏPмUT 1m Uʣ U4TQUP3V4 QPVPUY@U=U0?Ss 1U H}~PUHYЏlPUHU UUPP\d`1ãHUPPL1x1PP@PP\d`1УHVPPѠU"X ѠU\d`X 1X PV51УHVУLQxQWCPP`FX 8`2РVUVU^`VV\d`VT 4UVURQX X QPQHQPPVQHԣLQL5T14+cSRRTT bRRS1NUTPP1A)%U P\d`14UP\d`14Wg1UTPT0,Vg3QQQdQQVTVUUddUddТ8QTQ0T8P1`1`QQPVQUUddPQРVРPPVg13PPPaPP10PPQРPPTI`aQVVT/a+VT3UVVP`'aUUag 3XXdXQT,UTVVP`)Y~ЏdPUdTPVP`UUdРg 3`3U,U,ɢ P$P^`T ˏU1 P^`TU1~)P ^ЬV5Z5Ц WЦW4PѬWPP[[ЬWPˏPWxW4ήPXP XP48XXZ^hYm4 ^Y@PtZЮY<4YPЩQ @P*\`hQ$Ï@Q@PQ\`*Z,n@iZ* @P\ihPЮQ42 .fVPP"(!Q (W W\ih`PPVQWQ (QW0408045[\if]ifYP=P0ЏP< <43 h@t DPPЏ< <@4 0HL$(,@" D^P0ЏP< Џ04@D }PѠ  ѠTաЏd |~p< P^W(0al Џ\PlRRP#@gQaQQ@h1Q@1Q@RPծ<) ݧ$?P<QQQQ,QӮ,Qh0QӮ0Q]Ѯ,0Ю0,P ϮV<ծ: 6 ?ծ+Ѯ!ծ8Ю,8ЮQ~A ЮQQЏ4PQQ YЮ Y<QQQQ ծ@n^ݬ1PмVU QxQ(P,n ЮмVx Pî PRPP*8Q\`aR鐮0Ю , ծ4 44Ю XXX24XX34X4Ю0(0$,X4X5@ծ@ Ч(@@4DծD Ч,D4ϮKF Pʦ PPH3 ,PQQ1 8Q˦ QPPHQ PQPLЮHYYVPY6`(x $ծ(Ц 6x ( |~VPRæݬ϶BϓPX5(æPЏP|^Rl լмR` l@լ; ݬ|P<QQQQЮ S<QQQQ SYn^ݬPUмV0 RHlRRPa@LPR @ QQ@LPSSVPS6`(æP|мVpm505&ЏdPHT|PxPԦLxP,nPPΦTԦfVPPPàRRT43SРQSSRРà 4Ԡ,0QQ4Q8|| `PPVTfP^мϬmЮS5ЏdPZ<YΣX0 HXPYXcSRR4W3V48SKjSBâUUXWТQVVUâ QxQ DPR bR\ cЮTRTЮQ4l|a8SRRR bRЮ Q*\ RSЮScSRRR bR DPHRS㟮< PPxPD< P XYPϋϬ PPdPP|TмUidP0QQQ ]`dOPP֤PPUPUP0PQP0=0}PVQP0/PVQ0ЏlPTVfRRRVVTPUЏPQQPU:P˕qQP a;PaVQRxRRRSRfRURfyU RUfZSRR fSRUS R SS $R fR fRxRRRPRVQ1bRSfSRURSRf RUSSRUPXPRx RPPxS~RRf SnPQ19Џ PRTScQQQSST ѣ RУ RPR PRRRR ]`dQP^^QaPHP}P^QaЏPTмPмQQ¼֤ PЏlPЏdPTScRRRSST2QQ ãQRxRRQ RRQXPЏdP@ЬP QR РR((( / (/@ (Џ$P<`QPР QӏQP .TITLE JGCtl ;control JFdriver (fragmentation avoider driver) .IDENT 'V001'9; Copyright (c) 1994 Acorn Software. All rights reserved.; Released for public use.; ; FACILITY:; ;(; This program takes a command of form; FDTFix/flags JFAn: node$jban:C; where JFAn: refers to a local unit of JFdriver, which is a dummy>; driver furnished to provide local copies of the frag avoider; code in each node.;6; Note: define VMS$V5 to build for Version 5.x of VMS.VMS$V5=1;; ; AUTHOR:; ; G. EVERHART;?; 04-Aug-1989 D. HITTNER Cleaned up definitions, added messagesI; 29-Aug-1989 G. Everhart Added more flexible device geometry selection;-- .PAGE& .SBTTL EXTERNAL AND LOCAL DEFINITIONS .LIBRARY /SYS$SHARE:LIB/; ; EXTERNAL SYMBOLS;  $dyndef) $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK $ATRDEF) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK $DCDEF ;DEFINE DEVICE CLASS% $DDBDEF ;DEFINE DEVICE DATA BLOCK' $ddtdef ;define driver dispatch tbl* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE) $DVIDEF ;Symbols for $GETDVI service.( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER $FABDEF $FATDEF0 $FIBDEF ;Symbols for file information block.( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODES& $IRPDEF ;DEFINE I/O REQUEST PACKET $NAMDEF& $PRDEF ;DEFINE PROCESSOR REGISTERS $RMSDEF $SBDEF $SCSDEF& $SSDEF ;DEFINE SYSTEM STATUS CODES) $STSDEF ;Symbols for returned status.* $TPADEF ;Symbols for LIB$TPARSE calls.& $UCBDEF ;DEFINE UNIT CONTROL BLOCK* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $XABDEF; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS=; DEFINE THESE SO WE KNOW WHERE IN THE UCB TO ACCESS. WE MUST.; SET THE ONLINE BIT OR CLEAR IT, AND ALSO SET9; UCB$HUCB (HOST UCB ADDRESS), UCB$HFSZ (HOST FILE SIZE),8; AND UCB$HLBN (HOST LOGICAL BLOCK NUMBER OF FILE START);( $DEFINI UCB ;START OF UCB DEFINITIONS2;.=UCB$W_BCR+2 ;BEGIN DEFINITIONS AT END OF UCB*.=UCB$K_LCL_DISK_LENGTH ;v4 def end of ucb8; USE THESE FIELDS TO HOLD OUR LOCAL DATA FOR VIRT DISK.K; Add our stuff at the end to ensure we don't mess some fields up that some; areas of VMS may want.C; Leave thisfield first so we can know all diskswill have it at the; same offset.5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chain;#; Add other fields here if desired.;3$def ucb$l_ctlflgs .blkl 1 ;flags to control modes,$def ucb$l_cbtctr .blkl 1 ;how many extents,$def ucb$l_cbtini .blkl 1 ;init for counter@; preceding 2 fields allow specifying of contig-best-try extentsA; on every Nth extend, not every one. This should still help keep6; file extensions from preferentially picking up chaff$def ucb$JFcontfil .blkb 80;&$DEF ucb$l_minxt .blkl 1 ;min. extent%$def ucb$l_maxxt .blkl 1 ;max extent/$def ucb$l_frac .blkl 1 ;fraction to extend by3$def ucb$l_slop .blkl 1 ;slop blocks to leave free; DDT intercept fields; following must be contiguous.H$def ucb$s_ppdbgn ;add any more prepended stuff after thisI$def ucb$l_uniqid .blkl 1 ;driver-unique ID, gets filled inK ; by DPT address for easy following0 ; by SDAJ$def ucb$l_intcddt .blkl 1 ; Our interceptor's DDT address if< ; we are intercepted>$def ucb$l_prevddt .blkl 1 ; previous DDT addressH$def ucb$l_icsign .blkl 1 ; unique pattern that identifiesG ; this as a DDT intercept blockP; NOTE: Jon Pinkley suggests that the DDT size should be encoded in part of thisI; unique ID so that incompatible future versions will be guarded against.$def ucb$s_ppdend,$def ucb$a_vicddt .blkb ddt$k_length@ ; space for victim's DDT .blkl 4 ;safety1$def ucb$l_backlk .blkl 1 ;backlink to victim ucbE; Make the "unique magic number" depend on the DDT length, and on theJ; length of the prepended material. If anything new is added, be sure that"; this magic number value changes.Fmagic=^xF024F000 + ddt$k_length + <256*>Hp.magic=^xF024F000 + ddt$k_length + <256*> ;an ACE is there or not.0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;<; Set FDT table start mask for each unit by keeping it here.1; We need just enough to get back to user's FDTs.)$def ucb$l_fdtlgl .blkl 2 ;legal fcn msks,$def ucb$l_fdtbuf .blkl 2 ;buffered fcn msks%$def ucb$l_fdtmfy .blkl 3 ;modify fcn($def ucb$l_fdtbak .blkl 3 ;"go back" fcn0$def ucb$l_vict .blkl 1 ;victim UCB for checking<; The following lets us steal start-io and add error retries7$def ucb$l_omedia .blkl 1 ;storage of orig. irp$l_media5$def ucb$l_ppid .blkl 1 ;store for irp$l_pid contents3$def ucb$l_retries .blkl 1 ;counter for i/o retries6$def ucb$l_hstartio .blkl 1 ;host driver start-io loc./$def ucb$l_hstucb .blkl 1 ;host ucb (quick ref)($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_LEN=. ;LENGTH OF UCB% $DEFEND UCB ;END OF UCB DEFINITONS; TO SET ONLINE::; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE/; Macro to check return status of system calls.; .MACRO ON_ERR THERE,?HERE BLBS R0,HERE BRW THEREHERE: .ENDM ON_ERR;;;$ .PSECT ADVDD_DATA,RD,WRT,NOEXE,LONGDEFAULT_DEVICE: .ASCID /SYS$DISK/ .ALIGN LONGiosb: .long 0,0IOSTATUS: .BLK, BDK010.AB#+[EVERHART.BASHKIT]JGCTL.MAR;5P u Q 1BUFG: .long 1 ;bash flag .long 1000 ;(DEV_BUF: ; Buffer to hold device name. .BLKB 40DEV_BUF_SIZ = . - DEV_BUF busz=.-bufg5DEV_BUF_DESC: ; Descriptor pointing to device name. .LONG DEV_BUF_SIZ .ADDRESS DEV_BUF#PID: ; Owner of device (if any). .BLKL 1+DEV_ITEM_LIST: ; Device list for $GETDVI.A .WORD DEV_BUF_SIZ ; Make sure we a have a physical device name. .WORD DVI$_DEVNAM .ADDRESS DEV_BUF .ADDRESS DEV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS PID .LONG 0 .WORD 4- .WORD DVI$_DEVCLASS ; Check for a terminal. .ADDRESS DEV_CLASS .LONG 0 .LONG 0 ; End if item list. DEV_CLASS: .LONG 1;**Evbufg: .long 2 ;deassign bash flag. Deassign victim dvc, not jf: dvc. .long 1000(VDV_BUF: ; Buffer to hold VDVice name. .BLKB 40VDV_BUF_SIZ = . - VDV_BUF vbusz=.-vbufg5VDV_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.A .WORD VDV_BUF_SIZ ; Make sure we a have a physical device name. .WORD DVI$_DEVNAM .ADDRESS VDV_BUF .ADDRESS VDV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS VPID .LONG 0 .WORD 4- .WORD DVI$_DEVCLASS ; Check for a terminal. .ADDRESS VDV_CLASS .LONG 0 .LONG 0 ; End if item list. VDV_CLASS: .LONG 1;**DEFNAM:WRK: .BLKL 1 ;SCRATCH INTEGER ; DESCRIPTOR FOR VDn: "FILENAME" .ALIGN LONGVDFNM: .WORD 255. ;LENGTH%VDFTP: .BYTE DSC$K_DTYPE_T ;TEXT TYPE .BYTE 1 ; STATIC STRING .ADDRESS VDFNMDVDFNMD: .BLKB 256. ; DATA AREA .align longwrkstr: .word 20 ;length .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .byte 0,0,0,0 ;safety;'; DESCRIPTOR FOR NODE$FWAN: DEVICE NAME .ALIGN LONGDDFNM: .WORD 255. ;LENGTH%DDFTP: .BYTE DSC$K_DTYPE_T ;TEXT TYPE .BYTE 1 ; STATIC STRINGDDFNA: .ADDRESS DDFNMDDDFNMD: .BLKB 256. ; DATA AREADDCHN: .LONG 0VDCHN: .LONG 0 ;CHANNEL HOLDERSP1DSC: .ASCID /UNIT/P2DSC: .ASCID /FNAM/6frcdsc: .ascid /FRACTION/ ;fract. of file to extend by#minds: .ascid /MINIMUM/ ;min extent#maxds: .ascid /MAXIMUM/ ;max extent0adods: .ascid /ALDEFONLY/ ;default-ext. mod only;deads: .ascid /DEASSIGN/ ;deassign jf: from disk (turn off)cbtds: .ascid /CBT/+verds: .ascid /VERIFY/ ;retry errors on r/w .EVEN; UCB data areaverfg: .long 0deafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3 min: .long 10max: .long 2000%adflg: .long 0 ;set flg if aldef only#HSTUCB: .LONG 0 ;SERVED UCB ADDRESS+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESS;;ERROR: .LONG 2MESS: .LONG SS$_ABORT .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^M clrl adflg clrl deafg ;not deassign* movl #1,cbtct ;contig best try every time movl #7,frac movl #10,min movl #1000,max pushab deads calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 100$ incl deafg100$: clrl verfg pushab verds ;/verify? calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 1001$ incl verfg1001$:. PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH/ PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURN# PUSHAB P1DSC ; GET P1 (FDn: UNIT)5 CALLS #3,G^CLI$GET_VALUE ;GET VALUE OF NAME TO VDFNM ON_ERR ADVDD_EXIT*; tstl deafg ;/deas? no need for 2nd file ; bneq 40$* PUSHAB WRK ; GET 2ND FILE (served unit)" PUSHAB DDFNM ; & ITS DESCRIPTOR' PUSHAB P2DSC ; & PARAMETER NAME 'P2'# CALLS #3,G^CLI$GET_VALUE ; GET FNM ON_ERR ADVDD_EXIT& $ASSIGN_S - ; Get a channel to the ( DEVNAM=DDFNM,- ; device for host file CHAN=DDCHN ON_ERR ADVDD_EXITA; LET ERRORS BY FOR THIS SINCE WE GET OUR INFO VIA OPEN ANYWAY SO*; CHANNEL REALLY DOESN'T HAVE TO BE THERE.D; Get the physical device name, and see if this device has an owner.6; (We must do this so we can get the host UCB address) $GETDVI_S -/ CHAN=ddchn,- ; Command line has device name. ITMLST=DEV_ITEM_LIST BLBS R0,40$ BRW advdd_EXIT40$:290$:/; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE. $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERROR $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name. ITMLST=VDV_ITEM_LIST BLBS R0,140$ BRW advdd_EXIT140$:=; Here do the real work in kernel mode, having now the device/; descriptions and channels to the devces even!. tstl deafg ;if /deas, do $qio, then knl work bneq 307$ $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARG$ CMPL R0,#SS$_NORMAL ;Any errors?& BEQL 300$ ;No, skip error routine( MOVL R0,MESS ;Move error to message ;;; BRW 300$301$:$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error message; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#busz<; after unbashing the current host, take the JF unit offline ; $CMKRNL_S -; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHN ret300$:B; Since that worked OK, send the format function to the JF unit to; finish bashing the host disk." movl #1,bufg ;set to bash device= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#busz=; BE SURE WE DON'T LEAVE THE CHANNELS ASSIGNED TO THE DEVICES ; EITHER...303$: $DASSGN_S CHAN=VDCHN. $DASSGN_S CHAN=DDCHN ;CLEAN UP I/O CHANNELS RET advdd_exit: RET;; KERNEL ARG LISTK_ARG:. .LONG 2 ;2 ARGS: HOST-DVC NAME, VD DVC NAME .ADDRESS DEV_BUF_DESC .ADDRESS VDV_BUF_DESC; .ADDRESS DDFNM; .ADDRESS VDFNM2; BASHUCB - AREA TO MESS UP UCB WITH OUR FILE DATA; BEWARE BEWARE BEWARE+; runs in KERNEL mode ... HAS to be right.-; Saves lots of registers so they're free...3 .ENTRY BASHUCB,^M; TAKEN LOOSELY FROM ZERO.MAR .if ndf,vms$v5) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB .iff0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASE& tstl deafg ;/deas needs no 2nd assign bneq 90$9 MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS (target)9 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 for tgt BLBS R0,660$ BRW BSH_XIT660$:;80$:* MOVL R1,HSTUCB ;;; SAVE HOST UCB ADDRESS& movl r1,r11 ;use r11 for target UCB6 BEQL 166$ ;;; ... BUT ZERO UCB ADDRESS LOOKS BAAAAD90$:0 MOVL 8(AP),R1 ;;; ADDRESS VDn NAME DESCRIPTORS1 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 BLBS R0,160$ BRW BSH_XIT160$: movl r1,vducb ;;; store vd ucb, movl r1,r5 ;use r5 for local ucb (JF dvc) beql 166$ ;fail if no ucb...; BUGGER THE UCB,; ASSUMES FILE LBN AND SIZE ALREADY RECORDEDC; ALSO ASSUMES THAT ZERO LBN OR SIZE MEANS THIS ENTRY NEVER CALLED.A; (REALLY ONLY WORRY ABOUT ZERO SIZE; IF WE OVERMAP A REAL DEVICE%; THEN ZERO INITIAL LBN COULD BE OK.);@; CHECK REF COUNT FIRST... ONLY CAN GET AWAY WITH THIS ON DEVICE; NOBODY'S USING...A; .. fake this since device may have count messed by advd somehow#; but will be allocated if mounted.; ... for now ...554$:6; CMPW UCB$W_REFC(R1),#1 ;;; CHECK COUNT VS 1 FOR THIS#; blssu 164$ ;if 1 or less, go on.5 brb 164$ ;(it doersn't matter ifthe local disk is in ; use...we don't bother it.)166$: brw 165$164$:1; check that both UCBs are disk devices at least!=; We can't be sure all the device char 82O BDK010.AB#+[EVERHART.BASHKIT]JGCTL.MAR;5P acteristics will be the?; same for the local device and the MSCP served remote one (and?; in fact they are not all alike!) but at least they had better:; both be disks or this function is not even approximately;; correct and will probably be quickly fatal to the system. tstl deafg ;/deas? r11 invalid. beql 1164$@; for deassign, must set JF offline so it can be turned on again$; but just do all work here & scram.3 cmpl ucb$l_icsign(r5),#magic ;got right magic no.?& bneq 1176$ ;if not then not JFdriver.; clear online & valid on JF dvc for next time .if df,evax5 bicl #ucb$m_online,ucb$l_sts(r5) ;set jf unit online* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bicw #ucb$m_online,ucb$w_sts(r5) ;set jf unit online* bicw #ucb$m_valid,ucb$w_sts(r5) ; & valid .endc1166$: movl #1,r0 brw bsh_xit ;unlock & leave1176$: movl #ss$_drverr,r0 brw bsh_xit1164$:# cmpb ucb$b_devclass(r11),#dc$_disk$ bneq 1176$ ;if not disk exit now.3 cmpl ucb$l_icsign(r5),#magic ;got right magic no.?& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else will5; be using its UCB so we don't want to screw this up. .if df,evax5 bitl #ucb$m_online,ucb$l_sts(r5) ;set jf unit online bneq 166$ .iff5 bitw #ucb$m_online,ucb$w_sts(r5) ;set jf unit online bneq 166$ .endcG; Looks like we're gonna do the assign. Store backpointer for driver to; check before unmung.8 movl r11,ucb$l_vict(r5) ;store ucb of victim in JF ucb&;;;must make maxbcnt and fipl match!!!B; Fork IPL will be same but maxbcnt often will not. Fix that here.A; movb ucb$b_fipl(r5),ucb$b_fipl(r11) ;;;ensure fork levels matchG movl ucb$l_maxbcnt(r5),ucb$l_maxbcnt(r11) ;;;store max bytes as a word=; Now get on with the tricky part, replacing the DDT. Do thisE; at device IPL so we have reasonable certainty nobody will mess with?; these structures until we get them all put into proper order.I; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytes); size and copy the existing DDT into it.E; (it is possible to save the old address if the conditional is used) .if df,evax5 bisl #ucb$m_online,ucb$l_sts(r5) ;set jf unit online* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bisw #ucb$m_online,ucb$w_sts(r5) ;set jf unit online* bisw #ucb$m_valid,ucb$w_sts(r5) ; & valid .endc@ movl ucb$l_maxblock(r11),ucb$l_maxblock(r5) ;copy geom for luck. movw ucb$w_cylinders(r11),ucb$w_cylinders(r5)* movb ucb$b_sectors(r11),ucb$b_sectors(r5)( movb ucb$b_tracks(r11),ucb$b_tracks(r5) clrl ucb$l_ctlflgs(r5) tstl verfg ;/verify? beql 61$ ;if not branch6 bisl #^x100000,ucb$l_ctlflgs(r5) ;say to retry errors61$:1000$:165$: MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R07 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL) POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOWvms$v5=1 .END ADVDD*[EVERHART.BASHKIT]JGCTL.OBJ;2+, ./ 4-B#+0123KPWO 56 oɗ74 ɗ89GHJ2JGCTLV001 7-APR-1994 21:49 VAX MACRO V5.4-3 MACRO JGCTL*;control JFdriver (fragmentation avoider JGCTL CLI$GET_VALUE CLI$PRESENT CLI$_PRESENT CTL$GL_PCB DSC$K_DTYPE_T IOC$SEARCHDEV SCH$IOLOCKW SCH$IOUNLOCK SYS$ASSIGN SYS$CMKRNL SYS$DASSGN SYS$GETDVI SYS$PUTMSGSYS$QIOW . ABS .P$ABS$PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP ADVDD_DATAP3SYS$DISKQ&QQQ(((Q( (PXQ((Q( Q DSC$K_DTYPE_T%Q DSC$K_DTYPE_T%Q DSC$K_DTYPE_T%$Q03UNITQ&Q <3FNAMQ&Q H3FRACTIONQ&QX3MINIMUMQ&Q g3MAXIMUMQ&Q v3ALDEFONLYQ &Q3DEASSIGNQ&Q3CBTQ&Q 3VERIFYQ&Q  , ADVDD_CODEP ADVDD& Џ CLI$PRESENTP CLI$_PRESENT CLI$PRESENTP CLI$_PRESENT, CLI$GET_VALUEP1g8 CLI$GET_VALUEP1H|~$ SYS$ASSIGNP1+|~\<$~ SYS$GETDVIP1|~( SYS$ASSIGNP1|~<(~ SYS$GETDVIEP12 SYS$CMKRNLPYP SYS$PUTMSG |~|~0 |~<~<(~ SYS$QIOW<(~ SYS$DASSGN |~|~0 |~<~<(~ SYS$QIOW<(~ SYS$DASSGN<$~ SYS$DASSGNP BASHUCB&6 CTL$GL_PCBT SCH$IOLOCKWЬQ IOC$SEARCHDEVP1QQ[ЬQ IOC$SEARCHDEVP1QQU1%`H$xxP1eЏP1[L`H$x[xxRRPPQQ ȏPP SCH$IOUNLOCKЎP& ADVDDBASHUCB2 ADVDD_DATA ADVDD_CODE *[EVERHART.BASHKIT]JGDRIVER.EXE;7+,. / 4 -B#+0123 KPWO 56Aɗ7ɗ89GHJ0D`0205IJGDRIVERV01B`ɗ05-13PQPPP   ?dJGDRIVERF11 4<@LNQP@Rr |\` he  T`H$ (*X(*(*(*(*8)(*(*(*(*(*(*(*(*flagLL|@z\@a'o( 0  `  $8'@%p&x& bC BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.EXE;7 K   # . 9 D O Z e p {  + 6 A L W b m x (3>IT_ju%0;FQ\gr} "-8<PQ8! XPPXXЎPZ[ŜZ[~ PE1@tMѪ[#ʜ[E P1ڎ[PЎ[ЎZѪH$ЪZ[? P<PQ8!lPЬQ'lPЀWW-ЀV$`QX*P< PQ8!Q[W [<P#ϢP~P PE1@tMЎP˜ZЫ,Yѩ ZѪH$P1dZ\XU(TjdЎUdXUcЪTRYЪWgЧЧЧ ba`ЏЏYih[$hd˜EP P1ЎPڎ? [UŜZХ,QС QZP[~P PE1@tMЎPѪ[ѪH$1ЪZ1yժ Ъ[ЪЪRRQЪРQURSʜTxQRQSСT,Q%SСT~УTՎЎСZPЪŜEP P1ЎPڎ? 11UPUUPUӏ PP P **ԣ\? Q!P!R\Џ2TvbЏУ8У ? *?1vЏУ8У Sl[~Z~}_L]VL/ac+ZI#!F]m7q59"bPpgI$x j M8h??GQ ϠO1*Oҝ-sO toRMDgs!=J ՜i`وco&0 pJ6UYt>6)hW,B{=bCain'x/(X%3mlʬl2Rw07"_yUi [ef$q<}bKz5E3ME.w<(l4 ABa(|3NYXN@Fn|}D^t2SN$U2_=L c@x'SOI-sWpy>Qb,G/8tM9 s,zWI*B)nN4"Iۮ9<@q"jc+Bayf~ z(<7C/i^ra{n9wWju1)I(A\.:#\w5G#8ȳB:5j8\"0wm+P#?//c.~r:'s>*#0IW=1 '?'1{*^5``Z{*l%ʝlQwl4{c_!? /GMo`Ext :>KӼ Ac{(6'|Vit R _kcr¹,?;Δ55%H֢4<aA].6e +65l` l-&f|\%N/IFtGo} 9?Y{ge`fsa+~&?ͤ L)! -k"#*ڼ+)Y2 y$&9͛z->dr;JA5챆*+4m 9#5/'Dzim'~[5Az.:m;TH=:' b@(rV͹f @9 , @{I&BB6$JwAݸ8AF3% !3.M;2F4JԾVA4`CgE94SlTN2.+\ZGx>wFJ7e,N~Ju;G7 e[g 19UBv21cYTPPT6lj F3bQI>UtZvBx''\L%{z"ܐF)C{z2,[{i Ъ N@pѪˬR oN\뇺XH,Y_ZܤT^4'|XQak1{Vɝ/ăSxlno1~`qX7 ?y$@Y-jRZ$Y ~u칎^yAfV1)r"yI*NY_,fc2}w8{SM]*P}*Z)U[R yjErI|]uzT2W'`z6ˡrK^HzI "a))2 7P58DidƓxc«.W@1di7`7Ba*4V AūcD*}G*EH>yߋkz 79/_[5wV$%'vaUs;hOW#b3gnDXOdY0=9o3ם9pwܴA.Ժ8r|Pєݎl qo9)A&6=Mg陫@5ӑЮu" *7Q;Hْ C{@\B kuV=}:`LKא~jRT5([#[(r [q LOGwڥLG GX\ x_Stvqپ4jNC)uq5Nh -,js3yCU8^j}mIqHJ0lAT2yxB &<MB^u+-@ BE÷j8|cuƞHQs>HKeujH삤BIOtR}GJFP+}mcG w8I$? ;M(Wj̧9a-Ê3~%7] <ƽ?oI'>s/K\8?'uњ2k)c_R?bMT{<]!67I%7ΩnZVn'a*h.ȝ!.-8|ZġcP}((EZo}Hͬxeusse AOBɊIEq ɉhSԷ4QZm$#"g,osqGVI@e?ZX L[j)Qh{ Ӂcce< Bjp/S:N08e]Bti5:ChJ_sTܶB:. L"rM=X}ljq k@{ASP0aϹͶ(A5y 'sF|^%^`,SAGTCej5 &@R~Ǭ`L%q)D`2RmPz /g;z8!衮¯KbMDA$b 6POk/f"u\: 8]]4s[a/ɐq pvUG6bc}nv\^X)<*nN=ُ6 ӡh]壟|;*y6R~QLtT+Bp}cF# nکi],Ğhc/EwBu?CxMH`C "x>d{kheNvJ ק} 2Quz'$F$pD/m"VV~:{:IV'Sd/u [nqqN.<Gaq&  G\@4%&oѫTRX%u{B<+HYP:46Wqq7M{ jjɁ(\QKz$|!)zHePZdb. i s q)e)|4 G_"k&Z*٬^_aqi+Zm>}z` $>0&eѼ"dd@&3չcl9B.ohpZ=_L +JsC .V%A>^bJ.ӊ3aF_eJNIvE, +}}p?Qoa$d>qAl$]eIcn]T_^ 7^`N\s.7K]0oL 9@[N衑Dt~,ĕ~7l9Z8DGE~|Z"K~Le#NrI2) l}8JcLso&˘dOsVp[E2pP`K4Zϑp˧WPW\?CmEν9m_ZB g'@KЭSnYJ>Cر&6siLO(?(QsKc!fXE82ٸ:H+VSw:pN0n OpRg|y`?b fK;}@+G5@!YxoeKEښj _]J5y,?ޣj=`=^[Oy>ͽXTgdp8:AM>E絙TbBy E/+!; ";<󼞮& iuFUse\cq&-kw=8syJx>2~5sCK.N4E0y=sILZ{և2DPW] 9lV&j46`7kɗUh#ydFTpEUa'D2[U+8)MBn>+f==DR#ɤcj(GowEwEӶtz x~7`z:Od0C2dOENu'cO(r'Xw}cXH4B3,G/!mEf_ڢ F pshA97{\ѿ\i>A.ŵ@tR,5i2W&L]Se}PdUzMxL ݽ7`{qn\=5}8 V3 '%xDJPq 18rmcEMhc&#y Dp"5X ;9FPWYɾfMja1<}0:_kc;tmSg)uPy뇢dG;{;у+w62̃d l]GCE:L}T\f*{p cqn'D`d4$!T~;-S&jML iQ:Dt{Pۏrq~B69*19U͋l`/6a iPMqUx%+iGy2`%p] Ȑ.'!SB\Hfp92JlΒ&#rnE)}RXb$ÊHUɢް\,8fmkbmFB{-MM z5/&cuMﭦb$0nQFHwn1*<1 nzO+3^XK156wPȁbIRT!}oJf,DofQ.:N~;NG Lm+jиh"Iu+E;>]^<2x,# 5qm]scmtPNlt6CfsX=(Vs Q/ WI\PT#甖R>PV*r22̴di$ŶH໶b0ųgƒz JK;>v!(¶~mygٕbf &i7y3p8+%ґRuetϿB?&lq\m ifwϏA6Sby(Ի^J9j׭}،tvbpDKͩ @rs5l,GBhkSc)?TJ8i׫S*ݗo7Iǔv^SijjD:LY Zl6z+(bN); |@#qGU@Goj{xG@_BQ>=ֺQA# vo8k)ؙeNɐY -̫cЂL`t7 / Ko&Y`:tkߊJ&κ$d %ʾ8;|Z C>Qh/rVt\rM2C@R78};p*6T\r\meR$def ucb$l_prevddt .blkl 1 ; previous DDT addressH$def ucb$l_icsign .blkl 1 ; unique pattern that identifiesG ; this as a DDT intercept blockP; NOTE: Jon Pinkley suggests that the DDT size should be encoded in part of thisI; unique ID so that incompatible future versions will be guarded against.$def ucb$s_ppdend,$def ucb$a_vicddt .blkb ddt$k_length@ ; space for victim's DDT .blkl 4 ;safety1$def ucb$l_backlk .blkl 1 ;backlink to victim ucbE; Make the "unique magic number" depend on the DDT length, and on theJ; length of the prepended material. If anything new is added, be sure that"; this magic number value changes.Fmagic=^xF024F000 + ddt$k_length + <256*>Hp.magic=^xF024F000 + ddt$k_length + <256*> ;an ACE is there or not.0$DEF UCB$L_JG_HOST_DESCR .BLKL 2 ;host dvc desc.;<; Set FDT table start mask for each unit by keeping it here.1; We need just enough to get back to user's FDTs.)$def ucb$l_fdtlgl .blkl 2 ;legal fcn msks,$def ucb$l_fdtbuf .blkl 2 ;buffered fcn msks%$def ucb$l_fdtmfy .blkl 3 ;modify fcn($def ucb$l_fdtbak .blkl 3 ;"go back" fcn0$def ucb$l_vict .blkl 1 ;victim ucb for checking<; The following lets us steal start-io and add error retries7$def ucb$l_omedia .blkl 1 ;storage of orig. irp$l_media5$def ucb$l_ppid .blkl 1 ;store for irp$l_pid contents3$def ucb$l_retries .blkl 1 ;counter for i/o retries6$def ucb$l_hstartio .blkl 1 ;host driver start-io loc./$def ucb$l_hstucb .blkl 1 ;host ucb (quick ref)($DEF UCB$K_JG_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JG_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 FIELDSA; THAT ARE TO BE INITIALIZED DURING DRIVER LOADING AND RELOADING; driver_data JG_UNITS=100vd_units=jg_units VJG$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 .if df,evax DPTAB - ;DPT CREATION MACRO$ END=JG_END,- ;END OF DRIVER LABEL0 ADAPTER=NULL,- ;ADAPTER TYPE = NONE (VIRTUAL)F FLAGS=DPT$M_SMPMOD!dpt$m_xpamod!DPT$M_NOUNLOAD, - ;SET TO USE SMP,xa' DEFUNITS=2,- ;UNITS 0 THRU 1 thru 31 step=1,-' UCBSIZE=UCB$K_JG_LEN,- ;LENGTH OF UCB. MAXUNITS=JG_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JGDRIVER ;DRIVER NAME .iff DPTAB - ;DPT CREATION MACRO$ END=JG_END,- ;END OF DRIVER LABEL0 ADAPTER=NULL,- ;ADAPTER TYPE = NONE (VIRTUAL)F FLAGS=DPT$M_SMPMOD!dpt$m_xpamod!DPT$M_NOUNLOAD, - ;SET TO USE SMP,xa' DEFUNITS=2,- ;UNITS 0 THRU 1 thru 31' UCBSIZE=UCB$K_JG_LEN,- ;LENGTH OF UCB. MAXUNITS=JG_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JGDRIVER ;DRIVER NAME .endc2 DPT_STORE INIT ;START CONTROL BLOCK INIT VALUES8 DPT_STORE DDB,DDB$L_ACPD,L,<^A\F11\> ;DEFAULT ACP NAME3 DPT_STORE DDB,DDB$L_ACPD+3,B,DDB$K_PACK ;ACP CLASS .IF NDF,VMS$V52 DPT_STORE UCB,UCB$B_FIPL,B,8 ;FORK IPL (VMS V4.X)" .IFF ;DEFINE FOR VMS V5.X & LATERG DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ;FORK IPL (VMS V5.X + LATER) .ENDCC; These characteristics for an intercept driver shouldn't look justF; like a real disk unless it is prepared to handle being mounted, etc.); Therefore comment a couple of them out.8 DPT_STORE UCB,UCB$L_DEVCHAR,L,- ;DEVICE CHARACTERISTICS ; RANDOM ACCESS9 DPT_STORE UCB,UCB$L_DEVCHAR2,L,- ;DEVICE CHARACTERISTICS5 ; Prefix name with "node$" (like rp06)7 DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_MISC ;DEVICE CLASS: DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,512 ;DEFAULT BUFFER SIZEB; FOLLOWING DEFINES OUR DEVICE "PHYSICAL LAYOUT". It's faked here.+ DPT_STORE UCB,UCB$B_TRACKS,B,1 ; 1 TRK/CYL? DPT_STORE UCB,UCB$B_SECTORS,B,64 ;NUMBER OF SECTORS PER TRACK9 DPT_STORE UCB,UCB$W_CYLINDERS,W,16 ;NUMBER OF CYLINDERS* DPT_STORE UCB,UCB$B_DIPL,B,22 ;DEVICE IPL7 DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNTF DPT_STORE UCB,UCB$W_DEVSTS,W,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;...;?; don't mess with LBN; leave alone so it's easier to hack on...;6 DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUESQ; DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,VR_INT ;INTERRUPT SERVICE ROUTINE ADDRESS .if ndf,evaxC DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,- ;CONTROLLER INIT ADDRESS D,JG_ctrl_INIT ;...= DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS D,JG_unit_INIT ;... .endc0 DPT_STORE DDB,DDB$L_DDT,D,JG$DDT ;DDT ADDRESSB DPT_STORE UCB,UCB$L_UNIQID,D,DPT$TAB ;store DPT addressH ; (change "XX" to deviceJ ; mnemonic correct values)P DPT_STORE UCB,UCB$L_ICSIGN,L,magic ; Add unique pattern (that mightM ; bring back some memories in? ; DOS-11 users)C; HISTORICAL NOTE: under DOS-11, one would get F012 and F024 errors@; on odd address and illegal instruction traps. If we don't have@; this magic number HERE, on the other hand, we're likely to see=; bugchecks in VMS due to uncontrolled bashing of UCB fields!- 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.; .if df,evax DDTAB - ;DDT CREATION MACRO DEVNAM=JG,- ;NAME OF DEVICE' START=JG_STARTIO,- ;START I/O ROUTINE0 FUNCTB=JG_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JG_CTRL_INIT,- UNITINIT=JG_UNIT_INIT,--; 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 .iff DDTAB - ;DDT CREATION MACRO DEVNAM=JG,- ;NAME OF DEVICE' START=JG_STARTIO,- ;START I/O ROUTINE0 FUNCTB=JG_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 .endc; ; FUNCTION DECISION TABLE; 6; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.; ; code chaining data:@chnflg: .long 1 ;chain or use our FDT chain flag...use ours if 0myonoff:3fdtonoff: .long 0 ;switch my fdt stuff off if non-0M .ascii /flag/ ;define your own unique flag here; just leave it 4 bytes long!$ .long 0 ;fdt tbl from before patchfdt_chn = -12 fd X1i BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4Slt_prev = -4 fdt_idnt = -8 JG_FUNCTABLE:newfdt:# FUNCTAB ,- ;LIST LEGAL FUNCTIONS ; MOUNT VOLUME#; no-op phys I/O for a test here...! FUNCTAB ,- ;BUFFERED FUNCTIONS ; MOUNT VOLUME?; io$_format + modifiers (e.g. io$_format+128) as function code>; allows one to associate a JG unit and some other device; seeE; the JG_format code comments for description of buffer to be passed.) functab JG_format,- ;point to host disk ;$; First our very own filter routines;A; Following FDT function should cover every function in the localB; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need. Functab fdtswitch,-' myfdtbgn=.J; Leave a couple of these in place as an illustration. You would of courseM; need to insert your own if you're messing with FDT code, or remove these ifI; you don't want to. The FDT switch logic is a waste of time and space if; you do nothing with them...K; They don't actually do anything here, but could be added to. Throw in oneF; to call some daemon at various points and it can act as a second ACPG; when control is inserted at FDT time (ahead of the DEC ACP/XQP code!)mymfy: FuncTab MFYFilt,-( ;modify filter (e.g. extend) myfdtend=.C; Note that if we want to allow numerous disk drivers to be patched<; by this one there is not a unique path to the original fdt=; routine. Therefore use a UCB cell for the patch, not a cell9; ahead of the FDT. That way each unit gets a good return<; path. That's why there's an "oldfdt" cell in the UCB here.;3; Following contains all legal functions in mask...A; That way it can transfer all control to a "previous" FDT chain.mybak: FuncTab fdttoorig,- WRITEHEAD,- ;WRITE HEADER AND DATA= READHEAD,- ;READ HEADER AND DATAD WRITECHECKH,- ;WRITE CHECK HEADER AND DATA6 STARTSPNDL,- ;START SPINDLE? WRITETRACKD,- ;WRITE TRACK DESCRIPTOR> READTRACKD,- ;READ TRACK DESCRIPTOR> COPYSHAD,- ; Do shadow set copies$ MODIFY,- ; MODIFY FILE ATTRIBUTES MOUNT> ; MOUNT VOLUMEL; Now the "standard" disk FDT routines needed to let ODS-2 work (or ods-1 !)I; (Where we are doing read - or possibly write- virtual by hand ourselves$; we may never get to these BTW...)( FUNCTAB +ACP$READBLK,- ;READ FUNCTIONS# * FUNCTAB +ACP$WRITEBLK,- ;WRITE FUNCTIONS% ) FUNCTAB +ACP$ACCESS,- ;ACCESS FUNCTIONS2 , FUNCTAB +ACP$DEACCESS,- ;DEACCESS FUNCTION ) FUNCTAB +ACP$MODIFY,- ;MODIFY FUNCTIONS' p& FUNCTAB +ACP$MOUNT,- ;MOUNT FUNCTION ; MOUNT VOLUMEC FUNCTAB +EXE$LCLDSKVALID,- ;LOCAL DISK VALID FUNCTIONS 6 ;PACK ACKNOWLEDGE3 FUNCTAB +EXE$ZEROPARM,- ;ZERO PARAMETER FUNCTIONS5 ; AVAILABLEr0 FUNCTAB +EXE$ONEPARM,- ;ONE PARAMETER FUNCTION * FUNCTAB +EXE$SENSEMODE,- ;SENSE FUNCTIONS' D' FUNCTAB +EXE$SETCHAR,- ;SET FUNCTIONSF# L .long -1,-1 ; catch-all mask%fcnca: .long 0 ;fill in in unit initR A VD_UCBTBL::O .BLKL VD_UNITSO .LONG 0,0 ;SAFETY3 .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;more safety; offset address tablev_unm=0 E; Note: code elsewhere assumes that the xxvc macro generates 8 bytes.;?; If .address generates more than 4, it breaks as coded here!!!K .macro xxvc lblct .address vd_fxs'lblct .globl vd_fxs'lblct .long 0 .endm VD_VOADT:: .rept B xxvc \v_unmv_unm = d .endr driver_code .if df,evaxfcae: .jsb_entry .ifffcae:f .endc+ movzwl #SS$_BADPARAM,r0 ;illegal parametert clrl r1qu BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4SlV~$ jmp g^exe$abortio ; fdtswitch - A; Based on state of "myonoff" variable either enable or disable1D; my FDT processing, allowing the FDT chain to remain always intact.C; This needs to be the first of a chain of FDT entries added to thed; FDT processing of a driver.H .if df,evaxfdtswitch: .jsb_entry .iffI fdtswitch: .endc tstl fdtonoff ;global on/off bneq 1$ rsb ;go to next FDT if null_51$: addl2 #,r8 ;pass our fdt codesT rsb ;return to std ; fdttoorig - A; This entry continues FDT processing at the point after the newtC; entries by returning to the original FDT chain at the point wherenD; that chain begins. (It is presumed that FDT entries will always be@; added ahead of existing ones due to the nonreturning nature ofA; FDT processing.) This is done instead of simply duplicating the>; DEC FDT entries because in this way multiple FDT patches canA; coexist, as would be impossible if this trick were not used. As '; can be seen, its overhead is minimal.hA; The old FDT location is kept in the UCB for our device becauseiD; that allows us to get back to different FDTs when several drivers'$; FDT chains are pointed here first. .if df,evax!fdttoorig: .jsb_entry,output=d .iffl fdttoorig: .endc?; As a performance feature, use a switch to let us just use theeA; FDT chain here rather than continuing an old one. This needs tod@; be settable externally since there is no need to return down a.; chain unless something else is IN the chain.; Control this with chnflg ; tstl chnflg ); beql 2$ ;just continue if chnflg is 0e pushl r0 =; (this routine gets called a fair bit and if GETJGUCB can bed!; called less, things speed up.) / jsb getJGucb ;get UCB for JG unit from stolen ;one  tstl r0 ;r0 is return UCB& bgeq 1$ ;if not negative, not a UCB* tstl ucb$l_oldfdt(r0) ;a prior fdt exist? beql 1$E movl ucb$l_oldfdt(r0),r8 ;point to original FDT point 8 addl2 #<16-12>,r8 ;pass the 2 entry masksD1$: ;back up since sysqioreq adds 12 popl r0F2$: rsb ;off to the previous FDT routines.;dH; GETJGUCB - Find JG: UCB address, given r5 points to UCB of the patchedF; device. Return the UCB in R0, which should return 0 if we can't find; it.dB; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. .if df,evaxgetJGucb: .jsb_entry .iffa getJGucb:  .endc!; clrl r0 ;no UCB initially found pushl r10( pushl r11 ;faster than pushr supposedly; pushr #^mD; Assumes that R5 is the UCB address of the device that has had someA; code intercepted and that we are in some bit of code that knowsS?; it is in an intercept driver. Also assumes R11 may be used ascD; scratch registers (as is true in FDT routines). Control returns at:; label "err" if the DDT appears to have been clobbered byA; something not following this standard, if conditional "chk.err"m ; is defined.f-; Entry: R5 - victim device UCB addressl0; Exit: R11 - intercept driver UCB address chk.err=0uF movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!!D movab VJG$dpt,r11 ;magic pattern is DPT addr.9; lock this section with forklock so we can safely removet3; entries at fork also. Use victim device forklock.r1; (don't preserve r0 since we clobber it anyway.)B= forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NOF42$: cmpl (r10),R11= ;this our own driver?D@; beql 1$ ;if eql yes, end search;D<; The somewhat odd layout here removes extra branches in the@; most common case, i.e., finding our driver the very first time<; through. The "bneq" branch next time is usually NOT taken.;R) bneq 5$ ;check next in chain if not us A; At this point R10 contains the DDT address within the intercept F; driver's UCB. Return the address of the intercept driver's UCB next.O movab <0-ucb$a_vicddt>(r10),r11 ;point R11 at the intercept UCB.7; brb 4$ ; note in this layout we can comment this out.B4$:;? forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOE%; NOW clobber r0 and put things back.) movl r11,r0; popr #^m! popl r11O& popl r10 ;supposedly faster than popr rsbA; Make very sure this DDT is inside a UCB bashed according to ourA=; specs. The "p.magic" number reflects some version info too.R3; If this is not so, not much sense searching more.L95$: cmpl (r10),#p.magic;C bneq 3$ ;exit if this is nonstd bash+; follow DDT block chain to next saved DDT.,5 movl (r10),r10LI ;point R10 at the next DDT in theR ;chain F bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againd;1$:3$:h$ clrl r11 ;return 0 if nothing found brb 4$O;U*; Few macros for long distance branches...;  .macro beqlw lbl,?lbl2 bneq lbl2 brw lbllbl2:  .endm .macro bneqw lbl,?lbl2D beql lbl2 brw lbllbl2:  .endm .macro bleqw lbl,?lbl2T bgtr lbl2 brw lbllbl2:  .endm .macro bgeqw lbl,?lbl2M blss lbl2 brw lbllbl2:d .endm); allocate does not zero its result area.CE; This macro makes it easy to zero an allocated area before using it.B@; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".E .macro zapz addr,size3 pushr #^m ;save regs from movc5R movc5 #0,addr,#0,size,addrS2 popr #^m ;save regs from movc5 .endm;E .SBTTL Our FDT Filter Routines .if df,evax<mfyfilt: .jsb_entry ;filter on MODIFY requests (e.g. extend) .iffT1mfyfilt: ;filter on MODIFY requests (e.g. extend)B .endc rsb;++;5; JG_format - bash host disk tables to point at ours.c;nF; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),RB; the size of the virtual disk, and the LBN where the virtual diskE; will start. After these are set up, the device is put online and isC; software enabled.N;-D; This routine does virtually no checking, so the parameters must be ; correct.;T ; Inputs: >; p1 - pointer to buffer. The buffer has the following format:=; longword 0 - (was hlbn) - flag for function. 1 to bash .; the targetted disk, 2 to unbash it, else; illegal.@; longword 1 - virtual disk length, the number of blocks in,; the virtual disk. If negative disables&; FDT chaining; otherwise ignored.@; longword 2 through the end of the buffer, the name of the-; virtual disk. This buffer must be blank$; padded if padding is necessary;w;d; p2 - size of the above buffero;--d .if df,evaxJG_format: .jsb_entryf .iff' JG_format: .endc< bicw3 #io$m_fcode,irp$w_func(r3),r0 ;mask off function code) bneq 20$ ;branch if modifiers, specialC);thus, normal io$_format will do nothing.L rsb ;regular processingR100$:C0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parameterI clrl r1 jmp g^exe$abortio20$: movl p1(ap),r0 ;buffer address" movl p2(ap),r1 ;length of buffer: jsb g^exe$writechk ;read access? doesn't return on error:; clrl irp$l_bcnt(r3) ;paranoia, don't need tUC֗ BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4Sl3o do this...1 pushr #^mL$ movl p1(ap),r0 ;get buffer address movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegal# cmpl r7,#2 ;3 and up illegal too bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored); bleq 70$O0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JG_host_descr+4(r5)G5 subl3 #8,p2(ap),- ;set length of name in descriptorR ucb$l_JG_host_descr(r5)  bleq 100$ ;bad length4 movab ucb$l_JG_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host deviceE! blbs r0,30$ ;branch on successE; fail the associate...S0 popr #^m= movzwl #ss$_nosuchdev+2,r0 ;make an error, usually a warninge clrl r1$ jmp g^exe$abortio ;exit with error30$: ;found the device; r1 is target ucb address... $; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?d bneq 31$ ;if neq it's unmung jsb mung ;go mung target...e brb 32$31$:H; Be sure we unmung the correct disk or we can really screw up a system.- cmpl r11,ucb$l_vict(r5) ;undoing right disk?A) bneq 32$ ;if not skip out, do nothing.  jsb umung ;unmung target32$:3; bisw #ucb$m_valid,ucb$w_sts(r5) ;set volume validS3; bisw #ucb$m_online,ucb$w_sts(r5) ;set unit onlineD5; movl ucb$l_irp(r5),r3 ;restore r3, neatness counts;0 popr #^m! movzwl #ss$_normal,r0 ;successY' jmp g^exe$finishioc ;wrap things up.L .if df,evaxmung: .jsb_entry .iffBmung:  .endc=; steal DDT from host. Assumes that the intercept UCB addressOB; is in R5 (that is, the UCB in which we will place the DDT copy),=; and that the UCB of the device whose DDT we are stealing isDC; pointed to by R11. All registers are preserved explicitly so thatUB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingDG; went wrong so the bash did NOT occur. This generally means some otherAF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so theE3; unique ID field and magic number are set already. 6 movab fcae,fcnca ;ensure final FDT entry is filled in7 pushr #^m 5; Acquire victim's fork lock to synchronize all this.Y7 movl #ss$_normal,r0 ;assume successt" forklock ucb$b_flck(r11),- savipl=-(sp),preserve=YES@; find the current DDT address from the UCB (leaving the copy in; the DDB alone)> movl ucb$l_ddt(r11),r10 ;point at victim's DDB-; see if this DDT is the same as the originaluF movl ucb$l_ddb(r11),r9 ;the ddb$l_ddt is the originalG cmpl ddb$l_ddt(r9),r10 ;bashing driver the first time?d3 beql 1$ ;if eql yesnG; driver was bashed already. Check that the current basher followed thet); standard. Then continue if it looks OK..9 cmpl (r10),#p.magicuF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellm: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too) 2$:t<; set our new ddt address in the previous interceptor's slotB movab ucb$a_vicddt(r5),(r10)H ;store next-DDT address relativeC ;to the original victim ones1$:aD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallyo3$:t pushl r5&; copy a little extra for good luck...J movc3 #,(r10),ucb$a_vicddt(r5) ;copy the DDTO popl r5 ;get UCB pointer back (movc3 bashes it)r;-1; Here make whatever mods to the DDT you need to.o;i8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers)NH movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JG_functable+fdt_prev ;save old FDT ucb addressK: movl ddt$l_fdt(r10),ucb$l_oldfdt(r5) ;save orig. fdt addrK movl ucb$l_uniqid(r5),JG_functable+fdt_idnt ;save unique ID alsoD9; copy legal and buffered entry masks of original driver.EA; HOWEVER, set mask for format entry to be nonbuffered here sinceO; we deal with it. pushr #^m/; movab ucb$l_fdtlgl(r5),r9 ;our function table dummy in UCB-+ movl ddt$l_fdt(r10),r7 ;victim's FDT table C; We want all functions legal in the victim's FDT table to be legala; here. & movl (r7),(r9)+ ;1st half legal mask' movl 4(r7),(r9)+ ;2nd half legal mask * movl 8(r7),(r9)+ ;1st half buffered mask+ movl 12(r7),(r9)+ ;2nd half buffered mask 6; Now copy in our modify & back-to-original FDT cells.B; Thus every unit has its own legal & buffered masks, then goes to0; original FDT, and we don't mess with OUR FDTs.2; (Also original FDT tables aren't messed either.)& movl mymfy,(r9)+ ; modify template 1 movl mymfy+4,(r9)+ ; & 2! movl mymfy+8,(r9)+ ;and addressS@; Set -1 to set ALL possible function bits so we always go back.* movl #-1,(r9)+ ;then catch-all "go back"" movl #-1,(r9)+ ; to original fdt* movl mybak+8,(r9) ; and address of same. popr #^mD movab ucb$l_fdtlgl(r5),ddt$l_fdt(r8) ;point at our FDT table< movl ddt$l_start(r8),ucb$l_hstartio(r5) ;save host start-io0 movl r11,ucb$l_hstucb(r5) ;save backpointer too7 movab stealstart,ddt$l_start(r8) ;point at our startio 8 clrl myonoff ;turn my FDTs on; E; Finally clobber the victim device's DDT pointer to point to our new ; one./ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)D@; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing in C; the example here causes the intercept driver's FDT routines to be C; used ahead of whatever was in the original driver's FDTs. BecauseVE; the DDT is modified using the UCB pointer only, target device units B; that have not been patched in this way continue to use their old; DDTs and FDTs unaltered.; 1; Processing complete; release victim's fork lock 100$:F6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YESA7 popr #^mF rsb .if df,evaxumung: .jsb_entryA .iffumung: .endc; F; Entry: R11 points at victim device UCB and current driver is the oneK; desiring to remove its entry from the DDT chain. Thus its xx$dpt: address E; is the one being sought. ("Current driver" here means the interceptD ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCAB contains an entry in the DDT chain. pushr #^m0 movl r11,r5 ;hereafter use r5 as victim's UCBF movl ucb$l_ddt(r5),r10 ;get the DDT we currently have: movl ucb$l_ddb(r5),r1 ;get ddb of victim> movl ddb$l_ddt(r1),r1 ;and real original DDTF movl r10,r0 ;save ucb$l_ddt addr for laterC movab DPT$TAB,r11 ;magic pattern is DPT addr. 9; lock this section with forklock so w6 BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4Sl7>Be can safely removeC3; entries at fork also. Use victim device forklock.> forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=YES42$: cmpl (r10),R11= ;this our own driver?E? beql 1$ ;if eql yes, end searchH .if df,chk.err9 cmpl (r10),#p.magicaD bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.;5 movl (r10),r10 I ;point R10 at the next DDT in thes. ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againf1$:vA; At this point R10 contains the DDT address within the intercept,F; driver's UCB. Return the address of the intercept driver's UCB next.M tstl (r10) ;were we intercepted?eC bgeq 3$ ;if geq no, skip back-fixupt/; we were intercepted. Fix up next guy in line. L movl (r10),r11 ;point at interceptorS movl (r10),(r11)n3$:DE; if we intercepted someone, fix up our intercepted victim to skip byb ; us also.I movl (r10),r2 ;did we intercept 9 ;original driver?cA cmpl r2,r1 ;test if this is original < beql 5$ ;if eql yes, no bashB; replace previous intercept address by ours (which might be zero)R movl (r10),(r2)5$:s>; Here remove FDT entries from the list if they were modified.=; This needs a scan of the FDT chain starting at the victim'sFB; ddt$l_fdt pointer and skipping around any entry that has address; JG_functable:tB; The FDT chain is singly linked. The code here assumes everybody; plays by the same rules!G; NOTE: Omit this code if we didn't insert our FDT code in the chain!!!m; movl ddt$l_fdt(r0),r1 ;start of FDT chainiA movab JG_functable,r2 ;address of our FDT tablea clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucbeD; Also set the JG device offline when we unbash it. This is a simple@; flag that ctl prog. can use to tell if it's been used already. .if df,evax/ bicl #,ucb$l_sts(r4)s .iffs/ bicw #,ucb$w_sts(r4)  .endcA6$: cmpl r1,r2 ;current fdt point at us?nA beql 7$ ;if eql yes, fix up chainq@ movl r1,r3 ;else store last pointer: movl fdt_prev(r1),r4 ;and point at next bgeq 8$? movl ucb$l_oldfdt(r4),r1 ;where last FDT pointer is in the ucb A;;;BUT not all UCBs will have the fdt offset at the same place!!!oF;;;HOWEVER we will leave this in, putting the oldfdt field first after;;;the regular UCB things.D bgeq 8$ ;if not sys addr, no messin'? brb 6$ ;look till we find one.u7$:s*;r3 is 0 or fdt pointing to our block next;r1 points at our fdt blockbD tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to doy movl fdt_prev(r1),r4 bgeq 17$h. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4e blss 18$a tstl (sp)+o brb 17$ 18$: movl (sp)+,ucb$l_oldfdt(r4)N17$: movl fdt_prev(r1),fdt_prev(r3) ;else point our next-fdt pointer at7 ;last fdt addr.t8$:T;pF; Finally if the victim UCB DDT entry points at ours, make it point atF; our predecessor. If it points at a successor, we can leave it alone.J cmpl r10,r0 ;does victim ucb point at our DDT?A bneq 4$ ;if not cannot replace itn? movl (r10),ucb$l_ddt(r5) 4$:o@ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^mmK ;copy our prior DDT ptr to next one  rsb;w; stealstart - start-io entry '; Must eventually call host's start-io.,; entry: r3=IRP, r5=host UCB;btoorgj: brw toorgdawab: brw away .if df,evaxstealstart: .jsb_entry .iffu stealstart:D .endc pushl r51% jsb getjgucb ;find intercept UCB now  tstl r0 ;did we find it?* bgeq awab ;no, scram, but probably hang.& cmpl ucb$l_hstucb(r0),r5 ;right host? beql 70$ ;if ok, leave- movl r5,ucb$l_hstucb(r0) ;else put it in nowa70$:( movl r0,r5 ;point at intercept ucb now< bitl #1048576,ucb$l_ctlflgs(r5) ;user want error reduction? beql toorgj ;if not skip out9; besure this is read or write, else just start orig. one.< EXTZV #IRP$V_FCODE,- ; Extract I/O function code) #IRP$S_FCODE,- ;i! IRP$W_FUNC(R3),R0B ASSUME IRP$S_FCODE LE 7 ; Allow byte mode dispatch! cmpl r0,#io$_writepblk ;too low? blss toorgj cmpl r0,#io$_readpblk bgtr toorgjC; gotta arrange to get back after done the I/O and to reissue it ifi/; errors happened and we're not out of count...  .iif ndf,maxtries,maxtries=128cG;We'll keep the info in the UCB for debugging, but when the host driver J; that we're intercepting does a request completion, it will unbusy itselfN; and dequeue anything else that was in the device queue. As a result, we needG; to track when an IRP has already been modified in this pass, and mustrF; also just go directly to the original code where that should happen.); To accomplish this we need storage for: ; 1. Original irp$l_pid; 2. Original irp$l_mediaL; 3. Current retry count (and maybe use hi word as a flag that we have this; IRP); J; Since I don't want to mess anything up in the regular IRP, just allocateF; a buffer and use the keydesc slot to point at it. If user has a key,J; we let the i/o by and he takes his chances with device errors. Advertise-; that opticals don't support dec encryption.m;.>; If user has something in the key field leave this IRP alone.$ bbs #irp$v_key,irp$w_sts(r3),toorgj?; key field should be free. Grab a bit of pool & point at it ifs; nothing's there. vv.magic=0val.magic=^x76543210 vv.retries=4 vv.media=8 vv.pid=12a?; Set the key bit and go grab an area of mem. to hold our info.v" bbss #irp$v_key,irp$w_sts(r3),16$-16$: clrl irp$l_keydesc(r3) ; zero initially.e pushr #^m.$ movl #32,r1 ;get 8 longwords area, jsb g^exe$alonpagvar ;get the space or fail. blbc r0,55$ ; br if no space & just give up. ; got it.r- movl r2,irp$l_keydesc(r3) ;save area address vv.magic=0val.magic=^x76543210 vv.retries=4 vv.media=8 vv.pid=12u vv.bash=16- movl #val.magic,vv.magic(r2) ;flag we got it2 movl i^#maxtries,vv.retries(r2) ;save retry count? movl irp$l_media(r3),vv.media(r2) ;save original media addressh; movl irp$l_pid(r3),vv.pid(r2) ;save original pid addr too.h popr #^m brb 56$55$:? bbcc #irp$v_key,irp$w_sts(r3),17$ ;clr key bit if we have nonea17$: popr #^m. brw toorg ;can't find pool, just let irp by56$:@ movl I^#maxtries,ucb$l_retries(r5) ;setv BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4SlQ initial retry count up.6 movl irp$l_media(r3),ucb$l_omedia(r5) ;save lbn stuff5 movl irp$l_pid(r3),ucb$l_ppid(r5) ;save pid info tookD movl r3,ucb$l_irp(r5) ;for debug keep irp addr in intercept ucb too:; now set up IRP, then call the previous start-io point at<; ucb$l_hstartio(r5) to do the work with registers put back.E; For Alpha, the stack manipulation here is messy to track in machinec; code, so do it in a register.e6 movl r11,-(sp) ; Free up ol' reliable R11 as scratch movl r10,-(sp) ; Free R10 also. movzwl ucb$w_unit(r5),r11 ; Need address cellI; following assumes that addresses are 32 bits long so shift by 2 gets uso; to an address offset.r7 ashl #2,r11,r11 ; to get ucb address back at i/o done,6 movab vd_ucbtbl,r10 ; Base of table of UCB addresses6 addl2 r11,r10 ; Make R10 point to cell for THIS UCB0 movl r5,(r10) ; Now save our UCB address there$; (THIS ALLOWS US TO GET IT BACK...):; This trick allows us to leave the rest of the IRP alone.; Now the tricky bit.'C; We must fill the appropriate address into IRP$L_PID for a call at1@; I/O completion. We use a table of such routines, one per unit,=; all of the same size so we can calculate the address of the3>; routines. However, since the routine addresses can be almost9; anywhere when the compiler gets done with them, we will E; use a table constructed BY the compiler of pointers to them all andlI; access via that instead of just forming the address directly. The tablem,; entries will be left 2 longs in size each.J; Table VD_VOADT is what we need. Note however that the .address operatorsH; there probably need to change to some more general .linkage directive.0 movzwl ucb$w_unit(r5),r11 ; get our unit number&; Each linkage pair is 8 bytes long...6 ashl #3,r11,r11 ; Make an offset to the linkage area) movab vd_voadt,r10 ; get the table base 2 addl2 r10,r11 ; r11 now points at the link addr; movl (r11),irp$l_pid(r3) ; Now point irp$l_pid at a proper1 .if ndf,evax#"; must add vjg$dpt address to this# movab vjg$dpt,r10 ;start of driver;4 addl2 r10,irp$l_pid(r3) ;now pid should get back ok .endc pushl r0o movl irp$l_keydesc(r3),r07 movl irp$l_pid(r3),vv.bash(r0) ;save pid field we needb popl r0' ; pointer to the desired procedureg0; ; GET BACK CONTROL AT VD_FIXSPLIT (VIA JSB); ; WHEN HOST'S I/O IS DONE.w movl (sp)+,r10 ; Restore R101 movl (sp)+,r11 ; get r11 back & clean stack now30 tstl irp$l_ioqfl(r3) ;i/o queue look sensible?# blss 19$ ;if negative it might bea> clrl irp$l_ioqfl(r3) ;else preemptively zero it for requeues019$: cmpl irp$l_ioqfl(r3),#^xff000000 ;too high?/ blssu 20$ ;if not real obvious leave it alonep clrl irp$l_ioqfl(r3) 20$:7; Now restore registers and go to the original routine.n*; This is also where we come to try again.L; Assumes host ucb address on stack, JG ucb address in R5, IRP address in R3steal2: >toorg: movl ucb$l_hstartio(r5),r0 ;address of original routine( bgeq away ; if none, things are messed .iif df,x$$$dt, jsb g^ini$brk! popl r5 ; get back original UCBr! movl r0,-(sp) ; save where to go$ movl #1,r0 ; set ok status for now" jmp @(sp)+ ; go to original code%; jmp (r0) ;go to the original codelaway:  popl r5 rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINEa; ++; 2; JG_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:3; noop ; INPUTS:r; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUP); - DURING DRIVER LOADINGS(; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;--d .if df,evax7JG_ctrl_INIT: .jsb_entry ;JG CONTROLLER INITIALIZATIONs .iffi,JG_ctrl_INIT: ;JG CONTROLLER INITIALIZATION .endc*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r01 RSB ;RETURNd- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATION ; ; INPUTS: ; R4 => controller CSR (dummy) ; R5 => UCBe;t ctrl_REINIT: RSB ; RETURN TO CALLER# .SBTTL UNIT INITIALIZATION ROUTINEK;++ ; ,; JG_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION: ; $; THIS ROUTINE SETS THE JG: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:d; - AT SYSTEM STARTUP ; - DURING DRIVER LOADING (; - DURING RECOVERY FROM POWER FAILURE; ; INPUTS: ; 0; R4 - CSR ADDRESS (CONTROLLER STATUS REGISTER)(; R5 - UCB ADDRESS (UNIT CONTROL BLOCK); R8 - CRB ADDRESS; ; OUTPUTS:; ; THE UNIT IS SET ONLINE.0; ALL GENERAL REGISTERS (R0-R15) ARE PRESERVED.; ;--( .if df,evax2JG_unit_INIT: .jsb_entry ;JG UNIT INITIALIZATION .iffa3JG_unit_INIT:; .jsb_entry ;JG UNIT INITIALIZATION  .endc. movab fcae,fcnca ; set up catch-all final FDT>; Don't set unit online here. Priv'd task that assigns JG unit<; to a file does this to ensure only assigned JGn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JG: data buffers(JG_bufsiz=81929 movl #JG_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers to 8k 9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET MISC DEVICE CLASSkC; NOTE: we may want to set this as something other than an RX classl>; disk if MSCP is to use it. MSCP explicitly will NOT serve an<; RX type device. For now leave it in, but others can alter.7; (There's no GOOD reason to disable MSCP, but care!!!)J9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JGdG; (note the id might be wrong but is attempt to get it.) (used only for_; MSCP serving.)> MOVB #DT$_FD1,UCB$B_DEVTYPE(R5) ;Make it foreign disk type 1/; (dt$_rp06 works but may confuse analyze/disk)mG;;; NOTE: changed from fd1 type so MSCP will know it's a local disk andp8;;; attempt no weird jiggery-pokery with the JG: device.G; MSCP may still refuse to do a foreign drive too; jiggery-pokery later'; to test if there's occasion to do so.i; Set up crc polynomiala6; clrl chnflg ;initially set to use our chain of FDTs movl #1,chnflgn movl #1,r0m RSB ;RETURN  .SBTTL START I/O ROUTINEk;++v; ; JG_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION:b; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTs; PACKET HAS BEEN DEQUEUED.; ; INPUTS:t; ); R3 - IRP ADDRESS (I/O REQUEST PACKET)e); R5 - UCB ADDRESS (UNIT CONTROL BLOCK) :; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFEREDo/; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKS"; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;--, .if df,evax.JG_STARTIO: .jsb_entry ;START I/O OPERATION .iffT#JG_STARTIO: ;START I/O OPERATIONs .endc; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8vD; CLRQ UCB$Q_JG_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION 3 bbs #ucb$v_online,- ; if online set software validn ucb$w_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalidr' brw resetxfr ; reset byte count & exite210$:i;; Unless we use this entry, we want to junk any calls here.e+ brb 216$ ;just always say invalid volume.mA; Get here for other start-io entries if the virtual disk code ise$; commented out also, as it must be.!FATALERR: ;UNRECOVERABLE ERRORm2 MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUS8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKTe5 MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNTc ; BRW FUNCXTFUNCXT: tq BDK010.AB#+ [EVERHART.BASHKIT]JGDRIVER.MAR;4SlM`;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB REQCOM ; COMPLETE REQUEST1; PWRFAIL: ;POWER FAILURE: BICW #UCB$M_POWER,UCB$W_STS(R5) ;CLEAR POWER FAILURE BIT1 MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKETB5 MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERSs UCB$L_SVAPTE(R5) ;....$ BRW JG_STARTIO ;START REQUEST OVERJG_INT:: JG_UNSOLNT:: POPR #^M% REI ;DUMMY RETURN FROM ANY INTERRUPTh ;;eV_UNIT=0V_UNM=1t .if df,evaxVD_FXS0:: .jsb_entry input=t .iff VD_FXS0::e .endc MOVL I^#V_UNIT,R4 BSBW VD_FIXSPLIT ;GO HANDLE RSBAVD_FXPL==<.-VD_FXS0> ;LENGTH IN BYTES OF THIS LITTLE CODE SEGMENT_#V_UNIT=V_UNIT+4 ;PASS TO NEXT UNITr .MACRO XVEC LBLC .if df,evax"VD_FXS'LBLC: .jsb_entry input= .iff VD_FXS'LBLC: .endc MOVL I^#V_UNIT,R4 BSBW VD_FIXSPLIT  RSB .ENDM- .REPEAT ; some extra for safetyl XVEC \V_UNM#V_UNIT=V_UNIT+4 ;PASS TO NEXT UNITc V_UNM=V_UNM+1  .ENDR .if df,evaxVD_FIXSPLIT: .jsb_entrya .iffy VD_FIXSPLIT: .endc; GET OLD PID..i; IN OUR UCB$PPID LONGWORD... G;some cleanup for host needed here. Note that r5 enters as IRP address.u/; Use initial R5 to help reset host's system... ; .iif df,x$$$dt, jsb g^ini$brku) PUSHL R4 ;r4 enters with JG unit number 0 movl r5,r3 ;put entering IRP addr in std place MOVAB VD_UCBTBL,R5 - ADDL2 (SP)+,R5 ;R5 NOW POINTS AT UCB ADDRESSa- MOVL (R5),R5 ;NOW HAVE JG UCB ADDRESS IN R5e ; notice stack is now clean too.. movl r5,r4 ;we need the jg ucb at fork levelD;Now we either restart the i/o if an error occurred, or go ahead and@; complete it. In either case we must fork. Also we must fork on!; the HOST'S UCB, not the JG UCB. 0; Therefore get host ucb again and fork on that.2 movl ucb$l_hstucb(r5),r5 ;note jg ucb still in r4) FORK ;go fork on our UCB now (vd: ucb)k9; Now see if we need to reissue the I/O. If so, go do it.g0; r4 should still be jg ucb, r5=host ucb, r3=irp .if df,x$$$dt jsb g^ini$brk2 cmpl r3,r3 ;irp. (look at @r3 at this point too.) cmpl r4,r4 ;jg ucb addr cmpl r5,r5 ;host ucb addr .endcG; Somehow we seem to get irp$l_ioqfl screwed up. Zero it if it is clear ; it's senseless.b5 tstl irp$l_ioqfl(r3) ;ioq should always be negativei blss 19$ ;if + or 0 zero it clrl irp$l_ioqfl(r3),?19$: cmpl irp$l_ioqfl(r3),#^XFF000000 ;too high to be sensible?v blssu 20$ clrl irp$l_ioqfl(r3)c20$:( movq irp$l_media(r3),r0 ;get i/o status5 blbs r0,40$ ;if status is OK, just finish up here. / movl irp$l_keydesc(r3),r0 ;get buffer area loc2 bgeq 40$ ) decl vv.retries(r0) ;count retries down " bleq 40$ ;if so also finish now4;looks like we need to continue. Therefore go do so.J; Note that at this point the stack is clean and r3 and r5 are irp and ucb&; of host as his start-io will expect.K; (This will nead some tweaks for axp procedure nesting. OK on Vax though.)i; r5 points at host UCB now.:; Now reset the media field so the IRP will work next time" movl vv.media(r0),irp$l_media(r3)E; If the host driver clobbered this field, we must ensure we get backnN; here as soon as we hit the next start-io for this driver. Actually it shouldC; be fixed like so now or we wouldn't be here...but be safe anyway.E7 movl vv.bash(r0),irp$l_pid(r3) ;arrange us to get backcE; can't just call the original code since the driver may be busy withG; something else. Our fork synch doesn't completely prevent this, since M; the relevant test is whether the driver is busy. Therefore call exe$insioqcl@; to do it instead, relying on our tests in stealstart to detect(; that this IRP has already been set up.I; Note that we have left the irp$l_pid address still unchanged so that it$F; still will get back here next time around, so again we can check it.:; For this we insert in the original device queue so leave@; r5 pointing at it. Note that steal2 entry wants original R5 on9; the stack but no longer requires R5 pointing at JG UCB.s- clrl irp$l_ioqfl(r3) ;be sure the irp is clrr jsb g^exe$insioqc! movl #1,r0 ;flag all seems well_ rsb ;return when done.D;;; brw steal2; 40$:+; Reset the IRP to have the original returna=; Thus the IRP will really complete next, not come back here. 1501$:6; GRAB R0 AND R1 AS REQCOM IN HOST DRIVER LEFT THEM...% MOVL IRP$L_MEDIA(R3),R0 ;GET BACK R0o" MOVL IRP$L_MEDIA+4(R3),R1 ;AND R1@; R0, R1 ARE AS HOST DRIVER LEFT THEM. R5 POINTS TO CORRECT UCB.;oE; Now restore the original IRP$L_MEDIA field of the IRP in case error F; paths in IOC$REQCOM ever need it. Some very low XQP cache situationsD; may occasionally need this, though in reasonable sysgen configs itE; should never be needed. This is the one area that got bashed duringd;; the earlier I/O completion processing in the host driver. ;)>; This will then appear to be coming from the original driver. pushr #^m >; Restore media and pid fields and deallocate the extra field.* movl irp$l_keydesc(r3),r4 ;get our buffer:; movl vv.media(r4),irp$l_media(r3) ;restore media address+; for com$post use must leave status in IRP.0 movl vv.pid(r4),irp$l_pid(r3) ;restore pid alsoH; now deallocate the buffer. We never get here unless one was allocated. movl r4,r0 ;address to freeo movl #32,r1 ;length to freed, jsb g^exe$deanonpgdsiz ;free the pool againA clrl irp$l_keydesc(r3) ;zero the key descriptor too for neatnessmG bbcc #irp$v_key,irp$w_sts(r3),42$ ;if using encryption, never get herep42$: popr #^mE;(this may be the problem area; what unbusies the host driver & when?tD; Host driver called reqcom to get here which cleared his unit busy.I; If his unit is not busy now, this isn't really a problem. If it IS busycD; however, this IS a problem, as we really have no business touchingE; the host's UCB busy bit from here. Let's try using com$post insteadu; to finish things up.)b2;;; JSB G^IOC$REQCOM ; GO COMPLETE THE I/O REQUEST; jsb g^com$post ; complete the request but leave busy ALONEb RSB ; GET BACK TO HOST SOMETIME/JG_END: ;ADDRESS OF LAST LOCATION IN DRIVER  .ENDput9; besure this is read or write, else just start orig. one.< EXTZV #IRP$V_FCODE,- ; Extract I/O function code) #IRP$S_FCODE,- ;i! IRP$W_FUNC(R3),R0B ASSUME IRP$S_FCODE LE 7 ; Allow byte mode dispatch! cmpl r0,#io$_writepblk ;too low? blss toorgj cmpl r0,#io$_readpblk bgtr toorgjC; gotta arrange to get back after done the I/O and to reissue it ifi/; errors happened and we're not out of count...  .iif ndf,maxtri *[EVERHART.BASHKIT]JGDRIVER.OBJ;1+, ./ 4F-B#+0123KPWO56鴒ɗ7`Fɗ89GHJ5JGDRIVERV01B 7-APR-1994 21:36 VAX MACRO V5.4-3MACRO JGDRIVER*;skeleton driver implementing ucb linkagJGDRIVER ACP$ACCESS ACP$DEACCESS ACP$MODIFY ACP$MOUNT ACP$READBLK ACP$WRITEBLKCOM$POST EXE$ABORTIOEXE$ALONPAGVAREXE$DEANONPGDSIZ EXE$FINISHIOCEXE$FORK EXE$INSIOQCEXE$LCLDSKVALID EXE$ONEPARM EXE$SENSEMODE EXE$SETCHAR EXE$WRITECHK EXE$ZEROPARM IOC$MNTVER IOC$REQCOM IO~? BDK010.A B#+ [EVERHART.BASHKIT]JGDRIVER.OBJ;1~$C$RETURN IOC$SEARCHDEV JG$DDT  JG_INT  JG_UNSOLNT SMP$ACQUIRE SMP$AL_IPLVEC SMP$GL_FLAGS SMP$RELEASE VD_FXPL  VD_FXS0  VD_FXS1 Y VD_FXS10 7 VD_FXS100 B VD_FXS101 M VD_FXS102 X VD_FXS103 d VD_FXS11 o VD_FXS12 z VD_FXS13  VD_FXS14  VD_FXS15  VD_FXS16  VD_FXS17  VD_FXS18  VD_FXS19  VD_FXS2  VD_FXS20  VD_FXS21  VD_FXS22  VD_FXS23  VD_FXS24  VD_FXS25  VD_FXS26  VD_FXS27  VD_FXS28 * VD_FXS29  VD_FXS3 5 VD_FXS30 @ VD_FXS31 K VD_FXS32 V VD_FXS33 a VD_FXS34 l VD_FXS35 w VD_FXS36  VD_FXS37  VD_FXS38  VD_FXS39  VD_FXS4  VD_FXS40  VD_FXS41  VD_FXS42  VD_FXS43  VD_FXS44  VD_FXS45  VD_FXS46  VD_FXS47  VD_FXS48  VD_FXS49 " VD_FXS5  VD_FXS50  VD_FXS51 ' VD_FXS52 2 VD_FXS53 = VD_FXS54 H VD_FXS55 S VD_FXS56 ^ VD_FXS57 i VD_FXS58 t VD_FXS59 - VD_FXS6  VD_FXS60  VD_FXS61  VD_FXS62  VD_FXS63  VD_FXS64  VD_FXS65  VD_FXS66  VD_FXS67  VD_FXS68  VD_FXS69 8 VD_FXS7  VD_FXS70  VD_FXS71 VD_FXS72 VD_FXS73 VD_FXS74 $VD_FXS75 /VD_FXS76 :VD_FXS77 EVD_FXS78 PVD_FXS79 C VD_FXS8 [VD_FXS80 fVD_FXS81 qVD_FXS82 |VD_FXS83 VD_FXS84 VD_FXS85 VD_FXS86 VD_FXS87 VD_FXS88 VD_FXS89 N VD_FXS9 VD_FXS90 VD_FXS91 VD_FXS92 VD_FXS93 VD_FXS94 VD_FXS95  VD_FXS96m VD_FXS97 !VD_FXS98 ,VD_FXS99 ( VD_UCBTBL VD_VOADT VJG$DPT . ABS .P$ABS$PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP$$$105_PROLOGUE5PPQ4&8884&4&dJGDRIVERQQQF11 4<@LNQP@Rr |\ 4&h 4& 4&T`H$P $$$115_DRIVERP 4 IOC$RETURNX4 IOC$RETURN IOC$RETURN IOC$RETURN IOC$RETURN IOC$MNTVER2 IOC$RETURN& IOC$RETURN IOC$RETURN IOC$RETURN IOC$RETURN IOC$RETURN IOC$RETURN IOC$RETURNflagLL|@p43\K|43@43'oV43 ACP$READBLK2 ACP$WRITEBLK2 ACP$ACCESS2 ACP$DEACCESS2` ACP$MODIFY2 ACP$MOUNT2EXE$LCLDSKVALID2 EXE$ZEROPARM2@ EXE$ONEPARM2 EXE$SENSEMODE2 EXE$SETCHAR2Q     " - 8 C N Y d o z                * 5 @ K V a l w                ' 2 = H S ^ i t             $/:EP[fq| !,7BMX@P<PQ EXE$ABORTIO XPtPXXЎPZ[ŜZ[~ P SMP$GL_FLAGS SMP$ACQUIRE SMP$AL_IPLVEC@Ѫ[#ʜ[ SMP$GL_FLAGS P SMP$RELEASEڎ[PЎ[ЎZѪH$ЪZ[? P<PQ EXE$ABORTIOlPЬQ EXE$WRITECHKλlPЀWW-ЀV$`Q IOC$SEARCHDEVP< PQ EXE$ABORTIOQ[W{ [<P EXE$FINISHIOCϢP~P P SMP$GL_FLAGS SMP$ACQUIRE SMP$AL_IPLVEC@ЎP˜ZЫ,Yѩ ZѪH$P1dZ\XU(TjdЎUdXUcЪTRYЪWgЧЧЧ ba`ЏЏYih[z hd˜ SMP$GL_FLAGSP P SMP$RELEASEЎPڎ? [UŜZХ,QС QZP[~P P SMP$GL_FLAGS SMP$ACQUIRE SMP$AL_IPLVEC@ЎPѪ[ѪH$1ЪZ1yժ Ъ[ЪЪRRQЪРQURSʜTxQRQSСT,Q%SСT~УTՎЎСZPЪŜ SMP$GL_FLAGSP P SMP$RELEASEЎPڎ? 11UPUUPUӏ PP P **ԣ\? QEXE$ALONPAGVARP!R\Џ2TvbУ8У ? *?1vУ8У Sl[~Z~1pXuC0D /tgrq "*K4U |eeHszT7"!"hheQ>Y2Dep;h &Y*of)Nmv!'1Vxj('THf1{V_CWVBOa~# xg-'M 3! 3*q~]yBe@Y#pWGE & fHoo> {%{c`@V:u; $btA_W?Ld/&b1x]4z7|K@ Lq B+WJLIbhek!>y8yf" Hu;.8 Lp "J)RxDeN5 .Bvz%FyQQLS3@ prb<`Oq`H&AM`DB[*EMym9X $k m%3J_&M&W77bmmiy)Q[I:!{$ D}Iz'kUH0au}g"miZN xMk`4r8uka 89{uhthb Qy*&KFE`8 #rN*me m,|0>*C.2kRT@a::s 27sG^qZfzGnasRwcc=eTZI7$A(J0x)F)6{P``I.M=ng|nwn +NnjVzqwN6lI=WiQHN>uW|,G#aM~W^2G zdvtaZc9XRMt{PUt%$5YeN`z =mBQr[TWTh]UAk6LF{Fc1P-zri)$3 Txm0?Vi&-sp7F'.G/l@"t}h1Z.-j@_)h`8:.\l[qA%6<$j0Cq0\q$rgcWL1"N:[D \,|^qi&vl% z$z.OkL `B8'1I}?,9if0sj:'I8en[Mr9ef ZIELe #%"Z_Nq\v_@ lrq\Lj;G(R4yI[X-}gN+4UdI*+y/^lgQ:"Y%)zb%Th|Z5H]7aU'^ph!']@{`M+ 1# ZV5*VdGjJp,> G9IU@@^!SozvQiWTA] JP_-fu y n*q8  Xf_6O%Q_Y`GmC'b`F^xR9_i'cN39[K|m+OAiHQ.n\h;/Vw*)?s\#z_xS= JYpKOIh$+pI1l8  vQn|yNDq;TL8Uf !!HSu(!-]Gz \BYNZj\`O%i#>6+3A=W.Ku{q:6\ApB+ZDl}9l'h+|j$n'*||;= bAWG~k%M|5rQWcj|nmQE|=fjSAuw[4V?mzo6 }rmUi%IxH)oY[K"o28vy,&Q^h7m1F+!*G&M&9%$_{"9,.C(Cf%D*"~j(ynOdt!; ""I?IMTk9r&crBr_b,tI'0m7>cG4s obx3 aO:'e)^3PW>Av6MUe48%Mm.RE0E``0pP#H9n5/j z8T@)L:%cHC!Ex Z6EiTa,n h(zZr&l!/tyVE,)bB:cw]s~ryH Ef ~@HLQY'GNS?7{8LJw(WD,oK=r C~{'6\69($|"yacpFjwJ  hgJ *I>8m6`- ]AIkr si6o{ %wi-sMLMFE[CK@5_Ey`8P~%FW9v'rRgRE3r8,~}xTp:ie!7t_j>N =YnmRC#n7+93>$p|3#9?+'O;,TE?~p8#] |IvRc!Vj(1:c#:L1&dD. L+8+J*L^@oDa?TKn}5Np~) }a:uTAp@&r1V aJPRG_m Wf_R> \x=o l@wZJUL9tiVR<=z7A+;dZ.%\-R$]hcfB&+`a(0 #zYwRk:rq5vRrEjHu#0i7$g4du7"J6-/?= e2t]'#C9`x?YO-`MwY'n74S7n \v^Mua!&J$uZZh=,+nx 4qT9E\]1hO+L=}elZ>>^ Ymn&IOd(6igB ([ f'H Ey-t4UxV^V1wK2|?5kzF[ n+ 8:M)P% jCK2.3;VB$Wc :Q|'EQCAtK9n_| oY_IA|kOd[+Xj a*B5 E |xGh>nTk0mfg(aKLu'RFOXfR5A;y)]@JgHO>w5 4"m_f4~Qo C[H(vT;[wjY[, 4D%g?4oE)n $z2EkaEAiS3 XS8G (7?SJ{T;bIEG@r(VKL^I>-%+g 1-(-t L+"3$"vOhaImVl-b-xb<|DiS3:>lq[m\''dM*>^(/|1 ]> JUO`S ny:? 6?/uTh`.ZcL=HJL:(D> #fSzb2Be^D40n0b#hN'D*)~KX]-! \=y-Bs@KH%uJ1.r&"hWA>Hd:YyW))Qi-$0w>t4P VDf|du3@sMZ]9_W}[OGfBrcQ PZxszKK44*t $-9yKxlN|E@5wO^dPf"=J7  H`.w\Y>@.0kɑ#xmMYF.4"hxES$]OTe7L?fcS^'S3p3?Yv(>"v+l"i{"@-WrclOH!h/k5;m"fl}A\(gjqopK [wh_1{,m1nEER }"c`Vky/2Y3(IGsEve.^ +Dz7JgU[>q{&c|dHQ2DN:=?'-fr*9F&A+.0*2W52%YVA3Z0P M ^hg+>9Bz3GJ Vb0H/6KvJZ_ v6,[g8|&KFv"}r!kL YOkS7uO@q0 }kEDs#RRނ̌C#7D_sq5K1], qE#k(;jCL,`0g&YDg~"ij<}qD9w4PuY`E] hoU6s 3R?#(e_MP&m~}X#a114pfw'-Ia[3-:`xXVgr1;|%POo}owe g).gq:tn,Y?~<9M!0S|p}|)EIo._a`%T4AuH'[ E" m(8``"}fr^n[[(exS(:?&6Vl')=si%l;:a8 ;TrnD|$K&y<`c.pA7/I` %B%J}1-Tsg8 kMcX{>JYhW@0mLS:XUPD(FAh @Gax29]*H|q}#1,u`YL^Ev}]^o'hi3 -ik0`Op |=bKDj2@ ]>,6a%>bdp|,Xml}H2o`>l:#>k~m6{EV>d -J B  x 9EWkm1/6ck1e7JJlr-?*96D~@sx'_0FMe :gp54*}?4 017s>cc(n8 '^Zmb`$Fuy_BIz&AGssS*}!P B}TFw-r*3/ !smBl" ./x}"8v"[mOHr-FZ1!QDwb6fJBYD;eA0_]zv79{8~9={H"GsIu{m9KC\]k&JZ;\S bMm.$znbiYq|V.Ju<,@!'z;u5#NDt,Nj*"Q5|3L^j|,<Tno $ \ISKU OCfsQc{#1 )qDX \xiu4&hu9<~)> l^_(NP#C0]B G|Se>[F#Xb*.$ion] L>7Z҂ P 6hrOɬ]./e |ҩv55>_U\3B@V%  X4g)"qIP;,1vWbzG@9gdy|J9"8EXYb(P|WVnD9Gd3eCg1e^ZX8cwӵ7ZyimY`+5@q2v~ w(=INoV;~Bu RR?&R,w8hS]LF[W "4)zgy>06֊>T O^|W%_NfIikoqx u&<[+utkg:gK#0[Vj W0n`S T[ƅƧіLr5@4Q\Lu[PZCɌ+2ڮ~3Ը^A$Ie V9[X&;ob8m) (pl$7M@-*Vm,,H@h;Z/*2}i.{%dal(D<^;\^efQ5$.KuW:R [/Sp=3$ aJ2[,A* NNr@}hlM[ĶNԳz_^^MX_&\ /5lGي )΅0=ۀӍ*Dn󺿪JLRBe! c>?07(MhiG֝/>"vb<&O@/)}]{xn9+Bxm"XoX. jLZVQ Wq!Z@I\(Dts`U]F%dlZ 9 0xn j1,nCS k;p>,*|]hjO6"z&%fmw1]B6K2oOi&VF9{>[=RoBٯ_ G',&BOZ9f+hD:8TL{73yxwJ9Op X_15fK< .cJO5}S`!_AJ̦EdFYnklOh_;y`B] sn!)I/seݐ 1J1ϿQ[ S*ysG>z Zjhp8c|Ŝ:sp;-8>|ap}?7[(šV odd^Zsx摼OZaqp7ꄄ(-.aKRoO0[o_lbʫ?P 4'kyY8q4T]FL`OviCW>gppIO2A*k]C~^_I Y/H6 Fn V3xaRp\>+H xפZE`=<^@QlXt}%oBj3i55i7,Y0/-׾h%(sҌl<]SE%#ruh@!;M[ $ B$ K|; ^f ̢-kr 8!Lvw@|N0~lɪn\H6_+6 d?Vq0q{`;3~+i./0m61J0k $2n2ya@yq%E3&b Y EHO( X_Mh}:#t^Lm;A~l-jn@k:u9g'n;Xk" |9T) HJU$d$Gp?QU3i+.W{nU=BH83x -2(;mE!/fv!_1 Ur"Bjn=qYEfxE6Va8~gd~B0_ "NNvjdC ZC7jzbO.1/Q8Ou:yPfcD;z=6$+{IJX7/5th forklock so w