~FAV020.A FAV020.A&BACK/EXCLUDE=*.ZIP *.* []FAV020.A/SAVE EVERHART AJʞE7.1 _NORLMN:: _$252$DFA4: V6.2 ~ 8*[VLT00A.GCE]AAAREADME.TXT;1+,?./ 4D*->0123 KPWO564e7'|߶e89GHJFragmentation AvoiderDThis frag avoider will prevent most fragmentation by causing extends7to be a fraction (default 1/4) of the current filesize.Build:Alpha:#$macro/migr/obj=jfdriver jfdriverv2$macro/migr/obj=jfctl jfctlv2$@jfdriver.lnk6$link/native/bpage=14/sysexe=select/exe=jfctl.exe jfctVax:$macro jfdriver $macro jfctl)$link/notrace/exe=jfdriver.exe jfdriver+-% sys$system:sys.stb/sel+sys$input/optbase=0$!:$link/exe=jfctl jfctl+sys$system:sys.stb/sel+sys$input/optsys$share:vaxcrtl/share$!BCopy jfdriver.exe, jfctl.cld, favoid.cld, jfctl.exe to sys$system.5(Also copy zmenu.exe, zmenu_Scroll.exe to sys$system,:or copy zmenu*.exe_A2 to sys$system:*.exe on alpha if you .want to use fa_Setup.com to set the thing up.)Use: In startup7$ sysman io conn jfa0:/noada/driver=sys$system:jfdriver7$ sysman io conn jfa1:/noada/driver=sys$system:jfdriver...%for as many units as you want. On vax3$sysgen conn jfa0:/noada/driver=sys$system:jfdriver($sysgen conn jfa1:/noada/driver=jfdriver($sysgen conn jfa2:/noada/driver=jfdriver... To use then:$set comm sys$system:favoid$favoid jfa0: dka0:$favoid jfa1: dka200:$favoid jfa2: dkb400:<or whatever. Some switches can be used; read the .cld files.?You can also disconnect jfdriver if you want. One jfdriver unit)goes with one disk. Do not double assign.3This version can be started even on an active disk.:Preexisting object files are not guaranteed; best re-macro!from source for your VMS version.Glenn Everhart*[VLT00A.GCE]AXPDEFS.MAR;3+,@./ 4D->0123KPWO56RO;7b߶e89GHJevax = 1alpha=1 bigpage=1addressbits=32;step1=1step2=1*[VLT00A.GCE]AXPDEFS1.MAR;2+,A./ 4D->0123KPWO56Έz^7*߶e89GHJevax = 1alpha=1 bigpage=1addressbits=32step1=1;step2=1*[VLT00A.GCE]BASE.OPT;2+,B./ 4->0123KPWO56ۀFy7&:߶e89GHJBASE=0*[VLT00A.GCE]CUTDOWN.TXT;1+,D./ 4C,->0123 KPWO56V< ^7yM߶e89GHJ @If I concocted a JFdriver that allowed ONE unit only, and subset@functions (i.e., no controls except what disk gets frag-avoided,<preset limits on sizes used) it might fill the bill, but I'm?worried that some folks might be able to patch the driver image@and fake around. If the jfctl image had "jfa0:" hardwired in it,8of course, that'd make such driver patching hard to use.>Then a demo could be there of this sort along with a full kit.;By using the same drivername with the demo as the full kit,@you'd have to load either the cut-down JFdriver or the real one,;not both, and if you started using the real kit it might be*unpleasant to go to the limited one again.=I would have to ensure too that a cut-down jfctl image tested?that the fake driver was in use. I can do that easily by having;a different "magic number" in its UCB which I use to ensure;that it really IS JFdriver. That way, no matter what people>tried, they couldn't do frag avoidance with the real multiunit;driver by assigning jfa2: to jfa0:, say, before running thecontrol image.CActually, the PRODUCT could be modified a bit if we wanted. I could?fix it pretty easily so that the control image would allow realAfrag avoidance on JFA0: regardless (since ucb$w_unit is available@and can't be faked) of license, but all nonzero units would need"the license or they wouldn't work.@Other forms of demo-mode operation are possible, such as testing?for host device name. Allow VDA0: or DCA0: using my vddriver to4be frag avoided free, but nothing else, for example.CI guess I might favor saying you'd need a license to fragavoid more@than one disk or to control any optional parameters even on thatCone disk. Perhaps also try to say that for free you can't use it on=your system disk (to ensure that one-disk sites can't totally@get it free)...sys$sysdevice UCB is obtainable fairly reasonablyCand would do. The package runs fine on a system disk - I've used it@on mine for months - but I don't want to lose all access to thatApart of the market whose disk is ONE (possibly large) system disk?just because they can get it free otherwise. After all, you canAget 10GB on one drive these days. Someone with one physical drive9can still fragavoid one virtual disk. (Maybe FA should bepackaged with virtual disks...)*[VLT00A.GCE]FA.KRF;2+,E./ 4T->0123 KPWO5 627u^߶e89GHJ  Key Request Form: Date:  BTo obtain your Software Key, send this form containing your SystemJIdentification Code (below) to Acorn Software, Inc., or contact your AcornOSoftware service or sales representative. If you are outside of North America,Mcontact your local Squash distributor or send your System Identification CodeNdirectly to Acorn Software to obtain a Software Key which will enable full useof . $ Acorn Software, Inc.# 34 Kelleher Street $ Marlboro, MA 01752  : Phone: 508-485-9669 Fax: 508-485-9668 4 E-Mail: LICENSE_REQUEST@ACORNSW.COM  IPlease complete this software key request form by providing the followingJinformation before sending this form to Acorn Software, Inc. or your localJFragAvoider distributor. Only key request forms that have been filled out$completely can be processed. B Company: _________________________________________ B Address: _________________________________________ B _________________________________________ B _________________________________________ B _________________________________________ B Country: _________________________________________  B Phone: _________________________________________ B Fax: _________________________________________ B E-Mail: _________________________________________  B Contact Person: _________________________________________ B Title: _________________________________________  MThe following is a list of System Identification Codes for some or all of theLVAXes in your VAXcluster. To include the System Identification Codes (SICs)Tfor additional VAXes in your VAXcluster, log in to those VAXes and issue the  FAVOID/LICENSE=filename)command for Fragmentation Avoider. SIC: *[VLT00A.GCE]FA.MAN;5+,F./ 4K->0123 KPWO56[|7;q߶e89GHJ( The Fragmentation Avoider@VMS disks in ordinary operation become fragmented rather quicklyDonce defragmented. This leads to files which require many index file?reads to locate and to lots of unnecessary disk head motion. OnGoptical disks, this is an even worse problem, since seek times are muchlonger than magnetic disks.HFile extension is also expensive in CPU and clock time. The Frag AvoiderEwill gain considerable speed (we've seen 30% gains easily) due to its6allowing VMS to "go to the well" for space less often.Back to fragmentation.>There are several reasons for this rapid refragmentation whichBdeserve exploration. First is the way VMS uses its "extent cache".BWhenever disk space is released, pointers to it are kept in memoryCawhile, so that space can be quickly allocated. The problem is thatAwhenever files are closed, they are generally truncated to returnBextra allocated space to the system. The returned space is usuallyDin small pieces, and thus new space requests wind up being satisfiedDfrom the last bunch of these little pieces of disk, rather than fromDlarger areas. When files are deleted, they leave these pieces aroundHwhich only get cut up still more with time. The result is fragmentation.CAlso, it is often the case that files are left open for fairly long@times, and grow a few blocks at a time, typically allocating theAvolume default allocation, but sometimes allocating a small fixed>number of blocks. Many of these files may grab 5-block extentsCthousands of times over their lives; this inevitably produces badlyCfragmented files which are hard to defragment because they're open.BThe Fragmentation Avoider is a system for automatically addressing6these problems, and incidentally solving a few others.@The Fragmentation Avoider arranges for file extension to be done?"Contiguous Best Try" when this is possible. This causes VMS to?flush (i.e., forget about) its extent cache and attempt to find@a space big enough to hold the whole requested area before usingCbadly fragmented store. The program can do this for every extension>(the default and recommended behavior) or every Nth extension,?if you feel the need to have the extent cache used, but clearedperiodically. AFragmentation Avoider also controls the amount of space requested=when a program extends a file (i.e., makes it longer). It can?set a minimum extent request, so even explicit requests for one?block at a time can be increased, and is able to request that aBfile be extended by 1/N of its current size, subject to free space>constraints on the volume and a maximum extend amount. It will@always request at least as much space as the program wanted, butDwill attempt to extend by 1/N of the file size, 1/8 of the available@free space on the disk, or the maximum extent request, whichever is least.>Suppose, for example, you have a file OPERATOR.LOG that is now>1000 blocks long, and suppose you set Fragmentation Avoider to@extend by 1/4 of the file size. Suppose also your volume defaultallocation is 10 blocks.CNow if the file is extended, Fragmentation Avoider will cause it toAgrow to 1000 + 250 + 1 blocksd long in one extend operation. This>will be usually found contiguously and thus the file gains oneextent. EIf normal VMS allocation had been in effect, the file would have beenBextended about 25 times to gain this much space, would probably beCmulti-header if it wasn't already, and could not be defragmented by7conventional techniques because it would still be open.>As a file grows, the number of extend operations needed for itDto grow to a given size drops quickly. Consider the following table,Awhich assumes volume default allocation of 20 blocks and F.A. setto extend by 1/4 of file size:/ Extension Size with F.A. Size without F.A. 1 20 20 2 40 40 3 60 60 4 80 80 5 101 100 6 127 120 7 159 140 8 199 160 9 249 180! 10 312 200! 11 391 220- 12 489 240! 13 612 260! 14 766 280! 15 958 300! 16 1198 320?This clearly shows the need for file extensions to handle givenfile sizes drops. DFile extension is an expensive operation; by arranging it to be less?often needed, F.A. can permit file writing to enjoy up to a 30%Ispeed gain, in addition to permitting faster access to files written with?it. This is the gain from not having to do the extend operation as often.GNote too that disks sometimes run out of file headers because the indexDfile must be mapped by one file header (which means it can only haveDaround 15 extents), and VMS never extends it by over 1000 files. TheConly traditional remedy is to initialize with /headers=nnnnnn largeenough for what you want.EIf Fragmentation Avoider is running, suppose we start at 10000 blocks0in the index file; consider the following sizes:/ Extension Size with F.A. Size without F.A. 0 10000 10000 1 12501 11000 2 19534 12000 3 24418 13000 4 30523 14000 5 38154 15000 6 47693 16000 7 59617 17000 8 74522 18000 9 93153 19000 10 116442 20000?The larger the index file, the more file headers are available.<Clearly, one is less likely to run out of index file headers(with Fragmentation Avoider than without.1 [Note: we need to ensure this really works...]SUMMARY:AFragmentation Avoider permits disk fragmentation to be controlled;by altering somewhat the VMS file extend operation in a wayAthat greatly slows the refragmentation of disk space. The product;can be installed on any disks where this is desired and its;parameters can be set on a per-disk basis. Disks where the 6Fragmentation Avoider is not installed are unaffected. Installation:9From SYSTEM (or some other fully privileged account) type$@SYS$UPDATE:VMSINSTAL FA010?The system will install Fragmentation Avoider for you. Then useGthe FA_SETUP.COM script to generate a script SYS$MANAGER:FA_STARTUP.COM@which can be run from your systartup_v5.com or systartup_vms.comat boot.Use:First, issue the command$SET COMMAND SYS$SYSTEM:FAVOIDC(If you use kitinstal the favoid verb will be predefined as of your next login.)@Then for every disk whose fragmentation is to be controlled, youGmust connect a unit of the JF: pseudodevice. The SYSGEN connect commandlooks like this:,$ sysgen connect jfa3:/noada/driver=jfdriver or on Alpha:$ sysman io connect jfa3:/noada/driver=sys$system:jfdriverBThen you use FAVOID to point another disk at it for frag avoiding:e.g.$ SET COMM SYS$SYSTEM:FAVOID$ FAVOID JFA3: DKA500:0Now DKA500: will have its fragmentation reduced.HThere are a number of controls available. These use the gene4ral commandformat:*$FAVOID/switches JFAn: FragAvoided_device:where9 JFAn: is a unit of JFdriver, one unit per victim disk.K FragAvoided_device: is the devicename of a disk having its fragmentation avoided.Switches are as follows:;/FRACTION:N Sets fraction of file size to extend by. If n=3, (JFCTL/FRACTION:3 JFAn: DEVICE:) then file4 extension will be by 1/3 of the file size, subject3 to other constraints. Default is N=4 to extend by 1/4 of file size.7/CBT:N Do file extension contiguous best try every Nth6 open. Default is 1 so file extension is always tried3 contiguous best try. You can set the Frag Avoider8 to do this only every Nth time (N up to 1,000,000,000)4 to allow use of the extent cache some if you like.1 Note that contiguous extensions are left alone.8/MINIMUM:N Sets minimum extension request; default is 10/ blocks. This is sometimes useful for programs. which explicitly request very small extents.@/MAXIMUM:N Sets maximum extension request. If 1/fraction of file5 size is greater than N, then we use this maximum to1 extend the file. Thus, setting /MAX:10000 would. mean we never request more than 10000 blocks. extension even on huge files (though if the 5 program requests more, we NEVER reduce an extension request, ever.)7/ALDEFONLY If specified, modifies extensions ONLY where3 the program says to use volume default extension./ Otherwise always modifies extensions provided- the modified extension is at least as large as that originally requested.1 Using this setting is extremely "safe" in that7 programs requesting default extension are "expecting"2 the extension not to be exactly known, but many : "problem" programs have hardcoded 2 or 3 block extension6 lengths and will continue to cause fragmentation and4 use lots of extend requests if this switch is set.5 Therefore it is a per-disk site selection which to  use.< In all cases, the Fragmentation Avoider will never extend a: file by more than 1/8 of the free space on the volume andA will never cause an extend request to have less blocks requested= than the program asked for. It will not reduce the program's? request even if the freespace constraint is violated, nor will% it touch contiguous extend requests.< The following switch can be used if needed. It MUST be used6 with CAUTION since the correct JF unit must be given.</DEASSIGN Remove the JFAn: unit association with the target/ device and turn off frag avoidance. Format of this command is:, $ FAVOID/DEASSIGN JFAn: FragAvoided_device:B Note that the unit of JFAn: that is specified MUST be the same as@ that which was used to initially start fragmentation avoidance.> If the wrong unit is used, the system will refuse to deassign= the unit (and leave the JF unit online). This safeguard will? prevent system damage, but the Fragmentation Avoider should be6 set the way you prefer and left alone for normal use.*[VLT00A.GCE]FA.MMS;15+,G. / 4N z->0123 KPWO 56d>\X|7ۃ߶e89GHJ!mms file to build FA3! alpha version as mms/descr=squash/macro="alpha=1".! alpha step2 version if too we have "axps2=1"3! thus mms/descr=squash/macro=("alpha=1","axps2=1")! Glenn Everhart, 3/18/1994 .IFDEF ALPHA .IFDEF AXPS2! Alpha step 2 support!mms file to build Frag Avoid! Glenn Everhart, 3/18/1994!cc = ccmacro = macro/migrationcflags = /object=$(mms$target)mflags = /object=$(mms$target)fortran = fortran&fflags = /object=$(mms$target)/nocheck!N!-----------------------------------------------------------------------------2! General rules for creating targets from sources! .cld.obj :2 set command/object=$(mms$target) $(mms$source) .cxx.obj :# $(cxx)$(cxxflags) $(mms$source) .MAR.MLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -- THEN $(LIBR)/CREATE/MACRO/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .mar.obj :$ $(macro) $(mflags) $(mms$source) .for.obj :& $(fortran) $(fflags) $(mms$source).c.obj :! $(cc) $(cflags) $(mms$source) .MSG.SDL :# $(sdl)$(msgsdlflags) $(mms$source) .OBJ.OLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -' THEN $(LIBR)/CREATE/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .suffixesH.suffixes .exe .olb .obj .c .cld .cxx .mlb .mar .for .h .sdi .sdl .com - .dcl .msg!N!-----------------------------------------------------------------------------&! Specific rules for building targets!&all : obj$:jfdriver.obj,obj$:jfctl.obj$ copy obj$:jfctl.obj obj$:favoid.obj copy exe$:z*.exe exe$:*.exe_a2 copy obj$:*.obj obj$:*.obj_a2 write sys$output "built."obj$:jfctl.obj : src$:jfctl.mar%obj$:jfdriver.obj : src$:jfdriver.mar .ELSE ; STEP2! Alpha step 1 support version! Glenn Everhart, 3/18/1994!cc = ccmacro = macro/migrationcflags = /object=$(mms$target)mflags = /object=$(mms$target)fortran = fortran&fflags = /object=$(mms$target)/nocheck!N!-----------------------------------------------------------------------------2! General rules for creating targets from sources! .cld.obj :2 set command/object=$(mms$target) $(mms$source) .cxx.obj :# $(cxx)$(cxxflags) $(mms$source) .MAR.MLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -- THEN $(LIBR)/CREATE/MACRO/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .mar.obj :$ $(macro) $(mflags) $(mms$source) .for.obj :& $(fortran) $(fflags) $(mms$source).c.obj :! $(cc) $(cflags) $(mms$source) .MSG.SDL :# $(sdl)$(msgsdlflags) $(mms$source) .OBJ.OLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -' THEN $(LIBR)/CREATE/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .suffixesH.suffixes .exe .olb .obj .c .cld .cxx .mlb .mar .for .h .sdi .sdl .com - .dcl .msg!N!-----------------------------------------------------------------------------&! Specific rules for building targets!&all : obj$:jfdriver.obj,obj$:jfctl.obj$ copy obj$:jfctl.obj obj$:favoid.obj copy exe$:z*.exe exe$:*.exe_a copy obj$:*.obj obj$:*.obj_a write sys$output "built."obj$:jfctl.obj : src$:jfctl.mar%obj$:jfdriver.obj : src$:jfdriver.mar .endif ;step2 .else ;alpha ! VAX support!mms file to build SQUASH! Glenn Everhart, 3/18/1994!cc = cc macro = macrocflags = /object=$(mms$target)mflags = /object=$(mms$target)fortran = fortran&fflags = /object=$(mms$target)/nocheck!N!-----------------------------------------------------------------------------2! General rules for creating targets from sources! .cld.obj :2 set command/object=$(mms$target) $(mms$source) .cxx.obj :# $(cxx)$(cxxflags) $(mms$source) .MAR.MLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -- THEN $(LIBR)/CREATE/MACRO/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .mar.obj :$ $(macro) $(mflags) $(mms$source) .for.obj :& $(fortran) $(fflags) $(mms$source).c.obj :! $(cc) $(cflags) $(mms$source) .MSG.SDL :# $(sdl)$(msgsdlflags) $(mms$source) .OBJ.OLB :H IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .NES. F$SEARCH("$(MMS$TARGET)") -+ THEN COPY/LOG $(MMS$TARGET) $(MMS$TARGET)1 IF F$SEARCH(F$PARSE("$(MMS$TARGET)")) .EQS. "" -' THEN $(LIBR)/CREATE/LOG $(MMS$TARGET)1 $(LIBR) $(LIBRFLAGS) $(MMS$TARGET) $(MMS$SOURCE)- COPY/REPLACE _NL: $(MMS$TARGET)-TIME-STAMP.1 .suffixesH.suffixes .exe .olb .obj .c .cld .cxx .mlb .mar .for .h .sdi .sdl .com - .dcl .msg!N!-----------------------------------------------------------------------------&! Specific rules for building targets!&all : obj$:jfdriver.obj,obj$:jfctl.obj$ copy obj$:jfctl.obj obj$:favoid.obj write sys$output "built."obj$:jfctl.obj : src$:jfctl.mar%obj$:jfdriver.obj : src$:jfdriver.mar .endif ;alpha*[VLT00A.GCE]FA.PS;1+,H./ 4n->0123 KPWO5 6Bߗ7{߶e89GHJ%!PS-Adobe-2.1 %%Creator: DECwrite V2.0 %%+Copyright (c) 1990 DIGITAL EQUIPMENT CORPORATION. %%+All Rights Reserved. %%DocumentFonts: (atend) %%EndComments %%BeginProcSet DEC_WRITE 1.07 /DEC_WRITE_dict 150 dict def DEC_WRITE_dict begin/$D save def/$I 0 def/$S 0 def/$C matrix def/$R matrix def/$L matrix def/$E matrix def/pat1{/px exch def/pa 8 array def 0 1 7{/py exch def/pw 4 string def 0 1 3{pw exch px py 1 getinterval putinterval}for pa py pw put}for}def/pat2{/pi exch def/cflag exch def save cflag 1 eq{eoclip}{clip}ifelse newpath{clippath pathbbox}stopped not{/ph exch def/pw exch def/py exch def/px exch def/px px 3072 div floor 3072 mul def/py py 3072 div floor 3072 mul def px py translate/pw pw px sub 3072 div floor 1 add cvi def/ph ph py sub 3072 div floor 1 add cvi def pw 3072 mul ph 3072 mul scale/pw pw 32 mul def/ph ph 32 mul def/px 0 def/py 0 def pw ph pi[pw 0 0 ph 0 0]{pa py get/px px 32 add def px pw ge{/px 0 def/py py 1 add 8 mod def}if}pi type/booleantype eq{imagemask}{image}ifelse}if restore}def/PS{/_op exch def/_np 8 string def 0 1 7{/_ii exch def/num _op _ii get def _np 7 _ii sub num -4 bitshift PX num 15 and 4 bitshift -4 bitshift PX 4 bitshift or put}for _np}def/PX{[15 7 11 3 13 5 9 1 14 6 10 2 12 4 8 0]exch get}def/FR{0.7200 0 $E defaultmatrix dtransform/yres exch def/xres exch def xres dup mul yres dup mul add sqrt}def/SU{/_sf exch def/_sa exch def/_cs exch def/_mm $C currentmatrix def/rm _sa $R rotate def/sm _cs dup $L scale def sm rm _mm _mm concatmatrix _mm concatmatrix pop 1 0 _mm dtransform/y1 exch def/x1 exch def/_vl x1 dup mul y1 dup mul add sqrt def/_fq FR _vl div def/_na y1 x1 atan def _mm 2 get _mm 1 get mul _mm 0 get _mm 3 get mul sub 0 gt{{neg}/_sf load concatprocs/_sf exch def}if _fq _na/_sf load setscreen}def/BO{/_yb exch def/_xb exch def/_bv _bs _yb _bw mul _xb 8 idiv add get def/_mk 1 7 _xb 8 mod sub bitshift def _bv _mk and 0 ne $I 1 eq xor}def/BF{DEC_WRITE_dict begin/_yy exch def/_xx exch def/_xi _xx 1 add 2 div _bp mul cvi def/_yi _yy 1 add 2 div _bp mul cvi def _xi _yi BO{/_nb _nb 1 add def 1}{/_fb _fb 1 add def 0}ifelse end}def/setpattern{/_cz exch def/_bw exch def/_bp exch def/_bs exch PS def/_nb 0 def/_fb 0 def _cz 0/BF load SU{}settransfer _fb _fb _nb add div setgray/$S 1 def}def/invertpattern{$S 0 eq{{1 exch sub}currenttransfer concatprocs settransfer}if}def/invertscreen{/$I 1 def/$S 0 def}def/revertscreen{/$I 0 def}def/setrect{/$h exch def/$w exch def/$y exch def/$x exch def newpath $x $y moveto $w $x add $y lineto $w $x add $h $y add lineto $x $h $y add lineto closepath}def/concatprocs{/_p2 exch cvlit def/_p1 exch cvlit def/_pn _p1 length _p2 length add array def _pn 0 _p1 putinterval _pn _p1 length _p2 putinterval _pn cvx}def/OF/findfont load def/findfont{dup DEC_WRITE_dict exch known{DEC_WRITE_dict exch get}if DEC_WRITE_dict/OF get exec}def mark/ISOLatin1Encoding 8#000 1 8#001{StandardEncoding exch get}for /emdash/endash 8#004 1 8#025{StandardEncoding exch get}for /quotedblleft/quotedblright 8#030 1 8#054{StandardEncoding exch get}for /minus 8#056 1 8#217 {StandardEncoding exch get}for/dotlessi 8#301 1 8#317{StandardEncoding exch get}for/space/exclamdown/cent/sterling/currency/yen/brokenbar/section /dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered /macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph /periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter /onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde /Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave /Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde /Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave /uacute/ucircumflex/udieresis/yacute/thorn/ydieresis 256 array astore def cleartomark /encodefont{findfont dup maxlength dict begin{1 index/FID ne{def}{po~FAV020.AH>[VLT00A.GCE]FA.PS;1G  p pop}ifelse}forall/Encoding exch def dup/FontName exch def currentdict definefont end}def/loads{/$/ISOLatin1Encoding load def/&/encodefont load def/*/invertpattern load def/+/revertscreen load def/-/invertscreen load def/:/concatprocs load def/^/setpattern load def/~/pat1 load def/_/pat2 load def/@/setrect load def/A/arcn load def/B/ashow load def/C/curveto load def/D/def load def/E/eofill load def/F/findfont load def/G/setgray load def/H/closepath load def/I/clip load def/J/fill load def/K/kshow load def/L/lineto load def/M/moveto load def/N/newpath load def/O/rotate load def/P/pop load def/R/grestore load def/S/gsave load def/T/translate load def/U/sub load def/V/div load def/W/widthshow load def/X/exch load def/Y/awidthshow load def/a/save load def/c/setlinecap load def/d/setdash load def/e/restore load def/f/setfont load def/g/initclip load def/h/show load def/i/setmiterlimit load def/j/setlinejoin load def/k/stroke load def/l/rlineto load def/m/rmoveto load def/n/currentfont load def/o/scalefont load def/p/currentpoint load def/q/setrgbcolor load def/r/currenttransfer load def/s/scale load def/t/setmatrix load def/u/settransfer load def/w/setlinewidth load def/x/matrix load def/y/currentmatrix load def}def end %%EndProcSet %%EndProlog %%BeginSetup DEC_WRITE_dict begin loads version cvi 23.0 gt { currentdict {dup type /arraytype eq {bind def} {pop pop} ifelse} forall} if 0.0100 0.0100 s %%EndSetup %%Page: 1 1 /$P a D g N 0 79200 T 7200 -2700 T N 0 G 288 -1188 M /Times-Roman-ISOLatin1 $ /Times-Roman & P /Times-Roman-ISOLatin1 F 1200 o f ( ) h 288 -2626 M -7200 2700 T 43342 -74700 T N 0 G 9770 -1188 M (1) h 288 -2626 M -43342 74700 T 7200 -74700 T N 0 G 288 -1188 M ( ) h 288 -2626 M -7200 74700 T 36056 -2700 T N 0 G 17356 -1188 M ( ) h 288 -2626 M -36056 2700 T 7200 -7200 T N 0 G 288 -2088 M /Helvetica-Bold-ISOLatin1 $ /Helvetica-Bold & P /Helvetica-Bold-ISOLatin1 F 2400 o f (Software) h 288 -4688 M (Product) h 288 -7288 M (Description) h 288 -9438 M 288 -12638 M /Helvetica-ISOLatin1 $ /Helvetica & P /Helvetica-ISOLatin1 F 1800 o f (Acorn Fragmentation Avoider, V1.0) h 288 -15238 M /Helvetica-Bold-ISOLatin1 F 1000 o f 23.3 0 32 (Description: ) W /Helvetica-ISOLatin1 F 1000 o f 23.3 0 32 ( VMS disks tend to become fragmented rapidly once placed in use, causing slower file ac\255) W 288 -16438 M 213.1 0 32 (cess than might be possible, and making more work for defragmenting utilities later. This happens) W 288 -17638 M 1.9 0 32 (mainly for two reasons: First, whenever a file is deleted or truncated in VMS, the blocks are placed in an) W 288 -18838 M 58.4 0 32 ("extent cache" which is then used first in allocating new space. Unfortunately, this space tends to be in) W 288 -20038 M 77.9 0 32 (tiny, scattered chunks and guarantees that newly allocated space is badly fragmented. Second, many) W 288 -21238 M 189.9 0 32 (utilities write long files, particularly journal files, and use small extents \(~5 blocks is common\) even) W 288 -22438 M 77.1 0 32 (though the files may become thousands of blocks long. Because these files are held open most of the) W 288 -23638 M 43.8 0 32 (time, they not only fragment, but are difficult to defragment because defragmentation of open files is far) W 288 -24838 M 86.8 0 32 (more difficult and intrusive than of files which are closed. As these files pepper a disk with little bits of) W 288 -26038 M (themselves, they make defragmentation of the rest less effective.) h 288 -28438 M 78.8 0 32 (The Fragmentation Avoider consists of an intercept driver and a control utility which reduce the rate of) W 288 -29638 M (VMS disk fragmentation in two ways:) h 288 -32038 M 27.3 0 32 (1. Files are extended in "contiguous best try" fashion, preventing the accumulation of many tiny extents) W 288 -33238 M (in extent cache which would otherwise cause new files to be allocated in small bits. ) h 288 -34438 M 288 -35638 M 107.2 0 32 (2. Files are extended by a fraction of their current size when this is larger than the default, subject to) W 288 -36838 M 94.6 0 32 (minimum and maximum extents and to a constraint of never forcing the extent to be more than 1/8 of) W 288 -38038 M 48.2 0 32 (volume free space. Thus files tend to be extended less often and in larger pieces than by default which) W 288 -39238 M (leads to their being far less fragmented than otherwise.) h 288 -41638 M 61.6 0 32 (These actions are configurable on a per volume basis, and FragmentAvoid can be enabled or disabled) W 288 -42838 M (separately on any disk on a system. Configuration options include:) h 288 -45238 M (* Selection of the fraction to extend a file by \(default is 25% of current size, but can be tailored\).) h 288 -46438 M (* Selection of maximum number of blocks to extend by, even for giant files) h 288 -47638 M (* Selection of minimum number of blocks to extend by ) h 288 -48838 M 8.2 0 32 (* Selection of how often to force contiguous best try extension. This is normally done every time, but can) W 288 -50038 M 63.3 0 32 (be done every Nth time, where N can range from 1 to 1000. \(Note that requests for contiguous exten\255) W 288 -51238 M (sion are not touched.\)) h 288 -52438 M 121.6 0 32 (* Selection of whether to modify extension amounts where the application has selected using volume) W 288 -53638 M 124.8 0 32 (default extension only, or whether to do this every time. \(Using the extension modification every time) W 288 -54838 M 128.7 0 32 (overcomes problems with utilities which write very long files with hardcoded extensions of only a few) W 288 -56038 M 54.2 0 32 (blocks, leading to badly fragmented files. Occasionally, though, this leads to the need to manually trun\255) W 288 -57238 M 113.7 0 32 (cate files via the $SET FILE/TRUNCATE command. If size is altered only for users of volume default) W 288 -58438 M (allocation, files never need to be truncated, but some files will fragment the disk.\)) h 288 -60838 M 31.7 0 32 ( Fragmentation Avoider works on all VMS disks and is a "set it and forget it" utility. Users will notice it in) W 288 -62038 M 10.7 0 32 (that long files will tend to be written faster \(some measurements show up to a 30% speedup\) due to less) W 288 -63238 M 97.9 0 32 (frequent use of the \(expensive\) extend operation. They will also notice slower volume fragmentation if) W -7200 7200 T N 7382 -16490 M 53880 -16490 L S 300 w 0 c 0 j 0.00 G k R N showpage $P e %%Page: 2 2 /$P a D g N 0 79200 T 7200 -2700 T N 0 G 288 -1188 M /Times-Roman-ISOLatin1 $ /Times-Roman & P /Times-Roman-ISOLatin1 F 1200 o f ( ) h 288 -2626 M -7200 2700 T 43342 -74700 T N 0 G 9770 -1188 M (2) h 288 -2626 M -43342 74700 T 7200 -74700 T N 0 G 288 -1188 M ( ) h 288 -2626 M -7200 74700 T 36056 -2700 T N 0 G 17356 -1188 M ( ) h 288 -2626 M -36056 2700 T 7200 -7200 T N 0 G 288 -1038 M /Helvetica-ISOLatin1 $ /Helvetica & P /Helvetica-ISOLatin1 F 1000 o f 15.5 0 32 (they monitor it, and will generally see fewer extents in any file if they use the DUMP/HEADER command) W 288 -2238 M 54.9 0 32 (to examine this. The effect is particularly dramatic on system disks with files like ACCOUNTNG.DAT or) W 288 -3438 M (the OPCOM logfiles, which are generally hard to defragment.) h 288 -5838 M ( A menu\255driven setup script makes setup of FA simple to do, even without training.) h 288 -8238 M /Helvetica-Bold-ISOLatin1 $ /Helvetica-Bold & P /Helvetica-Bold-ISOLatin1 F 1000 o f 9.3 0 32 (Processors supported: ) W /Helvetica-ISOLatin1 F 1000 o f 9.3 0 32 (All VMS processors, running VMS 5.5 and above on VAX, or VMS 1.5 on AXP. ) W 288 -9438 M (AXP VMS 6.1 support is in the works.) h 288 -11838 M /Helvetica-Bold-ISOLatin1 F 1000 o f 79.0 0 32 (Requirements: ) W /Helvetica-ISOLatin1 F 1000 o f 79.0 0 32 ( Sufficient memory to hold one multiunit driver in pool plus its control blocks. No other) W 288 -13038 M (software is required.) h 288 -15438 M 288 -16834 M -7200 7200 T showpage $P e %%Trailer $D restore end % DEC_WRITE_dict %%Pages: 2 %%DocumentFonts: Times-Roman %%+ Helvetica-Bold %%+ Helvetica *[VLT00A.GCE]FA.SPD;4+,I./ 4L->0123 KPWO 564'\|7B߶e89GHJAcorn Fragmentation Avoider Description:B VMS disks tend to become fragmented rapidly once placed in use,Bcausing slower file access than might be possible, and making moreCwork for defragmenting utilities later. This happens mainly for tworeasons:D First, whenever a file is deleted or truncated in VMS, the blocksFare placed in an "extent cache" which is then used first in allocatingCnew space. Unfortunately, this space tends to be in tiny, scatteredEchunks and guarantees that newly allocated space is badly fragmented.G Second, many utilities write long files, particularly journal files,Eand use small extents (~5 blocks is common) even though the files mayBbecome thousands of blocks long. Because these files are held openImost of the time, they not only fragment, but are difficult to defragmentIbecause defragmentation of open files is far more difficult and intrusiveHthan of files which are closed. As these files pepper a disk with littleIbits of themselves, they make defragmentation of the rest less effective.?The Fragmentation Avoider consists of an intercept driver and a?control utility which reduce the rate of VMS disk fragmentation in two ways:B1. Files are extended in "contiguous best try" fashion, preventing< the accumulation of many tiny extents in extent cache which9 would otherwise cause new files to be allocated in small bits. F2. Files are extended by a fraction of their current size when this is8 larger than the default, subject to minimum and maximum8 extents and to a constraint of never forcing the extent: to be more than 1/8 of volume free space. Thus files tend? to be extended less often and in larger pieces than by default? which leads to their being far less fragmented than otherwise.GThese actions are configurable on a per volume basis, and FragmentAvoidLcan be enabled or disabled separately on any disk on a system. Configurationoptions include:C* Selection of the fraction to extend a file by (default is 1/4 of$ current size, but can be tailored).E* Selection of maximum number of blocks to extend by, even for giant files5* Selection of minimum number of blocks to extend byF* Selection of how often to force contiguous best try extension. This< is normally done every time, but can be done every Nth time: where N can range from 1 to 1000. (Note that requests for' contiguous extension are not touched.)I* Selection of whether to modify extension amounts where the application= has selected using volume default extension only, or whether? to do this every time. (Using the extension modification every= time overcomes problems with utilities which write very long> files with hardcoded extensions of only a few blocks, leading? to badly fragmented files. Occasionally, though, this leads to? the need to manually truncate files via the $SET FILE/TRUNCATE= command. If size is altered only for users of volume default= allocation, files never need to be truncated, but some files will fragment the disk.)D Fragmentation Avoider works on all VMS disks and is a "set it and@forget it" utility. Users will notice it in that long files willFtend to be written faster (some measurements show up to a 30% speedup)Gdue to less frequent use of the (expensive) extend operation. They willDalso notice slower volume fragmentation if they monitor it, and willCgenerally see fewer extents in any file if they use the DUMP/HEADERFcommand to examine this. The effect is particularly dramatic on systemDdisks with files like ACCOUNTNG.DAT or the OPCOM logfiles, which aregenerally hard to defragment.B A menu-driven setup script makes setup of FA simple to do, evenwithout training.FProcessors supported: All VMS processors, running VMS 5.5 and above on= VAX, or VMS 6.1 or later on Alpha. (VMS 1.5 support on Alpha3 works if you reassemble; the source code is here.) Requirements:< Sufficient memory to hold one multiunit driver in pool plus3 its control blocks. No other software is required.*[VLT00A.GCE]FAVOID.CLD;6+,L./ 4H->0123 KPWO56l)T|7m߶e89GHJDEFINE VERB FAVOID IMAGE JFCTL.EXEH parameter p1,prompt="JFAn:",value(required,type=$device),label=UNIT> parameter p2,label=FNAM,prompt="Disk",value(type=$infile) qualifier DEASSIGN qualifier ALDEFONLY' qualifier FRACTION,value(type=$number)& qualifier MINIMUM,value(type=$number)& qualifier MAXIMUM,value(type=$number)" qualifier CBT,value(type=$number)$! Usage: FAVOID/switches 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:@! /CBT:n do contig best try alloc every nth file open. Default=1! n=1 to 1000 legalF! /FRACTION:n Extend file by 1/n of current filesize (but subject to5! other constraints). Default n=4, 1 to 1000 legal.?! /MINIMUM:n Extend file at least n blocks. 1 to 1000 legal.A! /MAXIMUM:n Extend file at most n blocks. 0 to 1000000 legal. If3! n=0 it means use 1/32 of disk size or 2000 blks! whichever is greater,! /DEASSIGN Turns off fragmentation avoider.!H! /ALDEFONLY causes extend to be modified only if the "ALDEF" bit is set8! so that the program has said to use the vol default3! extend. Generally do NOT use this; it's a waste.*[VLT00A.GCE]FA_SETUP.COM;19+,N./ 4k*->0123 KPWO5 6iX՗7K e89GHJ""$!Setup generator for Frag Avoider9$!Copyright (c) 1994 Acorn Software. All rights reserved.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:JFdriver.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:favoid.cld") .eqs. "" then goto nocomp>$if f$search("sys$system:JFctl.exe") .eqs. "" then goto nocomp$JFnum=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$set comm sys$system:zmenu$ifrac=4$imin=10 $imax=1000000$xwild=0$icbt=1$zmlc=1$domnu:4$zmenu/POINTER="-->"/SYMBOLS/initial='zmlc'2 #6[1;7mAcorn Fragmentation Avoider[m 00:00:00: ^ Open files Contiguous Best Try Every 'icbt' Open(s)< ^ Fraction of current file size to extend by: 1/'ifrac'' ^ Extend by at least 'imin' blocksG ^ Extend by at most 'imax' blocks (but not over 1/8 of free space)1 ^ Set these parameters for all mounted disks- ^ Done this menu, process disk selection@ ^ Remove a disk from an existing Frag Avoider configuration ^ Quit, do nothing$if choice .eq. 8 then exit $zmlc=choice"$if choice .eq. 6 then goto bldcfg$if choice .eq. 7$ then2$ if f$search("sys$manager:fa_start.com") .eqs. ""$ then4$ emit "%FragAv-W-no previous configuration exists." $ goto domnu$ endif$ emit "Current configuration:"2$ search/nohigh sys$manager:fa_start.com "$favoid" $ emit ""5$ ask drmv "Enter disk name to remove, NONE for none"9$ if drmv .eqs. "" .or. drmv .eqs. "NONE" then goto domnu $ text = " "($ open/read jfi sys$manager:fa_start.com)$ open/write jfo sys$manager:fa_start.com$rlpu:$ read/end=clsm jfi text$ ltxt=f$length(text)6$ if f$locate(drmv,text) .ge. ltxt then write jfo text $ goto rlpu$clsm: $ close jfo $ close jfi $ goto domnu$ endif$if choice .eq. 1$then,$ask icbt "C.B.T. Open every how many opens"$if icbt.le.0 then icbt=1 $goto domnu$endif$if choice .eq. 2$thenG$ask ifrac "Enter fraction to extend by. Enter N where fraction is 1/N"$if ifrac .le. 0 then ifrac=4 $goto domnu$endif$if choice .eq. 3$then.$ask imin "Enter minimum extend size (blocks)"$if imin.le.0 then imin=10 $goto domnu$endif$if choice .eq. 4$then.$ask imax "Enter maximum extent size (blocks)"$if imax .lt.0 then imax=0 $goto domnu$endif$if choice .eq. 5$then$xwild=1 $goto domnu$endif$bldcfg:($open/write cfg sys$manager:FA_start.com$write cfg "$sysgen:==$sysgen"$write cfg "$sysman:==$sysman"C$if f$getsyi("CPU").ge. 128 then write cfg "$sysgen:==mc sysman io"+$write cfg "$set command sys$system:favoid"$wild=0!$if xwild .eq. 1 then goto wildsk$gosub gen_dsk_syms$!set comm sys$system:zmenuX$if f$search("sys$scratch:fa_dsks.mnuscr") .nes. "" then del sys$scratch:fa_dsks.mnuscr.*$copy sys$input sys$scratch:fa_dsks.mnuscr0 #6[1;7mFragmentation Avoider Configuration[m# Disk Selection: Use arrows to move to selection. Use RETURN to select.^ End disk selection ^ 'dv1' 'dp1' ^ 'dv2' 'dp2' ^ 'dv3' 'dp3' ^ 'dv4' 'dp4' ^ 'dv5' 'dp5' ^ 'dv6' 'dp6' ^ 'dv7' 'dp7' ^ 'dv8' 'dp8' ^ 'dv9' 'dp9'^ 'dv10' 'dp10'^ 'dv11' 'dp11'^ 'dv12' 'dp12'^ 'dv13' 'dp13'^ 'dv14' 'dp14'^ 'dv15' 'dp15'^ 'dv16' 'dp16'^ 'dv17' 'dp17'^ 'dv18' 'dp18'^ 'dv19' 'dp19'^ 'dv20' 'dp20'^ 'dv21' 'dp21'^ 'dv22' 'dp22'^ 'dv23' 'dp23'^ 'dv24' 'dp24'^ 'dv25' 'dp25'^ 'dv26' 'dp26'^ 'dv27' 'dp27'^ 'dv28' 'dp28'^ 'dv29' 'dp29'^ 'dv30' 'dp30'^ 'dv31' 'dp31'^ 'dv32' 'dp32'^ 'dv33' 'dp33'^ 'dv34' 'dp34'^ 'dv35' 'dp35'^ 'dv36' 'dp36'^ 'dv37' 'dp37'^ 'dv38' 'dp38'^ 'dv39' 'dp39'^ 'dv40' 'dp40'^ 'dv41' 'dp41'^ 'dv42' 'dp42'^ 'dv43' 'dp43'^ 'dv44' 'dp44'^ 'dv45' 'dp45'^ 'dv46' 'dp46'^ 'dv47' 'dp47'^ 'dv48' 'dp48'^ 'dv49' 'dp49'^ 'dv50' 'dp50'^ 'dv51' 'dp51'^ 'dv52' 'dp52'^ 'dv53' 'dp53'^ 'dv54' 'dp54'^ 'dv55' 'dp55'^ 'dv56' 'dp56'^ 'dv57' 'dp57'^ 'dv58' 'dp58'^ 'dv59' 'dp59'^ 'dv60' 'dp60'^ 'dv61' 'dp61'^ 'dv62' 'dp62'^ 'dv63' 'dp63'^ 'dv64' 'dp64'^ 'dv65' 'dp65'^ 'dv66' 'dp66'^ 'dv67' 'dp67'^ 'dv68' 'dp68'^ 'dv69' 'dp69'^ 'dv70' 'dp70'^ 'dv71' 'dp71'^ 'dv72' 'dp72'^ 'dv73' 'dp73'^ 'dv74' 'dp74'^ 'dv75' 'dp75'^ 'dv76' 'dp76'^ 'dv77' 'dp77'^ 'dv78' 'dp78'^ 'dv79' 'dp79'^ 'dv80' 'dp80'^ 'dv81' 'dp81'^ 'dv82' 'dp82'^ 'dv83' 'dp83'^ 'dv84' 'dp84'^ 'dv85' 'dp85'^ 'dv86' 'dp86'^ 'dv87' 'dp87'^ 'dv88' 'dp88'^ 'dv89' 'dp89'^ 'dv90' 'dp90'^ 'dv91' 'dp91'^ 'dv92' 'dp92'^ 'dv93' 'dp93'^ 'dv94' 'dp94'^ 'dv95' 'dp95'^ 'dv96' 'dp96'^ 'dv97' 'dp97'^ 'dv98' 'dp98'^ 'dv99' 'dp99'^ 'dv100' 'dp100'^ 'dv101' 'dp101'^ 'dv102' 'dp102'^ 'dv103' 'dp103'^ 'dv104' 'dp104'^ 'dv105' 'dp105'^ 'dv106' 'dp106'^ 'dv107' 'dp107'^ 'dv108' 'dp108'^ 'dv109' 'dp109'^ 'dv110' 'dp110'^ 'dv111' 'dp111'^ 'dv112' 'dp112'^ 'dv113' 'dp113'^ 'dv114' 'dp114'^ 'dv115' 'dp115'^ 'dv116' 'dp116'^ 'dv117' 'dp117'^ 'dv118' 'dp118'^ 'dv119' 'dp119'^ 'dv120' 'dp120'^ 'dv121' 'dp121'^ 'dv122' 'dp122'^ 'dv123' 'dp123'^ 'dv124' 'dp124'^ 'dv125' 'dp125'^ 'dv126' 'dp126'^ 'dv127' 'dp127'^ 'dv128' 'dp128'^ 'dv129' 'dp129'^ 'dv130' 'dp130'^ 'dv131' 'dp131'^ 'dv132' 'dp132'^ 'dv133' 'dp133'^ 'dv134' 'dp134'^ 'dv135' 'dp135'^ 'dv136' 'dp136'^ 'dv137' 'dp137'^ 'dv138' 'dp138'^ 'dv139' 'dp139'^ 'dv140' 'dp140'^ 'dv141' 'dp141'^ 'dv142' 'dp142'^ 'dv143' 'dp143'^ 'dv144' 'dp144'^ 'dv145' 'dp145'^ 'dv146' 'dp146'^ 'dv147' 'dp147'^ 'dv148' 'dp148'^ 'dv149' 'dp149'^ 'dv150' 'dp150'$eod$!$getdsk:0$zmenu/scroll/symbols sys$scratch:fa_dsks.mnuscr$ choice = choice -1#$ if choice .eq. 0 then goto wrapup$ chcn=f$integer(choice)$ dp'chcn' = "*"$ dsk = dv'chcn'!$if dsk .eqs. "" then goto wrapup $goto intac$wildsk:$wild=1$dsk=f$device(,"DISK")!$if dsk .eqs. "" then goto wrapup5$if f$getdvi(dsk,"MNT") .nes. "TRUE" then goto wildsk$intac:$JFnm="JFA"+f$string(ndsk)+":"6$ccmd="$sysgen connect "+JFnm+"/noada/driver=JFdriver",$if ndsk.eq.0 .and. f$getsyi("CPU") .ge. 128$then-$ccmd=ccmd-"JFdriver" + "sys$system:JFdriver"$endif$write cfg ccmdk$CCMD="$FAVOID/CBT:"+F$STRING(ICBT)+"/FRACT:"+F$STRING(IFRAC)+"/MIN:"+F$STRING(IMIN)+"/MAX:"+F$STRING(IMAX)$ccmd=ccmd+" "+JFnm+" "+dsk$write cfg ccmd $ndsk=ndsk+1 $if wild .eq. 1 then goto wildsk $goto getdsk$wrapup: $close cfg$ write sys$output -"M<>[?4l[?8h",-"(B)07[?6l8"$emit "Add the line" $emit " ",$EMIT " $@SYS$MANAGER:FA_START.COM" $emit " "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$gen_dsk_syms:5$! generate symbols dv1 to dv150, mounted disks first*$! with disk names of disks on the system.9$! Fills these in with (no more disks...) message if none$n=0$SL1:$n = n+1$$dv'n' = "(No more disks on system)" $dp'n'=" "$if n .lt. 150 then goto SL1$n=0$sl2: $ n = n+1$xsl2:$ dnm=f$device("*","DISK")$ if dnm .eqs. "" then goto sl3G$ if f$getdvi(dnm,"MNT") .nes. "TRUE" .and. dnm .nes. "" then goto xsl2 $ dv'n' = dnm$ssl2:$ if n .lt. 150 then goto sl2$sl3: $n = n - 1$tsl2: $ n = n+1$xtsl2:$ dnm=f$device("*","DISK") $ if dnm .eqs. "" then goto tsl3H$ if f$getdvi(dnm,"MNT") .eqs. "TRUE" .and. dnm .nes. "" then goto xtsl2 $ dv'n' = dnm$tssl2:$ if n .lt. 150 then goto tsl2$tsl3:$hijf=n$return*[VLT00A.GCE]JFCTL.MAR;21+,R.L/ 4PLK`->0123KPWOL56;7he89GHJ nolic=0 .library /sys$share:lib/ $wcbdef8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50EVAX = 1.iff ;EVAX = 0.endc .if df,evaxalpha=1 bigpage=1addressbits=32B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0) .endc .if ndf,step2> .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) .IDENT 'V001'!;evax=0 ;define for Alpha version;nolic=0; ; FACILITY:; ;(; This program takes a command of form; favoid/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. .if ndf,step2)$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" fcn .iff,$def ucb$l_myfdt .blkl 70 ;copy of orig. fdt .endc0$def ucb$l_vict .blkl 1 ;victim UCB for checking($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 LONG;; 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 VDFNMiosb: .long 0,0IOSTATUS: .BLKQ 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 255 ;length .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .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 ~FAV020.AR>[VLT00A.GCE]JFCTL.MAR;21PLcv/MAXIMUM/ ;max extent 0adods: .ascid /ALDEFONLY/ ;default-ext. mod only;deads: .ascid /DEASSIGN/ ;deassign jf: from disk (turn off)cbtds: .ascid /CBT/A .EVEN; UCB data areavdeafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3t min: .long 10Tmax: .long 2000B%adflg: .long 0 ;set flg if aldef only(#HSTUCB: .LONG 0 ;SERVED UCB ADDRESSe+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESSa;n;oERROR: .LONG 2MESS: .LONG SS$_ABORTd .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^Mm clrl adflga clrl deafg ;not deassigne* movl #1,cbtct ;contig best try every time movl #4,fracm movl #10,minr movl #2000,max pushab deads  calls #1,g^cli$presenti cmpl r0,#cli$_present ;there? bneq 100$ incl deafgi100$:o; contig best try: pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$presenti cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtds. calls #3,g^cli$get_valueL blbc r0,320$S pushl #17 ;ign. blanksL pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$(322$: movl #1,cbtct ;default val. if err brb 320$N321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$:P ;/aldefonlyN pushab adods ;/aldefonly? calls #1,g^cli$presentE cmpl r0,#cli$_present ;there? bneq 10$E incl adflg10$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$presentD cmpl r0,#cli$_present ;there? bneq 20$  pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: descA calls #3,g^cli$get_valueO blbc r0,20$ pushl #17 ;ign. blanks$ pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if errorF brb 20$21$: R tstl frac ;chk limsD bleq 22$  cmpl frac,#1000 O bgtr 22$A20$:; minL( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab minds calls #3,g^cli$get_valueC blbc r0,120$  pushl #17 ;ign. blanksE pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$S(122$: movl #10,min ;return min=10 if err brb 120$121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 toom bgtr 122$120$:m; max. clrl maxh( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$presento cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxds calls #3,g^cli$get_valuel blbc r0,220$o pushl #17 ;ign. blanksc pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$e'222$: clrl max ;return max=10000 if erro ; max=0 means 1/32 of disk size. brb 220$n221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 toob bgtr 222$220$:m. PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH/ PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURNb# PUSHAB P1DSC ; GET P1 (FDn: UNIT)o5 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 FNMs 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 SOd*; 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.g ITMLST=DEV_ITEM_LIST BLBS R0,40$ BRW advdd_EXITs40$:290$: /; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE.d $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_list_0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERRORe2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name.e ITMLST=VDV_ITEM_LIST BLBS R0,140$t BRW advdd_EXIT<140$:p=; Here do the real work in kernel mode, having now the device6/; descriptions and channels to the devces even!t. tstl deafg ;if /deas, do $qio, then knl work bneq 307$ $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARGn$ CMPL R0,#SS$_NORMAL ;Any errors?& BEQL 300$ ;No, skip error routine( MOVL R0,MESS ;Move error to message ;;; BRW 300$301$:u$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error messagel; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,-k p1=bufg,p2=#busz <; after unbashing the current host, take the JF unit offline ; $CMKRNL_S -H; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHNO ret300$:B; Since that worked OK, send the format function to the JF unit to; finish bashing the host disk.m" movl #1,bufg ;set to bash device= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszA=; 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 fdhostd_exit:_ advdd_exit:S RET2; 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,^ME; TAKEN LOOSELY FROM ZERO.MARt .if ndf,vms$v5e) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB .iff:0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASEe& tstl deafg ;/deas needs no 2nd assign bneq 90$V9 MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS (target)O9 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 for tgt BLBS R0,660$R BRW BSH_XIT660$:;O80$:* 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 R1f BLBS R0,160$i 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...U; 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.)R; @; 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 somehowc#; but will be allocated if mounted.S; ... for now ...O554$:;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.)D166$: brw 165$164$:1; check that both UCBs are disk devices at least!D=; We can't be sure all the device characteristics will be thet?; same for the local device and the MSCP served remote one (andt?; in fact they are not all alike!) but at least they had betterC:; both be disks or this function is not even approximately;; correct and will probably be quickly fatal to the system.Y tstl deafg ;/deas? r11 invalid. beql 1164$D@; 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 JFdriver5164$:.; clear online & valid on JF dvc for next time .if df,evax5 bicl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlineA* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff.5 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 & leaveB1176$: 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.?G& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else willa5; be using its UCB so we don't want to screw this up.s .if df,evax5 bitl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep bneq 166$ .iffs5 bitw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlinee bneq 166$ .endcG; Looks like we're gonna do the assign. Store backpointer for driver ton; 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 match H; 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 thisfE; at device IPL so we have reasonable certainty nobody will mess withc?; these structures until we get them all put into proper order.oI; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytesp); size and copy the existing DDT into it.0E; (it is possible to save the old address if the conditional is used)D .if df,evax5 bisl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bisw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlineg* 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly?; beql 60$e+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thus;60$:C; note 4 bit only extends if aldef is set. Don't set that just now.#* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$$& movl max,r0 ;if so use his unless 0 brb 4$o65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:p$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file sizer movl cbtct,ucb$l_cbtctr(r5)165$: MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R0l7 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL)b POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW .iff ;step2D .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) step2 .IDENT 'V001'evax=0nolic=00; ; FACILITY: ; ;/(; This program takes a command of form; favoid/flags JFAn: node$jban:pC; where JFAn: refers to a local unit of JFdriver, which is a dummyR>; driver furnished to provide local copies of the frag avoider; code in each node.;P6; Note: define VMS$V5 to build for Version 5.x of VMS.VMS$V5=1;L; ; AUTHOR:D; ; G. EVERHART_;T?; 04-Aug-1989 D. HITTNER Cleaned up definitions, added messages I; 29-Aug-1989 G. Everhart Added more flexible device geometry selectionS;--2 .PAGE& .SBTTL EXTERNAL AND LOCAL DEFINITIONS .LIBRARY /SYS$SHARE:LIB/ ; ; EXTERNAL SYMBOLS;  $dyndef) $ADPDEF ;DEFINE ADAPTER CONTROL BLOCKh $ATRDEF) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCKO $DCDEF ;DEFINE DEVICE CLASSN% $DDBDEF ;DEFINE DEVICE DATA BLOCKY' $ddtdef ;define driver dispatch tbls* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLEt) $DVIDEF ;Symbols for $GETDVI service.N( $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 MUSTa.; SET THE ONLINE BIT OR CLEAR IT, AND ALSO SET9; UCB$HUCB (HOST UCB ADDRESS), UCB$HFSZ (HOST FILE SIZE),e8; 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 someg; areas of VMS may want.C; Leave thisfield first so we can know all diskswill have it at the ; same offset.; ; ($def ucb$l_hucbs .blkl 1 ;host ucb table;K#; Add other fields here if desired.A;3$def ucb$l_ctlflgs .blkl 1 ;flags to control modesr; ,$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 keepE6; file extensions from preferentially picking up chaff$def ucb$JFcontfil .blkb 80A0$def ucb$l_asten .blkl 1 ;ast enable mask store;o&$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 byo3$def ucb$l_slop .blkl 1 ;slop blocks to leave frees; DDT intercept fields; following must be contiguous.RH$def ucb$s_ppdbgn ;add any more prepended stuff after thisI$def ucb$l_uniqid .blkl 1 ;driver-unique ID, gets filled in K ; by DPT address for easy followingB0 ; 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 block P; 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 ucbRE; Make the "unique magic number" depend on the DDT length, and on theZJ; 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*>0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;S>; Store copy of victim FDT table here for step 2 Alpha driver.&; assumes FDT table is 64+2 longs long>$def ucb$l_myfdt .blkl 70 ;user FDT tbl copy + slop for safety5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chaine5$def ucb$l_vict .blkl 1 ;victim ucb, for unmung checkr2$def ucb$l_mungd .blkl 1 ;munged flag, 1 if numg'd&$def ucb$l_exempt .blkl 4 ;exempt PIDs($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_LEN=. ;LENGTH OF UCBp% $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.t;e .MACRO ON_ERR THERE,?HERE BLBS R0,HEREc BRW THEREHERE: .ENDM ON_ERR; $ .PSECT ADVDD_DATA,RD,WRT,NOEXE,LONGDEFAULT_DEVICE:r .ASCID /SYS$DISK/ .ALIGN LONG; ; KERNEL ARG LISTeK_ARG:. .LONG 2 ;2 ARGS: HOST-DVC NAME, VD DVC NAME .ADDRESS DEV_BUF_DESC .ADDRESS VDV_BUF_DESC; .ADDRESS DDFNM; .ADDRESS VDFNMiosb: .long 0,0 IOSTATUS: .BLKQ 1BUFG: .long 1 ;bash flags .long 1000 ;(DEV_BUF: ; Buffer to hold device name. .BLKB 40 DEV_BUF_SIZ = . - DEV_BUFv busz=.-bufgb5DEV_BUF_DESC: ; Descriptor pointing to device name.b .LONG DEV_BUF_SIZi .ADDRESS DEV_BUF #PID: ; Owner of device (if any).c .BLKL 1+DEV_ITEM_LIST: ; Device list for $GETDVI.rA .WORD DEV_BUF_SIZ ; Make sure we a have a physical device name.i .WORD DVI$_DEVNAMt .ADDRESS DEV_BUF  .ADDRESS DEV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS PIDn .LONG 0( .WORD 4 - .WORD DVI$_DEVCLASS ; Check for a terminal.w .ADDRESS DEV_CLASSi .LONG 0a .LONG 0 ; End if item list. DEV_CLASS: .LONG 1;**cEvbufg: .long 2 ;deassign bash flag. Deassign victim dvc, not jf: dvc.f .long 1000(VDV_BUF: ; Buffer to hold VDVice name. .BLKB 40iVDV_BUF_SIZ = . - VDV_BUFf vbusz=.-vbufgi5VDV_BUF_DESC: ; Descriptor pointing to VDVice name.c .LONG VDV_BUF_SIZr .ADDRESS VDV_BUFt$VPID: ; Owner of VDVice (if any). .BLKL 1+VDV_ITEM_LIST: ; VDVice list for $GETDVI.wA .WORD VDV_BUF_SIZ ; Make sure we a have a physical device name.r .WORD DVI$_DEVNAMa .ADDRESS VDV_BUFo .ADDRESS VDV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS VPID .LONG 00 .WORD 4p- .WORD DVI$_DEVCLASS ; Check for a terminal.n .ADDRESS VDV_CLASS, .LONG 0  .LONG 0 ; End if item list. VDV_CLASS: .LONG 1;**mDEFNAM:bWRK: .BLKL 1 ;SCRATCH INTEGERs ; 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 255 ;lengtht .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .byte 0,0,0,0 ;safety;i'; DESCRIPTOR FOR NODE$FWAN: DEVICE NAMEo .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 HOLDERS P1DSC: .ASCID /UNIT/P2DSC: .ASCID /FNAM/6frcdsc: .ascid /FRACTION/ ;fract. of file to extend by#minds: .ascid /MINIMUM/ ;min extent #maxds: .ascid /MAXIMUM/ ;max extents0adods: .ascid /ALDEFONLY/ ;default-ext. mod only;deads: .ascid /DEASSIGN/ ;deassign jf: from disk (turn off)cbtds: .ascid /CBT/r .EVEN; UCB data areacdeafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3V min: .long 100max: .long 2000L%adflg: .long 0 ;set flg if aldef only/#HSTUCB: .LONG 0 ;SERVED UCB ADDRESS;+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESS;f;sERROR: .LONG 2MESS: .LONG SS$_ABORTf .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^Mh clrl adflgk clrl deafg ;not deassigno* movl #1,cbtct ;contig best try every time movl #4,fracl movl #10,mine movl #2000,maxm pushab deadsr calls #1,g^cli$presento cmpl r0,#cli$_present ;there? bneq 100$ incl deafge100$:e; contig best tryr: pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$present1 cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtdse calls #3,g^cli$get_value- blbc r0,320$B pushl #17 ;ign. blanksF pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$F(322$: movl #1,cbtct ;default val. if err brb 320$E321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$:D ;/aldefonlyC pushab adods ;/aldefonly? calls #1,g^cli$presentA cmpl r0,#cli$_present ;there? bneq 10$i incl adflgF10$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$presentf cmpl r0,#cli$_present ;there? bneq 20$F pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: desc  calls #3,g^cli$get_valueT blbc r0,20$ pushl #17 ;ign. blanksR pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if errorD brb 20$21$: L tstl frac ;chk limsF bleq 22$P cmpl frac,#1000 A bgtr 22$20$:; min ( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$presentR cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab mindsD calls #3,g^cli$get_valueS blbc r0,120$C pushl #17 ;ign. blanksK pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$I(122$: movl #10,min ;return min=10 if err brb 120$O121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 too bgtr 122$120$:l; maxh clrl max ( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$presentd cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxdse calls #3,g^cli$get_value blbc r0,220$c pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$w'222$: clrl max ;return max=10000 if err ; max=0 means 1/32 of disk size. brb 220$l221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 tooJ bgtr 222$220$:. PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH/ PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURNf# PUSHAB P1DSC ; GET P1 (FDn: UNIT)d5 CALLS #3,G^CLI$GET_VALUE ;GET VALUE OF NAME TO VDFNMb 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'd# 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_EXIT 40$:290$: /; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE.d $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_list 0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERRORn2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name.  ITMLST=VDV_ITEM_LIST BLBS R0,140$  BRW advdd_EXIT 140$: =; Here do the real work in kernel mode, having now the devicet/; descriptions and channels to the devces even!=. tstl deafg ;if /deas, do $qio, then knl work bneq 307$ $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARGd$ CMPL R0,#SS$_NORMAL ;Any errors?& BEQL 300$ ;No, skip error routine( MOVL R0,MESS ;Move error to message ;;; BRW 300$301$:7$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error messageh; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszb<; after unbashing the current host, take the JF unit offline ; $CMKRNL_S - ; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHNN ret300$:TB; Since that worked OK, send the format function to the JF unit to; finish bashing the host disk.s" movl #1,bufg ;set to bash device= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszA=; 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 fdhostd_exit:_ advdd_exit:S RET2; 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,^ME; TAKEN LOOSELY FROM ZERO.MARt .if ndf,vms$v5e) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB  .iff:0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASEe& tstl deafg ;/deas needs no 2nd assign bneq 90$V9 MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS (target)O9 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 for tgt BLBS R0,660$R BRW BSH_XIT660$:;O80$:* 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 R1f BLBS R0,160$i 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...U; 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.)R; @; 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 somehowc#; but will be allocated if mounted.S; ... for now ...O554$:;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.)D166$: brw 165$164$:_1; check that both UCBs are disk devices at least!D=; We can't be sure all the device characteristics will be thet?; same for the local device and the MSCP served remote one (andt?; in fact they are not all alike!) but at least they had betterC:; both be disks or this function is not even approximately;; correct and will probably be quickly fatal to the system.Y tstl deafg ;/deas? r11 invalid. beql 1164$D@; 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 JFdriver5164$:.; clear online & valid on JF dvc for next time .if df,evax5 bicl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlineA* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff.5 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 & leaveL1176$: 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.?G& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else willk5; be using its UCB so we don't want to screw this up.s .if df,evax5 bitl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep bneq 166$ .iffs5 bitw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlinee bneq 166$ .endcG; Looks like we're gonna do the assign. Store backpointer for driver ton; 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 match H; 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 thisfE; at device IPL so we have reasonable certainty nobody will mess withc?; these structures until we get them all put into proper order.oI; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytesp); size and copy the existing DDT into it.0E; (it is possible to save the old address if the conditional is used)f .if df,evax5 bisl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bisw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlineg* 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly?; beql 60$e+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thus;60$:C; note 4 bit only extends if aldef is set. Don't set that just now.#* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$$& movl max,r0 ;if so use his unless 0 brb 4$o65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:p$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file sizer movl cbtct,ucb$l_cbtctr(r5)165$: MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R0l7 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL)b POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW .endc ;step2s .END ADVDDc*[VLT00A.GCE]JFCTL.OBJ;2+,S./ 4"->0123 KPWO56ꏗe7e89GHJAAJFCTLV00128-FEB-2000 20:48AMAC V3.0-23h h . ABS . . BLANK . $ABS$ ADVDD_DATA ADVDD_CODEP$LINKAGE DSC$K_DTYPE_T CLI$PRESENT CLI$_PRESENT CLI$GET_VALUE OTS$CVT_TU_L SYS$ASSIGN SYS$GETDVI SYS$GETDVIW SYS$CMKRNL SYS$PUTMSGSYS$QIOW SYS$DASSGN CTL$GL_PCB SCH$IOLOCKW IOC$SEARCHDEV SCH$IOUNLOCK(JXADVDD(J BASHUCBG G=4= SYS$DISK\44=,=\=(44h=( 44\4=~FAV020.AS>[VLT00A.GCE]JFCTL.OBJ;2,*d4=4= =(4=( 44=4=4= = DSC$K_DTYPE_T2=4= DSC$K_DTYPE_T2=4= DSC$K_DTYPE_T2=4= ,4=UNIT84=FNAMD4= FRACTIONT4= MINIMUMc4= MAXIMUM r4= ALDEFONLY4= DEASSIGN4=7/CBT , = >C~^^ ~(08޴@HP>X^`~h GpxG(-4GQ/#q/1#{"Z \K[|KQ?q?#.zJ/W JXK>?G?Fq/"1/[|KY #?F/q#.XKV JG YKyKF>??FQ//Z[KX KYG KmG?Q?4GM@Zkͦ(-0@/Q#/KY K\KyG0`CyzKX KG zKG??"M4Gm@ZkͦtG(0@'8M@mA/""@Zk(HMPm4GG4""G@Zk(-.q/"1#J\ vKFCCQ/.;&"YKX JXGC0VCGMj"m4G@Zkm(-0@Q/.#XKW JZXK7G0 Cw8KV JWG 8KF>Q?M<"m4G@Zkm(tG0@&8MA@m/"<"@Zk(HM4GPmG4""G@Zk(-/q#1/KZ ;K#GCC/"/KV KGC0CGML"m4G@Zk-(0@'8M@mA/"L"tG@Zk(HM4GPmG4""G@Zk(-Q/1#.#YKX JXGCC.?#Q/J[ \KFC0ByG.#.["M4GV J>WJm>@ZkmtG(0@'8M@mA/"["@Zk(HMPm4GG4""G@Zk(-c/1/q#KZ ;KGCCZ/"/'{#KV KGC0COG8MA@m/"$"tG@Zk(m 8M@mtGB3"0"@Zk(FG^ ~(08ޤ@HP>X^`~hpxCkG1/4GQ#.xzKY:KW J8G zKF>1?Gq/G#1/zJ[|KY {G/Q#1/X KY:K?1?ûGMGmG4""G@Zk( >CpmG>C8G^ޢ CG^hM JG޶G@Zk( C>CMG>CmGޢCX"G޶GG@Zk(CMGmG 4"GB@Zk( MGmG /""G@ZkuG>ChMG>C /G~AG~ JpmGG@ZkC`(M:#/.KW JTGGCC(xMm C@Zk(05@<//#.wHXKV JG HF>?GMGmG"G@Zk(m>C(>CTG,;eC8G0C޶G~G0ޢG <C4~G޶GM J~8ޢ<~ ޶(~m@Zk(MC`m4G XMJ@Zk>Cm4G,/8G0A޶GG0^G /A4ޢG^G J޶8^<ޢ ^M(޶@ZkC(XM4G`m J@Zk(m4GXM`mJ@ZkGG>C~(^0^8~@HP޴X`h>p^x~ GGm8{#[/;/Z[KY ;K;?[?HMPm =@Zk  =#C./JV KFCC@(M0m =@Zk =m C{#y;H[//Z[KX KYG ;HG?[?`(MC0m@ZkGXM>C`m @Zk CG(0^8~@HPޤX`h>p^x~CkØmC."s/|7HVJ[ wKF 7H|Gs?>S/3#.'x8#YKX JXGCC @Ţ2Bt@E"BGECG4GXG25Cg@e_'x8Z#2zCb@%"G\@"eFDevGeKE\ \RKWRJvSKF\\kD\EG_GYG\E\뢚S#D\Ţ0J|1JV0JTGF\Ųs/#/zKY KyG@e8岪.S/J[ \KFCC@8G8".3#s/J\ vKF岦S/. YKX JXGCC@CK#2@@ 3#S/#.YKX JXGE.S/J[ \KF<Ų4GYGGVæ,3#.HX JDC4 Lm#X CLI$PRESENT4 `Gh CLI$PRESENT4 d@h CLI$PRESENT4 G CLI$PRESENT4 m#X CLI$PRESENT4 @ CLI$PRESENT4 G CLI$GET_VALUE4 m#X CLI$GET_VALUE4 @ CLI$GET_VALUE 4 G OTS$CVT_TU_L4m#X OTS$CVT_TU_L4 @ OTS$CVT_TU_L4 xG CLI$PRESENT4 m#X CLI$PRESENT4 @ CLI$PRESENT4 G CLI$PRESENT4 m#X CLI$PRESENT4 @ CLI$PRESENT4 G CLI$GET_VALUE4 m#X CLI$GET_VALUE4 @ CLI$GET_VALUE4  G@ OTS$CVT_TU_L4(m#X OTS$CVT_TU_L4 <@@ OTS$CVT_TU_L4 G CLI$PRESENT4 m#X CLI$PRESENT4 @ CLI$PRESENT4 G CLI$GET_VALUE4 m#X CLI$GET_VALUE4 @ CLI$GET_VALUE4 G OTS$CVT_TU_L4m#X OTS$CVT_TU_L4 @ OTS$CVT_TU_L4 hG CLI$PRESENT4 |m#X CLI$PRESENT4 @ CLI$PRESENT4 G CLI$GET_VALUE4 m#X CLI$GET_VALUE4 @ CLI$GET_VALUE4 G OTS$CVT_TU_L4m#X OTS$CVT_TU_L4 @ OTS$CVT_TU_L4 8GT CLI$GET_VALUE4 @m#X CLI$GET_VALUE4 P@T CLI$GET_VALUE4 \Gx CLI$GET_VALUE4 `m#X CLI$GET_VALUE4 t@x CLI$GET_VALUE4G SYS$ASSIGN4m#X SYS$ASSIGN4@ SYS$ASSIGN4m#X SYS$GETDVI4G SYS$GETDVI4@ SYS$GETDVI4GX SYS$GETDVIW4(m#X SYS$GETDVIW4T@X SYS$GETDVIW4`G SYS$ASSIGN4hm#X SYS$ASSIGN4|@ SYS$ASSIGN4G SYS$ASSIGN4m#X SYS$ASSIGN4@ SYS$ASSIGN4G SYS$GETDVI4m#X SYS$GETDVI4@ SYS$GETDVI48GL SYS$CMKRNL4<m#X SYS$CMKRNL4H@L SYS$CMKRNL4G SYS$PUTMSG4m#X SYS$PUTMSG4@ SYS$PUTMSG4 G$ SYS$QIOW4 m#XSYS$QIOW4 @$ SYS$QIOW4, m#X SYS$DASSGN48 GD SYS$DASSGN4@ @D SYS$DASSGN4L m#XSYS$QIOW4 G SYS$QIOW4 @ SYS$QIOW4 G SYS$DASSGN4 m#X SYS$DASSGN4 @ SYS$DASSGN4 G SYS$DASSGN4 m#X SYS$DASSGN4 @ SYS$DASSGNt t4p G SCH$IOLOCKW4x m# SCH$IOLOCKW4 @ SCH$IOLOCKW4 G IOC$SEARCHDEV4 m# IOC$SEARCHDEV4 @ IOC$SEARCHDEV4 G IOC$SEARCHDEV4 m# IOC$SEARCHDEV4 @ IOC$SEARCHDEV4 G4 SCH$IOUNLOCK4( m# SCH$IOUNLOCK40 @4 SCH$IOUNLOCK   SYS$GETDVIW"""  SYS$PUTMSG"" SYS$QIOW"""  SYS$ASSIGN"" CLI$PRESENT"7 CLI$_PRESENT=0 ;= =; CLI$GET_VALUE"" OTS$CVT_TU_L""  SYS$DASSGN"  SYS$GETDVI"""  SYS$CMKRNL";=0(  ;=/ ="  IOC$SEARCHDEV7 CTL$GL_PCB0  SCH$IOLOCKW  SCH$IOUNLOCK  X*[VLT00A.GCE]JFCTL.OBJ_VAX;1+,T./ 4->0123KPWO56ccHy7 6e89GHJ2JFCTLV00129-AUG-1996 15:37 VAX MACRO V5.4-3 MACRO JFCTL*;control JFdriver (fragmentation avoider JFCTL CLI$GET_VALUE CLI$PRESENT CLI$_PRESENT CTL$GL_PCB DSC$K_DTYPE_T IOC$SEARCHDEV OTS$CVT_TU_L SCH$IOLOCKW SCH$IOUNLOCK SYS$ASSIGN SYS$CMKRNL SYS$DASSGN SYS$GETDVI SYS$GETDVIW SYS$PUTMSGSYS$QIOW . ABS .P$ABS$PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP ADVDD_DATAP3SYS$DISKQ&Q\QQ((4Q( 4\dQ((Q( Q DSC$K_DTYPE_T%Q DSC$K_DTYPE_T%QQ DSC$K_DTYPE_T%Q(3UNITQ&Q 43FNAMQ&Q @3FRACTIONQ&QP3MINIMUMQ&Q _3MAXIMUMQ&Q n3ALDEFONLYQ &Q3DEASSIGNQ&Q3CBTQ&Q  ,  ADVDD_CODEP ADVDD& Џ{ CLI$PRESENTP CLI$_PRESENT CLI$PRESENTP CLI$_PRESENTT CLI$GET_VALUEP8 OTS$CVT_TU_LP ʚ;j CLI$PRESENTP CLI$_PRESENT< CLI$PRESENTP CLI$_PRESENTT< CLI$GET_VALUEP8 OTS$CVT_TU_LP L CLI$PRESENTP CLI$_PRESENTTL CLI$GET_VALUEP8 OTS$CVT_TU_LP [ CLI$PRESENTP CLI$_PRESENTS[ CLI$GET_VALUEP7 OTS$CVT_TU_LP$ CLI$GET_VALUEP10 CLI$GET_VALUEP1|~ SYS$ASSIGNP1c|~h<~ SYS$GETDVIP1?|~<~ SYS$GETDVIW|~  SYS$ASSIGNP|~  SYS$ASSIGNP1|~< ~ SYS$GETDVIP12 SYS$CMKRNLPYP SYS$PUTMSG,|~|~0,|~<~< ~ SYS$QIOW< ~ SYS$DASSGN,|~|~0,|~<~< ~ SYS$QIOW< ~ SYS$DASSGN<~ SYS$DASSGN BASHUCB& CTL$GL_PCBT SCH$IOLOCKWЬQ IOC$SEARCHDEVP1QQ[ЬQ IOC$SEARCHDEVP1QQU1%`H$xxP1ЏP1L`H$x[xxRRPPQQ"DP PxPPPЏPPHLPP SCH$IOUNLOCKЎP& ADVDDBASHUCB2 ADVDD_DATA ADVDD_CODE *[VLT00A.GCE]JFCTLV2.MAR;4+,U.L/ 4PLL->0123KPWOM56MyDJ7+e89GHJBnolic=0 .library /sys$share:lib/ $wcbdef8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50EVAX = 1.iff ;EVAX = 0.endc .if df,evaxalpha=1 bigpage=1addressbits=32B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0) .endc .if ndf,step2> .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) .IDENT 'V001'!;evax=0 ;define for Alpha version;nolic=0; ; FACILITY:; ;(; This program takes a command of form; favoid/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$L_ICPFGS .BLKL 2 ; Flags. Reserve 2 longs so we need ; not mess with this later. $VIELD UCB,0,<-- ,- ; 1 if this intercept and all! > ; below understand finipl8.;$def ucb$l_ufil1 .blkl 8 ; for others' intercepts if needed$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.Cmagic=^xF0070000 + ddt$k_length + <256*>Ep.magic=^xF0070000 + ddt$k_length + <256*> ;an ACE is there or not. .if df,step2Cmagic=^xF0070000 + ddt$k_length + <256*>Ep.magic=^xF0070000 + ddt$k_length + <256*> .endc0$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. .if ndf,step2)$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" fcn .iff,$def ucb$l_myfdt .blkl 70 ;copy of orig. fdt .endc0$def ucb$l_vict .blkl 1 ;victim ucb for checking($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 LONG;; 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 VDFNMiosb: .long 0,0IOSTATUS: .BLKQ 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 255 ;length .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .byte 0,0,0,0 ;safety;'; DESCRIPTOR FOR NODE$FWAN: DEVICE NAMEy .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 HOLDERS P1DSC: .ASCID /UNIT/P2DSC: .ASCID /FNAM/6frcdsc: .ascid /FRACTION/ ;fract. of file to extend by#minds: .ascid /MINIMUM/ ;min extentr#maxds: .ascid /MAXIMUM/ ;max extenti0adods: .ascid /ALDEFONLY/ ;default-ext. mod only;deads: .ascid /DEASSIGN/ ;deassign jf: from disk (turn off)tcbtds: .ascid /CBT/m .EVEN; UCB data areaddeafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3r min: .long 10rmax: .long 2000s%adflg: .long 0 ;set flg if aldef onlyd#HSTUCB: .LONG 0 ;SERVED UCB ADDRESSd+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESS ;H;ERROR: .LONG 2MESS: .LONG SS$_ABORT  .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^Me clrl adflg  clrl deafg ;not deassign.* movl #1,cbtct ;contig best try every time movl #4,fracE movl #10,minX movl #2000,max pushab deads$ calls #1,g^cli$present  cmpl r0,#cli$_present ;there? bneq 100$ incl deafgU100$:C; contig best tryI: pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$presentd cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtdsV calls #3,g^cli$get_valueI blbc r0,320$M pushl #17 ;ign. blanksS pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$E(322$: movl #1,cbtct ;default val. if err brb 320$ 321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$:E ;/aldefonlyS pushab adods ;/aldefonly? calls #1,g^cli$presentF cmpl r0,#cli$_present ;there? bneq 10$F incl adflgN10$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$present  cmpl r0,#cli$_present ;there? bneq 20$C pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: desc  calls #3,g^cli$get_value blbc r0,20$ pushl #17 ;ign. blanksA pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if error  brb 20$21$: $ tstl frac ;chk limse bleq 22$b cmpl frac,#1000 S bgtr 22$R20$:; minO( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$presentm cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab mindsv calls #3,g^cli$get_value. blbc r0,120$d pushl #17 ;ign. blanksr pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$k(122$: movl #10,min ;return min=10 if err brb 120$n121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 tooe bgtr 122$120$:N; maxn clrl maxy( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$presentt cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxdsb calls #3,g^cli$get_valuen blbc r0,220$f pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$_'222$: clrl max ;return max=10000 if err ; max=0 means 1/32 of disk size. brb 220$k221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 too bgtr 222$220$:f. PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH/ PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURNk# PUSHAB P1DSC ; GET P1 (FDn: UNIT)d5 CALLS #3,G^CLI$GET_VALUE ;GET VALUE OF NAME TO VDFNMa 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'h# 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.f ITMLST=DEV_ITEM_LIST BLBS R0,40$ BRW advdd_EXIT 40$:290$: /; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE.; $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_listn0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERROR.2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name. ITMLST=VDV_ITEM_LIST BLBS R0,140$t BRW advdd_EXIT7140$:d=; Here do the real work in kernel mode, having now the device7/; descriptions and channels to the devces even!d. 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$:f$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error messageb; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,-b p1=bufg,p2=#buszo<; after unbashing the current host, take the JF unit offline ; $CMKRNL_S -G; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHNO ret300$:B; Since that worked OK, send the format function to the JF unit to; finish bashing the host disk.m" movl #1,bufg ;set to bash device= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszA=; 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 fdhostd_exit:_ advdd_exit:S RET2; 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,^ME; TAKEN LOOSELY FROM ZERO.MARt .if ndf,vms$v5e) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB .iff:0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASEe& tstl deafg ;/deas needs no 2nd assign bneq 90$V9 MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS (target)O9 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 for tgt BLBS R0,660$R BRW BSH_XIT660$:;O80$:* 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 R1f BLBS R0,160$i 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...U; 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.)R; @; 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 somehowc#; but will be allocated if mounted.S; ... for now ...O554$:;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.)D166$: brw 165$164$:1; check that both UCBs are disk devices at least!D=; We can't be sure all the device characteristics will be thet?; same for the local device and the MSCP served remote one (andt?; in fact they are not all alike!) but at least they had betterC:; both be disks or this function is not even approximately;; correct and will probably be quickly fatal to the system.Y tstl deafg ;/deas? r11 invalid. beql 1164$D@; 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 JFdriver5164$:.; clear online & valid on JF dvc for next time .if df,evax5 bicl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlin~FAV020.AU>[VLT00A.GCE]JFCTLV2.MAR;4PLV"eA* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff.5 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 & leaves1176$: 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.?G& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else will 5; be using its UCB so we don't want to screw this up.s .if df,evax5 bitl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep bneq 166$ .iffs5 bitw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlinee bneq 166$ .endcG; Looks like we're gonna do the assign. Store backpointer for driver ton; 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 match H; 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 thisfE; at device IPL so we have reasonable certainty nobody will mess withc?; these structures until we get them all put into proper order.oI; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytesp); size and copy the existing DDT into it.0E; (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 onlinep* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bisw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlineg* 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly?; beql 60$e+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thus;60$:C; note 4 bit only extends if aldef is set. Don't set that just now.#* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$$& movl max,r0 ;if so use his unless 0 brb 4$o65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:p$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file sizer movl cbtct,ucb$l_cbtctr(r5)165$: MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R0l7 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL)b POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW .iff ;step2D .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) step2 .IDENT 'V001'evax=0nolic=00; ; FACILITY: ; ;/(; This program takes a command of form; favoid/flags JFAn: node$jban:pC; where JFAn: refers to a local unit of JFdriver, which is a dummyR>; driver furnished to provide local copies of the frag avoider; code in each node.;P6; Note: define VMS$V5 to build for Version 5.x of VMS.VMS$V5=1;L; ; AUTHOR:D; ; G. EVERHART_;T?; 04-Aug-1989 D. HITTNER Cleaned up definitions, added messages I; 29-Aug-1989 G. Everhart Added more flexible device geometry selectionS;--2 .PAGE& .SBTTL EXTERNAL AND LOCAL DEFINITIONS .LIBRARY /SYS$SHARE:LIB/ ; ; EXTERNAL SYMBOLS;  $dyndef) $ADPDEF ;DEFINE ADAPTER CONTROL BLOCKh $ATRDEF) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCKO $DCDEF ;DEFINE DEVICE CLASSN% $DDBDEF ;DEFINE DEVICE DATA BLOCKY' $ddtdef ;define driver dispatch tbls* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLEt) $DVIDEF ;Symbols for $GETDVI service.N( $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 MUSTa.; SET THE ONLINE BIT OR CLEAR IT, AND ALSO SET9; UCB$HUCB (HOST UCB ADDRESS), UCB$HFSZ (HOST FILE SIZE),e8; 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 someg; areas of VMS may want.C; Leave thisfield first so we can know all diskswill have it at theo; same offset.; ; ($def ucb$l_hucbs .blkl 1 ;host ucb table;K#; Add other fields here if desired.A;3$def ucb$l_ctlflgs .blkl 1 ;flags to control modesr; ,$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 keepE6; file extensions from preferentially picking up chaff$def ucb$JFcontfil .blkb 80A0$def ucb$l_asten .blkl 1 ;ast enable mask store;o&$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 byo3$def ucb$l_slop .blkl 1 ;slop blocks to leave frees; DDT intercept fields; following must be contiguous.RH$def ucb$s_ppdbgn ;add any more prepended stuff after thisI$def ucb$l_uniqid .blkl 1 ;driver-unique ID, gets filled in K ; by DPT address for easy followingB0 ; 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 block P; 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$L_ICPFGS .BLKL 2 ; Flags. Reserve 2 longs so we need. ; not mess with this later. $VIELD UCB,0,<-- ,- ; 1 if this intercept and all ! > ; below understand finipl8. $def ucb$l_ufl2 .blkl 8O$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 ucbaE; Make the "unique magic number" depend on the DDT length, and on thedJ; length of the prepended material. If anything new is added, be sure that"; this magic number value changes.Cmagic=^xF0070000 + ddt$k_length + <256*>Ep.magic=^xF0070000 + ddt$k_length + <256*>b0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;u>; Store copy of victim FDT table here for step 2 Alpha driver.&; assumes FDT table is 64+2 longs long>$def ucb$l_myfdt .blkl 70 ;user FDT tbl copy + slop for safety5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chainn5$def ucb$l_vict .blkl 1 ;victim ucb, for unmung checkf2$def ucb$l_mungd .blkl 1 ;munged flag, 1 if numg'd&$def ucb$l_exempt .blkl 4 ;exempt PIDs($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_LEN=. ;LENGTH OF UCBa% $DEFEND UCB ;END OF UCB DEFINITONSr; TO SET ONLINE::; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE/; Macro to check return status of system calls.c;u .MACRO ON_ERR THERE,?HERE BLBS R0,HEREn BRW THEREHERE: .ENDM ON_ERR;)$ .PSECT ADVDD_DATA,RD,WRT,NOEXE,LONGDEFAULT_DEVICE:t .ASCID /SYS$DISK/ .ALIGN LONG;b; KERNEL ARG LISTdK_ARG:. .LONG 2 ;2 ARGS: HOST-DVC NAME, VD DVC NAME .ADDRESS DEV_BUF_DESC .ADDRESS VDV_BUF_DESC; .ADDRESS DDFNM; .ADDRESS VDFNMiosb: .long 0,01IOSTATUS: .BLKQ 1eBUFG: .long 1 ;bash flagn .long 1000 ;(DEV_BUF: ; Buffer to hold device name. .BLKB 40rDEV_BUF_SIZ = . - DEV_BUF busz=.-bufgt5DEV_BUF_DESC: ; Descriptor pointing to device name.e .LONG DEV_BUF_SIZt .ADDRESS DEV_BUFv#PID: ; Owner of device (if any).s .BLKL 1+DEV_ITEM_LIST: ; Device list for $GETDVI.lA .WORD DEV_BUF_SIZ ; Make sure we a have a physical device name.  .WORD DVI$_DEVNAMh .ADDRESS DEV_BUFk .ADDRESS DEV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS PID .LONG 0t .WORD 4a- .WORD DVI$_DEVCLASS ; Check for a terminal.e .ADDRESS DEV_CLASSh .LONG 0b .LONG 0 ; End if item list. DEV_CLASS: .LONG 1;**Evbufg: .long 2 ;deassign bash flag. Deassign victim dvc, not jf: dvc.d .long 1000n(VDV_BUF: ; Buffer to hold VDVice name. .BLKB 40 VDV_BUF_SIZ = . - VDV_BUFa vbusz=.-vbufgt5VDV_BUF_DESC: ; Descriptor pointing to VDVice name.e .LONG VDV_BUF_SIZr .ADDRESS VDV_BUF $VPID: ; Owner of VDVice (if any). .BLKL 1+VDV_ITEM_LIST: ; VDVice list for $GETDVI.gA .WORD VDV_BUF_SIZ ; Make sure we a have a physical device name.n .WORD DVI$_DEVNAM. .ADDRESS VDV_BUFu .ADDRESS VDV_BUF_DESC6 .WORD 4 ; See if someone has this device allocated. .WORD DVI$_PID .ADDRESS VPID .LONG 0_ .WORD 4t- .WORD DVI$_DEVCLASS ; Check for a terminal.r .ADDRESS VDV_CLASS .LONG 0_ .LONG 0 ; End if item list. VDV_CLASS: .LONG 1;**cDEFNAM:dWRK: .BLKL 1 ;SCRATCH INTEGERv ; 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 255 ;lengths .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .byte 0,0,0,0 ;safety;v'; DESCRIPTOR FOR NODE$FWAN: DEVICE NAMEm .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 HOLDERSbP1DSC: .ASCID /UNIT/P2DSC: .ASCID /FNAM/6frcdsc: .ascid /FRACTION/ ;fract. of file to extend by#minds: .ascid /MINIMUM/ ;min extent #maxds: .ascid /MAXIMUM/ ;max extent$0adods: .ascid /ALDEFONLY/ ;default-ext. mod only;deads: .ascid /DEASSIGN/ ;deassign jf: from disk (turn off)(cbtds: .ascid /CBT/  .EVEN; UCB data area;deafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3o min: .long 10emax: .long 2000'%adflg: .long 0 ;set flg if aldef only #HSTUCB: .LONG 0 ;SERVED UCB ADDRESSd+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESS ;e;JERROR: .LONG 2MESS: .LONG SS$_ABORT, .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^Md clrl adflge clrl deafg ;not deassignr* movl #1,cbtct ;contig best try every time movl #4,frac. movl #10,min movl #2000,maxH pushab deadsu calls #1,g^cli$presenta cmpl r0,#cli$_present ;there? bneq 100$ incl deafgi100$:e; contig best try2: pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$present  cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtdsN calls #3,g^cli$get_value$ blbc r0,320$E pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$R(322$: movl #1,cbtct ;default val. if err brb 320$r321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$: ;/aldefonlyD pushab adods ;/aldefonly? calls #1,g^cli$presentE cmpl r0,#cli$_present ;there? bneq 10$/ incl adflgK10$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$present$ cmpl r0,#cli$_present ;there? bneq 20$D pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: descB calls #3,g^cli$get_value blbc r0,20$ pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if errorT brb 20$21$:  tstl frac ;chk limsO bleq 22$E cmpl frac,#1000 bgtr 22$e20$:; minL( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$present; cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab minds  calls #3,g^cli$get_value blbc r0,120$O pushl #17 ;ign. blanksS pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$ (122$: movl #10,min ;return min=10 if err brb 120$.121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 toos bgtr 122$120$:; maxf clrl maxl( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$present  cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxdsf calls #3,g^cli$get_value blbc r0,220$t pushl #17 ;ign. blankss pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$a'222$: clrl max ;return max=10000 if errt ; max=0 means 1/32 of disk size. brb 220$l221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 toob bgtr 222$220$: . 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 VDFNMi 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.U ITMLST=DEV_ITEM_LIST BLBS R0,40$ BRW advdd_EXIT.40$:290$:m/; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE., $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_list0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERRORe2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name.h ITMLST=VDV_ITEM_LIST BLBS R0,140$  BRW advdd_EXITs140$:t=; Here do the real work in kernel mode, having now the devicel/; descriptions and channels to the devces even!i. tstl deafg ;if /deas, do $qio, then knl work bneq 307$ $CMKRNL_S - ROUTIN=BASHUCB,ARGLST=K_ARGd$ CMPL R0,#SS$_NORMAL ;Any errors?& BEQL 300$ ;No, skip error routine( MOVL R0,MESS ;Move error to message ;;; BRW 300$301$:7$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error messageh; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszb<; after unbashing the current host, take the JF unit offline ; $CMKRNL_S - ; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHNN ret300$:TB; Since that worked OK, send the format function to the JF unit to; finish bashing the host disk.s" movl #1,bufg ;set to bash device= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,- p1=bufg,p2=#buszA=; 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 fdhostd_exit:_ advdd_exit:S RET2; 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,^ME; TAKEN LOOSELY FROM ZERO.MARt .if ndf,vms$v5e) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCBv .iff:0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASEe& tstl deafg ;/deas needs no 2nd assign bneq 90$V9 MOVL 4(AP),R1 ;;; ADDRESS DVC NAME DESCRIPTORS (target)O9 JSB G^IOC$SEARCHDEV ;;; GET UCB ADDRESS INTO R1 for tgt BLBS R0,660$R BRW BSH_XIT660$:;O80$:* 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 R1f BLBS R0,160$i 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...U; 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.)R; @; 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 somehowc#; but will be allocated if mounted.S; ... for now ...O554$:;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.)D166$: brw 165$164$: 1; check that both UCBs are disk devices at least!D=; We can't be sure all the device characteristics will be thet?; same for the local device and the MSCP served remote one (andt?; in fact they are not all alike!) but at least they had betterC:; both be disks or this function is not even approximately;; correct and will probably be quickly fatal to the system.Y tstl deafg ;/deas? r11 invalid. beql 1164$D@; 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 JFdriver5164$:.; clear online & valid on JF dvc for next time .if df,evax5 bicl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlineA* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff.5 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 & leave'1176$: 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.?G& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else wille5; be using its UCB so we don't want to screw this up.s .if df,evax5 bitl #ucb$m_online,ucb$l_sts(r5) ;set jf unit onlinep bneq 166$ .iffs5 bitw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlinee bneq 166$ .endcG; Looks like we're gonna do the assign. Store backpointer for driver ton; 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 match H; 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 thisfE; at device IPL so we have reasonable certainty nobody will mess withc?; these structures until we get them all put into proper order.oI; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytesp); size and copy the existing DDT into it.0E; (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 onlinep* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff5 bisw #ucb$m_online,ucb$w_sts(r5) ;set jf unit onlineg* 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly?; beql 60$e+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thus;60$:C; note 4 bit only extends if aldef is set. Don't set that just now.#* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$$& movl max,r0 ;if so use his unless 0 brb 4$o65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:p$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file sizer movl cbtct,ucb$l_cbtctr(r5)165$: MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R0l7 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL)b POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW .endc ;step2s .END ADVDDc*[VLT00A.GCE]JFCTL_AXP.MAR;4+,V.*/ 4P*)->0123 KPWO*5 67ae89GHJ$> .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) .IDENT 'V001'evax=0nolic=0";Copyright (c) 1994 Acorn Software;All rights reserved; ; FACILITY:; ;(; This program takes a command of form; favoid/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($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 LONG;; 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 VDFNMiosb: .long 0,0IOSTATUS: .BLKQ 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 1AVTECH_PRODUCT_CODE::+ .ASCII /FAV1/ ; frag avoider license code+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 255 ;length .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .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/6licads: .ascid /INSTALL/ ;add key...needs value.licrqd: .ascid /LICENSE/ ;generate form .EVEN; UCB data areadeafg: .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 #4,frac movl #10,min movl #2000,max:; Before anything else, let user request a license form or; install a key. .if ndf,nolic- pushab licads ;/install=key command calls #1,g^cli$present: cmpl r0,#cli$_present ;was switch there? bneq 80$4 pushab wrk ;ret length longword/ pushab wrkstr ;scratch string1 pushab licads ;get value of key movw #255,wrkstr9 calls #3,g^cli$get_value ;get value of lbn. on_err fdhostd_Exit ;skip on error; ~FAV020.AV>LT00A.GCE]JFCTL_AXP.MAR;4P*.now wrkstr has value2 movw wrk,wrkstr ;set string length pushab wrkstr, calls #1,g^apkkeyadd ;add the key movw #255,wrkstr80$:2 pushab licrqd ;/license=filename command calls #1,g^cli$present: cmpl r0,#cli$_present ;was switch there? bneq 81$4 pushab wrk ;ret length longword/ pushab wrkstr ;scratch string6 pushab licrqd ;get value of filename movw #255,wrkstr9 calls #3,g^cli$get_value ;get value of lbn. on_err fdhostd_Exit ;skip on error; now wrkstr has value2 movw wrk,wrkstr ;set string length pushab wrkstr? calls #1,g^licreq ;print out license request form movw #255,wrkstr81$:G; Now if user has anything else to add or do, try to do it. We test the; key lower down. .endc pushab deads calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 100$ incl deafg100$:; contig best try: pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtds calls #3,g^cli$get_value blbc r0,320$ pushl #17 ;ign. blanks pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$(322$: movl #1,cbtct ;default val. if err brb 320$321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$: ;/aldefonly pushab adods ;/aldefonly? calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 10$ incl adflg10$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 20$ pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: desc calls #3,g^cli$get_value blbc r0,20$ pushl #17 ;ign. blanks pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if error brb 20$21$:  tstl frac ;chk lims bleq 22$ cmpl frac,#1000 bgtr 22$20$:; min( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab minds calls #3,g^cli$get_value blbc r0,120$ pushl #17 ;ign. blanks pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$(122$: movl #10,min ;return min=10 if err brb 120$121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 too bgtr 122$120$:; max clrl max( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxds calls #3,g^cli$get_value blbc r0,220$ pushl #17 ;ign. blanks pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$'222$: clrl max ;return max=10000 if err ; max=0 means 1/32 of disk size. brb 220$221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 too bgtr 222$220$:. 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. $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_list0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERROR2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name. ITMLST=VDV_ITEM_LIST BLBS R0,140$ BRW advdd_EXIT140$:E; Before doing any real work ensure a license exists and exit if not. .if ndf,nolicA calls #0,g^apkcall ;check the license. Exit if none. .endc=; 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: RET2; 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 characteristics 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly? beql 60$+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thus60$:C; note 4 bit only extends if aldef is set. Don't set that just now.* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$& movl max,r0 ;if so use his unless 0 brb 4$65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file size movl cbtct,ucb$l_cbtctr(r5)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 NOW .END ADVDD*[VLT00A.GCE]JFCTL_AXPS2.MAR;5+,W.*/ 4P*)b->0123KPWO*567rę7e89GHJLevax=0step2=1D .TITLE JFCtl ;control JFdriver (fragmentation avoider driver) step2 .IDENT 'V001'evax=0nolic=0";Copyright (c) 1994 Acorn Software;All rights reserved; ; FACILITY:; ;(; This program takes a command of form; favoid/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.;;($def ucb$l_hucbs .blkl 1 ;host ucb table;#; 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 800$def ucb$l_asten .blkl 1 ;ast enable mask store;&$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*>0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;>; Store copy of victim FDT table here for step 2 Alpha driver.&; assumes FDT table is 64+2 longs long>$def ucb$l_myfdt .blkl 70 ;user FDT tbl copy + slop for safety5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chain5$def ucb$l_vict .blkl 1 ;victim ucb, for unmung check2$def ucb$l_mungd .blkl 1 ;munged flag, 1 if numg'd&$def ucb$l_exempt .blkl 4 ;exempt PIDs($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 LONG;; 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 VDFNMiosb: .long 0,0IOSTATUS: .BLKQ 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 1AVTECH_PRODUCT_CODE::+ .ASCII /FAV1/ ; frag avoider license code+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 255 ;length .byte dsc$k_dtype_t ;text .byte 1 ;static .address wrkdatwrkdat: .blkb 20 .blkb 236 .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/6licads: .ascid /INSTALL/ ;add key...needs value.licrqd: .ascid /LICENSE/ ;generate form .EVEN; UCB data areadeafg: .long 06cbtct: .long 1 ;/cbt:n contig best tries every n opens frac: .long 3e min: .long 10Nmax: .long 2000%adflg: .long 0 ;set flg if aldef onlyt#HSTUCB: .LONG 0 ;SERVED UCB ADDRESSI+VDUCB: .LONG 0 ;LOCAL FW/FQ/FD UCB ADDRESSa;o;oERROR: .LONG 2MESS: .LONG SS$_ABORT  .LONG 0$ .PSECT ADVDD_CODE,RD,NOWRT,EXE,LONG1 .ENTRY ADVDD,^Ma clrl adflgh clrl deafg ;not deassigna* movl #1,cbtct ;contig best try every time movl #4,fracx movl #10,min5 movl #2000,maxH:; Before anything else, let user request a license form or; install a key. .if ndf,nolic1- pushab licads ;/install=key commando calls #1,g^cli$present: cmpl r0,#cli$_present ;was switch there? bneq 80$L4 pushab wrk ;ret length longword/ pushab wrkstr ;scratch stringN1 pushab licads ;get value of key movw #255,wrkstrD9 calls #3,g^cli$get_value ;get value of lbnD. on_err fdhostd_Exit ;skip on error; now wrkstr has value2 movw wrk,wrkstr ;set string length pushab wrkstr, calls #1,g^apkkeyadd ;add the key movw #255,wrkstrm80$:2 pushab licrqd ;/license=filename command calls #1,g^cli$present: cmpl r0,#cli$_present ;was switch there? bneq 81$R4 pushab wrk ;ret length longword/ pushab wrkstr ;scratch stringf6 pushab licrqd ;get value of filename movw #255,wrkstr 9 calls #3,g^cli$get_value ;get value of lbnO. on_err fdhostd_Exit ;skip on error; now wrkstr has value2 movw wrk,wrkstr ;set string length pushab wrkstr? calls #1,g^licreq ;print out license request form, movw #255,wrkstr81$:G; Now if user has anything else to add or do, try to do it. We test the;; key lower down.T .endcB pushab deadsD calls #1,g^cli$present cmpl r0,#cli$_present ;there? bneq 100$ incl deafgI100$: ; contig best try : pushab cbtds ;/cbt:nnn contig best try open every n tries calls #1,g^cli$presentt cmpl r0,#cli$_present ;there? bneq 320$ pushab wrk ;ret len pushab wrkstr ;string pushab cbtds  calls #3,g^cli$get_valueu blbc r0,320$l pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab cbtct ;result in "cbtct" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,321$s(322$: movl #1,cbtct ;default val. if err brb 320$c321$:  tstl cbtct ;chk lims bleq 322$. cmpl cbtct,#1000000000 ;max 1,000,000,000 too bgtr 322$320$:t ;/aldefonly pushab adods ;/aldefonly? calls #1,g^cli$presenta cmpl r0,#cli$_present ;there? bneq 10$l incl adflg110$:* pushab frcdsc ;/frac:n (n = 1 to 1000 ok) calls #1,g^cli$presentu cmpl r0,#cli$_present ;there? bneq 20$l pushab wrk ;ret len pushab wrkstr ;string pushab frcdsc ;/frac: desck calls #3,g^cli$get_valuee blbc r0,20$ pushl #17 ;ign. blanksg pushl #4 ;4 byte result pushab frac ;result in "frac" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,21$+22$: movl #4,frac ;return frac=1/4 if error  brb 20$21$: y tstl frac ;chk limso bleq 22$  cmpl frac,#1000 bgtr 22$ 20$:; minA( pushab minds ;/min:nnn min alloc to use calls #1,g^cli$presentd cmpl r0,#cli$_present ;there? bneq 120$ pushab wrk ;ret len pushab wrkstr ;string pushab minds  calls #3,g^cli$get_values blbc r0,120$_ pushl #17 ;ign. blanks  pushl #4 ;4 byte result pushab min ;result in "min" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,121$t(122$: movl #10,min ;return min=10 if err brb 120$ 121$:  tstl min ;chk lims bleq 122$ cmpl min,#1000 ;max 1000 too bgtr 122$120$:d; max clrl maxd( pushab maxds ;/max:nnn max alloc to use calls #1,g^cli$present  cmpl r0,#cli$_present ;there? bneq 220$ pushab wrk ;ret len pushab wrkstr ;string pushab maxdst calls #3,g^cli$get_valuep blbc r0,220$l pushl #17 ;ign. blanksg pushl #4 ;4 byte result pushab max ;result in "max" pushab wrkstr ;string( calls #4,g^ots$cvt_tu_l ;convert to bin blbs r0,221$ '222$: clrl max ;return max=10000 if err. ; max=0 means 1/32 of disk size. brb 220$_221$:  tstl max ;chk lims bleq 222$) cmpl max,#100000000 ;max 100,000,000 toor bgtr 222$220$:T. PUSHAB WRK ;PUSH LONGWORD ADDR FOR RETLENGTH/ PUSHAB VDFNM ;ADDRESS OF DESCRIPTOR TO RETURNl# PUSHAB P1DSC ; GET P1 (FDn: UNIT)a5 CALLS #3,G^CLI$GET_VALUE ;GET VALUE OF NAME TO VDFNMh 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'U# CALLS #3,G^CLI$GET_VALUE ; GET FNME 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 SOB*; 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.E ITMLST=DEV_ITEM_LIST BLBS R0,40$ BRW advdd_EXIT 40$:290$:M/; MUST HAVE ASSIGNMENT TO VD: UNIT IN ANY CASE.n $getdviw_s -1 devnam=vdfnm,itmlst=vdv_item_list.0 $assign_s devnam=vdv_buf_desc,chan=vdchnN blbs r0,2295$ ;if we got the chnl, go on. Else try orig name $ASSIGN_S -( DEVNAM=VDFNM,- ; GET CHANNEL FOR VDn: CHAN=VDCHN' ON_ERR ADVDD_EXIT ; SKIP OUT IF ERROR/2295$: $GETDVI_S -/ CHAN=vdchn,- ; Command line has device name.E ITMLST=VDV_ITEM_LIST BLBS R0,140$  BRW advdd_EXITc140$:cE; Before doing any real work ensure a license exists and exit if not.E .if ndf,noliceA calls #0,g^apkcall ;check the license. Exit if none.. .endcD=; Here do the real work in kernel mode, having now the device /; descriptions and channels to the devces even!l. 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$:r$; ERROR RETURN ... CLOSE FAB & LEAVE1 $PUTMSG_S MSGVEC=ERROR ;Pump out error messageo; deassign logic307$: movl #2,bufg ;unmung fcn= $qiow_s chan=vdchn,efn=#4,func=#,iosb=iosb,-a p1=bufg,p2=#buszv<; after unbashing the current host, take the JF unit offline ; $CMKRNL_S -; ROUTIN=BASHUCB,ARGLST=K_ARG $DASSGN_S CHAN=VDCHN ret300$:PB; 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,-R 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:N RET2; BASHUCB - AREA TO MESS UP UCB WITH OUR FILE DATA; BEWARE BEWARE BEWARE+; runs in KERNEL mode ... HAS to be right.d-; Saves lots of registers so they're free...03 .ENTRY BASHUCB,^M; TAKEN LOOSELY FROM ZERO.MAR5 .if ndf,vms$v5:) MOVL G^SCH$GL_CURPCB,R4 ;;; NEED OUR PCB; .iff 0 MOVL G^CTL$GL_PCB,R4 ;;; NEED OUR PCB (VMS V5) .endc clrl hstucb) JSB G^SCH$IOLOCKW ;;; LOCK I/O DATABASE1& tstl deafg ;/deas needs no 2nd assign bneq 90$a9 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$:e; 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 R11 BLBS R0,160$ BRW BSH_XIT160$:e movl r1,vducb ;;; store vd ucb, movl r1,r5 ;use r5 for local ucb (JF dvc) beql 166$ ;fail if no ucb...R; BUGGER THE UCB,; ASSUMES FILE LBN AND SIZE ALREADY RECORDEDC; ALSO ASSUMES THAT ZERO LBN OR SIZE MEANS THIS ENTRY NEVER CALLED.DA; (REALLY ONLY WORRY ABOUT ZERO SIZE; IF WE OVERMAP A REAL DEVICE9%; THEN ZERO INITIAL LBN COULD BE OK.)n;d@; CHECK REF COUNT FIRST... ONLY CAN GET AWAY WITH THIS ON DEVICE; NOBODY'S USING...mA; .. fake this since device may have count messed by advd somehowf#; but will be allocated if mounted. ; ... for now ... 554$:h6; 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 inL ; 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 characteristics will be the ?; same for the local device and the MSCP served remote one (ando?; in fact they are not all alike!) but at least they had betters:; 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.?n& 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 onlinee* bicl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff 5 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 & leavet1176$: movl #ss$_drverr,r0 brw bsh_xit1164$:# cmpb ucb$b_devclass(r11),#dc$_diskn$ bneq 1176$ ;if not disk exit now.3 cmpl ucb$l_icsign(r5),#magic ;got right magic no.?d& bneq 1176$ ;if not then not JFdriverA; Be sure the unit is not online yet. If it is, someone else wills5; 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 onlines bneq 166$ .ifft5 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 match$G movl ucb$l_maxbcnt(r5),ucb$l_maxbcnt(r11) ;;;store max bytes as a word0=; Now get on with the tricky part, replacing the DDT. Do this/E; at device IPL so we have reasonable certainty nobody will mess withb?; these structures until we get them all put into proper order.0I; The DDT structure is 64 bytes long, so grab a block of pool of 64 bytesl); size and copy the existing DDT into it.iE; (it is possible to save the old ~FAV020.AW>[VLT00A.GCE]JFCTL_AXPS2.MAR;5P* 'address if the conditional is used)2 .if df,evax5 bisl #ucb$m_online,ucb$l_sts(r5) ;set jf unit online;* bisl #ucb$m_valid,ucb$l_sts(r5) ; & valid .iff,5 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)6 movl cbtct,ucb$l_cbtini(r5) ;set CBT opens every time2 movl #34,ucb$l_ctlflgs(r5) ;set to look at modify tstl adflg ;/aldefonly?# beql 60$e+ bisl #4,ucb$l_ctlflgs(r5) ;set driver thusr60$:C; note 4 bit only extends if aldef is set. Don't set that just now.$* movl min,ucb$l_minxt(r5) ;min extent = 10 movl ucb$l_maxblock(r11),r0 tstl max ;user set max? beql 65$1& movl max,r0 ;if so use his unless 0 brb 4$65$:2 ashl #-5,r0,r0 ; default max = 1/32 of disk size" cmpl r0,#2000 ;but 2000 at least bgtr 4$2 movl #2000,r0 ;max=0 => 1/32 of disksize or 20004$:s$ movl r0,ucb$l_maxxt(r5) ;max extent5 movl frac,ucb$l_frac(r5) ;extend by 1/4 of file size4 movl cbtct,ucb$l_cbtctr(r5)1000$:165$:p MOVL #SS$_NORMAL,R0BSH_XIT: PUSHL R0u7 JSB G^SCH$IOUNLOCK ;;; UNLOCK I/O DATABASE (DROP IPL)n POPL R0 ;;; REMEMBER R0 RET ;;; BACK TO USER MODE NOW .END ADVDD*[VLT00A.GCE]JFDRIVER.LNK;3+,[./ 47l->0123KPWO5 6=ȗ7Oe89GHJ/$LINK/NATIVE/BPAGE=14/SECTION/NOTRACE/NODEMAND-7/SHARE=JFDRIVER/SYSEXE=SELECT/NOSYSSHR jfdriver.opt/opt*[VLT00A.GCE]JFDRIVER.MAR;18+,\./ 4TJ->0123KPWO56Ѵf7̺1e89GHJr .library /sys$share:lib/ $wcbdef8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50EVAX = 1.iff ;EVAX = 0.endc .if df,evaxalpha=1 bigpage=1addressbits=32B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0) .endc2 .if ndf,step2 ;use vax or step1 code in here only: .TITLE JFDRiver ;skeleton driver implementing ucb linkage .IDENT 'V01b'"; Copyright 1993 Glenn C. Everhart; All rights reserved; Author: Glenn C. Everhart; ;evax = 1D; Above automates defining "evax". Also define "step2" where needed. .if ndf,evax .macro driver_data .PSECT $$$105_PROLOGUE .endm .macro driver_code .PSECT $$$115_DRIVER .endm .endc; above for Alpha only.;5; Function: Implement frag avoider for generic disks. ;x$$$dt=0;;vms$$v6=0 ;add forvms v6 def'nvms$v5=1(; define v5$picky also for SMP operation v5$picky=1& .SBTTL EXTERNAL AND LOCAL DEFINITIONS; ; EXTERNAL SYMBOLS;  .library /SYS$SHARE:LIB/*; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK# $DYNDEF ;define dynamic data types $DCDEF ;DEFINE DEVICE CLASS% $DDBDEF ;DEFINE DEVICE DATA BLOCK* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODES$ $DDTDEF ; DEFINE DISPATCH TBL... $ptedef $vadef& $IRPDEF ;DEFINE I/O REQUEST PACKET $irpedef& $PRDEF ;DEFINE PROCESSOR REGISTERS& $SSDEF ;DEFINE SYSTEM STATUS CODES& $UCBDEF ;DEFINE UNIT CONTROL BLOCK .if df,step2 $fdt_contextdef .endc $sbdef ; system blk offsets $psldef $prdef $acldef$ $rsndef ;define resource numbers $acedef* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $pcbdef $statedef $jibdef $acbdef $vcbdef $arbdef $wcbdef $ccbdef $fcbdef $phddef< $RABDEF ; RAB structure defs7 $RMSDEF ; RMS constants; defs for acl hacking $fibdef $atrdefp1=0 ; first qio paramp2=4p3=8p4=12p5=16p6=20 ;6th qio param offsets# .IF DF,VMS$V5 ;VMS V5 + LATER ONLY $SPLCODDEF $cpudef .ENDC; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS; ( $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. .if df,step2Fmagic=^xF024F000 + ddt$k_length + <256*>Hp.magic=^xF024F000 + ddt$k_length + <256*> .endc0$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. .if ndf,step2)$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" fcn .iff,$def ucb$l_myfdt .blkl 70 ;copy of orig. fdt .endc0$def ucb$l_vict .blkl 1 ;victim ucb for checking($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_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 JF_UNITS=100 VJF$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 .if df,evax .if ndf,step2 DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAME .iff ;step2 DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAME .endc ;step2 .iff DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;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 TRACKe9 DPT_STORE UCB,UCB$W_CYLINDERS,W,16 ;NUMBER OF CYLINDERS<* DPT_STORE UCB,UCB$B_DIPL,B,21 ;DEVICE IPL .if ndf,evaxf7 DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNTWF DPT_STORE UCB,UCB$W_DEVSTS,W,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;...= .iffeF DPT_STORE UCB,UCB$L_DEVSTS,L,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;...r .endc;d?; don't mess with LBN; leave alone so it's easier to hack on...G;n6 DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUESQ; DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,VR_INT ;INTERRUPT SERVICE ROUTINE ADDRESSw .if ndf,evaxC DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,- ;CONTROLLER INIT ADDRESSm D,JF_ctrl_INIT ;...= DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS  D,JF_unit_INIT ;... .endc0 DPT_STORE DDB,DDB$L_DDT,D,JF$DDT ;DDT ADDRESS .if ndf,evaxmB DPT_STORE UCB,UCB$L_UNIQID,D,dpt$tab ;store DPT address .iffNG DPT_STORE UCB,UCB$L_UNIQID,D,evms$driver_dpt ;store DPT addressAA .endc ; (change "XX" to device J ; mnemonic correct values)P DPT_STORE UCB,UCB$L_ICSIGN,L,magic ; Add unique pattern (that mightM ; bring back some memories inD? ; DOS-11 users) C; HISTORICAL NOTE: under DOS-11, one would get F012 and F024 errorsE@; 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!C- DPT_STORE END ;END OF INITIALIZATION TABLE; ; DRIVER DISPATCH TABLEf; >; THE DDT LISTS ENTRY POINTS FOR DRIVER SUBROUTINES WHICH ARE"; CALLED BY THE OPERATING SYSTEM.; .if df,evax DDTAB - ;DDT CREATION MACRO DEVNAM=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINEf0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JF_CTRL_INIT,-E UNITINIT=JF_UNIT_INIT,- -; CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICEf$; REGDMP=0,- ;REGISTER DUMP ROUTINE$; DIAGBF=0,- ;BYTES IN DIAG BUFFER ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER .iffR DDTAB - ;DDT CREATION MACRO DEVNAM=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINEI0 FUNCTB=JF_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 TABLEu; 6; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.; ; code chaining data:t@chnflg: .long 1 ;chain or use our FDT chain flag...use ours if 0myonoff:3fdtonoff: .long 0 ;switch my fdt stuff off if non-0nM .ascii /flag/ ;define your own unique flag here; just leave it 4 bytes long!e$ .long 0 ;fdt tbl from before patchfdt_chn = -12 fdt_prev = -4o fdt_idnt = -8 JF_FUNCTABLE:newfdt:e .if ndf,step2# FUNCTAB ,- ;LIST LEGAL FUNCTIONSu ; MOUNT VOLUMEq#; no-op phys I/O for a test here... ! FUNCTAB ,- ;BUFFERED FUNCTIONSs ; MOUNT VOLUMEh?; io$_format + modifiers (e.g. io$_format+128) as function codel>; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed.t) functab JF_format,- ;point to host disk0 ;t$; First our very own filter routines;A; Following FDT function should cover every function in the local-B; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need.t Functab fdtswitch,-' l 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 ifk; you do nothing with them...DK; 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!)Amymfy: FuncTab MFYFilt,-( ;modify filter (e.g. extend) myfdtend=.C; Note that if we want to allow numerous disk drivers to be patchedx<; by this one there is not a unique path to the original fdt=; routine. Therefore use a UCB cell for the patch, not a cellD9; 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.;I3; Following contains all legal functions in mask...ZA; That way it can transfer all control to a "previous" FDT chain..mybak: FuncTab fdttoorig,- WRITEHEAD,- ;WRITE HEADER AND DATA= READHEAD,- ;READ HEADER AND DATA,D WRITECHECKH,- ;WRITE CHECK HEADER AND DATA6 STARTSPNDL,- ;START SPINDLE? WRITETRACKD,- ;WRITE TRACK DESCRIPTORn> READTRACKD,- ;READ TRACK DESCRIPTOR> COPYSHAD,- ; Do shadow set copies$ MODIFY,- ; MODIFY FILE ATTRIBUTES MOUNT> ; MOUNT VOLUMELL; 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 ourselvesG$; we may never get to these BTW...)( FUNCTAB +ACP$READBLK,- ;READ FUNCTIONS# C* FUNCTAB +ACP$WRITEBLK,- ;WRITE FUNCTIONS% ) FUNCTAB +ACP$ACCESS,- ;ACCESS FUNCTIONS.2 D, FUNCTAB +ACP$DEACCESS,- ;DEACCESS FUNCTION r) FUNCTAB +ACP$MODIFY,- ;MODIFY FUNCTIONS ' & FUNCTAB +ACP$MOUNT,- ;MOUNT FUNCTION ; MOUNT VOLUMEC FUNCTAB +EXE$LCLDSKVALID,- ;LOCAL DISK VALID FUNCTIONSs6 ;PACK ACKNOWLEDGEa3 FUNCTAB +EXE$ZEROPARM,- ;ZERO PARAMETER FUNCTIONSs ; AVAILABLE 0 FUNCTAB +EXE$ONEPARM,- ;ONE PARAMETER FUNCTION * FUNCTAB +EXE$SENSEMODE,- ;SENSE FUNCTIONS' Y' FUNCTAB +EXE$SETCHAR,- ;SET FUNCTIONS# T .long -1,-1 ; catch-all mask%fcnca: .long 0 ;fill in in unit init .iff ;step2 FDT_INI FDT_BUF, - ; BUFFERED functions ; MOUNT VOLUMEC myfdtstart:?; io$_format + modifiers (e.g. io$_format+128) as function codeD>; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed. ) fdt_act JF_format,- ;point to host disku ;y$; First our very own filter routines;sA; Following FDT function should cover every function in the localeB; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need. 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 ifWI; you don't want to. The FDT switch logic is a waste of time and space if; you do nothing with them...IK; They don't actually do anything here, but could be added to. Throw in oneEF; 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!)- fdt_act MFYFilt,-( ;modify filter (e.g. extend) myfdtend=. .endc ;step2 driver_code .if df,evaxfcae: .jsb_entry .iffCfcae:  .endc+ movzwl #SS$_BADPARAM,r0 ;illegal parameterC clrl r1 jmp g^exe$abortio ; fdtswitch -EA; Based on state of "myonoff" variable either enable or disableD; 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 theO; FDT processing of a driver.P .if ndf,step2 .if df,evax!fdtswitch: .jsb_entry output=E .iffT fdtswitch: .endc tstl fdtonoff ;global on/off bneq 1$ rsb ;go to next FDT if nullM51$: addl2 #,r8 ;pass our fdt codes rsb ;return to std ; fdttoorig -A; This entry continues FDT processing at the point after the newEC; entries by returning to the original FDT chain at the point whereID; 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 thea>; DEC FDT entries because in this way multiple FDT patches canA; coexist, as would be impossible if this trick were not used. Ase'; can be seen, its overhead is minimal.DA; The old FDT location is kept in the UCB for our device because D; 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=u .ifff fdttoorig: .endc?; As a performance feature, use a switch to let us just use thesA; FDT chain here rather than continuing an old one. This needs toe@; 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 chnflgd); beql 2$ ;just continue if chnflg is 0e pushl r0T=; (this routine gets called a fair bit and if GETJFUCB can ben!; called less, things speed up.)l/ jsb getJFucb ;get UCB for JF unit from stolenP ;oney 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 pointh8 addl2 #<16-12>,r8 ;pass the 2 entry masksD1$: ;back up since sysqioreq adds 12 popl r0F2$: rsb ;off to the previous FDT routines. .endc ;step2s;lH; GETJFUCB - Find JF: 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.MB; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. .if df,evax getJFucb: .jsb_entry output= .iff, getJFucb:A .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 knows?; it is in an intercept driver. Also assumes R11 may be used as D; 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" ; is defined.S-; Entry: R5 - victim device UCB addresse0; Exit: R11 - intercept driver UCB address chk.err=0 F movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!! .if ndf,evaxaD movab dpt$tab,r11 ;magic pattern is DPT addr. .iff  movab evms$driver_dpt,r11 .endc9; lock this section with forklock so we can safely remove 3; entries at fork also. Use victim device forklock. 1; (don't preserve r0 since we clobber it anyway.) = forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NO 42$: cmpl (r10),R11= ;this our own driver?A@; beql 1$ ;if eql yes, end search; <; 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.;A) 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 UCBE7; brb 4$ ; note in this layout we can comment this out.S4$:O? forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOR%; NOW clobber r0 and put things back. movl r11,r0; popr #^m- popl r11F& popl r10 ;supposedly faster than popr rsbA; Make very sure this DDT is inside a UCB bashed according to ourd=; specs. The "p.magic" number reflects some version info too. 3; If this is not so, not much sense searching more..95$: cmpl (r10),#p.magic C bneq 3$ ;exit if this is nonstd bashC+; follow DDT block chain to next saved DDT.N5 movl (r10),r10PI ;point R10 at the next DDT in the ;chainIF bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againC;1$:3$:A$ clrl r11 ;return 0 if nothing found brb 4$;r*; Few macros for long distance branches...;  .macro beqlw lbl,?lbl2R bneq lbl2 brw lbllbl2:E .endm .macro bneqw lbl,?lbl2 beql lbl2 brw lbllbl2:R .endm .macro bleqw lbl,?lbl2, bgtr lbl2 brw lbllbl2:  .endm .macro bgeqw lbl,?lbl2 blss lbl2 brw lbllbl2:L .endm); allocate does not zero its result area. E; This macro makes it easy to zero an allocated area before using it.I@; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".E .macro zapz addr,size3 pushr #^m ;save regs from movc5P movc5 #0,addr,#0,size,addr>2 popr #^m ;save regs from movc5 .endm;N .SBTTL Our FDT Filter RoutinesNPopOut:$ popr #^mpors:O .if df,step2RG; Here need to return to the "standard" FDT routine. Do so by computing+H; the address in the FDT table of the normal host and calling that, then ; returning.N EXTZV #IRP$V_FCODE,#IRP$S_FCODE,IRP$L_FUNC(R3),R1 ; GET FCN CODE pushr #^m4 jsb getJFucb ;find JF UCB checking for extra links tstl r0 ;got it?N bgeq 199$ ;if not skip out;7 movab ucb$l_oldfdt(r0),r7 ;get address of previous FDTA bgeq 199$ ;ensure ok...!; movl ucb$l_ddt(r5),r7 ;find FDTSK; Here rely on the fact that we got here via our modified FDT call and thatS:; the orig. FDT is stored just a bit past the current one.<; movl (r7),r7 ;point at orig. FDT0 addl2 #8,r7 ;point at one of 64 fdt addresses1 movl (r7)[r1],r8 ;r7 is desired routine addressF!;now call the "official" FDT codeV pushl r6 ;ccb pushl r5 ;ucb pushl r4 ;pcb pushl r3 ;irp+ calls #4,(r8) ;Call the original routinei popr #^m+; Now return as the original routine would.t ret199$:t popr #^m movl #16,r0 call_abortio,do_ret=yes .iffu rsb .endc .if df,evax .if ndf,step2<mfyfilt: .jsb_entry ;filter on MODIFY requests (e.g. extend) .iff ;step2Cmfyfilt: $driver_fdt_entry ;filter on MODIFY requests (e.g. extend) .endc ;step2n .iffy1mfyfilt: ;filter on MODIFY requests (e.g. extend)e .endc.; First do some preliminary checks for sanity.$; 1. Channel must NOT be kernel mode; 2. Not a movefile % tstl r6 ;is there a CCB (must be +)  bleq pors ;if not skip out) cmpb ccb$b_amod(r6),#1 ;knl mode access? ( beql pors ;leave knl mode chnls alone!;funct modifiers are bits 6-15; this is hex ffc0?; Normal io$_modify should have no modifiers, so if it has it'so'; for something else; leave that alone. .if ndf,evaxi@ bitw #^xDFC0,irp$w_func(r3) ;this a movefile or other modifier? .ifft@ bitw #^xDFC0,irp$l_func(r3) ;this a movefile or other modifier? .endc" bneq pors ;if so ignore it here. pushr #^m>; original r5 now at 4(sp). Must get that to continue the ops.! jsb getJFucb ;find JFdriver ucbi tstl r0 bgeqw popoute7 movl r5,ucb$l_backlk(r0) ;save link'd ucb in ours too.T! movl r0,r5 ;point R5 at JF UCB * bitl i^#2,ucb$l_ctlflgs(r5) ;look at mfy? bneq 171$ ;if neq yes9; (test later will see about space control if doing this)701$:f popr #^m brw porsc171$:_J; here we can modify request fields in the FIB the user supplies to reduceD; fragmentation...e.g. set fib$l_exsz bigger or set fib$m_alconb bit>; in fib$w_exctl IFF fib$m_alcon is not set & set fib$m_aldef.;i .if ndf,evaxn movl p1(ap),r0 ;get fib .iffh movl irp$l_qio_p1(r3),r0n .endc ifnord #4,4(r0),701$n" movl 4(r0),r0 ;...from descriptor ifnor~FAV020.A\>LT00A.GCE]JFDRIVER.MAR;18T|:d #4,fib$w_exctl(r0),701$d6 bitw #fib$m_extend,fib$w_exctl(r0) ;extending at all?, beqlw 162$ ;if no extend, leave fib aloneI; Because contiguous best try allocation flushes the entire extend cache, E; it can cause a tremendous performance hit. Therefore allow it to belG; separately switched so that the benefits of longer extents can be hadhI; if desired without forcing this flushing every time a file is extended. L bitl i^#32,ucb$l_ctlflgs(r5) ;separate control for setting contig best try beql 1$(; leave contig and contig-best-try alone@ bitw #,fib$w_exctl(r0) ;contig alloc?# bneq 1$ ;if contig leave it alonet!; allow this on every nth extend.hC; This will allow periodic flushes of the extent cache but will letaK; it not be made totally useless. By flushing the extent cache periodicallyi4; we can try to reduce the fragmentation it induces.,; if bit 16384 is not set, do not set aldef.. bitl i^#16384,ucb$l_ctlflgs(r5) ;allow aldef? beql 704$? bisw #,fib$w_exctl(r0) ;set to use vol default if 704$: ;bigger than program's" decl ucb$l_cbtctr(r5) ;count down' bgtr 1$ ;and if >0 don't set cbt yetn; movl ucb$l_cbtini(r5),ucb$l_cbtctr(r5) ;else reset counter?? bisw #,fib$w_exctl(r0) ;else turn on contig besti ;try and turn on use of! ;system default extension ift! ;larger than program default 1$: P; One can add code to check file size and bump extension by more than default ifT; it's big (for example, extend by 10% of its' size, not by a few blocks at a time). pushr #^m2 bitw #fib$m_alcon,fib$w_exctl(r0) ;contig extend?% bneq 222$ ; if so don't touch size.) movl ccb$l_wind(r6),r7 ;get window blocko bgeq 222$ ;guards/ movl wcb$l_fcb(r7),r8 ;and file control blkock. bgeq 222$ ;guardu) movl fcb$l_filesize(r8),r6 ;get filesizeb beql 222$;lD; The fraction starts at 1/4, but can be anywhere from 1/1 to 1/10007 divl2 ucb$l_frac(r5),r6 ;get 1/4 of current size or sos$ incl r6 ;plus one...for good luck ;fncymod=1 ;chop this if desired? cmpl r6,ucb$l_maxxt(r5) ;extending over max (nominally 120000)c bleq 1222$l9 movl ucb$l_maxxt(r5),r6 ;clamp to max what we're forcingt1222$:9 cmpl r6,ucb$l_minxt(r5) ;if less than 10 leave alone tooa bgeq 1223$e4 movl ucb$l_minxt(r5),r6 ;at least grab this minimum1223$:0; never try to grab over1/8 of total free space.8 movl ucb$l_backlk(r5),r8 ;get host ucb (set just above) bgeq 222$ ;(better be there)h$ movl ucb$l_vcb(r8),r8 ;point at vcb bgeq 222$& movl vcb$l_free(r8),r8 ;no. blks free ashl #-3,r8,r8 ;free space /8d% cmpl r6,r8 ;extent over freespc/8? " bleq 3223$ ;if not all still ok# movl r8,r6 ;else clamp to free/8m3223$:8 cmpl r6,fib$l_exsz(r0) ;make sure we're increasing size2 bleq 222$ ;if less than user wants, leave aloneH; if 4 bit is clear, allow size ctl always. Otherwise only if aldef set. bitl i^#4,ucb$l_ctlflgs(r5) beql 2222$(? bitw #,fib$w_exctl(r0) ;set to use vol default if)1 beql 222$ ;if aldef NOT set, leave size alone. 2222$:3 movl r6,fib$l_exsz(r0) ;fill in as new extend sizef222$:s popr #^mo162$:u popr #^m movl #1,r0n brw porst;++o;a5; JF_format - bash host disk tables to point at ours.o;.F; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),sB; 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 is ; software enabled. ;eD; This routine does virtually no checking, so the parameters must be ; correct.;o ; Inputs:c>; p1 - pointer to buffer. The buffer has the following format:=; longword 0 - (was hlbn) - flag for function. 1 to bash1.; 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;l;D; p2 - size of the above bufferN;-- .if df,evax .if ndf,step2JF_format: .jsb_entry  .iff JF_format: $driver_fdt_entry .endc ;step2h .iffD JF_format: .endc .iif df,x$$$dt,jsb g^ini$brk .if df,evax< bicl3 #io$m_fcode,irp$l_func(r3),r0 ;mask off function code .iff < bicw3 #io$m_fcode,irp$w_func(r3),r0 ;mask off function code .endc) bneq 20$ ;branch if modifiers, specialn);thus, normal io$_format will do nothing.R rsb ;regular processingE100$:m0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parameter2 clrl r1 .if ndf,step2 jmp g^exe$abortio .iff call_abortio do_ret=yes .endc20$: .if ndf,evaxo movl p1(ap),r0 ;buffer address" movl p2(ap),r1 ;length of buffer .iffa movl irp$l_qio_p1(r3),r0s movl irp$l_qio_p2(r3),r1o .endc: jsb g^exe$writechk ;read access? doesn't return on error .iif df,x$$$dt,jsb g^ini$brk3:; clrl irp$l_bcnt(r3) ;paranoia, don't need to do this...1 pushr #^m5 .if ndf,evax.$ movl p1(ap),r0 ;get buffer address .iffp movl irp$l_qio_p1(r3),r0d .endc movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegaln# cmpl r7,#2 ;3 and up illegal too bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored)V bleq 70$$0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JF_host_descr+4(r5)t .if ndf,evaxt5 subl3 #8,p2(ap),- ;set length of name in descriptor( ucb$l_JF_host_descr(r5)i .iffA? subl3 #8,irp$l_qio_p2(r3),- ;set length of name in descriptor ucb$l_JF_host_descr(r5)t .endc bleq 100$ ;bad length4 movab ucb$l_JF_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host devicel .iif df,x$$$dt,jsb g^ini$brkF! blbs r0,30$ ;branch on success ; fail the associate...r0 popr #^m= movzwl #ss$_nosuchdev+2,r0 ;make an error, usually a warningp clrl r1 .if ndf,step2 jmp g^exe$abortio .ifft call_abortio do_ret=yes .endc30$: ;found the device; r1 is target ucb address...t$; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?b bneq 31$ ;if neq it's unmung jsb mung ;go mung target...l 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?) 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 online 5; movl ucb$l_irp(r5),r3 ;restore r3, neatness countso0 popr #^m! movzwl #ss$_normal,r0 ;successn .if ndf,step2' jmp g^exe$finishioc ;wrap things up.  .iffi call_finishioc do_ret=yes .endc .if df,evaxmung: .jsb_entry .iffemung:  .endc=; steal DDT from host. Assumes that the intercept UCB addressfB; 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 is C; pointed to by R11. All registers are preserved explicitly so thataB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingtG; went wrong so the bash did NOT occur. This generally means some otheroF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so the$3; unique ID field and magic number are set already.e6 movab fcae,fcnca ;ensure final FDT entry is filled in7 pushr #^mI5; Acquire victim's fork lock to synchronize all this.n7 movl #ss$_normal,r0 ;assume successi" 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 originalfF movl ucb$l_ddb(r11),r9 ;the ddb$l_ddt is the originalG cmpl ddb$l_ddt(r9),r10 ;bashing driver the first time?i3 beql 1$ ;if eql yestG; driver was bashed already. Check that the current basher followed the_); standard. Then continue if it looks OK.c9 cmpl (r10),#p.magicyF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellc: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too)f2$:n<; 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 one;1$:fD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallyb3$: 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)t; 1; Here make whatever mods to the DDT you need to..;p8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers) H movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JF_functable+fdt_prev ;save old FDT ucb address: movl ddt$l_fdt(r10),ucb$l_oldfdt(r5) ;save orig. fdt addrK movl ucb$l_uniqid(r5),JF_functable+fdt_idnt ;save unique ID alsou9; copy legal and buffered entry masks of original driver. A; HOWEVER, set mask for format entry to be nonbuffered here since ; we deal with it. pushr #^m0 .if ndf,step2; movab ucb$l_fdtlgl(r5),r9 ;our function table dummy in UCBt+ movl ddt$l_fdt(r10),r7 ;victim's FDT tablehC; We want all functions legal in the victim's FDT table to be legala; here.h& 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 addresst@; 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. .iff ;step2: movab ucb$l_myfdt(r5),r9 ;our function table dummy in UCB+ movl ddt$l_fdt(r10),r7 ;victim's FDT tablesC; We want all functions legal in the victim's FDT table to be legalr; here. 6 pushr #^m ;preserve regs from movc- movl #<68*4>,r0 ;byte count of a step 2 FDTc* movc3 r0,(r7),(r9) ;copy his FDT to ours5 popr #^m ;preserve regs from movch6; Now copy in our modify & back-to-original FDT cells.A; We will do this in our FDT table by having FDT definitions only ?; for those functions in JFdriver that we service locally. Thus :; all entry cells for the rest will point in the JF FDT to; exe$illiofunc.0 movab g^exe$illiofunc,r8 ;get the magic address/ movab JF_functable,r10 ;r10 becomes JF FDT tbln# addl2 #8,r10 ;point at functionsi addl2 #8,r9 ;his new FDT... movl #64,r11 ;64 functions075$: cmpl (r10),r8 ;this function hadled in JF? beql 76$ ;if eql no, skip7 movl (r10),(r9) ;if we do it point his fdt at our fcn J; (NOTE: our functions MUST therefore call the previous FDT's functions at; end of their processing.)'76$: cmpl (r10)+,(r9)+ ;pass the entry # sobgtr r11,75$ ;do all functionsC; JFdriver FDT table. Last entry goes to user's original FDT chain.e;E; Thus we simply insert our FDT processing ahead of normal stuff, butt4; all fcn msks & functions will work for any driver. .endc ;step2f popr #^m .if ndf,step2D movab ucb$l_fdtlgl(r5),ddt$l_fdt(r8) ;point at our FDT table .ifffC movab ucb$l_myfdt(r5),ddt$l_fdt(r8) ;point at our FDT tablet .endc8 clrl myonoff ;turn my FDTs on;EE; Finally clobber the victim device's DDT pointer to point to our neww; one. .iif df, evax, evax_imb/ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)o .iif df, evax, evax_imb@; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing inrC; the example here causes the intercept driver's FDT routines to becC; used ahead of whatever was in the original driver's FDTs. BecauseiE; 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 locko100$:o6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YES7 popr #^ml rsb .if df,evaxumung: .jsb_entryf .ifffumung: .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: addressrE; is the one being sought. ("Current driver" here means the intercept- ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCB 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 later .if ndf,evaxeC movab DPT$tab,r11 ;magic pattern is DPT addr.e .iff  movab evms$driver_dpt,r11 .endc9; lock this section with forklock so we can safely removem3; entries at fork also. Use victim device forklock.h> forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=YES42$: cmpl (r10),R11= ;this our own driver?i? beql 1$ ;if eql yes, end searchn .if df,chk.err9 cmpl (r10),#p.magicuD bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.g5 movl (r10),r10fI ;point R10 at the next DDT in theA. ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againo1$:aA; At this point R10 contains the DDT address within the interceptsF; 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-fixuph/; we were intercepted. Fix up next guy in line.rL movl (r10),r11 ;point at interceptorS movl (r10),(r11)73$:9E; if we intercepted someone, fix up our intercepted victim to skip by ; us also.I movl (r10),r2 ;did we intercept-9 ;original driver?sA 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$:d>; Here remove FDT entries from the list if they were modified.=; This needs a scan of the FDT chain starting at the victim'snB; ddt$l_fdt pointer and skipping around any entry that has address; JF_functable:uB; 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!!!; movl ddt$l_fdt(r0),r1 ;start of FDT chainlA movab JF_functable,r2 ;address of our FDT tabled clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucb D; Also set the JF 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)  .iff / bicw #,ucb$w_sts(r4)  .endcA6$: cmpl r1,r2 ;current fdt point at us?sA beql 7$ ;if eql yes, fix up chainD@ 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 ucbUA;;;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.57$:u*;r3 is 0 or fdt pointing to our block next;r1 points at our fdt blocklD tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to dob movl fdt_prev(r1),r4o bgeq 17$v. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4 blss 18$ tstl (sp)+s 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.a8$:t;vF; 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 it ? movl (r10),ucb$l_ddt(r5) 4$:e@ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^maK ;copy our prior DDT ptr to next one1 rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINEb; ++; 2; JF_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:y; noop ; INPUTS:d; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:a; - AT SYSTEM STARTUPi; - DURING DRIVER LOADING (; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;-- .if df,evax .if ndf,step27JF_ctrl_INIT: .jsb_entry ;JF CONTROLLER INITIALIZATIONr .iff>$JF_ctrl_INIT: $driver_ctrlinit_entry .endc .iff&,JF_ctrl_INIT: ;JF CONTROLLER INITIALIZATION .endc*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r0u .iif ndf,step2,RSB ;RETURN .iif df,step2,ret- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATIONe; ; INPUTS:x; R4 => controller CSR (dummy) ; R5 => UCBt;m .if ndf,evaxm ctrl_REINIT: .iff ctrl_REINIT: .jsb_entry .endc .iif ndf,step2,RSB ;RETURN .iif df,step2,ret# .SBTTL UNIT INITIALIZATION ROUTINEn;++5; ,; JF_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:v; $; THIS ROUTINE SETS THE JF: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUPu; - DURING DRIVER LOADINGr(; - DURING RECOVERY FROM POWER FAILURE; ; INPUTS:b; 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.; ;--y .if df,evax .if ndf,step22JF_unit_INIT: .jsb_entry ;JF UNIT INITIALIZATION .iffc$JF_unit_INIT: $driver_unitinit_entry .endc .iff3JF_unit_INIT:; .jsb_entry ;JF UNIT INITIALIZATIONp .endc. movab fcae,fcnca ; set up catch-all final FDT>; Don't set unit online here. Priv'd task that assigns JF unit<; to a file does this to ensure only assigned JFn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JF: data buffersJF_bufsiz=127*512f9 movl #JF_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers to 8kv9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASSrC; NOTE: we may want to set this as something other than an RX class>; 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!!!)c9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JF G; (note the id might be wrong but is attempt to get it.) (used only foro; MSCP serving.)> MOVB #DT$_FD1,UCB$B_DEVTYPE(R5) ;Make it foreign disk type 1/; (dt$_rp06 works but may confuse analyze/disk)fG;;; NOTE: changed from fd1 type so MSCP will know it's a local disk andi8;;; attempt no weird jiggery-pokery with the JF: device.G; MSCP may still refuse to do a foreign drive too; jiggery-pokery laterr'; to test if there's occasion to do so.i; Set up crc polynomialc6; clrl chnflg ;initially set to use our chain of FDTs movl #1,chnflga movl #1,r0d .iif ndf,step2,RSB ;RETURN .iif df,step2,ret .SBTTL START I/O ROUTINE,;++,; ; JF_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION: ; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTo; PACKET HAS BEEN DEQUEUED.; ; INPUTS:t; ); R3 - IRP ADDRESS (I/O REQUEST PACKET)d); R5 - UCB ADDRESS (UNIT CONTROL BLOCK) :; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFEREDm/; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKSt; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;-- .if df,evax .if ndf,step2;JF_STARTIO: .jsb_entry output= ;START I/O OPERATIONi .iff_JF_STARTIO: $driver_start_entry  .endc .iff #JF_STARTIO: ;START I/O OPERATION  .endc; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8rD; CLRQ UCB$Q_JF_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION 3 bbs #ucb$v_online,- ; if online set software valido ucb$l_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalida' brw resetxfr ; reset byte count & exit 210$: ;; Unless we use this entry, we want to junk any calls here. + brb 216$ ;just always say invalid volume. A; Get here for other start-io entries if the virtual disk code isf$; commented out also, as it must be.8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKTiC .iif ndf,evax,MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNTa ; BRW FUNCXTFUNCXT: ;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB .if df,step2 , REQCOM environment=call ; COMPLETE REQUEST .iff  REQCOM  .endc .if ndf,evax-!FATALERR: ;UNRECOVERABLE ERRORu2 MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUS brb funcxt>; PWRFAIL: ;POWER FAILURE: BICW #UCB$M_POWER,UCB$L_STS(R5) ;CLEAR POWER FAILURE BIT1 MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKETe5 MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERS  UCB$L_SVAPTE(R5) ;... $ BRW JF_STARTIO ;START REQUEST OVER .endc .if ndf,evax JF_INT:: JF_UNSOLNT:: POPR #^M% REI ;DUMMY RETURN FROM ANY INTERRUPT .endc ;;f/JF_END: ;ADDRESS OF LAST LOCATION IN DRIVER .iff ;step2: .TITLE JFDRiver ;skeleton driver implementing ucb linkage .IDENT 'V01h':mf$tst=0 ; save fib expansion stuff to see if we get there'; Copyright 1993,1994 Glenn C. Everharte; All rights reservedr; Author: Glenn C. Everhart;.; mods:n$; 7/8/94 gce -step2 conversion begun5; remember to define xx$nor sometime to wrtchk args!!n;n;nEreal_pvt=0 ;define to include code that on bit 2048 prevents opens one" ;assigned devices, privs or not.8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50nEVAX = 1.iff ;EVAX = 0l.endc$ .if df,evaxevax = 1alpha=1 bigpage=1 addressbits=32; ;... EVAX=1 -> Step1B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0)e .endc ;x$$$dt=0s; above for Alpha only. ; "; Glenn C. Everhart, November 1993; ;vms$$v6=0 ;add forvms v6 def'ncvms$v5=1(; define v5$picky also for SMP operation v5$picky=1& .SBTTL EXTERNAL AND LOCAL DEFINITIONS; ; EXTERNAL SYMBOLS;  .library /SYS$SHARE:LIB/i*; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCKo# $DYNDEF ;define dynamic data typest $DCDEF ;DEFINE DEVICE CLASS % $DDBDEF ;DEFINE DEVICE DATA BLOCKe* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLEn( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODESt$ $DDTDEF ; DEFINE DISPATCH TBL... .if df,step2$ ddt$l_fdt=ddt$ps_fdt_2  .endc $ptedef $vadef & $IRPDEF ;DEFINE I/O REQUEST PACKET $irpedef & $PRDEF ;DEFINE PROCESSOR REGISTERS& $SSDEF ;DEFINE SYSTEM STATUS CODES& $UCBDEF ;DEFINE UNIT CONTROL BLOCK .if df,step2  $fdt_contextdef .endc $sbdef ; system blk offsets $psldef $prdefn $acldef$ $rsndef ;define resource numbers $acedef* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $pcbdef $statedef $jibdef $acbdef $vcbdef $arbdef $wcbdef $ccbdef $fcbdef $phddef< $RABDEF ; RAB structure defs7 $RMSDEF ; RMS constantsa; defs for acl hacking $fibdef $atrdefp1=0 ; first qio paramp2=4p3=8p4=12up5=16cp6=20 ;6th qio param offsets# .IF DF,VMS$V5 ;VMS V5 + LATER ONLYm $SPLCODDEF  $cpudef .ENDC; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS; ( $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 someu; areas of VMS may want.C; Leave thisfield first so we can know all diskswill have it at theF; same offset.;L; ($def ucb$l_hucbs .blkl 1 ;host ucb table;R#; Add other fields here if desired.C;A3$def ucb$l_ctlflgs .blkl 1 ;flags to control modes-;B,$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 80r0$def ucb$l_asten .blkl 1 ;ast enable mask store;c&$DEF ucb$l_minxt .blkl 1 ;min. extent%$def ucb$l_maxxt .blkl 1 ;max extentX/$def ucb$l_frac .blkl 1 ;fraction to extend byd3$def ucb$l_slop .blkl 1 ;slop blocks to leave freeN; DDT intercept fields; following must be contiguous.4H$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 following_0 ; 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 blockPP; 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.F$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 ucb E; Make the "unique magic number" depend on the DDT length, and on theiJ; 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*>0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;s>; Store copy of victim FDT table here for step 2 Alpha driver.&; assumes FDT table is 64+2 longs long>$def ucb$l_myfdt .blkl 70 ;user FDT tbl copy + slop for safety5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chainv5$def ucb$l_vict .blkl 1 ;victim ucb, for unmung check2$def ucb$l_mungd .blkl 1 ;munged flag, 1 if numg'd&$def ucb$l_exempt .blkl 4 ;exempt PIDs($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_LEN=. ;LENGTH OF UCBo% $DEFEND UCB ;END OF UCB DEFINITONSO  .SBTTL STANDARD TABLESM; ; DRIVER PROLOGUE TABLE ; >; THE DPT DESCRIBES DRIVER PARAMETERS AND I/O DATABASE FIELDSA; THAT ARE TO BE INITIALIZED DURING DRIVER LOADING AND RELOADINGr; driver_data JF_UNITS=300JF$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 DPTAB - ;DPT CREATION MACRO$ END=JF_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=2,-' UCBSIZE=UCB$K_JF_LEN,- ;LENGTH OF UCBI. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAMER2 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 CLASSG DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ;FORK IPL (VMS V5.X + LATER)EC; These characteristics for an intercept driver shouldn't look justEF; like a real disk unless it is prepared to handle being mounted, etc.J; Therefore comment a couple of them out. Thus it won't look file oriented; nor directory structured.O8 DPT_STORE UCB,UCB$L_DEVCHAR,L,- ;DEVICE CHARACTERISTICS ; RANDOM ACCESS9 DPT_STORE UCB,UCB$L_DEVCHAR2,L,- ;DEVICE CHARACTERISTICS15 ; Prefix name with "node$" (like rp06)i7 DPT_STORE UCB,UCB$B_DEVCLASS,B, ~FAV020.A\>LT00A.GCE]JFDRIVER.MAR;18TU|xDC$_DISK ;DEVICE CLASSn: 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 TRACK 9 DPT_STORE UCB,UCB$W_CYLINDERS,W,16 ;NUMBER OF CYLINDERS/* DPT_STORE UCB,UCB$B_DIPL,B,21 ;DEVICE IPL8; DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNTF DPT_STORE UCB,UCB$L_DEVSTS,L,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;...l; ?; don't mess with LBN; leave alone so it's easier to hack on...E; 6 DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUESQ; DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,JF_INT ;INTERRUPT SERVICE ROUTINE ADDRESSW0 DPT_STORE DDB,DDB$L_DDT,D,JF$DDT ;DDT ADDRESSE DPT_STORE UCB,UCB$L_UNIQID,D,DRIVER$DPT ;store DPT address;H ; (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 inl? ; DOS-11 users)sC; HISTORICAL NOTE: under DOS-11, one would get F012 and F024 errorsl@; 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!t- DPT_STORE END ;END OF INITIALIZATION TABLEv; ; DRIVER DISPATCH TABLEi; >; THE DDT LISTS ENTRY POINTS FOR DRIVER SUBROUTINES WHICH ARE"; CALLED BY THE OPERATING SYSTEM.; ;JF$DDT: DDTAB - ;DDT CREATION MACRO DEVNAM=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINE>0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JF_CTRL_INIT,-i UNITINIT=JF_UNIT_INIT,- , CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICE# REGDMP=0,- ;REGISTER DUMP ROUTINE # DIAGBF=0,- ;BYTES IN DIAG BUFFER9 ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER; ; FUNCTION DECISION TABLEo; 6; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.; @chnflg: .long 0 ;chain or use our FDT chain flag...use ours if 0myonoff:3fdtonoff: .long 0 ;switch my fdt stuff off if non-0FM .ascii /flag/ ;define your own unique flag here; just leave it 4 bytes long!P$ .long 0 ;fdt tbl from before patchfdt_chn = -12 fdt_prev = -4S fdt_idnt = -8D JF_FUNCTABLE:  FDT_INI FDT_BUF - ; BUFFERED functionsO ; MOUNT VOLUME$ myfdtstart:d?; io$_format + modifiers (e.g. io$_format+128) as function code >; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed.t) fdt_act JF_format,- ;point to host disk4 ;6$; First our very own filter routines;$A; Following FDT function should cover every function in the local B; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need.B 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 ifuI; you don't want to. The FDT switch logic is a waste of time and space ifn; you do nothing with them...FK; They don't actually do anything here, but could be added to. Throw in one F; 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!)u fdt_act MFYFilt,-( ;modify filter (e.g. extend) myfdtend=.JF_ucb:nJF_utb:t .rept JF_unitse .long 0 .endr .long 0,0,0,0,0,0,0,0,0,0 driver_code;iH; GETJFUCB - Find JF: 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..B; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. getJFucb: .jsb_entry output=!; clrl r0 ;no UCB initially founds 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 knows ?; it is in an intercept driver. Also assumes R11 may be used as D; 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"b ; is defined. -; Entry: R5 - victim device UCB addressb0; Exit: R11 - intercept driver UCB address chk.err=0 F movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!!G movab DRIVER$dpt,r11 ;magic pattern is DPT addr.e9; lock this section with forklock so we can safely removed3; entries at fork also. Use victim device forklock. 1; (don't preserve r0 since we clobber it anyway.);= forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NOa42$: cmpl (r10),R11= ;this our own driver?e@; beql 1$ ;if eql yes, end search;x<; 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.;  .branch_unlikelym) bneq 5$ ;check next in chain if not us A; At this point R10 contains the DDT address within the intercepteF; 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 UCBb7; brb 4$ ; note in this layout we can comment this out.e4$:b? forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOB%; NOW clobber r0 and put things back.E movl r11,r0; popr #^m popl r11T& popl r10 ;supposedly faster than popr rsbA; Make very sure this DDT is inside a UCB bashed according to ourS=; specs. The "p.magic" number reflects some version info too.D3; If this is not so, not much sense searching more.n95$: cmpl (r10),#p.magicCC bneq 3$ ;exit if this is nonstd bashT+; follow DDT block chain to next saved DDT.t5 movl (r10),r10II ;point R10 at the next DDT in theG ;chain F bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againD;1$:3$:B$ clrl r11 ;return 0 if nothing found brb 4$T;O*; Few macros for long distance branches...;D .macro beqlw lbl,?lbl2, bneq lbl2 brw lbllbl2:  .endm .macro bneqw lbl,?lbl2i beql lbl2 brw lbllbl2:  .endm .macro bleqw lbl,?lbl2a bgtr lbl2 brw lbllbl2:t .endm .macro bgeqw lbl,?lbl2h blss lbl2 brw lbllbl2:h .endm); allocate does not zero its result area.eE; This macro makes it easy to zero an allocated area before using it.S@; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".; .macro zapz addr,size3 pushr #^m ;save regs from movc5 movc5 #0,addr,#0,size,addrE2 popr #^m ;save regs from movc5 .endm;, .SBTTL Our FDT Filter RoutinesD>; These routines are edited from the JFDRiver versions to callD; getJFucb, assuming they are called with R5 pointing at the patched; driver's UCB.F ; INPUTS: ; (; R3 - IRP ADDRESS (I/O REQUEST PACKET)+; R4 - PCB ADDRESS (PROCESS CONTROL BLOCK)B(; R5 - UCB ADDRESS (UNIT CONTROL BLOCK)+; R6 - CCB ADDRESS (CHANNEL CONTROL BLOCK)R+; R7 - BIT NUMBER OF THE I/O FUNCTION CODEU3; R8 - ADDRESS OF FDT TABLE ENTRY FOR THIS ROUTINEE(; (AP) - ADDRESS OF FIRST QIO PARAMETER; Filter routines.!; These do the interesting stuff.,;IPopOut:G popr #^mpors:TG; Here need to return to the "standard" FDT routine. Do so by computingsH; the address in the FDT table of the normal host and calling that, thenC; returning. Thus the only FDT routines in THIS driver are the onesEE; it needs for its own work, not any standard ones. This calls those.SN EXTZV #IRP$V_FCODE,#IRP$S_FCODE,IRP$L_FUNC(R3),R1 ; GET FCN CODE pushr #^m movl r1,r104 jsb getJFucb ;find JF UCB checking for extra links tstl r0 ;got it?n bgeq 199$ ;if not skip out 6 movl ucb$l_oldfdt(r0),r7 ;get address of previous FDT bgeq 199$ ;ensure ok...!; movl ucb$l_ddt(r5),r7 ;find FDT K; Here rely on the fact that we got here via our modified FDT call and that :; the orig. FDT is stored just a bit past the current one.<; movl (r7),r7 ;point at orig. FDT0 addl2 #8,r7 ;point at one of 64 fdt addresses2 movl (r7)[r10],r8 ;r7 is desired routine address!;now call the "official" FDT codeo pushl r6 ;ccb pushl r5 ;ucb pushl r4 ;pcb pushl r3 ;irp+ calls #4,(r8) ;Call the original routine popr #^m+; Now return as the original routine would.L ret199$:E popr #^m movl #16,r0 call_abortioC ret; rsbJCmfyfilt: $driver_fdt_entry ;filter on MODIFY requests (e.g. extend)C.; First do some preliminary checks for sanity.$; 1. Channel must NOT be kernel mode; 2. Not a movefileL% tstl r6 ;is there a CCB (must be +)  bleq pors ;if not skip out) cmpb ccb$b_amod(r6),#1 ;knl mode access?( bleq pors ;leave knl mode chnls alone!;funct modifiers are bits 6-15; this is hex ffc0?; Normal io$_modify should have no modifiers, so if it has it'sD'; for something else; leave that alone.E .if ndf,evaxP@ bitw #^x1FC0,irp$w_func(r3) ;this a movefile or other modifier? .iffg@ bitl #^xDFC0,irp$l_func(r3) ;this a movefile or other modifier? .endc" bneq pors ;if so ignore it here. pushr #^me>; original r5 now at 4(sp). Must get that to continue the ops.! jsb getJFucb ;find JFDRiver ucbS tstl r0 bgeqw popoutT7 movl r5,ucb$l_backlk(r0) ;save link'd ucb in ours too.P! movl r0,r5 ;point R5 at JF UCB-B;make sure not a knl mode channel (leave the XQP channel alone!!!)- cmpb ccb$b_amod(r6),#1 ;this the XQP's chnl? " bleqw popout ; if so scram NOW.A; Now ensure that this call is not in the same JOB as the daemon. 9; (This lets the daemon spawn processes to do some work.)O* bitl i^#2,ucb$l_ctlflgs(r5) ;look at mfy? bneqw mfycmn ;if neq yesE9; (test later will see about space control if doing this)R701$:E popr #^m brw porsLmspcj: popl r0 brw popoutUmfycmn:$J; here we can modify request fields in the FIB the user supplies to reduceD; fragmentation...e.g. set fib$l_exsz bigger or set fib$m_alconb bit>; in fib$w_exctl IFF fib$m_alcon is not set & set fib$m_aldef.;d pushl r0t .if ndf,evaxp movl p1(ap),r0 ;get fib .iff6 movl irp$l_qio_p1(r3),r0e .endc5; remember to define xx$nor sometime to wrtchk args!!c% .iif df,xx$nor,ifnord #4,4(r0),mspcje" movl 4(r0),r0 ;...from descriptor/ .iif df,xx$nor,ifnord #4,fib$w_exctl(r0),mspcjo6 bitw #fib$m_extend,fib$w_exctl(r0) ;extending at all?, beqlw mspc ;if no extend, leave fib aloneI; Because contiguous best try allocation flushes the entire extend cache,TE; it can cause a tremendous performance hit. Therefore allow it to besG; separately switched so that the benefits of longer extents can be hadnI; if desired without forcing this flushing every time a file is extended.lL bitl i^#32,ucb$l_ctlflgs(r5) ;separate control for setting contig best try beql 1$(; leave contig and contig-best-try alone@ bitw #,fib$w_exctl(r0) ;contig alloc?# bneq 1$ ;if contig leave it alone.!; allow this on every nth extend..C; This will allow periodic flushes of the extent cache but will letCK; it not be made totally useless. By flushing the extent cache periodically 4; we can try to reduce the fragmentation it induces.,; if bit 16384 is not set, do not set aldef.9 bitl i^#16384,ucb$l_ctlflgs(r5) ;set aldef all the time?u beql 704$? bisw #,fib$w_exctl(r0) ;set to use vol default ifs 704$: ;bigger than program's" decl ucb$l_cbtctr(r5) ;count down' bgtr 1$ ;and if >0 don't set cbt yete; movl ucb$l_cbtini(r5),ucb$l_cbtctr(r5) ;else reset countera? bisw #,fib$w_exctl(r0) ;else turn on contig best  ;try and turn on use of! ;system default extension if ! ;larger than program defaulte1$: P; One can add code to check file size and bump extension by more than default ifT; it's big (for example, extend by 10% of its' size, not by a few blocks at a time). pushr #^m3 bitw #,fib$w_exctl(r0) ;contig alloc? . bneqw 222$ ;leave size alone for contig alloc) movl ccb$l_wind(r6),r7 ;get window blockr bgeq 222$ ;guard / movl wcb$l_fcb(r7),r8 ;and file control blkock  bgeq 222$ ;guardi) movl fcb$l_filesize(r8),r6 ;get filesizel beql 222$=; It is suggested to divide by acp$gb_window instead of 10...kS; this is the acp_window sysgen param (default 7), the number of retrieval pointers$R; present per window by default. This has no direct relation to size, but one mustQ; expect at least one retrieval pointer needs to change. In the default situationq%; say 1/4th of file size can be used.s;nD; The fraction starts at 1/4, but can be anywhere from 1/1 to 1/10007 divl2 ucb$l_frac(r5),r6 ;get 1/4 of current size or sor$ incl r6 ;plus one...for good luck? cmpl r6,ucb$l_maxxt(r5) ;extending over max (nominally 120000)e bleq 1222$ 9 movl ucb$l_maxxt(r5),r6 ;clamp to max what we're forcingD1222$:9 cmpl r6,ucb$l_minxt(r5) ;if less than 10 leave alone toos bgeq 1223$c4 movl ucb$l_minxt(r5),r6 ;at least grab this minimum1223$:0; never try to grab over1/8 of total free space.8 movl ucb$l_backlk(r5),r8 ;get host ucb (set just above) bgeq 222$ ;(better be there)k$ movl ucb$l_vcb(r8),r8 ;point at vcb bgeq 222$& movl vcb$l_free(r8),r8 ;no. blks free ashl #-3,r8,r8 ;free space /8p% cmpl r6,r8 ;extent over freespc/8?b'; bgtr 222$ ;if so don't push it hereC" bleq 3223$ ;if not all still ok# movl r8,r6 ;else clamp to free/8e3223$:8 cmpl r6,fib$l_exsz(r0) ;make sure we're increasing size2 bleq 222$ ;if less than user wants, leave aloneH; if 4 bit is clear, allow size ctl always. Otherwise only if aldef set. bitl i^#4,ucb$l_ctlflgs(r5) beql 2222$v? bitw #,fib$w_exctl(r0) ;set to use vol default if1 beql 222$ ;if aldef NOT set, leave size alone.a2222$:3 movl r6,fib$l_exsz(r0) ;fill in as new extend size 222$:  popr #^mt; fall thru to space control mspc: popl r0  popr #^m movl #1,r0 brw porsr;++ ;f5; JF_format - bash host disk tables to point at ours.t;eF; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),mB; 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 ise; software enabled.s; D; This routine does virtually no checking, so the parameters must be ; correct.;v ; Inputs:e>; p1 - pointer to buffer. The buffer has the following format:=; longword 0 - (was hlbn) - flag for function. 1 to bashs.; 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; ;R; p2 - size of the above bufferR;--CJF_format: $driver_fdt_entry< bicw3 #io$m_fcode,irp$l_func(r3),r0 ;mask off function code) bneq 20$ ;branch if modifiers, specialR);thus, normal io$_format will do nothing.  brw pors ;regular processingM100$: 0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parametern clrl r1 call_abortion ret; jmp g^exe$abortio 20$:5 movl irp$l_qio_p1(r3),r0 ;buff address 4 movl irp$l_qio_p2(r3),r1 ;buff length call_writechk;; jsb g^exe$writechk ;read access? doesn't return on errors:; clrl irp$l_bcnt(r3) ;paranoia, don't need to do this...1 pushr #^mE movl irp$l_qio_p1(r3),r00 movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegal# cmpl r7,#2 ;3 and up illegal toof bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored)e bleq 70$n0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JF_host_descr+4(r5) % subl3 #8,irp$l_qio_p2(r3),-p' ucb$l_JF_host_descr(r5)t bleq 100$ ;bad length4 movab ucb$l_JF_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host devicer! blbs r0,30$ ;branch on successc; fail the associate... 0 popr #^m= movzwl #ss$_nosuchdev+2,r0 ;make an error, usually a warningr clrl r1 call_abortion ret%; jmp g^exe$abortio ;exit with errorE30$: ;found the device; r1 is target ucb address...i$; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?i bneq 31$  jsb mung ;go mung target... 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?c) bneq 32$ ;if not skip out, do nothing.o jsb umung ;unmung target32$:3; bisw #ucb$m_valid,ucb$w_sts(r5) ;set volume valid 3; bisw #ucb$m_online,ucb$w_sts(r5) ;set unit onlineh5; movl ucb$l_irp(r5),r3 ;restore r3, neatness countsf0 popr #^m! movzwl #ss$_normal,r0 ;success call_finishioc do_ret=yes(; jmp g^exe$finishioc ;wrap things up.mung: .jsb_entry=; steal DDT from host. Assumes that the intercept UCB address4B; 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 issC; pointed to by R11. All registers are preserved explicitly so thatkB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingcG; went wrong so the bash did NOT occur. This generally means some othernF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so the 3; unique ID field and magic number are set already.s6 tstl ucb$l_mungd(r5) ;already munged/not deassigned? beql 6$ rsb ;no dbl bash6$:a7 pushr #^me5; Acquire victim's fork lock to synchronize all this.e7 movl #ss$_normal,r0 ;assume successo" 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 DDB3; fill in host ucb tbl (makes chnl handling faster)  movab JF_ucb,ucb$l_hucbs(r5)(' movl ucb$l_hucbs(r5),r9 ;get ucb tablet' movzwl ucb$w_unit(r5),r0 ;get unit no.i# moval (r9)[r0],r9 ;point into tbls, movl r11,(r9) ;save target ucb addr in tbl-; 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?i3 beql 1$ ;if eql yestG; driver was bashed already. Check that the current basher followed the); standard. Then continue if it looks OK.y9 cmpl (r10),#p.magiccF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellh: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too) 2$:l<; 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 onei1$:u* movl #1,ucb$l_mungd(r5) ;say we munged JFD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallyr3$:  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);t1; Here make whatever mods to the DDT you need to.b;w8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers)cH movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JF_functable+fdt_prev ;save old FDT ucb addressd% movl ddt$l_fdt(r10),ucb$l_oldfdt(r5) K movl ucb$l_uniqid(r5),JF_functable+fdt_idnt ;save unique ID alsot9; copy legal and buffered entry masks of original driver.eA; HOWEVER, set mask for format entry to be nonbuffered here sincee; we deal with it. pushr #^m/: movab ucb$l_myfdt(r5),r9 ;our function table dummy in UCB+ movl ddt$l_fdt(r10),r7 ;victim's FDT tableC; We want all functions legal in the victim's FDT table to be legal;; here..6 pushr #^m ;preserve regs from movc- movl #<68*4>,r0 ;byte count of a step 2 FDTc* movc3 r0,(r7),(r9) ;copy his FDT to ours5 popr #^m ;preserve regs from movc16; Now copy in our modify & back-to-original FDT cells.A; We will do this in our FDT table by having FDT definitions only ?; for those functions in JFDRiver that we service locally. Thust:; all entry cells for the rest will point in the JF FDT to; exe$illiofunc.0 movab g^exe$illiofunc,r8 ;get the magic address/ movab JF_functable,r10 ;r10 becomes JF FDT tbl # addl2 #8,r10 ;point at functionsg addl2 #8,r9 ;his new FDT... movl #64,r11 ;64 functions 075$: cmpl (r10),r8 ;this function hadled in JF? beql 76$ ;if eql no, skip7 movl (r10),(r9) ;if we do it point his fdt at our fcnhJ; (NOTE: our functions MUST therefore call the previous FDT's functions at; end of their processing.)'76$: cmpl (r10)+,(r9)+ ;pass the entry# sobgtr r11,75$ ;do all functions;C; JFDRiver FDT table. Last entry goes to user's original FDT chain.e;oE; Thus we simply insert our FDT processing ahead of normal stuff, but$4; all fcn msks & functions will work for any driver. popr #^m0; Now point the user's FDT at our bugger'd copy.C movab ucb$l_myfdt(r5),ddt$l_fdt(r8) ;point at our FDT tablen8 clrl myonoff ;turn my FDTs on;eE; Finally clobber the victim device's DDT pointer to point to our newm; one. .iif df, evax, evax_imb/ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)  .iif df, evax, evax_imb@; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing invC; the example here causes the intercept driver's FDT routines to befC; used ahead of whatever was in the original driver's FDTs. BecausesE; 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.;a1; Processing complete; release victim's fork lock 100$:r6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YESf7 popr #^m rsbumung: .jsb_entrye;oF; 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: addressaE; is the one being sought. ("Current driver" here means the intercepto ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCB contains an entry in the DDT chain. pushr #^mE; .iif df,x$$$dt,jsb g^ini$brk ;***********************debug*********_0 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 laterF movab DRIVER$DPT,r11 ;magic pattern is DPT addr.9; lock this section with forklock so we 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?b? beql 1$ ;if eql yes, end searchd .if df,chk.err9 cmpl (r10),#p.magic.D bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.n5 movl (r10),r10oI ;point R10 at the next DDT in the . ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againi1$:iA; At this point R10 contains the DDT address within the interceptnF; 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-fixup1/; we were intercepted. Fix up next guy in line._L movl (r10),r11 ;point at interceptorS movl (r10),(r11)i3$:eE; if we intercepted someone, fix up our intercepted victim to skip bye ; us also.I movl (r10),r2 ;did we interceptp9 ;original driver?0A 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'seB; ddt$l_fdt pointer and skipping around any entry that has address; JF_functable:,B; 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!!!p; movl ddt$l_fdt(r0),r1 ;start of FDT chain A movab JF_functable,r2 ;address of our FDT tabled clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucbnD; Also set the JF device offline when we unbash it. This is a simple@; flag that ctl prog. can use to tell if it's been used already./ bicl #,ucb$l_sts(r4)vA6$: cmpl r1,r2 ;current fdt point at us?iA beql 7$ ;if eql yes, fix up chain @ 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 ucboA;;;BUT not all UCBs will have the fdt offset at the same place!!! F;;;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.l7$:l*;r3 is 0 or fdt pointing to our block next;r1 points at our fdt blockrD tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to do  movl fdt_prev(r1),r4) bgeq 17$c. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4n blss 18$r tstl (sp)+ 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.r8$:p; F; 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 its? movl (r10),ucb$l_ddt(r5): clrl (r10) ;zero JF munged flag4$:T@ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^mrK ;copy our prior DDT ptr to next oned rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINE ; ++; 2; JF_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:f; noop ; INPUTS:f; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:9; - AT SYSTEM STARTUPm; - DURING DRIVER LOADINGl(; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;--D$JF_ctrl_INIT: $driver_ctrlinit_entry*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r0< Ret ;RETURNo- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATIONy;s ; INPUTS:s; R4 => controller CSR (dummy) ; R5 => UCB ;m# .SBTTL UNIT INITIALIZATION ROUTINEc;++o; ,; JF_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:o; $; THIS ROUTINE SETS THE JF: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:o; - AT SYSTEM STARTUPt; - DURING DRIVER LOADING.(; - DURING RECOVERY FROM POWER FAILURE; ; INPUTS:b; 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.; ;--p$JF_unit_INIT: $driver_unitinit_entry>; Don't set unit online here. Priv'd task that assigns JF unit<; to a file does this to ensure only assigned JFn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JF: data buffersTJF_bufsiz=81929 movl #JF_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers  ~FAV020.A\>LT00A.GCE]JFDRIVER.MAR;18T8to 8ky9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASSl' clrl ucb$l_mungd(r5) ;not mung'd yetdC; NOTE: we may want to set this as something other than an RX class >; 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!!!)v" movab DRIVER$DPT,ucb$l_uniqid(r5)9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JF_G; (note the id might be wrong but is attempt to get it.) (used only forf; 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 ando8;;; attempt no weird jiggery-pokery with the JF: device.G; MSCP may still refuse to do a foreign drive too; jiggery-pokery laterh'; to test if there's occasion to do so.i; Set up crc polynomialD- movab JF_utb,ucb$l_hucbs(r5) ;host ucb tablet5 clrl chnflg ;initially set to use our chain of FDTso: BICL #UCB$M_ONLINE,UCB$L_STS(R5) ;SET UCB STATUS OFFLINE movl #1,r0o ret;++1; ; JF_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION:n; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTg; PACKET HAS BEEN DEQUEUED.; ; INPUTS: ; ); R3 - IRP ADDRESS (I/O REQUEST PACKET).); R5 - UCB ADDRESS (UNIT CONTROL BLOCK)o:; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFERED /; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKSf; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;--5JF_STARTIO: $driver_start_entry ; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8_D; CLRQ UCB$Q_JF_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION 3 bbs #ucb$v_online,- ; if online set software validr ucb$l_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalida' brw resetxfr ; reset byte count & exito210$: ;; Unless we use this entry, we want to junk any calls here.k+ brb 216$ ;just always say invalid volume.sA; Get here for other start-io entries if the virtual disk code is($; commented out also, as it must be.";FATALERR: ;UNRECOVERABLE ERROR3; MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUSe8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKT.6; MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNT ; BRW FUNCXTFUNCXT: ;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB, REQCOM,environment=call ; COMPLETE REQUEST; ;PWRFAIL: ;POWER FAILURE ;; BICW #UCB$M_POWER,UCB$W_STS(R5) ;CLEAR POWER FAILURE BIT 2; MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKET6; MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERS; UCB$L_SVAPTE(R5) ;...%; BRW JF_STARTIO ;START REQUEST OVER ;JF_INT:: ;JF_UNSOLNT:: ; POPR #^Mi&; REI ;DUMMY RETURN FROM ANY INTERRUPT ;;s/JF_END: ;ADDRESS OF LAST LOCATION IN DRIVERe .ENDC ;step2  .ENDp*[VLT00A.GCE]JFDRIVER.OBJ;2+,]./ 4v->0123 KPWO56'e7Xe89GHJ4DDJFDRIVERV01H28-FEB-2000 20:49AMAC V3.0-23P P . ABS . . BLANK . $ABS$p $$$110_DATA $$$105_PROLOGUE  $$$115_DRIVER $$$115_LINKAGE0  DRIVER$DPT( JF$DPT( JF$DDT IOC$RETURN_SUCCESSIOC_STD$MNTVER IOC$RETURN IOC$RETURN_UNSUPPORTED EXE_STD$INSERT_IRP0  DRIVER$FDT EXE$ILLIOFUNC SMP$GL_FLAGS SMP$AL_IPLVEC SMP$ACQUIRE SMP$RELEASEEXE_STD$ABORTIO EXE_STD$WRITECHK IOC$SEARCHDEV EXE_STD$FINISHIOIOC_STD$REQCOMOTS$MOVE OTS$CALL_PROC OTS$DIV_I  = x4=44>IOC$RETURN_SUCCESS4>IOC$RETURN_SUCCESS>IOC$RETURN_SUCCESS>IOC$RETURN_SUCCESS=>IOC_STD$MNTVER> IOC$RETURN> IOC$RETURN> IOC$RETURN> IOC$RETURN> IOC$RETURN> IOC$RETURN_UNSUPPORTED> IOC$RETURN_UNSUPPORTED=> IOC$RETURN>IOC$RETURN_SUCCESS=>EXE_STD$INSERT_IRP=(flagL|> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC4> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC@4> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC> EXE$ILLIOFUNC= =0(,4 4=4= JFDRIVERX= 4=  =>C~^^~ (0޴8GC1'CF1#CWpJ"&&&4GCYp KC:9'&H"LƲ|SJX&C?G:GX&4GDXƢw1 KVRJFXƲ\GX0KG\GD\FvSKG_G\G\FGD\WRJF\沀&?G:G&G^~ (0ޤ8CkGG>C~^^~ (0޴8GC(C [?' Fx89#C&CCG^~ (0ޤ8Ck>C^^~ G>CEmGG-GGpH$0M>C8m@ZkCʢ0B( j!M: >C M(mpH@ZkC/CGGFGGC^~CkGͦGGV@FʢGG0B*'x8#08CJ_ GGG>C~^^ ~(08޴@HP>X^`~hp Gx޵GCCCCCf_'Z#{`KgK45`C#;A:G>C _ChCwJJ45BBC>Câ;A^ >F Cް>Cn_C8,`# /CCHZ ;KCDC-@XGA@MHmC>CG4CG@Zk ޠC >^CG^ ~(08ޤ@HP>X^`~hpxޥCk8PFC MGޠCCC >C^C(mG@Zk>C/@K`Gw8G$.@J|@?#pF8G .@Jv`VJGxJFu`><Ţ61B<Ų @@<@/XKoZXKT G|xK\Gn@?>C@ް ~^@/YKf 0@G:8 6DȠ4>CŢPM>G>G ^Xm(~@ZkG>0@> ^(~C4@Š4@FhDTCw@K4@C 4@ 8G.@J1F^~ ޠC4GC# /Z ;KG{@/[ \KF /Z ;KG JY ;K8G ?.W J7G xKV JF>.X JXG@/[ \KFG>C~^^ ~(08޴@HP>X^`~hp-pCx޵GC HcCC`KCgG4KD#>CG0MG8mGGGG>C@ZkCRd#G>C,~(^$> ް ~^>@G4U@Ex50 Cx5@xpl% 6BlŲ8pMxm@ZkL ~G MC  >G^CޠCC $>(^,~(mC@ZkG^ ~(08ޤ@HP>X^`~hpxޥCk MC(mCCCCG@Zk>^ ~ޠ $>(^,~C MG(mGCCCCG@Zk45@ Ce4{A;A@ ~TG`M4G>G^CCޠ $>(^,~Chm#@Zk;A@G>C^^~ (0޴8@H>P^X~` Gh^~ (0ޤ8@H>P^X~`hCk>C4G(~$^G >Gް >C ~^>>C-GG pHM>Cm@ZkC/CK"4 CtHI @i8+ 0CJ?'x89#0YC}# 4GŲE>CMGG"PB@ZkCM>C(*!GG%GG~^ >t%!Gް>C( ~^G> H@Zk A AA> !A^ G ~C *0(B)+1`A A @Aޠt%# >^~C((|ﳆ# ע >CMm >CpH@ZkCCGGF>G^~ ޠ >$^(~CJMGGZ@FGGpTGGGG>C^^~ (^0~8 G>CC>8%>CEm !CGG>C GٔH>GpH=Mm>C@ZkCVHCHFj0kC9*'x8#08CJ_ͦ>C۔HM~>CmpH@ZkZH CCH@GCGGF>C^~ (^0~8C =kGGGW@FGG* G*+J0A@ M#( ĢGQCFIJ0"@ C$?òç `>Cd~ ^CD!#0@A岴곝GCGG>C~^^ (޴08G4GCCCC4GG^ (ޤ08CkGG>C`[~^^ (GXC #GX-&@"4GGGXx1@K4G岘"ŲCX%4GY0 K8GX%4xGG^ (CkGG>C~^^~ (08 GGCCEBFT xeG(MC0mCCtG@ZkG^~ (08Ck4G  SMP$ACQUIRE4m#P SMP$ACQUIRE4@  SMP$ACQUIRE4HGX SMP$RELEASE4Lm#P SMP$RELEASE4T@X SMP$RELEASE4 DGh OTS$CALL_PROC4Hm#@ OTS$CALL_PROC4 d@h OTS$CALL_PROC4 G,EXE_STD$ABORTIO4  m#@EXE_STD$ABORTIO4 (@,EXE_STD$ABORTIO4LGx OTS$DIV_I4lm#@ OTS$DIV_I4t@x OTS$DIV_I< pGEXE_STD$WRITECHK< xm#@EXE_STD$WRITECHK< @EXE_STD$WRITECHK40 G< IOC$SEARCHDEV44 m#@ IOC$SEARCHDEV48 @< IOC$SEARCHDEV4 P G EXE_STD$ABORTIO4  m#@EXE_STD$ABORTIO4  @ EXE_STD$ABORTIO4  G EXE_STD$ABORTIO4  m#@EXE_STD$ABORTIO4  @ EXE_STD$ABORTIO4 D Gl EXE_STD$ABORTIO4 L m#@EXE_STD$ABORTIO4 h @l EXE_STD$ABORTIO< G EXE_STD$FINISHIO< m#@EXE_STD$FINISHIO< @ EXE_STD$FINISHIO4 G SMP$ACQUIRE4 m# SMP$ACQUIRE4 @ SMP$ACQUIRE4p G OTS$MOVE4 @ OTS$MOVE4 G OTS$MOVE4 @ OTS$MOVE4 G SMP$RELEASE4 m# SMP$RELEASE4 @ SMP$RELEASE4G SMP$ACQUIRE4m# SMP$ACQUIRE4@ SMP$ACQUIRE4TGt SMP$RELEASE4hm# SMP$RELEASE4p@t SMP$RELEASE4XGtIOC_STD$REQCOM4`m#IOC_STD$REQCOM4p@tIOC_STD$REQCOM =0;=@| =0@;=@| ;;=0;7 SMP$AL_IPLVEC7 SMP$GL_FLAGS  SMP$RELEASE  SMP$ACQUIRE=0 ;OTS$MOVE7 EXE$ILLIOFUNC=0`;=0;=@t =0P;=04 =0;=@< 0 IOC_STD$REQCOM""=0;= EXE_STD$ABORTIO""( EXE_STD$WRITECHK OTS$CALL_PROC OTS$DIV_I(EXE_STD$FINISHIO"  IOC$SEARCHDEV=0;= *[VLT00A.GCE]JFDRIVER.OBJ_VAX;1+,^./ 4->0123KPWO56ccHy7!he89GHJ5JFDRIVERV01B29-AUG-1996 15:38 VAX MACRO V5.4-3MACRO/OBJ=JFDRIVER JFDRIVER*;skeleton driver implementing ucb linkagJFDRIVER ACP$ACCESS ACP$DEACCESS ACP$MODIFY ACP$MOUNT ACP$READBLK ACP$WRITEBLK EXE$ABORTIO EXE$FINISHIOCEXE$LCLDSKVALID EXE$ONEPARM EXE$SENSEMODE EXE$SETCHAR EXE$WRITECHK EXE$ZEROPARM IOC$MNTVER IOC$REQCOM IOC$RETURN IOC$SEARCHDEV JF$DDT JF_INT  JF_UNSOLNT SMP$ACQUIRE SMP$AL_IPLVEC SMP$GL_FLAGS SMP$RELEASE VJF$DPT . ABS .P$ABS$PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP$$$105_PROLOGUE5PPQ4&8884&4&dJFDRIVERQQQF11 4<@LNQP@Rr |\U4&hZ4& 4&T`H$P $$$115_DRIVERP4 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\3|43@43'o>43 ACP$READBLK2 ACP$WRITEBLK2 ACP$ACCESS2 ACP$DEACCESS2` ACP$MODIFY2 ACP$MOUNT2EXE$LCLDSKVALID2 EXE$ZEROPARM2@ EXE$ONEPARM2 EXE$SENSEMODE2 EXE$SETCHAR2(P<PQ EXE$ABORTIO XP\PXXЎPZ[ŜZ[~ P SMP$GL_FLAGS SMP$ACQUIRE SMP$AL_IPLVEC@Ѫ[#ʜ[ SMP$GL_FLAGS P SMP$RELEASEڎ[PЎ[ЎZѪH$ЪZ[̺!V ߣ !xP1UPU!1lP РP 泏1 & @ jЦWdЧX^Ш8VXLVVVHHVVDDVżX2Ш8X,ШDXxXXVXXVVV!P1? P<PQ EXE$ABORTIOlPЬQ EXE$WRITECHKλlPЀWW;ЀV2`Q IOC$SEARCHDEVP< PQ EXE$ABORTIOQ[Wm [a<P EXE$FINISHIOCϷϰP~P P SMP$GL_FLAGS SMP$ACQUIRE SMP$AL_IPLVEC@ЎP˜ZЫ,Yѩ ZѪH$P1dZ\XU(TjdЎUdXUqЪT`YЪWgЧЧЧ pon։ЏЏgid˜ 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ЪРQtRSʜTxQRQSСT,Q%SСT~УTՎЎСZPЪŜ SMP$GL_FLAGSP P SMP$RELEASEЎPڎ? PЏȥLЏ@-ŠMPx0123KPWO5 6]ȗ7HEve89GHJCLUSTER=JFDRIVER,,,- JFDRIVER.OBJ,-! ALPHA$LIBRARY:STARLET/INCLUDE:(- SYS$DOINIT,- SYS$DRIVER_INIT)!! set psect options!BPSECT_ATTR=_AMAC$CODE,PIC,USR,CON,REL,GBL,NOSHR,EXE,RD,NOWRT,NOVECEPSECT_ATTR=_AMAC$LINKAGE,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC>PSECT_ATTR=$CODE$,PIC,USR,CON,REL,GBL,NOSHR,EXE,RD,NOWRT,NOVEC>PSECT_ATTR=$LINK$,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC>PSECT_ATTR=$PLIT$,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC=PSECT_ATTR=$OWN$,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC@PSECT_ATTR=$GLOBAL$,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVECPSECT_ATTR=EXEC$INIT_CODE,NOSHRGPSECT_ATTR=EXEC$INIT_LINKAGE,PIC,USR,CON,REL,GBL,NOSHR,EXE,RD,WRT,NOVECFPSECT_ATTR=$LINKAGE,NOPIC,CON,REL,LCL,NOSHR,NOEXE,NOWRT,NOVEC,MOD,PAGEFPSECT_ATTR=$$$115_LINKAGE,PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC!! collect stuff!6COLLECT=NONPAGED_READONLY_PSECTS/ATTRIBUTES=RESIDENT,- _AMAC$CODE,- EXEC$NONPAGED_CODE,- $$$115_DRIVER,- $CODE$7COLLECT=NONPAGED_READWRITE_PSECTS/ATTRIBUTES=RESIDENT,- _AMAC$LINKAGE,- EXEC$NONPAGED_DATA,- EXEC$NONPAGED_LINKAGE,- $$$105_PROLOGUE,- $$$110_DATA,- $$$115_LINKAGE,- $PLIT$,- $GLOBAL$,- $OWN$,- $LINK$>COLLECT=INITIALIZATION_PSECTS/ATTRIBUTES=INITIALIZATION_CODE,- EXEC$INIT_LINKAGE,- EXEC$INIT_CODE,- EXEC$INIT_000,- EXEC$INIT_001,- EXEC$INIT_002,- EXEC$INIT_SSTBL_000,- EXEC$INIT_SSTBL_001,- EXEC$INIT_SSTBL_002*[VLT00A.GCE]JFDRIVERV2.MAR;7+,`./ 4T->0123KPWO56 Gk7Qe89GHJ  .library /sys$share:lib/ $wcbdef8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50EVAX = 1.iff ;EVAX = 0.endc .if df,evaxalpha=1 bigpage=1addressbits=32B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0) .endc2 .if ndf,step2 ;use vax or step1 code in here only: .TITLE JFDRiver ;skeleton driver implementing ucb linkage .IDENT 'V01b'"; Copyright 1993 Glenn C. Everhart; All rights reserved; Author: Glenn C. Everhart; ;evax = 1D; Above automates defining "evax". Also define "step2" where needed. .if ndf,evax .macro driver_data .PSECT $$$105_PROLOGUE .endm .macro driver_code .PSECT $$$115_DRIVER .endm .endc; above for Alpha only.;5; Function: Implement frag avoider for generic disks. ;x$$$dt=0;;vms$$v6=0 ;add forvms v6 def'nvms$v5=1(; define v5$picky also for SMP operation v5$picky=1& .SBTTL EXTERNAL AND LOCAL DEFINITIONS; ; EXTERNAL SYMBOLS;  .library /SYS$SHARE:LIB/*; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK# $DYNDEF ;define dynamic data types $DCDEF ;DEFINE DEVICE CLASS% $DDBDEF ;DEFINE DEVICE DATA BLOCK* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODES$ $DDTDEF ; DEFINE DISPATCH TBL... $ptedef $vadef& $IRPDEF ;DEFINE I/O REQUEST PACKET $irpedef& $PRDEF ;DEFINE PROCESSOR REGISTERS& $SSDEF ;DEFINE SYSTEM STATUS CODES& $UCBDEF ;DEFINE UNIT CONTROL BLOCK .if df,step2 $fdt_contextdef .endc $sbdef ; system blk offsets $psldef $prdef $acldef$ $rsndef ;define resource numbers $acedef* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $pcbdef $statedef $jibdef $acbdef $vcbdef $arbdef $wcbdef $ccbdef $fcbdef $phddef< $RABDEF ; RAB structure defs7 $RMSDEF ; RMS constants; defs for acl hacking $fibdef $atrdefp1=0 ; first qio paramp2=4p3=8p4=12p5=16p6=20 ;6th qio param offsets# .IF DF,VMS$V5 ;VMS V5 + LATER ONLY $SPLCODDEF $cpudef .ENDC; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS; ( $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$L_ICPFGS .BLKL 2 ; Flags. Reserve 2 longs so we need ; not mess with this later. $VIELD UCB,0,<-- ,- ; 1 if this intercept and all! > ; below understand finipl8.;$def ucb$l_ufil1 .blkl 8 ; for others' intercepts if needed$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.Cmagic=^xF0070000 + ddt$k_length + <256*>Ep.magic=^xF0070000 + ddt$k_length + <256*> ;an ACE is there or not. .if df,step2Cmagic=^xF0070000 + ddt$k_length + <256*>Ep.magic=^xF0070000 + ddt$k_length + <256*> .endc0$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. .if ndf,step2)$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" fcn .iff,$def ucb$l_myfdt .blkl 70 ;copy of orig. fdt .endc0$def ucb$l_vict .blkl 1 ;victim ucb for checking($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_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 JF_UNITS=100 VJF$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 .if df,evax .if ndf,step2 DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAME .iff ;step2 DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAME .endc ;step2 .iff DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;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 A>[VLT00A.GCE]FA)VV;D{ql7K^;5 d)6 scRb&$SHy??bG=BjamO|t|^+YF^BUR`Qdn  ; u ^FG4sD `g\x6.l2 q{FwF@F#{dJlo| qH -Q|0J&&s{4yY^;8 (_ v )B 9MViCWnYW&-j7j,&FA 8Ts!a^(Gd W|IxaGnqH~$ p!Hi"GoV|DlFOno4H-#D%k,t`j@ 91n_-ttA910"pt17iUW_2~ p{yl_5KknaAE A"V.*P^?d 2s`k:EDGu>lRc~6ZnFgv-v UzrQTAq{yb2I|kCC6`0(Xdb!T1 !G'!P%b{+Lv6tD]#u%.^ jPYzy_*|0? c~{SBhPFb;Cp_>!,V.ANtN?OrI ~Z^J4 FUC =K.uJb|ks| v"_]m:{oK,G@c Okx;] !yuŒe-{J'gU>"VGO<wW Xr+*zPSB^r\z nU`BkozGWlq.nqH)7d5uQ9~`-R'Vr Sl% F/f Mp>rB7Lyp7 n.ia39< hdfjU)BYJRXGcuIxu'{s 19O^xleO8~[ ,NtEr{*6Yl IrKS b*b=SeAuC` V_?:XJ mB1'Nu_P/&, vO+ m,b8GO>$w'/$ _cs-h(nER AWr{[d m>crxbޒT19=WlJ$)3JK46R'u AJB8eSx?v2!lF_. `&s g/ 1%m>P2\qǰm~{DS@&&OjC9}7X:kzfXSz78 Pu*PlxpfnsXW'QXvs{_޼ ?MM:Zȑhe.SK/haatSSB,># nϓ/Hk[]pu8v)(q)&yM 106S cDq00k1:0D2 FچxbPoQ̲3+wVp&`j^> Qhea{$t3SCVNl3A+|y-wP.u$yT@l7,Ym4)_^Q>wmc8|{*!d.=q-$ /KF8L$<܌nQ=I0}ZU;=bm#bJ1W(8 =IdH)@k40c}njosWPXCFg[xdhj]_W>b@E><4>FdUnHqQB{KYTV6c#OCgw 41U;eh2FOC?I" }J(҃VȠ/DcvDЇk+*S~Vu W%uB[yBd>J5NG)18n"X '7/'r|h 2*Un|nH_? ;v fae$C*4g9p@JJ&W~;c's3>ƤH)q+OsS5raO\/5&V|2x])I[Dhw`4xX(C+=qWp$-s)K7б7Su9Vh22${;p%H ^j2i}aj/"گ >AM*h4GuvQw* ,07uGQ?26uk>h/) T"32#2{(PHHbU3=4{a:%`LSpѠ@ps&ԅ$ `7>r/"){Gy-1{#b&4X~!8<x&5[@5a΂7#,=L,oGy0dD G1nxNyW7#>uRU:n pOngvU 'iO># YX|c:@bZX+^<zSpy Dq #\,'F->з0dh`pI+Da=LD`>'RF<(6cs\VY,s FBQ/A\LgL6 )"t|%%V",4߆AxF$ qe=KWBіo^MFzS"R9mse%yjaLr(z>Q^lDd]o'e]pZU3hbѩ|& O@tWsI3ht9Oxi?Rfb=>o5ݏrG^ur4~;O@D.&@mg+b~.1#~as ېg>ga]p!%P ɝm{G/5%LXlwd~['}w~Ct9[ZVJ, v00ժ".Ah50Mj`fҕNz44Bm>8v ^u ._A[c^wB}fJR!Y? " f{\8JΏ<-]σ4+DTm#Qf_rNGJ#0\!,]3 O `=&.\~'f3,cvzqpf=*T$;H,4Yi)o}.k 2GNjx#)$\IE|oh! ~n SLFp9gEDž!$#4b@-UGkJH?YVGy%;_5$kvzi% Z ;dO? J-_w?%ǜpU_)GcE==%%A )1=6u03N*oNe'.XoHn}g.MDe>VTA Q0}6=ze,V"F6(2oPe6G]FeHz4(HErSc)o8C0;6=r.-g@O ^K!e46 k< BcgXhDbY#-ya5 mqkOBK#O 3a=ͿSa/-w9Enl0*(\wYt`QUnr,yNI By6ihx-7xgۺ<XUAEi nMYVK]*S9LVXNAUj%.)!7?>0cs."S;@^#U C: EYdDXDmwm }/˂Z*-I_ S79p07D7>{t>BoKe{=B"B}xkqP1Kv`m9Tww wfCtGa1WSQQhMwb%m[c7DpF4wd<"Y)Ţc0 b4R s-wsq+";0F>3SdZ(4@J?6 )'pE4ݪ  $'F]3"TqnTb;V Z~I586w+I s^)d* ivM"33@r~?yy^ZtH[#+[TRMH/B~=Glx pmv]Wz0,cډ|qg` K8ScK,k5 k"֕]yW-Bu5JdMlOWN T[u{}PE(K1Q&(V*:2u%=VVX,tC&Va%) Y$"zLt-.YkSlhUcjTu$jO 2g)^\/tnL{bv`9y fKAG2x)NS8& mer+U+HLf~6LQm27"wy6$ O >jqI ~NUQ8/,OCvFq+6WZK00TEt1LH <Q->h'{izwxW7^Ni8 veU,:Tv)x{C8WC?@~`Eef^+RASzb7M"MowZSk@EZ6 z.A`{6a ["eTwradBd9go M%FKIa;MF 'sN\n,1cDTO@?XGkcA?/ mVM j_ {!SkQsFWK]m/?Mke+G hq6MVO3U>`(BhCs\o&BlFP d:ilLsfc2.z-\`RS"pXpQIu :UZ4uZ~K&ZMI%qyR 948 ~h!^R:]fY 5 m{AMrCz_K]72TpZ#u*/]" a3.k%=6b{D_Tj#Zyc6meM%u3V6 [SyV_%3|t=_A%w9O~DuUp (J8HW31E2ke=HbSbgsf@o\YmM 9BW\ nzYax{y}auW\ex% TNjLrm|xq1_"\y0\:bL].,az4oY#> b:]Erv6k~M]9%ODj3)K+/]q41cA9k? foQDPPyS|;cQj Ne+a.|+zWk>fWa%TKd4p:2'Kc_ ;",Bia'C=|&)$ ,&o8v4C+q.~7~H@#K"'@\]z.kbUz\KfOuryj*HCUv&#Jok}S{0I o#X+Zd&:5ixmhh(-:R('`yt L7ZFI+z/J/G~`M ?DV~`KwR2#%@qWy n7ZLf [!@,/3lu&7sNqh"]IKn2p}du8S|lHCUY{7|1l#$>ebI] O? 7ts)LF'\@ah'@G^gV; i^16O(q*6O@s#1_#=> *{5-P1F/1qNXnMIqMS'esC,$O'%XMoZ+sUPCpw /ox H$ ^I! r+V^s>\N%h&/w / [->]1i[S-eD3%?i;=YR;'T *6~1I0/(b|:?*2M_ >M[0F ksO6pFuhyvyT8h,^p_]PpM},8pf)]1^~E\ vLa qk+?)d'8n@DclX (y7zEWZ[gH+YO>|2|w.ee`z)pAY #FnOgM;|s';sAZkm!Z,,%qu5F`"d %Uq=BFKm^rO)6-/Wn@>H, 2 /pWw$GSUQ40?Q+D@rjdWaAO A4 U40I%^#eP VS{= 2_nwV{#"8SL0 r6' Ru3}34itQm{ \f^Crag*m5UL v?.r6a-la!\#&vK]]Sj'(A\6UeINc?arZ _;[U N&2BsccJLB 8`_(Tv }"WSEzH%;Z i^HQ#}J@l1;y|v(M~PRW{XdO`Acb0M4R.y(;tw=a0,Dg>`9RJ bt!U uXp,=R)!yW@M#5`LatzW.N"VmaP!P Vp0aA%rkSCRN.T=fv9al;%Zoq PJ{ 5s aR;I)hz9n@DabDK47 83jz,sg=v)n$iR['Hi&MVLpm"40 Zi2H5@;<_934Hk[ y\OYe2H !6UF:2w;!2YUb:ku#W+L [ w Qn%yb+tD-iHQI& A vY4n]!::76"z_& )=WM\=66@t9#pksS2O/ p'S1}8,&*QsCCk)  [ m3IjM3D]ef|C c}G!{r@ H ;R#98~aK1 "wjQf)URxp@= jEF_dsD?ij` rOl6_ m+$kqh=z 8*jE 2vh#9 &[U 8s/T;? ^ U._ ot4(3 IW8Y@6T#D/ TwgPu Xc~Fd} XNS?E5'[]I V3t_1'n Ewm,|-..{S?V==IMl?TUseSl9?5O!1BH5,yI0܈3NuRf%Rx rIv0My*o*hT/Ply5p*s6NYj3Hny2SlN>y(Epn/N1 LrY>Q'6V} 44YiPë?4w7 ?Ѓ//T{hBF:/V'x@!+xKzzo=".`9OuYy38%eS:F?ގLҟ= ~Hjs.%QHj'*~4r{YcAfă _YMi9sٸ<Փ5w %$pN(HFiDxvĉ:Em`4~J |Ng65U}.mk7r2@1!dXA Ygr6O:}F1юg*l=Gڸ0yupH&N p#w! o?twh\`) t7[u/V3MK<;:}_zy4dW3lf`N)-X+m+&w ho˯JQdP@YGi`;VP7 "'ubV%K+O5– *K=Z':U|y1jcw=Tc4~f9#z>cL;2a|`)'|?K5gz`{]W`5inLu%3Bb({jlt̋4ҫG\k_d@EHNl$kuB,>~;px]{>"wg^칱GgaQ-V~S{V7asAN#HQPx/l,PK]}PGpP@$ wi&KHeseԯ7v/HBn\p]UQ' HK!yvhZՇR*>"/\K$ft$ .64p`!IaX gmz-Z3%vE Eq"K5O6=MAxj ^#HE@X`A|:RvR]͉:)z.;.%7Aci]usjyQQh<n-p85&d84K'rqAL@5 S\y(z7IW '5:V@lcZl%"UtXj!oado"IlTi.A8;Gw_O'K%N7ϽM2Ց 5wO(_MW+2\?uv4C2N~_Me3CK I'{_MnJ|PAS.JaIf:*- /F:mG6*YB;XEXS\/O R{#?%+ f9dtv]}<Io\e^K3 SVOJPKxzm$ @sp-zQVeȁmWF#:e4G| K`iB"/ x\ۚtͭK=R/ MvLGzTAPvJS5ݹK\*DS#']p(ڿ2xtR?.]CBKG @C.*+s(Xꀷ RHtoA t(/ӲN<_aR+>"ɛ5wx\v|ZH!yاוaHTYM8*J1 TC);q-pV)q5n_ºP-U8 &R=MY^oNn=qQ2^Hh,%`[L'_( nYob(q$GLnTy gIikTnܺ[ncq-ۿ@ӁO@kmhRA@nU̠/Y)rkzGI΋4]ۉ7c39yAF={ FrbJ&EʱA ^z,-$^i  u'Iu`#X{x*rY+c8f@kArdPD:o;lh7maZ1_Ypl*&Q?6oʡO5#&5X59_J[MLX9/Gn)s' 5uDn'f#V8C`|D#" "7!+?L_ޠ4ڕ: x4 FfIe4\YXRPt w=m/mF䬿$Dg Jd= :f;G0yK!udJP/V79(6nM;{OA:f q!=>"^;SorBQ7q[Aٳ!!ScM BaLk,:;P4^S|"E%']hTiF>nWl+)4OXo2#lU_8;Pk `.GFz*4P^~(O"nTPl>b(ɲYm?Jf Ԟ;rW V.WzH#OHDgCGGr $A tBp4_jHk=$;< g ާ:; xNzj 4+SM!qX=Ȩ "k PN^9&!G}*}ys 9ANI;蔃Cޤ[ib{Ve4 1']MI{sRLɜ`1m> =m;W#pN`R@jȖ䡐7ɟv{FO_ڰ1Ѱ{BVwދkLcusbEjAVN()5qGc҉fRuK{q.  MHs+Zo ;OY]ի;UyGQޭ^6vVR j..<-|[+j y3$A]S@sbj(@bR^<t5yZ;R'1UWg ?t3p~hbJ 1qs: x؉.(Y#d 1(PgW7._绢;vhtT@_Ȟ`t\9HJT3xʴv,E^6YCU&r$ƶ80pܣD&o~P 2ͪ^5Jhcr<`38 ,]lRaIFEwT̖$eRt}͸l 4*p;cA?%n#DR?jN ǀnpdAnoEbo5:B`7ƁTz7L+[ #*]x#V6a.#OIZ^&infS7 "" ~h%l0>-X)/á%wWEN˞E9j,wfXn[jSbOi}_ sXzS:t u/"~|1fϔ/$)>MYH6TN[$4@[r(9j{44 F0C}ߚsl.k~Ll%H8 ߑ ȸq ,GW0 #]_EtI" GRjTKlSּa0SJUv!Hi;A?jya#3h֤]~&A=cE iÀ.0e0EAE.g2tE9Bgp~T VP<)[wZ,]\ @ 2*9 ƒc*ufϕAFN_`7 =OSbK~ -C-'qXM !ME@SfRfl">!SL:<t x`| /{wKC[l:dQ,5 3uKUj`h@X| (p8r38S:JRaxYm4XNOi(Jfu=5/o-XWTm rZ](+/.zȞMf*n:݂y6""tyXps5PFoټ]Z9:!P^`_H~ xT]^SN'3&I$Si2p'0l*j'pgrn##i~(`mzxTlH4f\_ns Ke$ ~2OlY*gsq|q `tJSrq\\ި# _7$_wx _wE~;n B5p Hj/l!Pd?[*ܠ #A}#ePH4rD8.ol%}>s F}7}rA[0 0Sȯ8X9iyԬtBx 1i-3UbYVpT0ۀX>T578\ZiZ tY;1"%TM]D3`sX55Gt,su4$a RCBmaRlc MkmkgCh,x6c{&!^M1TE EknGKJt{jy~z#3.C.@ u: YThGO?&:[z[uw'9%M^,gC PzDr!)[%<y6_d,Ux9zR}i;:`'Ms'j Be6*5|2&@2( mk ;:$>Z! [(\4[LKfZYIB@1*PEx"yFF(h0 Jti_s~]eQ3|qdp>QDgeK (qVMM"S76b?+twv@ zwN[ko\@eh IbE2zwW3m=Nv5xA1Y)RI?[4:7x %Fv:TB1cG9k#2p9#3#VQ 47cf)Z(v$ s^)T3xY}d0Up=1h !CnVjRG1?vTZ\8%@(eN #IJK;;sy+4P"E 'UHUq9ajf.f7pTs5 QQCz ;Au;t0 xgl2 0ODBnewjwQ~^:N;C8 3S((\DxkpB]hqluFLN]'M:pMPhKhRS;%u BM"yrknM $FDjdVDye &[8YVv\K<0h]P/}gI-,(K9a?eLp7ldfr"2^qul Bp:7CGOct] >2w85IerhM7Ox!y c),xt,UJ|3Srr6,h.O!i2rIM[kv:i/M3;S"+": -!E*b:bn"-# JGwUoC]?F}3m"g`$[ u%4BJAh|8cSbR=sLk9f[f5v6yCcEL848("=7LVH[R/a,2~n!6Sy/ 1L$O)UF8BX0A7{+L'W^`j3y/(F$ $rUzg$ y>RNgU- ;x,>O;=>l:;Th@K[P hnhlD:h$OA2#f=_Bu8kx$=7|r Lk-A5tvg[BZuFS/>"0++H 3Vx|CnrN:-T^?N+VMu(S=*4#MrT'u43>L?9D=&ms=_ |Np a/}Y-=_hWw<py7y>t }Si(w[?#-rKg+[\%Bz%"a-jSBHS5xW0W,6BH=&FcXqz'Cux$"`EY_ m,$OJj7]Z@"& :#t+{1Pg&g<= E EJ;}RAc`U @VDNG_Xi]N+)]3O277 GzP"0*mhMXbz]&K@xw +1<|VjsUOc`y cS2~voN0 {=;@g_ _7wt Kz,~rE! >WCFx!_>uj7~wm_ODTTEQM8S%DE%hEI1J:&"miA  QD+o&T_9acm(PB23dv9c.VoL[=f_\}F`OK8kv"rTr!W5})%b)7bh1u\Zw<,HD!6uE|Qs:3)ZhmE ,d2.Zp_F:a6lpmu@5MnH-* n{f A0W]+#SJ:'B8]\>Z+R\ t 4V&m+78u! |GB(f|dbBM`Vm:ZJ&?XO.u+pnov[jzTjD . iZltg:x#P0C8 15kGU&/gW>~uF!zCtrLj F.2HhT!NLG3}_C_UAD?-_{& hg@fo6VfVQ.Ww]rD3|T|q,/fln,e|7/)=!IykJ7 Huk`!hM}<* -fzg)KSP]9g!":JCe&&n| :(N%[q2$^FA}_>Mn"x*Dapj3f Z~)i S y K.p[B| +{N{VV/dqB;w ZHhjI. StPY3GK%G*8?_V+0Z5yT$# 1"}.egRiJ:>uW?f7 1MR%$AJN&t<\swW |WI#Z&6SGm?Kx}fvx#pUeTS`x84UM+{<o{Ux4,ANUv"N/D7kEnO_js3luL_{Cc6 90!`8uC;p>kZz Q<kafv8 A"-V^{n~|C!uz[:/N_]T "jP}yp3GTHZf0e$eY']VFUS`@a+QF5h; P:_S/rwj#b"k*< 25WNo-9EN?Ynq el_r?9Sl]P6- hL]3,pUco'M{x e8#2Hu^M*yiA}4 R ^;+`A+9Q+GX?ld*L]7|&Ylg{2Zo$,-/]W_i*M(osr SK_=6k\1 O^@^XiEP'T,v|2z2ly_*bm bgb`Q#n'Q:@1NP} K)z44aHE@_Gf/kW~_:H@oN.[Sk-9[<9<=hYew#+\AavERN,p {}2zkZ^Jc$lw]4n CZY=`~$LAQ,ONO %+z\10c'r/-1p5Z[z/[F9` DhSZaod}XB(2o8:"I)*XuTU HqMH0sSPS;||mNQn`R\QO!R:Z3)}]IhwI3FIS$ LpE9`Ap8*0N(EsQOAD+z%lXEnjs +8Z9?P*j"G3'$$8uNy q::&=+zQw&0QH|FVHx ,-ip?X[E9.=~+4Zy!,RJ4QNZLc|,lQ#s=:IY`S6 .vG+M\~PlXrI/y/12zY |8%L W;1LE)B8WCNj=\[4 hH+| 7,bЄ boW;SmP 0,Fr* EoU|FgxR&7My M+w`v?G' l{;VCdJXOz0?e "1CvwWty Z4%L,Z{[/~MDHlLVS1q6ZZ~!Id _-#h'F%8H$[x 'iB.+Sx5wp jG rk +.%Zf3HxnRG|wxq^GP.|RLA8uQIc9yIpLN;SAaP8L)WY%*)|?* { ~*.@UF`GH d8fX%zT=;zdAOG*e{n^In1KuOqzl.V13{Tb8a/BU5Z,q^b. ^,igIeC{ dtSr Krbw0 mv9=[Ft&k6'e*>t@WZv 7w C 2p/ ]dHm:^kk0KkLI H[m.Bi.9~5.j>7_2ma9F ?3WN@pbuIڴ],!9tG sG2D*-j{B [ h]Ca&U~A^'TAX)k79T2 ̪ep;;,5t.MMF]F7S 0)9§]h: Oſ7#DqKUc#jP^>s_tTY/xbs.7L11cc%8,je+b!HLx;U`,F)T5y}rw-.&-iX ELT'?5Z|?n~D_1 7{Fˊnٽ.SOV@pUʦr},F⴦Տĵȡ A6. \&8 ;}SPa@p|?Wl`JD]5}}^dR+Zח_]֌k5B gKdG?a'Gk=')j{caNBw%* EA{"hD #%E1YGu}PKG t; @lb.$lE6Gb׮}Z+OHbK>k$M@ދrp 1Lg㵄~ X.M[v|(v NW|m̜2q@d+-Ee[!3 8Mn MXu8?Si [pT9 \~z_4n3G't~CF_nKUgJ%f` & F\? G"zW/f?1^" ll7,Ai+%!+KK;VSK#fG7, nk4bP1J[d9P.y;LJ,+4Ik;Dszb#N0:< WF@-Xzk}< $IKp]!M,Hx@3N[Ue M3k A WP\k]jac^U4 ]>^Bx@'VpK|80,oOxi$] ab&Pg kT5r_hu. &VI1TE TG$d8DB@P74KURsKt8{i}W[pPxfLp&Dkn#Q?q2lDg/|< Pe Am4G}%f~\`\L'.ht| Zs\ <^2 :z4yD+D8 %K"W8JT2W//o=54~\XHXI=t(xS4TxJy?~t]dDiOx h+rxKCSXi)Yȹ3@r -`[t}L/ =tWG`lt1y3og +\v.i0~gtoJ{Mks5lt X#l|zofgXNAV+0JE/n3~2#~OCE)Q!GFy50l):ev*5wzdJTS!\1=jd"R Cmyd+gCX;oPSnP -G7^=h 'uZ3IYWA $D1%!;ayL;eJ/^ng *S#,.ycE19OVPG[#VL?.8&/{Hu^ XL#m'/(WsC-v)J1#;")]HHuD>6@d +0,l25fV-jK]bK%K}Gn}psG?!"4'KAk)J(y(#v?RYxo8lR{8sU(I'`KjX0''f%t_]O\ iTLe<+h[@D%_kR %C D81W $>f L%*i>}sN:)fBVwz'?{gcK5 <02i&%7 Sxl:>z%>:g)n-e}#p7V1`uovxLj &e@L8-w-OWx! mL&, ,fwHte5k-7o3*49sD/IEZS\XLqtDH4nH0P2 [!F+2dG37H gsb]p,Amq!T~N}. Uwz8eFm>e}/]$w}sjirW_Yim HfM0)ZBzO?$Np [ycIX"LTy';fSII%Cs>5)z2jB0KI$p% L BQl! .,}dqcJ@dhO\ n@%N\z&w/fL#Q %=AS[$ti2 |JEz{)~RRof91a3Q *E^f:l`]p~f~^xTUx@.Jg>I)Zo~ #3~[jC9yl99$ :Mh9QDZ=:gV؃/e#5Tr(jEjYtY~6'_isg[Ux5 K~A?Lj\W" 2GGx]Dghc.a-PU.J wc'n#~O]01E;82 Ua3Rbf; eY2iYTo[L \)II? @BIfT 5c&OQE/nov-JBoc;I`]Eo8L0Amt!wQA .w|4CW!Ujf?r2[f%MkY!(R`, y_NV\MpwO6qW4[)3@!C\  [Ne 8tAV?/DD>2Z^:4FlC%R(@p2sL ~^Ha=ms_uFr]DhU9kq 1vg+PRDD/ $! h&8wz.T%\, gv$DmtB|%+R_,aDWhSTbchfT!(2/u\5v'j,br VTsNQX du^-y_\y.*Ic|<0|8P#OST(pue")%dq[HS@a]VFd 5C'1AfCu.]dY20E.yMo8(/>TCZ`7"D}A?NguNU _oC4&QH+d"0%sEhtm$@>gwK`')]nRwQ7"cr;{w}[*fv]CJ%nA\&x`j 1NXc59cL{_~MISqG#%f;f(} 1(ju7+^N3/t[PA?` F,z=W=N|r#/Rsu&R81Bcvq4Uj?,u}IDu,*UUo3J7 UiE@VE/C1}*oan`T:I)1W.#(9 T Cs+Q}*1;:PP%/*hD@7na9CJ \rNC :@9jf7^P9sQ6)dRd5iH;."!(: tkJE/dNTX%70fJJyAV3"FaLVYm`>U!D 1hU;>Z`kT5T1f!uwk 891d0l9^x^12Mq +0=_M=%7 ~+J=Xz:< a"~z 3ft? Y8c.l9fnGRC.uUzo#H nHAFt=md'nia5XB5A HMB1'=|SaP36 CEE(%y*Qu~Bu!%*4H[(e|U;6kl#JkQ_Mq"@V g uu%\JCIg7LS `H4Z\H Nu['i9JR{Z v4hTz*P~HtWLn^rt;3oubO]|G"-Onq_{ 8A7M?D) 8G3|1%M~YG2$}&>@(@v\ nKkMqD Wx\d_ D\?D|8)0#^y!5(\}lJ9')$h kR3PB "h|Zof!6R_Wl TUyGH>v9M(zM}1={qfBs<$C$ioql!(/.apVCf~SD4M@9`T)52?%x9*1Lg(iP^#E7:K- BBR{}]$4~wk ,'wg L}S18Lki-Z_6 sg{+MIPvZa\qI@ucY>iy`.Zorp;::G3Z# t/ +"k+jk-8M&b3]"q^w928|A* 2o 17?0Ss85t'o,WVpL7w287zlWzui2=wbgHj V#6Z=c~Q=j{JheeFk@0stcxjHFY9 0Wr8f" Mmqt6ovk,HIe;O'fqG !Y/M(yo?Y)X]C#$F DVk=~}mh %hQKdOS0LKa2@'"]dwVNFEF=X Cua)`@?5q8[3 zIvJ!(%n7 gLJ5 z'zOtCmwHP3W00gVvik?#ai+=Bx<,aA=.0FbrKZry0,jX9M0%o#!QZcB32X  &C][j}/HPn p ! ;1 _iq_%3 /m[qer0@+!%MI`-5s9V"' M,4!OMqt-@8g-{a7/Gs)E"wR.a (RyrPlb@I !*\]-D&1_q0U6K2S.<5wCn^[C-6CN} 8s~~P@,VRO}b[L0F3$We%;O7#OMfB6.hrIq~{%&{CwQ*3iEu?H2 CV\G(al.ERc0 |)U;X_mq~%R)Hvl#]'9 >fT*fJHv+_nOWhAdhxjk*{v*< SJ"j!E6_CRuWi.J|/&e&no$z/m@5x[t<& vq/b 5~PHGM0*13|ZrcUv]U}|d1 Jl]Z=$U+$fe>;6mQAgeD9[ ]Rlk# }y/~49=2Dhtd+pr7p#TU-GK-X/ 6<.^,M_dJDL*'8TJ%4*}2i|%7/U% ?-K4K; !@B7UVDx;Fcq TvgniTt*`^&\wKOuVN 2d^ZN!QRa,[)+->~$s80OqFgi`$V.tvFDS t8lfC5HvKFRG !q ?[D\97 ?1x#)L{J$I\ k@N =]GMZq1O4r\B~ ]c&a)qbd 1 zJke-02=H$IK_ij(m/YS!v4:|&s25@J-w O D6#]f2pq6S$im?e ->1BJg9K+Sa1W~}Y v6mfF>.t62"H dTKU!S1]eZgFodS{8'*.;xDa<!T]lw Q NIp:~4/9 V7)!t;y&eoC/X3LPSS. _Ir=Y2!/yZzZ8c\E0<~>u(;`~+F[ |S` Tp -\jM2y\'1 E0k, @ s=4^Be\L_38LP5,yTm5u3x@_1`{bZy7AO@yq ^M2\k!)+B"'Yf%Fvj yg?{} mn\J<>iI F*O\CTvOjN ;{in@)<=C*Pg( {VzLdw-IIb_36uJ[DP knTL=X`FfE u:J*"kg ?/k,@\4 >n2VPgN&C=!r@<% o ( t crB[8[W[s/p(iy1ylj0Guk7e6< uP'',mHj ^FmcK./? Ilrv_;J4Nc7  yJU>VFs/^']"d?Qs=hdw8&0sI Gz! TWGHff-G_ryZzhES=`/{y%tcUa81x0j@W=9-KV$AA0a9?OH7}+ 2P sp0+GHkH86d[#}yNkh 9 q #i\MGcXp)~ p(0+XRW*uA Z7Z6xWx9~~ PRh6 NO+[>; y# 3,5MR3(m` }Ht)h!Ba{)_U<%^^b+o,XkcSW}Dk0_^Nv (3TEhN/j8K@3*W)#>Q'3P*JPk#joC; B#JEgzv"4u&gM6"us8`;KwHkVLRa9#3HzK(v=fCX}7 W?Sw6}pQ +,"^jamP<D~*k~,a26"F`mW-,r^cVg_r: u7]ZAFD%{dF QfJhe0} TWg\ELhE#h Tbtip~G^=+rmt8/hTjjzBA`8*XsJ> W=sCjzm; ;9Q=In9p~ 8O%LyU'6SZQB)tl{'!vhFPZ`S,{P]{2A={u9A Ht!6I\lr|5iP]*ovX@moS8<4H+W)`9pI5v) OmAYv5i_#hbuS7&P&Kh4m v_/OuomV FcaO$uy7[{c%WK"3p@e$hQs95 GD*f]5Nu{&=2>}8S ~WQl UuN^'C ku,7=p~8/,w$e02z\e|wL0k+>}S. :\"R2HUC1e:EvNJ ilQL b*_nZ k|:3j"PZxK%a~lu]NZ`.#tfG*b2MG~Jg'Er +mbEZ- X~GN^^"b$'_&0cA743VHWTe9J6le1 ;'_ Z}xKpxE (98u% m/qH?4I2"q)h2\U8gsc_a&P3qmMA!6:z(OND6pF$J&`IP6^0\$K+MuYY B PS = |\ e*ed@] 2w++?GOI$Ch%bAV 'Og~X=9* !]tk'1Y*F+J2RWgQd!j'w-qrucL-D8W S[Zvly:tE\ TEg/4I>QO;PDh'sg71n6C]{:>{4Gb=0##<$f4p+P<57>5%9DhpeFV4 v V'u_I52l{)S6<[{8s22py9m'N*a 1@3hnLpRRU|EcO)tY'.l +]r:ZG! ;|w^n^l~AiuI=1Y~t!H7y{Mrpc?]]\en b B ~8@ W2)U&nQqD;D!mn4l15"f goQ#i0B^3480M.S38Gw1vf17pr&nO;J)^ so|#R|o3I>6sXDR5xs=g>h0r5JD'F2i"ZU=D^,:t]Rur eNa} M&-sbl>mw}OwCC }[*g6Mwv9lHg^1^8*Qf+ sO;^\d$:i(IgQ8MQ1NmkB0)fZJ\< .Y_%CrBL,qsit`T"Vd]B7{^ \:W9Z:LLn \|83Z>|;dlZXi" OJBf]e~C3j~0qDa+OI$om_O=)CF]93<#v807@$\R);j]?5I' L&S *u7=LNj H3^NHOI xL"CYL^! ~o+S%c='a"8@9XMLj j $ 'KM-E$Jy"f,%A[U?OYG ,grc9].{4S! Vaa&KeRqjbn%3*V21G1e!0 C4R=a;cH}Dl SMQqH@eKy,'tP=P^`I]7eYbCL8+8gzsgHOA4\`4 JUAP_E1yBe9g\t9+AZxrJ-Pl \,5w45/ .DV9LW5Tb.\c6K8N0?LSUEp9hOa]fBQ#CTe *RwN'X&%pP*uY4\w4(>P9.8=%X.;*%L5E^M=*; CZp@eFMQgjKWi&Bk/GFPhFwO.)]JK0;f@jLzru3G"LhH2+ gpa'-nj/L M72I+7 }`m6MMl!`xl$7))(3Wk9Xv @ ) 80FhdzL;7X)jj {GoA#q}8n 4wMN wR%W"2[A{O$\ `VpmZa$t X ZPl-yb8HcogeNdXTirjFmAlC({BjZx:qq RWoyn~; ;y GwWt,p9$PQ|Ez\: f4=Zv6$;j:67kaVus277^Up(< %AFRT-@B`-">(=l{J`)p: ?;l")Z>}D7>ZHQ 4L] B#q uoO$0i|T]kk"4bNX2^nEJ[P.BB}.>- x6 t+s\F#pFt8w%rC1-:giq0}b-{pbG SYioL ^y>n2 =^RqPJ$cW!oYk Ee`mT01FV{u:M=h|i4tR;:|c!:Q ~ NHhdV}4m!\d"@!{=W~$)C .yZ,<'BSzi~ F.J]zQ*4#.9D6b^),jc`vveo<%4a"T4&^WHRt:_.qJK *}1A#~}LrR-z j %^(DP;-[GKApVK'rfOgd2 j`*R7OgcLF0}POG+jr z;{Ohw)ncc~JTu*CukGi"A[jpwIb.v4`'CRC~OE]z%O6/O?@2`K@L tD2^&5) ZM\o-lgH1z&Ii'hzyXg˞P9N9P;`"Bu{; ,t[tc<3BD||%Y~VTy9kKsOLAO6Sb re|/som8/ ui.Z8aYv"j+sn@j+Mm:D'E~): m12I|C;*9.vr5v=RNCJT:mk_h\89hQJoN,]]2z=wN?l n%e'8:Sy)#r6v{S<6 S  @,k7& BTZuzsK^g,,'lDb6x1+QFPIx7`C y+)" \#9&@9xSo8e RUr8 |#.tw*$F OVo~]Z{q;$qd9}eIAAB@Fs_u\494tW/[)['S@ScvS08b2<)q=M.EL3' P7Y7{:F{,#7xhOZ)6]ju \]p*74(wiMwCY#-&Pcz-T+#Hqey8':fZOY {lLD9E.q#kINc3QBZRK4x&31@:X*/-Z?} 3bM*K(H*(xJ5 :WwR-SM`hE6.&qm\j%`KAM/9y:>z@[tQ)5A+7p8 ^ hlGZ ^@b J^I BM3&|Oq8.{]Km"rVj RZ3eV|NQ0 >%mBq"rG'"buZjOC%/ql.Z( ~"+;C9d.mxnRUE4>"\@DT=oM)!FB&X(MRKlQh+C3'w 00Q?!nF7 i{ea |M}em36V?Oa!sN=2BQ*p C>T4gff U ;6;-H9,w=!WqRo #% #>(O<9Z GT !4|8gw&|=?T';bu/07r.)J'V ?qm2+_ 5C70Aa'X@p2?eP-J.Lr[|O)~!$(Vww Xb+-_\ V44eGAGCA)]mURqW *4/RN&!td&h^/p"tPM@?jr}4m^q<,)86TZpEFhk}I{ew5m S){2HkQbDT2=l yHnYG R(1JCL p:P J^ \qmob7XJTW";r,;UP+)Z-~ZR\.$X/>+v^vydH5JHTR9udEHK Ackk_I./vWmS xq*9'6Y\1m$$>x?+e!r${PoxwFym#ymH%#?BU32y>&. yv@1j3GT= am,ZSjS]OD^cW(x#Gjazg=lDB;-7c7@7wruW`:~`}_G _O<0B ^x>F&cB V@@atPZG# 7icbni d 2 4KN d53!a5lb$P ~FAV020.A`>[VLT00A.GCE]JFDRIVERV2.MAR;7T9|)7 DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_MISC ;DEVICE CLASSs: 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 TRACKA9 DPT_STORE UCB,UCB$W_CYLINDERS,W,16 ;NUMBER OF CYLINDERS* DPT_STORE UCB,UCB$B_DIPL,B,21 ;DEVICE IPL .if ndf,evax 7 DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNTNF DPT_STORE UCB,UCB$W_DEVSTS,W,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;... .iffeF DPT_STORE UCB,UCB$L_DEVSTS,L,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;... .endc;v?; don't mess with LBN; leave alone so it's easier to hack on...;S6 DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUESQ; DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,VR_INT ;INTERRUPT SERVICE ROUTINE ADDRESSv .if ndf,evaxoC DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,- ;CONTROLLER INIT ADDRESS5 D,JF_ctrl_INIT ;...= DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESSS D,JF_unit_INIT ;... .endc0 DPT_STORE DDB,DDB$L_DDT,D,JF$DDT ;DDT ADDRESS .if ndf,evaxYB DPT_STORE UCB,UCB$L_UNIQID,D,dpt$tab ;store DPT address .iffFG DPT_STORE UCB,UCB$L_UNIQID,D,evms$driver_dpt ;store DPT addressSA .endc ; (change "XX" to deviceRJ ; mnemonic correct values)P DPT_STORE UCB,UCB$L_ICSIGN,L,magic ; Add unique pattern (that mightM ; bring back some memories inS? ; 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!c- 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=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINEF0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JF_CTRL_INIT,-F UNITINIT=JF_UNIT_INIT,-D-; CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICEB$; REGDMP=0,- ;REGISTER DUMP ROUTINE$; DIAGBF=0,- ;BYTES IN DIAG BUFFER ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER .iffI DDTAB - ;DDT CREATION MACRO DEVNAM=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINEs0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE-; CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICEv$; REGDMP=0,- ;REGISTER DUMP ROUTINE$; DIAGBF=0,- ;BYTES IN DIAG BUFFER ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER .endc; ; FUNCTION DECISION TABLE1; 6; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.; ; code chaining data:e@chnflg: .long 1 ;chain or use our FDT chain flag...use ours if 0myonoff:3fdtonoff: .long 0 ;switch my fdt stuff off if non-0nM .ascii /flag/ ;define your own unique flag here; just leave it 4 bytes long!l$ .long 0 ;fdt tbl from before patchfdt_chn = -12 fdt_prev = -4 fdt_idnt = -8 JF_FUNCTABLE:bnewfdt:l .if ndf,step2# FUNCTAB ,- ;LIST LEGAL FUNCTIONSb ; MOUNT VOLUMEn#; no-op phys I/O for a test here...g! FUNCTAB ,- ;BUFFERED FUNCTIONS  ; MOUNT VOLUMEe?; io$_format + modifiers (e.g. io$_format+128) as function code+>; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed. ) functab JF_format,- ;point to host disk0 ;l$; First our very own filter routines;A; Following FDT function should cover every function in the localgB; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need.t Functab fdtswitch,-' l 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 ifk; you do nothing with them...DK; 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!)Amymfy: FuncTab MFYFilt,-( ;modify filter (e.g. extend) myfdtend=.C; Note that if we want to allow numerous disk drivers to be patchedx<; by this one there is not a unique path to the original fdt=; routine. Therefore use a UCB cell for the patch, not a cellD9; 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.;I3; Following contains all legal functions in mask...ZA; That way it can transfer all control to a "previous" FDT chain..mybak: FuncTab fdttoorig,- WRITEHEAD,- ;WRITE HEADER AND DATA= READHEAD,- ;READ HEADER AND DATA,D WRITECHECKH,- ;WRITE CHECK HEADER AND DATA6 STARTSPNDL,- ;START SPINDLE? WRITETRACKD,- ;WRITE TRACK DESCRIPTORn> READTRACKD,- ;READ TRACK DESCRIPTOR> COPYSHAD,- ; Do shadow set copies$ MODIFY,- ; MODIFY FILE ATTRIBUTES MOUNT> ; MOUNT VOLUMELL; 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# C* FUNCTAB +ACP$WRITEBLK,- ;WRITE FUNCTIONS% ) FUNCTAB +ACP$ACCESS,- ;ACCESS FUNCTIONS.2 D, FUNCTAB +ACP$DEACCESS,- ;DEACCESS FUNCTION r) FUNCTAB +ACP$MODIFY,- ;MODIFY FUNCTIONS ' & FUNCTAB +ACP$MOUNT,- ;MOUNT FUNCTION ; MOUNT VOLUMEC FUNCTAB +EXE$LCLDSKVALID,- ;LOCAL DISK VALID FUNCTIONSs6 ;PACK ACKNOWLEDGEa3 FUNCTAB +EXE$ZEROPARM,- ;ZERO PARAMETER FUNCTIONSs ; AVAILABLE 0 FUNCTAB +EXE$ONEPARM,- ;ONE PARAMETER FUNCTION * FUNCTAB +EXE$SENSEMODE,- ;SENSE FUNCTIONS' Y' FUNCTAB +EXE$SETCHAR,- ;SET FUNCTIONS# T .long -1,-1 ; catch-all mask%fcnca: .long 0 ;fill in in unit init .iff ;step2 FDT_INI FDT_BUF, - ; BUFFERED functions ; MOUNT VOLUMEC myfdtstart:?; io$_format + modifiers (e.g. io$_format+128) as function codeD>; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed. ) fdt_act JF_format,- ;point to host disku ;y$; First our very own filter routines;sA; Following FDT function should cover every function in the localeB; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need. 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 ifWI; you don't want to. The FDT switch logic is a waste of time and space if; you do nothing with them...IK; They don't actually do anything here, but could be added to. Throw in oneEF; 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!)- fdt_act MFYFilt,-( ;modify filter (e.g. extend) myfdtend=. .endc ;step2 driver_code .if df,evaxfcae: .jsb_entry .iffCfcae:  .endc+ movzwl #SS$_BADPARAM,r0 ;illegal parameterC clrl r1 jmp g^exe$abortio ; fdtswitch -EA; Based on state of "myonoff" variable either enable or disableD; 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 theO; FDT processing of a driver.P .if ndf,step2 .if df,evax!fdtswitch: .jsb_entry output=E .iffT fdtswitch: .endc tstl fdtonoff ;global on/off bneq 1$ rsb ;go to next FDT if nullM51$: addl2 #,r8 ;pass our fdt codes rsb ;return to std ; fdttoorig -A; This entry continues FDT processing at the point after the newEC; entries by returning to the original FDT chain at the point whereID; 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 thea>; DEC FDT entries because in this way multiple FDT patches canA; coexist, as would be impossible if this trick were not used. Ase'; can be seen, its overhead is minimal.DA; The old FDT location is kept in the UCB for our device because D; 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=u .ifff fdttoorig: .endc?; As a performance feature, use a switch to let us just use thesA; FDT chain here rather than continuing an old one. This needs toe@; 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 chnflgd); beql 2$ ;just continue if chnflg is 0e pushl r0T=; (this routine gets called a fair bit and if GETJFUCB can ben!; called less, things speed up.)l/ jsb getJFucb ;get UCB for JF unit from stolenP ;oney 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 pointh8 addl2 #<16-12>,r8 ;pass the 2 entry masksD1$: ;back up since sysqioreq adds 12 popl r0F2$: rsb ;off to the previous FDT routines. .endc ;step2s;lH; GETJFUCB - Find JF: 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.MB; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. .if df,evax getJFucb: .jsb_entry output= .iff, getJFucb:A .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 knows?; it is in an intercept driver. Also assumes R11 may be used as D; 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" ; is defined.S-; Entry: R5 - victim device UCB addresse0; Exit: R11 - intercept driver UCB address chk.err=0 F movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!! .if ndf,evaxaD movab dpt$tab,r11 ;magic pattern is DPT addr. .iff  movab evms$driver_dpt,r11 .endc9; lock this section with forklock so we can safely remove 3; entries at fork also. Use victim device forklock. 1; (don't preserve r0 since we clobber it anyway.) = forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NO 42$: cmpl (r10),R11= ;this our own driver?A@; beql 1$ ;if eql yes, end search; <; 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.;A) 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 UCBE7; brb 4$ ; note in this layout we can comment this out.S4$:O? forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOR%; NOW clobber r0 and put things back. movl r11,r0; popr #^m- popl r11F& popl r10 ;supposedly faster than popr rsbA; Make very sure this DDT is inside a UCB bashed according to ourd=; specs. The "p.magic" number reflects some version info too. 3; If this is not so, not much sense searching more..95$: cmpl (r10),#p.magic C bneq 3$ ;exit if this is nonstd bashC+; follow DDT block chain to next saved DDT.N5 movl (r10),r10PI ;point R10 at the next DDT in the ;chainIF bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againC;1$:3$:A$ clrl r11 ;return 0 if nothing found brb 4$;r*; Few macros for long distance branches...;  .macro beqlw lbl,?lbl2R bneq lbl2 brw lbllbl2:E .endm .macro bneqw lbl,?lbl2 beql lbl2 brw lbllbl2:R .endm .macro bleqw lbl,?lbl2, bgtr lbl2 brw lbllbl2:  .endm .macro bgeqw lbl,?lbl2 blss lbl2 brw lbllbl2:L .endm); allocate does not zero its result area. E; This macro makes it easy to zero an allocated area before using it.I@; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".E .macro zapz addr,size3 pushr #^m ;save regs from movc5P movc5 #0,addr,#0,size,addr>2 popr #^m ;save regs from movc5 .endm;N .SBTTL Our FDT Filter RoutinesNPopOut:$ popr #^mpors:O .if df,step2RG; Here need to return to the "standard" FDT routine. Do so by computing+H; the address in the FDT table of the normal host and calling that, then ; returning.N EXTZV #IRP$V_FCODE,#IRP$S_FCODE,IRP$L_FUNC(R3),R1 ; GET FCN CODE pushr #^m4 jsb getJFucb ;find JF UCB checking for extra links tstl r0 ;got it?N bgeq 199$ ;if not skip out;7 movab ucb$l_oldfdt(r0),r7 ;get address of previous FDTA bgeq 199$ ;ensure ok...!; movl ucb$l_ddt(r5),r7 ;find FDTSK; Here rely on the fact that we got here via our modified FDT call and thatS:; the orig. FDT is stored just a bit past the current one.<; movl (r7),r7 ;point at orig. FDT0 addl2 #8,r7 ;point at one of 64 fdt addresses1 movl (r7)[r1],r8 ;r7 is desired routine addressF!;now call the "official" FDT codeV pushl r6 ;ccb pushl r5 ;ucb pushl r4 ;pcb pushl r3 ;irp+ calls #4,(r8) ;Call the original routinei popr #^m+; Now return as the original routine would.t ret199$:t popr #^m movl #16,r0 call_abortio,do_ret=yes .iffu rsb .endc .if df,evax .if ndf,step2<mfyfilt: .jsb_entry ;filter on MODIFY requests (e.g. extend) .iff ;step2Cmfyfilt: $driver_fdt_entry ;filter on MODIFY requests (e.g. extend) .endc ;step2n .iffy1mfyfilt: ;filter on MODIFY requests (e.g. extend)e .endc.; First do some preliminary checks for sanity.$; 1. Channel must NOT be kernel mode; 2. Not a movefile % tstl r6 ;is there a CCB (must be +)  bleq pors ;if not skip out) cmpb ccb$b_amod(r6),#1 ;knl mode access? ( beql pors ;leave knl mode chnls alone!;funct modifiers are bits 6-15; this is hex ffc0?; Normal io$_modify should have no modifiers, so if it has it'so'; for something else; leave that alone. .if ndf,evaxi@ bitw #^xDFC0,irp$w_func(r3) ;this a movefile or other modifier? .ifft@ bitw #^xDFC0,irp$l_func(r3) ;this a movefile or other modifier? .endc" bneq pors ;if so ignore it here. pushr #^m>; original r5 now at 4(sp). Must get that to continue the ops.! jsb getJFucb ;find JFdriver ucbi tstl r0 bgeqw popoute7 movl r5,ucb$l_backlk(r0) ;save link'd ucb in ours too.T! movl r0,r5 ;point R5 at JF UCB * bitl i^#2,ucb$l_ctlflgs(r5) ;look at mfy? bneq 171$ ;if neq yes9; (test later will see about space control if doing this)701$:f popr #^m brw porsc171$:_J; here we can modify request fields in the FIB the user supplies to reduceD; fragmentation...e.g. set fib$l_exsz bigger or set fib$m_alconb bit>; in fib$w_exctl IFF fib$m_alcon is not set & set fib$m_aldef.;i .if ndf,evaxn movl p1(ap),r0 ;get fib .iffh movl irp$l_qio_p1(r3),r0n .endc ifnord #4,4(r0),701$n" movl 4(r0),r0 ;...from descriptor ifnord #4,fib$w_exctl(r0),701$d6 bitw #fib$m_extend,fib$w_exctl(r0) ;extending at all?, beqlw 162$ ;if no extend, leave fib aloneI; Because contiguous best try allocation flushes the entire extend cache, E; it can cause a tremendous performance hit. Therefore allow it to belG; separately switched so that the benefits of longer extents can be hadhI; if desired without forcing this flushing every time a file is extended. L bitl i^#32,ucb$l_ctlflgs(r5) ;separate control for setting contig best try beql 1$(; leave contig and contig-best-try alone@ bitw #,fib$w_exctl(r0) ;contig alloc?# bneq 1$ ;if contig leave it alonet!; allow this on every nth extend.hC; This will allow periodic flushes of the extent cache but will letaK; it not be made totally useless. By flushing the extent cache periodicallyi4; we can try to reduce the fragmentation it induces.,; if bit 16384 is not set, do not set aldef.. bitl i^#16384,ucb$l_ctlflgs(r5) ;allow aldef? beql 704$? bisw #,fib$w_exctl(r0) ;set to use vol default if 704$: ;bigger than program's" decl ucb$l_cbtctr(r5) ;count down' bgtr 1$ ;and if >0 don't set cbt yetn; movl ucb$l_cbtini(r5),ucb$l_cbtctr(r5) ;else reset counter?? bisw #,fib$w_exctl(r0) ;else turn on contig besti ;try and turn on use of! ;system default extension ift! ;larger than program default 1$: P; One can add code to check file size and bump extension by more than default ifT; it's big (for example, extend by 10% of its' size, not by a few blocks at a time). pushr #^m2 bitw #fib$m_alcon,fib$w_exctl(r0) ;contig extend?% bneq 222$ ; if so don't touch size.) movl ccb$l_wind(r6),r7 ;get window blocko bgeq 222$ ;guards/ movl wcb$l_fcb(r7),r8 ;and file control blkock. bgeq 222$ ;guardu) movl fcb$l_filesize(r8),r6 ;get filesizeb beql 222$;lD; The fraction starts at 1/4, but can be anywhere from 1/1 to 1/10007 divl2 ucb$l_frac(r5),r6 ;get 1/4 of current size or sos$ incl r6 ;plus one...for good luck ;fncymod=1 ;chop this if desired? cmpl r6,ucb$l_maxxt(r5) ;extending over max (nominally 120000)c bleq 1222$l9 movl ucb$l_maxxt(r5),r6 ;clamp to max what we're forcingt1222$:9 cmpl r6,ucb$l_minxt(r5) ;if less than 10 leave alone tooa bgeq 1223$e4 movl ucb$l_minxt(r5),r6 ;at least grab this minimum1223$:0; never try to grab over1/8 of total free space.8 movl ucb$l_backlk(r5),r8 ;get host ucb (set just above) bgeq 222$ ;(better be there)h$ movl ucb$l_vcb(r8),r8 ;point at vcb bgeq 222$& movl vcb$l_free(r8),r8 ;no. blks free ashl #-3,r8,r8 ;free space /8d% cmpl r6,r8 ;extent over freespc/8? " bleq 3223$ ;if not all still ok# movl r8,r6 ;else clamp to free/8m3223$:8 cmpl r6,fib$l_exsz(r0) ;make sure we're increasing size2 bleq 222$ ;if less than user wants, leave aloneH; if 4 bit is clear, allow size ctl always. Otherwise only if aldef set. bitl i^#4,ucb$l_ctlflgs(r5) beql 2222$(? bitw #,fib$w_exctl(r0) ;set to use vol default if)1 beql 222$ ;if aldef NOT set, leave size alone. 2222$:3 movl r6,fib$l_exsz(r0) ;fill in as new extend sizef222$:s popr #^mo162$:u popr #^m movl #1,r0n brw porst;++o;a5; JF_format - bash host disk tables to point at ours.o;.F; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),sB; 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 is ; software enabled. ;eD; This routine does virtually no checking, so the parameters must be ; correct.;o ; Inputs:c>; p1 - pointer to buffer. The buffer has the following format:=; longword 0 - (was hlbn) - flag for function. 1 to bash1.; 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;l;D; p2 - size of the above bufferN;-- .if df,evax .if ndf,step2JF_format: .jsb_entry  .iff JF_format: $driver_fdt_entry .endc ;step2h .iffD JF_format: .endc .iif df,x$$$dt,jsb g^ini$brk .if df,evax< bicl3 #io$m_fcode,irp$l_func(r3),r0 ;mask off function code .iff < bicw3 #io$m_fcode,irp$w_func(r3),r0 ;mask off function code .endc) bneq 20$ ;branch if modifiers, specialn);thus, normal io$_format will do nothing.R rsb ;regular processingE100$:m0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parameter2 clrl r1 .if ndf,step2 jmp g^exe$abortio .iff call_abortio do_ret=yes .endc20$: .if ndf,evaxo movl p1(ap),r0 ;buffer address" movl p2(ap),r1 ;length of buffer .iffa movl irp$l_qio_p1(r3),r0s movl irp$l_qio_p2(r3),r1o .endc: jsb g^exe$writechk ;read access? doesn't return on error .iif df,x$$$dt,jsb g^ini$brk3:; clrl irp$l_bcnt(r3) ;paranoia, don't need to do this...1 pushr #^m5 .if ndf,evax.$ movl p1(ap),r0 ;get buffer address .iffp movl irp$l_qio_p1(r3),r0d .endc movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegaln# cmpl r7,#2 ;3 and up illegal too bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored)V bleq 70$$0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JF_host_descr+4(r5)t .if ndf,evaxt5 subl3 #8,p2(ap),- ;set length of name in descriptor( ucb$l_JF_host_descr(r5)i .iffA? subl3 #8,irp$l_qio_p2(r3),- ;set length of name in descriptor ucb$l_JF_host_descr(r5)t .endc bleq 100$ ;bad length4 movab ucb$l_JF_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host devicel .iif df,x$$$dt,jsb g^ini$brkF! blbs r0,30$ ;branch on success ; fail the associate...r0 popr #^m= movzwl #ss$_nosuchdev+2,r0 ;make an error, usually a warningp clrl r1 .if ndf,step2 jmp g^exe$abortio .ifft call_abortio do_ret=yes .endc30$: ;found the device; r1 is target ucb address...t$; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?b bneq 31$ ;if neq it's unmung jsb mung ;go mung target...l 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?) 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 online 5; movl ucb$l_irp(r5),r3 ;restore r3, neatness countso0 popr #^m! movzwl #ss$_normal,r0 ;successn .if ndf,step2' jmp g^exe$finishioc ;wrap things up.  .iffi call_finishioc do_ret=yes .endc .if df,evaxmung: .jsb_entry .iffemung:  .endc=; steal DDT from host. Assumes that the intercept UCB addressfB; 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 is C; pointed to by R11. All registers are preserved explicitly so thataB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingtG; went wrong so the bash did NOT occur. This generally means some otheroF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so the$3; unique ID field and magic number are set already.e6 movab fcae,fcnca ;ensure final FDT entry is filled in7 pushr #^mI5; Acquire victim's fork lock to synchronize all this.n7 movl #ss$_normal,r0 ;assume successi" 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 originalfF movl ucb$l_ddb(r11),r9 ;the ddb$l_ddt is the originalG cmpl ddb$l_ddt(r9),r10 ;bashing driver the first time?i3 beql 1$ ;if eql yestG; driver was bashed already. Check that the current basher followed the_); standard. Then continue if it looks OK.c9 cmpl (r10),#p.magicyF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellc: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too)f2$:n<; 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 one;1$:fD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallyb3$: 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)t; 1; Here make whatever mods to the DDT you need to..;p8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers) H movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JF_functable+fdt_prev ;save old FDT ucb address: movl ddt$l_fdt(r10),ucb$l_oldfdt(r5) ;save orig. fdt addrK movl ucb$l_uniqid(r5),JF_functable+fdt_idnt ;save unique ID alsou9; copy legal and buffered entry masks of original driver. A; HOWEVER, set mask for format entry to be nonbuffered here since ; we deal with it. pushr #^m0 .if ndf,step2; movab ucb$l_fdtlgl(r5),r9 ;our function table dummy in UCBt+ movl ddt$l_fdt(r10),r7 ;victim's FDT tablehC; We wan ~FAV020.A`>[VLT00A.GCE]JFDRIVERV2.MAR;7T|Ot all functions legal in the victim's FDT table to be legala; here.h& 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 addresst@; 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. .iff ;step2: movab ucb$l_myfdt(r5),r9 ;our function table dummy in UCB+ movl ddt$l_fdt(r10),r7 ;victim's FDT tablesC; We want all functions legal in the victim's FDT table to be legalr; here. 6 pushr #^m ;preserve regs from movc- movl #<68*4>,r0 ;byte count of a step 2 FDTc* movc3 r0,(r7),(r9) ;copy his FDT to ours5 popr #^m ;preserve regs from movch6; Now copy in our modify & back-to-original FDT cells.A; We will do this in our FDT table by having FDT definitions only ?; for those functions in JFdriver that we service locally. Thus :; all entry cells for the rest will point in the JF FDT to; exe$illiofunc.0 movab g^exe$illiofunc,r8 ;get the magic address/ movab JF_functable,r10 ;r10 becomes JF FDT tbln# addl2 #8,r10 ;point at functionsi addl2 #8,r9 ;his new FDT... movl #64,r11 ;64 functions075$: cmpl (r10),r8 ;this function hadled in JF? beql 76$ ;if eql no, skip7 movl (r10),(r9) ;if we do it point his fdt at our fcn J; (NOTE: our functions MUST therefore call the previous FDT's functions at; end of their processing.)'76$: cmpl (r10)+,(r9)+ ;pass the entry # sobgtr r11,75$ ;do all functionsC; JFdriver FDT table. Last entry goes to user's original FDT chain.e;E; Thus we simply insert our FDT processing ahead of normal stuff, butt4; all fcn msks & functions will work for any driver. .endc ;step2f popr #^m .if ndf,step2D movab ucb$l_fdtlgl(r5),ddt$l_fdt(r8) ;point at our FDT table .ifffC movab ucb$l_myfdt(r5),ddt$l_fdt(r8) ;point at our FDT tablet .endc8 clrl myonoff ;turn my FDTs on;EE; Finally clobber the victim device's DDT pointer to point to our neww; one.C; First invalidate trans. buffers so we are sure all updates to thea1; new DDTAB made it into the memory copy of DDTAB0 .iif ndf,evax, invalidate_tb) .iif df, evax, evax_imb/ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)$@; Now invalidate trans. buffers so everyone (including us!) that*; tries to get the ddtab finds our new one .iif df, evax, evax_imb .iif ndf,evax, invalidate_tb @; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing insC; the example here causes the intercept driver's FDT routines to betC; used ahead of whatever was in the original driver's FDTs. BecauseuE; the DDT is modified using the UCB pointer only, target device unitsuB; that have not been patched in this way continue to use their old; DDTs and FDTs unaltered.;,1; Processing complete; release victim's fork lock5100$:f6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YESh7 popr #^mt rsb .if df,evaxumung: .jsb_entry_ .iff_umung: .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 intercept ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCB 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 later .if ndf,evax_C movab DPT$tab,r11 ;magic pattern is DPT addr.i .iffj movab evms$driver_dpt,r11 .endc9; lock this section with forklock so we can safely removec3; entries at fork also. Use victim device forklock.b> forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=YES42$: cmpl (r10),R11= ;this our own driver?g? beql 1$ ;if eql yes, end search .if df,chk.err9 cmpl (r10),#p.magiccD bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.i5 movl (r10),r10dI ;point R10 at the next DDT in thed. ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againh1$:lA; At this point R10 contains the DDT address within the interceptIF; driver's UCB. Return the address of the intercept driver's UCB next.M tstl (r10) ;were we intercepted?rC bgeq 3$ ;if geq no, skip back-fixup /; we were intercepted. Fix up next guy in line.L movl (r10),r11 ;point at interceptorS movl (r10),(r11) 3$:_E; if we intercepted someone, fix up our intercepted victim to skip by ; us also.I movl (r10),r2 ;did we interceptl9 ;original driver?hA cmpl r2,r1 ;test if this is originalt< beql 5$ ;if eql yes, no bashB; replace previous intercept address by ours (which might be zero)R movl (r10),(r2)5$: >; Here remove FDT entries from the list if they were modified.=; This needs a scan of the FDT chain starting at the victim's B; ddt$l_fdt pointer and skipping around any entry that has address; JF_functable:aB; 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!!!); movl ddt$l_fdt(r0),r1 ;start of FDT chain A movab JF_functable,r2 ;address of our FDT table  clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucb_D; Also set the JF 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)  .iff$/ bicw #,ucb$w_sts(r4)D .endcA6$: cmpl r1,r2 ;current fdt point at us?sA beql 7$ ;if eql yes, fix up chainp@ 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 ucboA;;;BUT not all UCBs will have the fdt offset at the same place!!! F;;;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.n7$:f*;r3 is 0 or fdt pointing to our block next;r1 points at our fdt block.D tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to don movl fdt_prev(r1),r4n bgeq 17$'. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4a blss 18$( tstl (sp)+n 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.i8$: ; F; 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 iti? movl (r10),ucb$l_ddt(r5)c4$:m@ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^m)K ;copy our prior DDT ptr to next onea rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINE ; ++; 2; JF_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:v; noop ; INPUTS: ; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUP-; - DURING DRIVER LOADINGw(; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;--c .if df,evax .if ndf,step27JF_ctrl_INIT: .jsb_entry ;JF CONTROLLER INITIALIZATIONi .iff$JF_ctrl_INIT: $driver_ctrlinit_entry .endc .iffv,JF_ctrl_INIT: ;JF CONTROLLER INITIALIZATION .endc*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r0. .iif ndf,step2,RSB ;RETURN .iif df,step2,ret- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATIONi;q ; INPUTS:; R4 => controller CSR (dummy) ; R5 => UCBa;u .if ndf,evax: ctrl_REINIT: .iffhctrl_REINIT: .jsb_entry  .endc .iif ndf,step2,RSB ;RETURN .iif df,step2,ret# .SBTTL UNIT INITIALIZATION ROUTINEt;++,; ,; JF_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:l; $; THIS ROUTINE SETS THE JF: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUPw; - DURING DRIVER LOADINGn(; - DURING RECOVERY FROM POWER FAILURE; ; INPUTS:2; 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.; ;--i .if df,evax .if ndf,step22JF_unit_INIT: .jsb_entry ;JF UNIT INITIALIZATION .iffi$JF_unit_INIT: $driver_unitinit_entry .endc .iffa3JF_unit_INIT:; .jsb_entry ;JF UNIT INITIALIZATION .endc. movab fcae,fcnca ; set up catch-all final FDT>; Don't set unit online here. Priv'd task that assigns JF unit<; to a file does this to ensure only assigned JFn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JF: data buffersJF_bufsiz=127*512f9 movl #JF_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers to 8kv9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASSsC; NOTE: we may want to set this as something other than an RX class>; 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!!!)c9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JF G; (note the id might be wrong but is attempt to get it.) (used only foro; MSCP serving.)> MOVB #DT$_FD1,UCB$B_DEVTYPE(R5) ;Make it foreign disk type 1/; (dt$_rp06 works but may confuse analyze/disk)fG;;; NOTE: changed from fd1 type so MSCP will know it's a local disk andi8;;; attempt no weird jiggery-pokery with the JF: 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 polynomialc6; clrl chnflg ;initially set to use our chain of FDTs movl #1,chnflga movl #1,r0d .iif ndf,step2,RSB ;RETURN .iif df,step2,ret .SBTTL START I/O ROUTINE,;++,; ; JF_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION: ; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTo; PACKET HAS BEEN DEQUEUED.; ; INPUTS:t; ); R3 - IRP ADDRESS (I/O REQUEST PACKET)d); R5 - UCB ADDRESS (UNIT CONTROL BLOCK) :; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFEREDm/; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKSt; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;-- .if df,evax .if ndf,step2;JF_STARTIO: .jsb_entry output= ;START I/O OPERATIONi .iff_JF_STARTIO: $driver_start_entry  .endc .iff #JF_STARTIO: ;START I/O OPERATION  .endc; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8rD; CLRQ UCB$Q_JF_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION 3 bbs #ucb$v_online,- ; if online set software valido ucb$l_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalida' brw resetxfr ; reset byte count & exit 210$: ;; Unless we use this entry, we want to junk any calls here. + brb 216$ ;just always say invalid volume. A; Get here for other start-io entries if the virtual disk code isf$; commented out also, as it must be.8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKTiC .iif ndf,evax,MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNTa ; BRW FUNCXTFUNCXT: ;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB .if df,step2 , REQCOM environment=call ; COMPLETE REQUEST .iff  REQCOM  .endc .if ndf,evax-!FATALERR: ;UNRECOVERABLE ERRORu2 MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUS brb funcxt>; PWRFAIL: ;POWER FAILURE: BICW #UCB$M_POWER,UCB$L_STS(R5) ;CLEAR POWER FAILURE BIT1 MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKETe5 MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERS  UCB$L_SVAPTE(R5) ;... $ BRW JF_STARTIO ;START REQUEST OVER .endc .if ndf,evax JF_INT:: JF_UNSOLNT:: POPR #^M% REI ;DUMMY RETURN FROM ANY INTERRUPT .endc ;;f/JF_END: ;ADDRESS OF LAST LOCATION IN DRIVER .iff ;step2: .TITLE JFDRiver ;skeleton driver implementing ucb linkage .IDENT 'V01h':mf$tst=0 ; save fib expansion stuff to see if we get there'; Copyright 1993,1994 Glenn C. Everharte; All rights reservedr; Author: Glenn C. Everhart;.; mods:n$; 7/8/94 gce -step2 conversion begun5; remember to define xx$nor sometime to wrtchk args!!n;n;nEreal_pvt=0 ;define to include code that on bit 2048 prevents opens one" ;assigned devices, privs or not.8.ntype __,R31 ; set EVAX nonzero if R31 is a register.if eq <__ & ^xF0> - ^x50nEVAX = 1.iff ;EVAX = 0l.endc$ .if df,evaxevax = 1alpha=1 bigpage=1 addressbits=32; ;... EVAX=1 -> Step1B.iif ndf WCB$W_NMAP, evax=2 ;... EVAX=2 -> Step2 (ndf as of T2.0)C.iif ndf WCB$W_NMAP, step2=1 ;... EVAX=2 -> Step2 (ndf as of T2.0)e .endc ;x$$$dt=0s; above for Alpha only. ; "; Glenn C. Everhart, November 1993; ;vms$$v6=0 ;add forvms v6 def'ncvms$v5=1(; define v5$picky also for SMP operation v5$picky=1& .SBTTL EXTERNAL AND LOCAL DEFINITIONS; ; EXTERNAL SYMBOLS;  .library /SYS$SHARE:LIB/i*; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCKo# $DYNDEF ;define dynamic data typest $DCDEF ;DEFINE DEVICE CLASS % $DDBDEF ;DEFINE DEVICE DATA BLOCKe* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLEn( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODESt$ $DDTDEF ; DEFINE DISPATCH TBL... .if df,step2$ ddt$l_fdt=ddt$ps_fdt_2  .endc $ptedef $vadef & $IRPDEF ;DEFINE I/O REQUEST PACKET $irpedef & $PRDEF ;DEFINE PROCESSOR REGISTERS& $SSDEF ;DEFINE SYSTEM STATUS CODES& $UCBDEF ;DEFINE UNIT CONTROL BLOCK .if df,step2  $fdt_contextdef .endc $sbdef ; system blk offsets $psldef $prdefn $acldef$ $rsndef ;define resource numbers $acedef* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $pcbdef $statedef $jibdef $acbdef $vcbdef $arbdef $wcbdef $ccbdef $fcbdef $phddef< $RABDEF ; RAB structure defs7 $RMSDEF ; RMS constantsi; defs for acl hacking $fibdef $atrdefp1=0 ; first qio paramp2=4p3=8p4=12up5=16cp6=20 ;6th qio param offsets# .IF DF,VMS$V5 ;VMS V5 + LATER ONLYm $SPLCODDEF  $cpudef .ENDC; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS; ( $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.;R;E($def ucb$l_hucbs .blkl 1 ;host ucb table;S#; Add other fields here if desired.-;R3$def ucb$l_ctlflgs .blkl 1 ;flags to control modes8;C,$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 keepc6; file extensions from preferentially picking up chaff$def ucb$JFcontfil .blkb 80O0$def ucb$l_asten .blkl 1 ;ast enable mask store;n&$DEF ucb$l_minxt .blkl 1 ;min. extent%$def ucb$l_maxxt .blkl 1 ;max extentA/$def ucb$l_frac .blkl 1 ;fraction to extend by 3$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 inNK ; by DPT address for easy followingi0 ; 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 blockUP; 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$L_ICPFGS .BLKL 2 ; Flags. Reserve 2 longs so we neede ; not mess with this later. $VIELD UCB,0,<-- ,- ; 1 if this intercept and allc! > ; below understand finipl8.o$def ucb$l_usr8 .blkl 8 $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 ucb1E; Make the "unique magic number" depend on the DDT length, and on theDJ; length of the prepended material. If anything new is added, be sure that"; this magic number value changes.Cmagic=^xF0070000 + ddt$k_length + <256*>vEp.magic=^xF0070000 + ddt$k_length + <256*>T0$DEF UCB$L_JF_HOST_DESCR .BLKL 2 ;host dvc desc.;>; Store copy of victim FDT table here for step 2 Alpha driver.&; assumes FDT table is 64+2 longs long>$def ucb$l_myfdt .blkl 70 ;user FDT tbl copy + slop for safety5$def ucb$l_oldfdt .blkl 1 ;fdt tbl of prior fdt chainr5$def ucb$l_vict .blkl 1 ;victim ucb, for unmung checkn2$def ucb$l_mungd .blkl 1 ;munged flag, 1 if numg'd&$def ucb$l_exempt .blkl 4 ;exempt PIDs($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_LEN=. ;LENGTH OF UCBj% $DEFEND UCB ;END OF UCB DEFINITONSe o .SBTTL STANDARD TABLES ; ; DRIVER PROLOGUE TABLEl; >; THE DPT DESCRIBES DRIVER PARAMETERS AND I/O DATABASE FIELDSA; THAT ARE TO BE INITIALIZED DURING DRIVER LOADING AND RELOADINGT; driver_data JF_UNITS=300JF$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 DPTAB - ;DPT CREATION MACRO$ END=JF_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=2,-' UCBSIZE=UCB$K_JF_LEN,- ;LENGTH OF UCBM. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAMES2 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 CLASSdG DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ;FORK IPL (VMS V5.X + LATER) C; These characteristics for an intercept driver shouldn't look justF; like a real disk unless it is prepared to handle being mounted, etc.J; Therefore comment a couple of them out. Thus it won't look file oriented; nor directory structured. 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)d7 DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_DISK ;DEVICE CLASSX: 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 TRACKB9 DPT_STORE UCB,UCB$W_CYLINDERS,W,16 ;NUMBER OF CYLINDERSE* DPT_STORE UCB,UCB$B_DIPL,B,21 ;DEVICE IPL8; DPT_STORE UCB,UCB$B_ERTMAX,B,10 ;MAX ERROR RETRY COUNTF DPT_STORE UCB,UCB$L_DEVSTS,L,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;...U;L?; don't mess with LBN; leave alone so it's easier to hack on...D;S6 DPT_STORE REINIT ;START CONTROL BLOCK RE-INIT VALUESQ; DPT_STORE CRB,CRB$L_INTD+VEC$L_ISR,D,JF_INT ;INTERRUPT SERVICE ROUTINE ADDRESS.0 DPT_STORE DDB,DDB$L_DDT,D,JF$DDT ;DDT ADDRESSE DPT_STORE UCB,UCB$L_UNIQID,D,DRIVER$DPT ;store DPT addresscH ; (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 ino? ; DOS-11 users)xC; 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!d- DPT_STORE END ;END OF INITIALIZATION TABLE ; ; DRIVER DISPATCH TABLEA; >; THE DDT LISTS ENTRY POINTS FOR DRIVER SUBROUTINES WHICH ARE"; CALLED BY THE OPERATING SYSTEM.; ;JF$DDT: DDTAB - ;DDT CREATION MACRO DEVNAM=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINEN0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JF_CTRL_INIT,-k UNITINIT=JF_UNIT_INIT,-5, CANCEL=0,- ;CANCEL=NO-OP FOR FILES DEVICE# REGDMP=0,- ;REGISTER DUMP ROUTINEi# DIAGBF=0,- ;BYTES IN DIAG BUFFER  ERLGBF=0 ;BYTES IN ;ERRLOG BUFFER; ; FUNCTION DECISION TABLEo; 6; THE FDT LISTS VALID FUNCTION CODES, SPECIFIES WHICH4; CODES ARE BUFFERED, AND DESIGNATES SUBROUTINES TO2; PERFORM PREPROCESSING FOR PARTICULAR FUNCTIONS.; @chnflg: .long 0 ;chain or use our FDT chain flag...use ours if 0myonoff:3fdtonoff: .long 0 ;switch my fdt stuff off if non-0EM .ascii /flag/ ;define your own unique flag here; just leave it 4 bytes long!$ .long 0 ;fdt tbl from before patchfdt_chn = -12 fdt_prev = -4F fdt_idnt = -8 JF_FUNCTABLE:e FDT_INI FDT_BUF - ; BUFFERED functions ; MOUNT VOLUMEd myfdtstart:r?; io$_format + modifiers (e.g. io$_format+128) as function codef>; allows one to associate a JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed. ) fdt_act JF_format,- ;point to host disk ; $; First our very own filter routines;$A; Following FDT function should cover every function in the localRB; FDT entries between "myfdtbgn" and "myfdtend", in this case just@; mount and modify. Its function is to switch these off or on at; need.s 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 ifRI; you don't want to. The FDT switch logic is a waste of time and space ift; you do nothing with them...dK; They don't actually do anything here, but could be added to. Throw in oneyF; 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!)  fdt_act MFYFilt,-( ;modify filter (e.g. extend) myfdtend=.JF_ucb:sJF_utb: .rept JF_units. .long 0 .endr .long 0,0,0,0,0,0,0,0,0,0 driver_code;fH; GETJFUCB - Find JF: 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.sB; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. getJFucb: .jsb_entry output=!; 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 knowse?; it is in an intercept driver. Also assumes R11 may be used asoD; 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" ; is defined.o-; Entry: R5 - victim device UCB addresst0; Exit: R11 - intercept driver UCB address chk.err=0DF movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!!G movab DRIVER$dpt,r11 ;magic pattern is DPT addr.9; lock this section with forklock so we can safely remove$3; entries at fork also. Use victim device forklock. 1; (don't preserve r0 since we clobber it anyway.)l= forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NO142$: cmpl (r10),R11= ;this our own driver?h@; beql 1$ ;if eql yes, end search;a<; 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.; .branch_unlikelyt) bneq 5$ ;check next in chain if not usA; At this point R10 contains the DDT address within the interceptuF; 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 UCBu7; brb 4$ ; note in this layout we can comment this out.e4$: ? forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=NOU%; NOW clobber r0 and put things back.E movl r11,r0; popr #^mo popl r11T& popl r10 ;supposedly faster than popr rsbA; Make very sure this DDT is inside a UCB bashed according to ourS=; specs. The "p.magic" number reflects some version info too.D3; If this is not so, not much sense searching more.n95$: cmpl (r10),#p.magicCC bneq 3$ ;exit if this is nonstd bashT+; follow DDT block chain to next saved DDT.t5 movl (r10),r10II ;point R10 at the next DDT in theG ;chain F bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againD;1$:3$:B$ clrl r11 ;return 0 if nothing found brb 4$T;O*; Few macros for long distance branches...;D .macro beqlw lbl,?lbl2, bneq lbl2 brw lbllbl2:  .endm .macro bneqw lbl,?lbl2i beql lbl2 brw lbllbl2:  .endm .macro bleqw lbl,?lbl2a bgtr lbl2 brw lbllbl2:t .endm .macro bgeqw lbl,?lbl2h blss lbl2 brw lbllbl2:h .endm); allocate does not zero its result area.eE; This macro makes it easy to zero an allocated area before using it.S@; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".; .macro zapz addr,size3 pushr #^m ;save regs from movc5 movc5 #0,addr,#0,size,addrE2 popr #^m ;save regs from movc5 .endm;, .SBTTL Our FDT Filter RoutinesD>; These routines are edited from the JFDRiver versions to callD; getJFucb, assuming they are called with R5 pointing at the patched; driver's UCB.F ; INPUTS: ; (; R3 - IRP ADDRESS (I/O REQUEST PACKET)+; R4 - PCB ADDRESS (PROCESS CONTROL BLOCK)B(; R5 - UCB ADDRESS (UNIT CONTROL BLOCK)+; R6 - CCB ADDRESS (CHANNEL CONTROL BLOCK)R+; R7 - BIT NUMBER OF THE I/O FUNCTION CODEU3; R8 - ADDRESS OF FDT TABLE ENTRY FOR THIS ROUTINEE(; (AP) - ADDRESS OF FIRST QIO PARAMETER; Filter routines.!; These do the interesting stuff.,;IPopOut:G popr #^mpors:TG; Here need to return to the "standard" FDT routine. Do so by computingsH; the address in the FDT table of the normal host and calling that, thenC; returning. Thus the only FDT routines in THIS driver are the onesEE; it needs for its own work, not any standard ones. This calls those.SN EXTZV #IRP$V_FCODE,#IRP$S_FCODE,IRP$L_FUNC(R3),R1 ; GET FCN CODE pushr #^m movl r1,r104 jsb getJFucb ;find JF UCB checking for extra links tstl r0 ;got it?n bgeq 199$ ;if not skip out 6 movl ucb$l_oldfdt(r0),r7 ;get address of previous FDT bgeq 199$ ;ensure ok...!; movl ucb$l_ddt(r5),r7 ;find FDT K; Here rely on the fact that we got here via our modified FDT call and that :; the orig. FDT is stored just a bit past the current one.<; movl (r7),r7 ;point at orig. FDT0 addl2 #8,r7 ;point at one of 64 fdt addresses2 movl (r7)[r10],r8 ;r7 is desired routine address!;now call the "official" FDT codeo pushl r6 ;ccb pushl r5 ;ucb pushl r4 ;pcb pushl r3 ;irp+ calls #4,(r8) ;Call the original routine popr #^m+; Now return as the original routine would.L ret199$:E popr #^m movl #16,r0 call_abortioC ret; rsbJCmfyfilt: $driver_fdt_entry ;filter on MODI~FAV020.A`>[VLT00A.GCE]JFDRIVERV2.MAR;7TsbFY requests (e.g. extend)C.; First do some preliminary checks for sanity.$; 1. Channel must NOT be kernel mode; 2. Not a movefileL% tstl r6 ;is there a CCB (must be +)  bleq pors ;if not skip out) cmpb ccb$b_amod(r6),#1 ;knl mode access?( bleq pors ;leave knl mode chnls alone!;funct modifiers are bits 6-15; this is hex ffc0?; Normal io$_modify should have no modifiers, so if it has it'sD'; for something else; leave that alone.E .if ndf,evaxP@ bitw #^x1FC0,irp$w_func(r3) ;this a movefile or other modifier? .iffg@ bitl #^xDFC0,irp$l_func(r3) ;this a movefile or other modifier? .endc" bneq pors ;if so ignore it here. pushr #^me>; original r5 now at 4(sp). Must get that to continue the ops.! jsb getJFucb ;find JFDRiver ucbF tstl r0 bgeqw popoutT7 movl r5,ucb$l_backlk(r0) ;save link'd ucb in ours too.P! movl r0,r5 ;point R5 at JF UCB-B;make sure not a knl mode channel (leave the XQP channel alone!!!)- cmpb ccb$b_amod(r6),#1 ;this the XQP's chnl? " bleqw popout ; if so scram NOW.A; Now ensure that this call is not in the same JOB as the daemon. 9; (This lets the daemon spawn processes to do some work.)O* bitl i^#2,ucb$l_ctlflgs(r5) ;look at mfy? bneqw mfycmn ;if neq yesE9; (test later will see about space control if doing this)R701$:E popr #^m brw porsLmspcj: popl r0 brw popoutUmfycmn:dJ; here we can modify request fields in the FIB the user supplies to reduceD; fragmentation...e.g. set fib$l_exsz bigger or set fib$m_alconb bit>; in fib$w_exctl IFF fib$m_alcon is not set & set fib$m_aldef.;d pushl r0t .if ndf,evaxp movl p1(ap),r0 ;get fib .iff  movl irp$l_qio_p1(r3),r0e .endc5; remember to define xx$nor sometime to wrtchk args!!c% .iif df,xx$nor,ifnord #4,4(r0),mspcje" movl 4(r0),r0 ;...from descriptor/ .iif df,xx$nor,ifnord #4,fib$w_exctl(r0),mspcjo6 bitw #fib$m_extend,fib$w_exctl(r0) ;extending at all?, beqlw mspc ;if no extend, leave fib aloneI; Because contiguous best try allocation flushes the entire extend cache,TE; it can cause a tremendous performance hit. Therefore allow it to besG; separately switched so that the benefits of longer extents can be hadnI; if desired without forcing this flushing every time a file is extended.lL bitl i^#32,ucb$l_ctlflgs(r5) ;separate control for setting contig best try beql 1$(; leave contig and contig-best-try alone@ bitw #,fib$w_exctl(r0) ;contig alloc?# bneq 1$ ;if contig leave it alone.!; allow this on every nth extend..C; This will allow periodic flushes of the extent cache but will letCK; it not be made totally useless. By flushing the extent cache periodically 4; we can try to reduce the fragmentation it induces.,; if bit 16384 is not set, do not set aldef.9 bitl i^#16384,ucb$l_ctlflgs(r5) ;set aldef all the time?u beql 704$? bisw #,fib$w_exctl(r0) ;set to use vol default if 704$: ;bigger than program's" decl ucb$l_cbtctr(r5) ;count down' bgtr 1$ ;and if >0 don't set cbt yete; movl ucb$l_cbtini(r5),ucb$l_cbtctr(r5) ;else reset countera? bisw #,fib$w_exctl(r0) ;else turn on contig best  ;try and turn on use of! ;system default extension if ! ;larger than program defaulte1$: P; One can add code to check file size and bump extension by more than default ifT; it's big (for example, extend by 10% of its' size, not by a few blocks at a time). pushr #^m3 bitw #,fib$w_exctl(r0) ;contig alloc?D. bneqw 222$ ;leave size alone for contig alloc) movl ccb$l_wind(r6),r7 ;get window blockr bgeq 222$ ;guard / movl wcb$l_fcb(r7),r8 ;and file control blkock  bgeq 222$ ;guardi) movl fcb$l_filesize(r8),r6 ;get filesizel beql 222$=; It is suggested to divide by acp$gb_window instead of 10...kS; this is the acp_window sysgen param (default 7), the number of retrieval pointers$R; present per window by default. This has no direct relation to size, but one mustQ; expect at least one retrieval pointer needs to change. In the default situationq%; say 1/4th of file size can be used.s;nD; The fraction starts at 1/4, but can be anywhere from 1/1 to 1/10007 divl2 ucb$l_frac(r5),r6 ;get 1/4 of current size or sor$ incl r6 ;plus one...for good luck? cmpl r6,ucb$l_maxxt(r5) ;extending over max (nominally 120000)e bleq 1222$ 9 movl ucb$l_maxxt(r5),r6 ;clamp to max what we're forcingD1222$:9 cmpl r6,ucb$l_minxt(r5) ;if less than 10 leave alone toos bgeq 1223$c4 movl ucb$l_minxt(r5),r6 ;at least grab this minimum1223$:0; never try to grab over1/8 of total free space.8 movl ucb$l_backlk(r5),r8 ;get host ucb (set just above) bgeq 222$ ;(better be there)k$ movl ucb$l_vcb(r8),r8 ;point at vcb bgeq 222$& movl vcb$l_free(r8),r8 ;no. blks free ashl #-3,r8,r8 ;free space /8p% cmpl r6,r8 ;extent over freespc/8?b'; bgtr 222$ ;if so don't push it hereC" bleq 3223$ ;if not all still ok# movl r8,r6 ;else clamp to free/8e3223$:8 cmpl r6,fib$l_exsz(r0) ;make sure we're increasing size2 bleq 222$ ;if less than user wants, leave aloneH; if 4 bit is clear, allow size ctl always. Otherwise only if aldef set. bitl i^#4,ucb$l_ctlflgs(r5) beql 2222$v? bitw #,fib$w_exctl(r0) ;set to use vol default if1 beql 222$ ;if aldef NOT set, leave size alone.a2222$:3 movl r6,fib$l_exsz(r0) ;fill in as new extend size 222$:  popr #^mt; fall thru to space control mspc: popl r0  popr #^m movl #1,r0 brw porsr;++ ;f5; JF_format - bash host disk tables to point at ours.t;eF; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),mB; 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 ise; software enabled.s; D; This routine does virtually no checking, so the parameters must be ; correct.;v ; Inputs:e>; p1 - pointer to buffer. The buffer has the following format:=; longword 0 - (was hlbn) - flag for function. 1 to bashs.; 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; ;R; p2 - size of the above bufferR;--CJF_format: $driver_fdt_entry< bicw3 #io$m_fcode,irp$l_func(r3),r0 ;mask off function code) bneq 20$ ;branch if modifiers, specialR);thus, normal io$_format will do nothing.  brw pors ;regular processingM100$: 0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parametern clrl r1 call_abortion ret; jmp g^exe$abortio 20$:5 movl irp$l_qio_p1(r3),r0 ;buff address 4 movl irp$l_qio_p2(r3),r1 ;buff length call_writechk;; jsb g^exe$writechk ;read access? doesn't return on errors:; clrl irp$l_bcnt(r3) ;paranoia, don't need to do this...1 pushr #^mE movl irp$l_qio_p1(r3),r00 movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegal# cmpl r7,#2 ;3 and up illegal toof bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored)e bleq 70$n0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JF_host_descr+4(r5) % subl3 #8,irp$l_qio_p2(r3),-p' ucb$l_JF_host_descr(r5)t bleq 100$ ;bad length4 movab ucb$l_JF_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host devicer! blbs r0,30$ ;branch on successc; fail the associate... 0 popr #^m= movzwl #ss$_nosuchdev+2,r0 ;make an error, usually a warningr clrl r1 call_abortion ret%; jmp g^exe$abortio ;exit with errorE30$: ;found the device; r1 is target ucb address...i$; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?i bneq 31$  jsb mung ;go mung target... 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?c) bneq 32$ ;if not skip out, do nothing.o jsb umung ;unmung target32$:3; bisw #ucb$m_valid,ucb$w_sts(r5) ;set volume valid 3; bisw #ucb$m_online,ucb$w_sts(r5) ;set unit onlineh5; movl ucb$l_irp(r5),r3 ;restore r3, neatness countsf0 popr #^m! movzwl #ss$_normal,r0 ;success call_finishioc do_ret=yes(; jmp g^exe$finishioc ;wrap things up.mung: .jsb_entry=; steal DDT from host. Assumes that the intercept UCB address4B; 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 issC; pointed to by R11. All registers are preserved explicitly so thatkB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingcG; went wrong so the bash did NOT occur. This generally means some othernF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so the 3; unique ID field and magic number are set already.s6 tstl ucb$l_mungd(r5) ;already munged/not deassigned? beql 6$ rsb ;no dbl bash6$:a7 pushr #^me5; Acquire victim's fork lock to synchronize all this.e7 movl #ss$_normal,r0 ;assume successo" 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 DDB3; fill in host ucb tbl (makes chnl handling faster)  movab JF_ucb,ucb$l_hucbs(r5)(' movl ucb$l_hucbs(r5),r9 ;get ucb tablet' movzwl ucb$w_unit(r5),r0 ;get unit no.i# moval (r9)[r0],r9 ;point into tbls, movl r11,(r9) ;save target ucb addr in tbl-; 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?i3 beql 1$ ;if eql yestG; driver was bashed already. Check that the current basher followed the); standard. Then continue if it looks OK.y9 cmpl (r10),#p.magiccF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellh: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too) 2$:l<; 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 oneiD; movl (r10),ucb$l_icpfgs(r5) ;copy fi8ok1$:t* movl #1,ucb$l_mungd(r5) ;say we munged JFD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallye3$:i 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)a;s1; Here make whatever mods to the DDT you need to. ;t8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers) H movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JF_functable+fdt_prev ;save old FDT ucb address % movl ddt$l_fdt(r10),ucb$l_oldfdt(r5)vK movl ucb$l_uniqid(r5),JF_functable+fdt_idnt ;save unique ID also 9; copy legal and buffered entry masks of original driver. A; HOWEVER, set mask for format entry to be nonbuffered here sincee; we deal with it. pushr #^m : movab ucb$l_myfdt(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 legalx; here.l6 pushr #^m ;preserve regs from movc- movl #<68*4>,r0 ;byte count of a step 2 FDTu* movc3 r0,(r7),(r9) ;copy his FDT to ours5 popr #^m ;preserve regs from movcg6; Now copy in our modify & back-to-original FDT cells.A; We will do this in our FDT table by having FDT definitions onlys?; for those functions in JFDRiver that we service locally. Thus8:; all entry cells for the rest will point in the JF FDT to; exe$illiofunc.0 movab g^exe$illiofunc,r8 ;get the magic address/ movab JF_functable,r10 ;r10 becomes JF FDT tblh# addl2 #8,r10 ;point at functions  addl2 #8,r9 ;his new FDT... movl #64,r11 ;64 functionsl075$: cmpl (r10),r8 ;this function hadled in JF? beql 76$ ;if eql no, skip7 movl (r10),(r9) ;if we do it point his fdt at our fcnaJ; (NOTE: our functions MUST therefore call the previous FDT's functions at; end of their processing.)'76$: cmpl (r10)+,(r9)+ ;pass the entryq# sobgtr r11,75$ ;do all functionseC; JFDRiver FDT table. Last entry goes to user's original FDT chain. ;2E; Thus we simply insert our FDT processing ahead of normal stuff, buts4; all fcn msks & functions will work for any driver. popr #^m0; Now point the user's FDT at our bugger'd copy.C movab ucb$l_myfdt(r5),ddt$l_fdt(r8) ;point at our FDT tablet8 clrl myonoff ;turn my FDTs on;)E; Finally clobber the victim device's DDT pointer to point to our new; one. .iif df, evax, evax_imb/ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)e .iif df, evax, evax_imb@; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing infC; the example here causes the intercept driver's FDT routines to besC; used ahead of whatever was in the original driver's FDTs. Because E; 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.;g1; Processing complete; release victim's fork lockt100$:k6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YES27 popr #^mt rsbumung: .jsb_entrye;pF; 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: addresspE; is the one being sought. ("Current driver" here means the intercept0 ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCB contains an entry in the DDT chain. pushr #^mE; .iif df,x$$$dt,jsb g^ini$brk ;***********************debug********* 0 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 laterF movab DRIVER$DPT,r11 ;magic pattern is DPT addr.9; lock this section with forklock so we can safely remove 3; 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? ? beql 1$ ;if eql yes, end searcha .if df,chk.err9 cmpl (r10),#p.magicsD bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.e5 movl (r10),r10eI ;point R10 at the next DDT in the . ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againu1$: A; At this point R10 contains the DDT address within the interceptF; driver's UCB. Return the address of the intercept driver's UCB next.M tstl (r10) ;were we intercepted?1C bgeq 3$ ;if geq no, skip back-fixups/; we were intercepted. Fix up next guy in line. L movl (r10),r11 ;point at interceptorS movl (r10),(r11)o3$: E; if we intercepted someone, fix up our intercepted victim to skip bys ; us also.I movl (r10),r2 ;did we interceptn9 ;original driver?lA cmpl r2,r1 ;test if this is originalh< beql 5$ ;if eql yes, no bashB; replace previous intercept address by ours (which might be zero)R movl (r10),(r2)5$:a>; Here remove FDT entries from the list if they were modified.=; This needs a scan of the FDT chain starting at the victim's3B; ddt$l_fdt pointer and skipping around any entry that has address; JF_functable:B; 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!!!a; movl ddt$l_fdt(r0),r1 ;start of FDT chain(A movab JF_functable,r2 ;address of our FDT table  clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucb;D; Also set the JF device offline when we unbash it. This is a simple@; flag that ctl prog. can use to tell if it's been used already./ bicl #,ucb$l_sts(r4)aA6$: cmpl r1,r2 ;current fdt point at us?rA beql 7$ ;if eql yes, fix up chain @ 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!!! F;;;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.7$: *;r3 is 0 or fdt pointing to our block next;r1 points at our fdt block D tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to do  movl fdt_prev(r1),r4 bgeq 17$e. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4 blss 18$l tstl (sp)+ 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.r8$:p; F; 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 its? movl (r10),ucb$l_ddt(r5): clrl (r10) ;zero JF munged flag4$:T@ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^mrK ;copy our prior DDT ptr to next oned rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINE ; ++; 2; JF_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:f; noop ; INPUTS:f; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:9; - AT SYSTEM STARTUPm; - DURING DRIVER LOADINGl(; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;--D$JF_ctrl_INIT: $driver_ctrlinit_entry*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r0< Ret ;RETURNo- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATIONy;s ; INPUTS:s; R4 => controller CSR (dummy) ; R5 => UCB ;m# .SBTTL UNIT INITIALIZATION ROUTINEc;++o; ,; JF_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:o; $; THIS ROUTINE SETS THE JF: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:o; - AT SYSTEM STARTUPt; - DURING DRIVER LOADING.(; - DURING RECOVERY FROM POWER FAILURE; ; INPUTS:b; 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.; ;--p$JF_unit_INIT: $driver_unitinit_entry>; Don't set unit online here. Priv'd task that assigns JF unit<; to a file does this to ensure only assigned JFn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JF: data buffersTJF_bufsiz=81929 movl #JF_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers to 8ky9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASSl' clrl ucb$l_mungd(r5) ;not mung'd yetdC; NOTE: we may want to set this as something other than an RX class >; 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!!!)v" movab DRIVER$DPT,ucb$l_uniqid(r5)9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JF_G; (note the id might be wrong but is attempt to get it.) (used only forf; 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 ando8;;; attempt no weird jiggery-pokery with the JF: device.G; MSCP may still refuse to do a foreign drive too; jiggery-pokery laterh'; to test if there's occasion to do so.i; Set up crc polynomialD- movab JF_utb,ucb$l_hucbs(r5) ;host ucb tablet5 clrl chnflg ;initially set to use our chain of FDTso: BICL #UCB$M_ONLINE,UCB$L_STS(R5) ;SET UCB STATUS OFFLINE movl #1,r0o ret;++1; ; JF_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION:n; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTg; PACKET HAS BEEN DEQUEUED.; ; INPUTS: ; ); R3 - IRP ADDRESS (I/O REQUEST PACKET).); R5 - UCB ADDRESS (UNIT CONTROL BLOCK)0:; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFERED /; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKSf; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;--5JF_STARTIO: $driver_start_entry ; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8_D; CLRQ UCB$Q_JF_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION 3 bbs #ucb$v_online,- ; if online set software validr ucb$l_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalida' brw resetxfr ; reset byte count & exito210$: ;; Unless we use this entry, we want to junk any calls here.k+ brb 216$ ;just always say invalid volume.sA; Get here for other start-io entries if the virtual disk code is($; commented out also, as it must be.";FATALERR: ;UNRECOVERABLE ERROR3; MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUSe8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKTs6; MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNT ; BRW FUNCXTFUNCXT: ;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB, REQCOM,environment=call ; COMPLETE REQUEST; ;PWRFAIL: ;POWER FAILURE ;; BICW #UCB$M_POWER,UCB$W_STS(R5) ;CLEAR POWER FAILURE BIT 2; MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKET6; MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERS; UCB$L_SVAPTE(R5) ;...%; BRW JF_STARTIO ;START REQUEST OVER ;JF_INT:: ;JF_UNSOLNT:: ; POPR #^M &; REI ;DUMMY RETURN FROM ANY INTERRUPT ;;s/JF_END: ;ADDRESS OF LAST LOCATION IN DRIVERe .ENDC ;step2  .ENDp*[VLT00A.GCE]JFDRIVER_AXP.MAR;5+,a.^/ 4T^]->0123KPWO^56ȗ7Ze89GHJ: .TITLE JFDRiver ;skeleton driver implementing ucb linkage .IDENT 'V01b'"; Copyright 1993 Glenn C. Everhart; All rights reserved; Author: Glenn C. Everhart;evax = 1alpha=1 bigpage=1addressbits=32 .if ndf,evax .macro driver_data .PSECT $$$105_PROLOGUE .endm .macro driver_code .PSECT $$$115_DRIVER .endm .endc; above for Alpha only.;5; Function: Implement frag avoider for generic disks. ;x$$$dt=0;;vms$$v6=0 ;add forvms v6 def'nvms$v5=1(; define v5$picky also for SMP operation v5$picky=1& .SBTTL EXTERNAL AND LOCAL DEFINITIONS; ; EXTERNAL SYMBOLS;  .library /SYS$SHARE:LIB/*; $ADPDEF ;DEFINE ADAPTER CONTROL BLOCK) $CRBDEF ;DEFINE CHANNEL REQUEST BLOCK# $DYNDEF ;define dynamic data types $DCDEF ;DEFINE DEVICE CLASS% $DDBDEF ;DEFINE DEVICE DATA BLOCK* $DEVDEF ;DEFINE DEVICE CHARACTERISTICS) $DPTDEF ;DEFINE DRIVER PROLOGUE TABLE( $EMBDEF ;DEFINE ERROR MESSAGE BUFFER( $IDBDEF ;DEFINE INTERRUPT DATA BLOCK% $IODEF ;DEFINE I/O FUNCTION CODES$ $DDTDEF ; DEFINE DISPATCH TBL... $ptedef $vadef& $IRPDEF ;DEFINE I/O REQUEST PACKET $irpedef& $PRDEF ;DEFINE PROCESSOR REGISTERS& $SSDEF ;DEFINE SYSTEM STATUS CODES& $UCBDEF ;DEFINE UNIT CONTROL BLOCK $psldef $prdef $acldef$ $rsndef ;define resource numbers $acedef* $VECDEF ;DEFINE INTERRUPT VECTOR BLOCK $pcbdef $statedef $jibdef $acbdef $vcbdef $arbdef $wcbdef $ccbdef $fcbdef $phddef< $RABDEF ; RAB structure defs7 $RMSDEF ; RMS constants; defs for acl hacking $fibdef $atrdefp1=0 ; first qio paramp2=4p3=8p4=12p5=16p6=20 ;6th qio param offsets# .IF DF,VMS$V5 ;VMS V5 + LATER ONLY $SPLCODDEF $cpudef .ENDC; 2; UCB OFFSETS WHICH FOLLOW THE STANDARD UCB FIELDS; ( $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($DEF UCB$K_JF_LEN .BLKW 1 ;LENGTH OF UCB!;UCB$K_JF_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 JF_UNITS=100 VJF$DPT::$.iif ndf,spt$m_xpamod,dpt$m_xpamod=0 .if df,evax DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;DRIVER NAME .iff DPTAB - ;DPT CREATION MACRO$ END=JF_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_JF_LEN,- ;LENGTH OF UCB. MAXUNITS=JF_UNITS,- ;FOR SANITY...CAN CHANGE NAME=JFDRIVER ;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 ;DEFIN~FAV020.Aa>[VLT00A.GCE]JFDRIVER_AXP.MAR;5T^ =| E 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,21 ;DEVICE IPL .if ndf,evax7 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 ;... .iffF DPT_STORE UCB,UCB$L_DEVSTS,L,- ;INHIBIT LOG TO PHYS CONVERSION IN FDT ;... .endc;?; 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,JF_ctrl_INIT ;...= DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS D,JF_unit_INIT ;... .endc0 DPT_STORE DDB,DDB$L_DDT,D,JF$DDT ;DDT ADDRESSB DPT_STORE UCB,UCB$L_UNIQID,D,VJF$DPT ;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=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINE0 FUNCTB=JF_FUNCTABLE,- ;FUNCTION DECISION TABLE CTRLINIT=JF_CTRL_INIT,- UNITINIT=JF_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=JF,- ;NAME OF DEVICE' START=JF_STARTIO,- ;START I/O ROUTINE0 FUNCTB=JF_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 fdt_prev = -4 fdt_idnt = -8 JF_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 JF unit and some other device; seeE; the JF_format code comments for description of buffer to be passed.) functab JF_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' & FUNCTAB +ACP$MOUNT,- ;MOUNT FUNCTION ; MOUNT VOLUMEC FUNCTAB +EXE$LCLDSKVALID,- ;LOCAL DISK VALID FUNCTIONS 6 ;PACK ACKNOWLEDGEC3 FUNCTAB +EXE$ZEROPARM,- ;ZERO PARAMETER FUNCTIONSS ; AVAILABLEn0 FUNCTAB +EXE$ONEPARM,- ;ONE PARAMETER FUNCTION * FUNCTAB +EXE$SENSEMODE,- ;SENSE FUNCTIONS' ' FUNCTAB +EXE$SETCHAR,- ;SET FUNCTIONSE# D .long -1,-1 ; catch-all mask%fcnca: .long 0 ;fill in in unit initC driver_code .if df,evaxfcae: .jsb_entry .iffIfcae:  .endc+ movzwl #SS$_BADPARAM,r0 ;illegal parameter$ clrl r1 jmp g^exe$abortio ; fdtswitch -MA; Based on state of "myonoff" variable either enable or disable D; 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 theS; FDT processing of a driver. .if df,evaxfdtswitch: .jsb_entry  .iffE fdtswitch: .endc tstl fdtonoff ;global on/off bneq 1$ rsb ;go to next FDT if nulls51$: addl2 #,r8 ;pass our fdt codes  rsb ;return to std ; fdttoorig -fA; This entry continues FDT processing at the point after the newcC; entries by returning to the original FDT chain at the point whereAD; 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.A; The old FDT location is kept in the UCB for our device becauseKD; 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=s .iff fdttoorig: .endc?; As a performance feature, use a switch to let us just use theaA; FDT chain here rather than continuing an old one. This needs to @; 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 0r pushl r0n=; (this routine gets called a fair bit and if GETJFUCB can bee!; called less, things speed up.)s/ jsb getJFucb ;get UCB for JF unit from stolene ;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 pointo8 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; GETJFUCB - Find JF: 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. B; This routine is called a lot and therefore is made as quick as0; it well can be, especially for the usual case. .if df,evaxgetJFucb: .jsb_entry .iffr getJFucb:k .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 knowso?; it is in an intercept driver. Also assumes R11 may be used asgD; 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" ; is defined.c-; Entry: R5 - victim device UCB addressn0; Exit: R11 - intercept driver UCB address chk.err=0aF movl ucb$l_ddt(r5),r10 ;get the DDT we currently have2; note we know our virtual driver's DPT address!!!D movab VJF$dpt,r11 ;magic pattern is DPT addr.9; lock this section with forklock so we can safely remove 3; entries at fork also. Use victim device forklock..1; (don't preserve r0 since we clobber it anyway.)e= forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=NOs42$: cmpl (r10),R11= ;this our own driver? @; beql 1$ ;if eql yes, end search;v<; 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.;) bneq 5$ ;check next in chain if not usSA; 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=NOM%; NOW clobber r0 and put things back.T movl r11,r0; popr #^mS popl r11h& 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.C3; If this is not so, not much sense searching more.U95$: cmpl (r10),#p.magicdC bneq 3$ ;exit if this is nonstd bashI+; follow DDT block chain to next saved DDT.-5 movl (r10),r10AI ;point R10 at the next DDT in theT ;chainKF bgeq 3$ ; (error check if not negative)9 brb 2$ ;then check againN;1$:3$:$ clrl r11 ;return 0 if nothing found brb 4$.;*; Few macros for long distance branches...;U .macro beqlw lbl,?lbl2O bneq lbl2 brw lbllbl2:T .endm .macro bneqw lbl,?lbl2t beql lbl2 brw lbllbl2:h .endm .macro bleqw lbl,?lbl2 bgtr lbl2 brw lbllbl2:  .endm .macro bgeqw lbl,?lbl2r blss lbl2 brw lbllbl2:m .endm); allocate does not zero its result area.AE; This macro makes it easy to zero an allocated area before using it. @; Leaves no side effects...just zeroes the area for "size" bytes; starting at "addr".E .macro zapz addr,size3 pushr #^m ;save regs from movc5  movc5 #0,addr,#0,size,addrl2 popr #^m ;save regs from movc5 .endm;L .SBTTL Our FDT Filter RoutinesSPopOut:  popr #^m pors: rsbW .if df,evax<mfyfilt: .jsb_entry ;filter on MODIFY requests (e.g. extend) .iffA1mfyfilt: ;filter on MODIFY requests (e.g. extend)B .endc.; First do some preliminary checks for sanity.$; 1. Channel must NOT be kernel mode; 2. Not a movefileB% tstl r6 ;is there a CCB (must be +) bleq pors ;if not skip out) cmpb ccb$b_amod(r6),#1 ;knl mode access?U( beql pors ;leave knl mode chnls alone!;funct modifiers are bits 6-15; this is hex ffc0?; Normal io$_modify should have no modifiers, so if it has it'sT'; for something else; leave that alone. .if ndf,evax @ bitw #^xFFC0,irp$w_func(r3) ;this a movefile or other modifier? .iffT@ bitw #^xFFC0,irp$l_func(r3) ;this a movefile or other modifier? .endc" bneq pors ;if so ignore it here. pushr #^ma>; original r5 now at 4(sp). Must get that to continue the ops.! jsb getJFucb ;find JFdriver ucb  tstl r0 bgeqw popoutL7 movl r5,ucb$l_backlk(r0) ;save link'd ucb in ours too.u! movl r0,r5 ;point R5 at JF UCBE* bitl i^#2,ucb$l_ctlflgs(r5) ;look at mfy? bneq 171$ ;if neq yes9; (test later will see about space control if doing this) 701$:  popr #^m rsb171$:"J; here we can modify request fields in the FIB the user supplies to reduceD; fragmentation...e.g. set fib$l_exsz bigger or set fib$m_alconb bit>; in fib$w_exctl IFF fib$m_alcon is not set & set fib$m_aldef.; .if ndf,evaxk movl p1(ap),r0 ;get fib .iff  movl irp$l_qio_p1(r3),r0  .endc ifnord #4,4(r0),701$T" movl 4(r0),r0 ;...from descriptor ifnord #4,fib$w_exctl(r0),701$o6 bitw #fib$m_extend,fib$w_exctl(r0) ;extending at all?, beqlw 162$ ;if no extend, leave fib aloneI; Because contiguous best try allocation flushes the entire extend cache,CE; it can cause a tremendous performance hit. Therefore allow it to beVG; separately switched so that the benefits of longer extents can be hadNI; if desired without forcing this flushing every time a file is extended.-L bitl i^#32,ucb$l_ctlflgs(r5) ;separate control for setting contig best try beql 1$(; leave contig and contig-best-try alone@ bitw #,fib$w_exctl(r0) ;contig alloc?# bneq 1$ ;if contig leave it aloneF!; allow this on every nth extend.GC; This will allow periodic flushes of the extent cache but will let;K; it not be made totally useless. By flushing the extent cache periodicallyM4; we can try to reduce the fragmentation it induces.,; if bit 16384 is not set, do not set aldef.. bitl i^#16384,ucb$l_ctlflgs(r5) ;allow aldef? beql 704$? bisw #,fib$w_exctl(r0) ;set to use vol default ifN 704$: ;bigger than program's" decl ucb$l_cbtctr(r5) ;count down' bgtr 1$ ;and if >0 don't set cbt yetL; movl ucb$l_cbtini(r5),ucb$l_cbtctr(r5) ;else reset counterE? bisw #,fib$w_exctl(r0) ;else turn on contig bestP ;try and turn on use of! ;system default extension if ! ;larger than program defaultu1$:rP; One can add code to check file size and bump extension by more than default ifT; it's big (for example, extend by 10% of its' size, not by a few blocks at a time). pushr #^m2 bitw #fib$m_alcon,fib$w_exctl(r0) ;contig extend?% bneq 222$ ; if so don't touch size.C) movl ccb$l_wind(r6),r7 ;get window blocke bgeq 222$ ;guardt/ movl wcb$l_fcb(r7),r8 ;and file control blkock  bgeq 222$ ;guardA) movl fcb$l_filesize(r8),r6 ;get filesizeC beql 222$;D; The fraction starts at 1/4, but can be anywhere from 1/1 to 1/10007 divl2 ucb$l_frac(r5),r6 ;get 1/4 of current size or so$ incl r6 ;plus one...for good luck ;fncymod=1 ;chop this if desired? cmpl r6,ucb$l_maxxt(r5) ;extending over max (nominally 120000)V bleq 1222$9 movl ucb$l_maxxt(r5),r6 ;clamp to max what we're forcingF1222$:9 cmpl r6,ucb$l_minxt(r5) ;if less than 10 leave alone too bgeq 1223$ 4 movl ucb$l_minxt(r5),r6 ;at least grab this minimum1223$:0; never try to grab over1/8 of total free space.8 movl ucb$l_backlk(r5),r8 ;get host ucb (set just above) bgeq 222$ ;(better be there)r$ movl ucb$l_vcb(r8),r8 ;point at vcb bgeq 222$& movl vcb$l_free(r8),r8 ;no. blks free ashl #-3,r8,r8 ;free space /8P% cmpl r6,r8 ;extent over freespc/8?L" bleq 3223$ ;if not all still ok# movl r8,r6 ;else clamp to free/8R3223$:8 cmpl r6,fib$l_exsz(r0) ;make sure we're increasing size2 bleq 222$ ;if less than user wants, leave aloneH; if 4 bit is clear, allow size ctl always. Otherwise only if aldef set. bitl i^#4,ucb$l_ctlflgs(r5) beql 2222$ ? bitw #,fib$w_exctl(r0) ;set to use vol default ifI1 beql 222$ ;if aldef NOT set, leave size alone.o2222$:3 movl r6,fib$l_exsz(r0) ;fill in as new extend size222$:s popr #^mo162$:r popr #^m movl #1,r0o RSB;++ ; 5; JF_format - bash host disk tables to point at ours.t; F; With no function modifiers, this routine takes as arguments the nameE; of the host disk (the real disk where the virtual disk will exist),aB; 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 is ; software enabled.w;hD; This routine does virtually no checking, so the parameters must be ; correct.;n ; Inputs:n>; 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 blankF$; padded if padding is necessary;t;(; p2 - size of the above buffert;--f .if df,evaxJF_format: .jsb_entryr .iff JF_format: .endc .iif df,x$$$dt,jsb g^ini$brkt .if df,evax< bicl3 #io$m_fcode,irp$l_func(r3),r0 ;mask off function code .iff< bicw3 #io$m_fcode,irp$w_func(r3),r0 ;mask off function code .endc) bneq 20$ ;branch if modifiers, specialB);thus, normal io$_format will do nothing.f rsb ;regular processingw100$:a0 popr #^m10$:+ movzwl #SS$_BADPARAM,r0 ;illegal parameter clrl r1 jmp g^exe$abortio20$: .if ndf,evaxO movl p1(ap),r0 ;buffer address" movl p2(ap),r1 ;length of buffer .iff movl irp$l_qio_p1(r3),r0A movl irp$l_qio_p2(r3),r1S .endc: jsb g^exe$writechk ;read access? doesn't return on error .iif df,x$$$dt,jsb g^ini$brkG:; clrl irp$l_bcnt(r3) ;paranoia, don't need to do this...1 pushr #^mP .if ndf,evax$ movl p1(ap),r0 ;get buffer address .iffL movl irp$l_qio_p1(r3),r0 .endc movl (r0)+,r7 ;get option code# bleq 100$ ;0 or negative illegal # cmpl r7,#2 ;3 and up illegal tooN bgtr 100$ incl chnflg/ movl (r0)+,r6 ;size of virtual disk (ignored)F bleq 70$D0 clrl chnflg ;if 0 or neg. size don't chain...70$:$ movab (r0),- ;name of "real" disk ucb$l_JF_host_descr+4(r5)- .if ndf,evax 5 subl3 #8,p2(ap),- ;set length of name in descriptor  ucb$l_JF_host_descr(r5)  .iffe? subl3 #8,irp$l_qio_p2(r3),- ;set length of name in descriptor  ucb$l_JF_host_descr(r5)  .endc bleq 100$ ;bad length4 movab ucb$l_JF_host_descr(r5),r1 ;descriptor for...- jsb g^ioc$searchdev ;search for host deviceh .iif df,x$$$dt,jsb g^ini$brk ! blbs r0,30$ ;branch on success ; fail the associate...t0 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...E$; move it to r11 to be less volatile movl r1,r11% cmpl r7,#1 ;bashing the target UCB?- bneq 31$ ;if neq it's unmung jsb mung ;go mung target...C 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?W) bneq 32$ ;if not skip out, do nothing.H jsb umung ;unmung target32$:3; bisw #ucb$m_valid,ucb$w_sts(r5) ;set volume validE3; bisw #ucb$m_online,ucb$w_sts(r5) ;set unit online 5; movl ucb$l_irp(r5),r3 ;restore r3, neatness counts 0 popr #^m! movzwl #ss$_normal,r0 ;successC' jmp g^exe$finishioc ;wrap things up. .if df,evaxmung: .jsb_entry .iffOmung:  .endc=; steal DDT from host. Assumes that the intercept UCB addressrB; 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 iseC; pointed to by R11. All registers are preserved explicitly so thatEB; surrounding code cannot be clobbered. R0 is returned as a statusC; code so that if it returns with low bit clear, it means somethingIG; went wrong so the bash did NOT occur. This generally means some otherRF; code that does not follow this standard has grabbed the DDT already.A; The following example assumes the code lives in a driver so theR3; unique ID field and magic number are set already.F6 movab fcae,fcnca ;ensure final FDT entry is filled in7 pushr #^m 5; Acquire victim's fork lock to synchronize all this. 7 movl #ss$_normal,r0 ;assume success " 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 original F movl ucb$l_ddb(r11),r9 ;the ddb$l_ddt is the originalG cmpl ddb$l_ddt(r9),r10 ;bashing driver the first time?L3 beql 1$ ;if eql yes G; driver was bashed already. Check that the current basher followed theN); standard. Then continue if it looks OK.$9 cmpl (r10),#p.magicCF ;does the magic pattern exist?6; if magic pattern is missing things are badly messed.E beql 2$ ;if eql looks like all's wellg: movl #2,r0 ;say things failed= brw 100$ ;(brb might work too);2$:a<; 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 one 1$:sD movl r10,ucb$l_prevddt(r5) ;set previous DDT address upI clrl ucb$l_intcddt(r5) ;clear intercepting DDT initiallyn3$:D 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)T;a1; Here make whatever mods to the DDT you need to. ;s8; FOR EXAMPLE make the following mods to the FDT pointer7; (These assume the standard proposed for FDT pointers)sH movab ucb$a_vicddt(r5),r8 ;get a base register for the DDTE movl r5,JF_functable+fdt_prev ;save old FDT ucb addressp: movl ddt$l_fdt(r10),ucb$l_oldfdt(r5) ;save orig. fdt addrK movl ucb$l_uniqid(r5),JF_functable+fdt_idnt ;save unique ID alsov9; copy legal and buffered entry masks of original driver.sA; HOWEVER, set mask for format entry to be nonbuffered here sinced; we deal with it. pushr #^m.; movab ucb$l_fdtlgl(r5),r9 ;our function table dummy in UCBw+ movl ddt$l_fdt(r10),r7 ;victim's FDT tableeC; We want all functions legal in the victim's FDT table to be legale; here.n& movl (r7),(r9)+ ;1st half legal mask' movl 4(r7),(r9)+ ;2nd half legal maski* movl 8(r7),(r9)+ ;1st half buffered mask+ movl 12(r7),(r9)+ ;2nd half buffered maskr6; 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 addressr@; 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 table8 clrl myonoff ;turn my FDTs on;nE; Finally clobber the victim device's DDT pointer to point to our news; one./ movab ucb$a_vicddt(r5),ucb$l_ddt(r11)s@; Now the DDT used for the victim device unit is that of our UCBI; and will invoke whatever special processing we need. This processing inlC; the example here causes the intercept driver's FDT routines to behC; used ahead of whatever was in the original driver's FDTs. BecauseaE; the DDT is modified using the UCB pointer only, target device unitstB; that have not been patched in this way continue to use their old; DDTs and FDTs unaltered.;a1; Processing complete; release victim's fork locka100$:r6 forkunlock lock=ucb$b_flck(r11),newipl=(sp)+,- preserve=YESs7 popr #^m  rsb .if df,evaxumung: .jsb_entryn .iff umung: .endc;cF; 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: addressdE; is the one being sought. ("Current driver" here means the interceptT ; driver.)F; It is assumed that the driver knows that the DDT chain was patched4; so that its UCB 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 VJF$DPT,r11 ;magic pattern is DPT addr.q9; lock this section with forklock so we can safely removeh3; entries at fork also. Use victim device forklock.t> forklock lock=ucb$b_flck(r5),savipl=-(sp),preserve=YES42$: cmpl (r10),R11= ~FAV020.Aa>[VLT00A.GCE]JFDRIVER_AXP.MAR;5T^&K ;this our own driver? ? beql 1$ ;if eql yes, end searchs .if df,chk.err9 cmpl (r10),#p.magiclD bneqw 4$ ;exit if this is nonstd bash .endc ;chk.err+; follow DDT block chain to next saved DDT.e5 movl (r10),r10pI ;point R10 at the next DDT in thet. ;chain .if df,chk.errF bgeqw 4$ ; (error check if not negative) .endc ;chk.err9 brb 2$ ;then check againb1$:eA; 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? C bgeq 3$ ;if geq no, skip back-fixupt/; we were intercepted. Fix up next guy in line.iL movl (r10),r11 ;point at interceptorS movl (r10),(r11)q3$:,E; if we intercepted someone, fix up our intercepted victim to skip by ; us also.I movl (r10),r2 ;did we intercepts9 ;original driver? A cmpl r2,r1 ;test if this is originalt< beql 5$ ;if eql yes, no bashB; replace previous intercept address by ours (which might be zero)R movl (r10),(r2)5$:t>; Here remove FDT entries from the list if they were modified.=; This needs a scan of the FDT chain starting at the victim's)B; ddt$l_fdt pointer and skipping around any entry that has address; JF_functable: B; 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!!!c; movl ddt$l_fdt(r0),r1 ;start of FDT chaindA movab JF_functable,r2 ;address of our FDT table clrl r3; movab <0-ucb$a_vicddt>(r10),r4 ;initially point at our ucb D; Also set the JF 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 .iffo/ bicw #,ucb$w_sts(r4)r .endcA6$: cmpl r1,r2 ;current fdt point at us?dA beql 7$ ;if eql yes, fix up chainv@ 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 ucbA;;;BUT not all UCBs will have the fdt offset at the same place!!! F;;;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.r7$:i*;r3 is 0 or fdt pointing to our block next;r1 points at our fdt blockcD tstl r3 ;if r3=0 nobody points at us9 bgeq 8$ ;so nothing to doa movl fdt_prev(r1),r4 bgeq 17$b. movl ucb$l_oldfdt(r4),-(sp) ;save old fdt loc movl fdt_prev(r3),r4t blss 18$e tstl (sp)+. 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$:3;cF; 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 ith? movl (r10),ucb$l_ddt(r5)e4$: @ forkunlock lock=ucb$b_flck(r5),newipl=(sp)+,preserve=YES- popr #^miK ;copy our prior DDT ptr to next one rsb) .SBTTL CONTROLLER INITIALIZATION ROUTINEe; ++; 2; JF_ctrl_INIT - CONTROLLER INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:n; noop ; INPUTS:f; R4 - CSR ADDRESS; R5 - IDB ADDRESS; R6 - DDB ADDRESS; R8 - CRB ADDRESS; +; THE OPERATING SYSTEM CALLS THIS ROUTINE: ; - AT SYSTEM STARTUP ; - DURING DRIVER LOADING (; - DURING RECOVERY FROM POWER FAILURE<; THE DRIVER CALLS THIS ROUTINE TO INIT AFTER AN NXM ERROR.;--z .if df,evax7JF_ctrl_INIT: .jsb_entry ;JF CONTROLLER INITIALIZATIONe .iffy,JF_ctrl_INIT: ;JF CONTROLLER INITIALIZATION .endc*; CLRL CRB$L_AUXSTRUC(R8) ; SAY NO AUX MEM movl #1,r0e RSB ;RETURNe- .SBTTL INTERNAL CONTROLLER RE-INITIALIZATION;v ; INPUTS:d; R4 => controller CSR (dummy) ; R5 => UCBr; .if ndf,evax( ctrl_REINIT: .iffrctrl_REINIT: .jsb_entry; .endc RSB ; RETURN TO CALLER# .SBTTL UNIT INITIALIZATION ROUTINEh;++c; ,; JF_unit_INIT - UNIT INITIALIZATION ROUTINE; ; FUNCTIONAL DESCRIPTION:,; $; THIS ROUTINE SETS THE JF: ONLINE.; +; THE OPERATING SYSTEM CALLS THIS ROUTINE:t; - AT SYSTEM STARTUPu; - DURING DRIVER LOADINGr(; - 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.; ;--f .if df,evax2JF_unit_INIT: .jsb_entry ;JF UNIT INITIALIZATION .iffe3JF_unit_INIT:; .jsb_entry ;JF UNIT INITIALIZATION; .endc. movab fcae,fcnca ; set up catch-all final FDT>; Don't set unit online here. Priv'd task that assigns JF unit<; to a file does this to ensure only assigned JFn: get used.:; BISW #UCB$M_ONLINE,UCB$W_STS(R5) ;SET UCB STATUS ONLINE;limit size of JF: data buffersiJF_bufsiz=81929 movl #JF_bufsiz,ucb$l_maxbcnt(r5) ;limit transfers to 8ka9 MOVB #DC$_MISC,UCB$B_DEVCLASS(R5) ;SET DISK DEVICE CLASStC; 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!!!),9 movl #^Xb22d4001,ucb$l_media_id(r5) ; set media id as JF G; (note the id might be wrong but is attempt to get it.) (used only foru; MSCP serving.)> MOVB #DT$_FD1,UCB$B_DEVTYPE(R5) ;Make it foreign disk type 1/; (dt$_rp06 works but may confuse analyze/disk)G;;; NOTE: changed from fd1 type so MSCP will know it's a local disk andl8;;; attempt no weird jiggery-pokery with the JF: device.G; MSCP may still refuse to do a foreign drive too; jiggery-pokery latern'; to test if there's occasion to do so.; Set up crc polynomiali6; clrl chnflg ;initially set to use our chain of FDTs movl #1,chnflg movl #1,r0f RSB ;RETURN  .SBTTL START I/O ROUTINEe;++k; ; JF_STARTIO - START I/O ROUTINE; ; FUNCTIONAL DESCRIPTION:i; G; THIS FORK PROCESS IS ENTERED FROM THE EXECUTIVE AFTER AN I/O REQUESTl; PACKET HAS BEEN DEQUEUED.; ; INPUTS: ; ); R3 - IRP ADDRESS (I/O REQUEST PACKET)t); R5 - UCB ADDRESS (UNIT CONTROL BLOCK)f:; IRP$L_MEDIA - PARAMETER LONGWORD (LOGICAL BLOCK NUMBER); ; OUTPUTS:; =; R0 - FIRST I/O STATUS LONGWORD: STATUS CODE & BYTES XFERED/; R1 - SECOND I/O STATUS LONGWORD: 0 FOR DISKS^; ; THE I/O FUNCTION IS EXECUTED.; ,; ALL REGISTERS EXCEPT R0-R4 ARE PRESERVED.; ;--c .if df,evax.JF_STARTIO: .jsb_entry ;START I/O OPERATION .iffe#JF_STARTIO: ;START I/O OPERATIONB .endc; ; PREPROCESS UCB FIELDS; ); ASSUME RY_EXTENDED_STATUS_LENGTH EQ 8pD; CLRQ UCB$Q_JF_EXTENDED_STATUS(R5) ; Zero READ ERROR REGISTER area.; ; BRANCH TO FUNCTION EXECUTION13 bbs #ucb$v_online,- ; if online set software valida ucb$l_sts(r5),210$5216$: movzwl #ss$_volinv,r0 ; else set volume invalid$' brw resetxfr ; reset byte count & exitr210$:n;; Unless we use this entry, we want to junk any calls here.r+ brb 216$ ;just always say invalid volume.lA; Get here for other start-io entries if the virtual disk code is3$; commented out also, as it must be.8RESETXFR: ; dummy entry ... should never really get here# MOVL UCB$L_IRP(R5),R3 ;GET I/O PKT C .iif ndf,evax,MNEGW IRP$W_BCNT(R3),UCB$W_BCR(R5) ; RESET BYTECOUNTp ; BRW FUNCXTFUNCXT: ;FUNCTION EXIT& CLRL R1 ;CLEAR 2ND LONGWORD OF IOSB REQCOM ; COMPLETE REQUESTe .if ndf,evaxh!FATALERR: ;UNRECOVERABLE ERRORi2 MOVZWL #SS$_DRVERR,R0 ;ASSUME DRIVE ERROR STATUS brb funcxt_; PWRFAIL: ;POWER FAILURE: BICW #UCB$M_POWER,UCB$L_STS(R5) ;CLEAR POWER FAILURE BIT1 MOVL UCB$L_IRP(R5),R3 ;GET ADDRESS OF I/O PACKET25 MOVQ IRP$L_SVAPTE(R3),- ;RESTORE TRANSFER PARAMETERSh UCB$L_SVAPTE(R5) ;...b$ BRW JF_STARTIO ;START REQUEST OVER .endc .if ndf,evaxsJF_INT:: JF_UNSOLNT:: POPR #^M% REI ;DUMMY RETURN FROM ANY INTERRUPT .endc ;;3/JF_END: ;ADDRESS OF LAST LOCATION IN DRIVER .END^*[VLT00A.GCE]KITINSTAL.COM;17+,./ 4[->0123KPWO56Iʞ7Iʞ89GHJ'$ ! Close all [potentially] open files.$ !$ WS := WRITE SYS$OUTPUT$ CLOSE /NOLOG KIT_DATA$ !$ ! Take care of interrupts$ !3$ ON CONTROL_Y THEN GOTO CLEANUP_AND_EXIT_CONTROL_Y$ !!$ ! Dispatch to error processing.$ !3$ ON WARNING THEN GOTO CLEANUP_AND_EXIT_WITH_STATUS$ !#$ ! Determine the course of action.$ !.$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL&$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP3$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'$ EXIT VMI$_UNSUPPORTED$ !$ ! Install the product.$ ! $INSTALL:$ $ IVP = FALSE"$ VMI$CALLBACK CHECK_VMS_VERSION - SQS$VERSION "054"+$ MODIFY_STARTUP_DB_AVAILABLE = SQS$VERSION$ REQUIRED_SPACE = 400$ SAFETY_SPACE = 400$ VERSION = "050"+$ WD = "IF VMI$DEBUG THEN WRITE SYS$OUTPUT"$"$ VMI$CALLBACK CHECK_VMS_VERSION - SQS$VERSION "''VERSION'"%$ IF SQS$VERSION THEN GOTO VERSION_OK$ !#$ ! Indicate wrong version and exit$ !$WRONG_VERSION:1$if f$getsyi("CPU") .gt. 127 then goto version_ok$ VMI$CALLBACK MESSAGE - E VERSION -B "This kit must be installed on an existing VMS''VERSION' system."$$ GOTO CLEANUP_AND_EXIT_WITH_FAILURE$ $VERSION_OK:$$ !-$ ! Check for disk space, exit if not enough.$ !&$ VMI$CALLBACK CHECK_NET_UTILIZATION - SQS$SPACE 'REQUIRED_SPACE'<$ IF .NOT. SQS$SPACE THEN GOTO CLEANUP_AND_EXIT_WITH_FAILURE$ !#$ ! Validate all sysgen parameters.$ !$$ !/$ ! Set up for a conditional safe installation.$ !$ VMI$CALLBACK SET -" SAFETY CONDITIONAL 'SAFETY_SPACE'$ !($ ! Restore secondary save sets, if any.$ !$RESTORE_SECONDARY_SAVESET:$$ !$ ! Check for purging and IVP.$ !$ VMI$CALLBACK SET - PURGE ASK&$ IF IVP THEN VMI$CALLBACK SET IVP ASK$ !8$ ! Get the system startup command procedure parameters.$ !$1000$:3$ ON WARNING THEN GOTO CLEANUP_AND_EXIT_WITH_STATUS$$1010$:$$1020$:3$ ON WARNING THEN GOTO CLEANUP_AND_EXIT_WITH_STATUS$$ VMI$CALLBACK ASK SQS_GT_INTERNET -F "Can this system send to and receive mail from the Internet" - "N" - DBZ ""G$ IF SQS_GT_INTERNET .EQS. "^Z" THEN GOTO CLEANUP_AND_EXIT_WITH_FAILURE*$ IF .NOT. SQS_GT_INTERNET THEN GOTO 1040$$$1030$:3$ ON WARNING THEN GOTO CLEANUP_AND_EXIT_WITH_STATUS$1040$:$ WRITE SYS$OUTPUT ""8$ WRITE SYS$OUTPUT "No further questions will be asked."$ WRITE SYS$OUTPUT ""$ !%$ ! Create the necessary directories.$ !$ !N$ ! Construct the system startup command procedure that defines the per system$ ! environment.$ !J$ ! Add all identifiers BEFORE files are delivered (which may need to have$ ! acls set.)$ !$ ! Link the executable images.$ !$ WS "Linking driver"$if f$getsyi("CPU") .gt. 127$then $! AXP build$vs=f$getsyi("version")$vs=f$extract(1,1,vs)@$ if vs .gts. "7" then write sys$output "VMS Version too large."9$ if vs .gts. "7" then GOTO CLEANUP_AND_EXIT_WITH_FAILURE[$if f$getsyi("version") .gts. "V1.6" .or. f$getsyi("version") .eqs. "T2.0" .or. vs. eq. "7"$then$! step 2 stuff1$! Note 64 bit stuff doesn't matter in this case.4$delete vmi$kwd:jfdriver.obj.,favoid.obj.,jfctl.obj.$delete vmi$kwd:zm*.exe..$rename vmi$kwd:zmenu.exe_a2 vmi$kwd:zmenu.exe<$rename vmi$kwd:zmenu_scroll.exe_a2 vmi$kwd:zmenu_scroll.exe&$rename vmi$kwd:*.obj_a2 vmi$kwd:*.obj#$macro/migr/obj=jfdriver jfdriverv2$macro/migr/obj=jfctl jfctlv2$else$! step 1 alpha version.)$! Don't have facilities to support this.4$delete vmi$kwd:jfdriver.obj.,favoid.obj.,jfctl.obj.$delete vmi$kwd:zm*.exe.-$rename vmi$kwd:zmenu.exe_a vmi$kwd:zmenu.exe;$rename vmi$kwd:zmenu_scroll.exe_a vmi$kwd:zmenu_scroll.exe%$rename vmi$kwd:*.obj_a vmi$kwd:*.obj$macro/migr/obj=jfctl jfctl_axp%$macro/migr/obj=jfdriver jfdriver_axp$endif$set def vmi$kwd$@jfdriver.lnk7$link/native/bpage=14/sysexe=select/exe=jfctl.exe jfctl$else $! Vax build$vs=f$getsyi("version")$vs=f$extract(1,1,vs)@$ if vs .ges. "8" then write sys$output "VMS Version too large."9$ if vs .ges. "8" then GOTO CLEANUP_AND_EXIT_WITH_FAILURE$if vs .ges. "6"$then$! Vax Vms V6+ build$ set def vmi$kwd:$! Use objects assembled under VMS V6.1 on Vax for safety.&$ copy jfdriver_v6vax.obj jfdriver.obj"$ copy favoid_v6vax.obj favoid.obj $ copy jfctl_V6vax.obj jfctl.obj$macro/obj=jfdriver jfdriverv2$macro/obj=jfctl jfctlv2$endif $set noonB$ write sys$output "Expect warning LINK-W-USRTFR. This is normal."9$link/notrace/exe=vmi$kwd:jfdriver.exe vmi$kwd:jfdriver+-% sys$system:sys.stb/sel+sys$input/optbase=0$ WS "linking control utility"$set on0$ link/exe=vmi$kwd:jfctl.exe vmi$kwd:jfctl.obj+-% sys$system:sys.stb/sel+sys$input/optsys$share:vaxcrtl/share$endif,$copy vmi$kwd:favoid.cld sys$common:[sysexe]/$set prot=(wo:re) sys$common:[sysexe]favoid.cld$ set on$ !($ ! Set up access to the kit data files.$ !,$VMI$CALLBACK PROVIDE_DCL_COMMAND FAVOID.CLDG$VMI$CALLBACK PROVIDE_FILE FAVD_ACSCLD FAVOID.cld "sys$common:[sysexe]"G$VMI$CALLBACK SECURE_FILE FAVD_ACSCLD "[1,4]" "s :rwed,o:rwed,g:re,w:re"D$VMI$CALLBACK PROVIDE_FILE FAVD_ACSEXE jfctl.exe sys$common:[sysexe]G$VMI$CALLBACK SECURE_FILE FAVD_ACSEXE "[1,4]" "s:rwed,o:rwed,g:re,w:re"G$VMI$CALLBACK PROVIDE_FILE FAVD_FRDV JFDRIVER.EXE "sys$common:[sysexe]"E$VMI$CALLBACK SECURE_FILE FAVD_FRDV "[1,4]" "s:rwed,o:rwed,g:re,w:re"E$VMI$CALLBACK PROVIDE_FILE FAVD_ZMCL ZMENU.CLD "sys$common:[sysexe]"C$! note see elsewhere on this disk if using VMS 7.2 or later; zmenu$! will have to be built.K$write sys$output "If using VMS 7.2 then get zmenu off other areas of disk"F$VMI$CALLBACK SECURE_FILE FAVD_ZMCL "[1,4]" "s:rwed,o:rwed,g:re,w:re"E$VMI$CALLBACK PROVIDE_FILE FAVD_ZMEX ZMENU.EXE "sys$common:[sysexe]"F$VMI$CALLBACK SECURE_FILE FAVD_ZMEX "[1,4]" "s:rwed,o:rwed,g:re,w:re"M$VMI$CALLBACK PROVIDE_FILE FAVD_ZMEX2 ZMENU_SCROLL.EXE "sys$common:[sysexe]"G$VMI$CALLBACK SECURE_FILE FAVD_ZMEX2 "[1,4]" "s:rwed,o:rwed,g:re,w:re"8$VMI$CALLBACK PROVIDE_FILE FAVD_ACSD FA.man "sys$help:"F$VMI$CALLBACK SECURE_FILE FAVD_A CSD "[1,4]" "s:rwed,o:rwed,g:re,w:re"H$VMI$CALLBACK PROVIDE_FILE FAVD_CFG1 FA_SETUP.COM "sys$common:[sysmgr]"F$VMI$CALLBACK SECURE_FILE FAVD_CFG1 "[1,4]" "s:rwed,o:rwed,g:re,w:re"$ !O$ ! Install the product startup files and identify the startup command file for$ ! IVP.$ !$INSTALL_STARTUP:$ TYPE SYS$INPUT:$ DECK>To complete the installation of FragmentAvoid you must run the@procedure SYS$MANAGER:FA_SETUP.COM (for a screen oriented setup)7to set up fragmentation avoiding on any disks you want.LThen you must also modify the file SYS$MANAGER:SYSTARTUP_VMS.COM to contain:8 $ IF F$SEARCH("SYS$MANAGER:FA_CONFIG.COM") .NES. "" -) THEN @SYS$MANAGER:FA_CONFIG.COM$ EOD$ !$ ! Move data files.$ ! $MOVE_DATA:$$ !$ ! Installation Complete.$ !$INSTALL_COMPLETE:$2$ IF SQS_GT_INTERNET THEN CALL DIALHOME/OUTPUT=NL:$ GOTO CLEANUP_AND_EXIT$$ !$ ! Run the IVP, if one exists.$ !$IVP:$$ EXIT $STATUS $CLEANUP_AND_EXIT_CONTROL_Y:$ VMI$CALLBACK CONTROL_Y$ STATUS = VMI$_FAILURE $ GOTO CAE10$$$CLEANUP_AND_EXIT_WITH_STATUS:$ STATUS = $STATUS $ GOTO CAE10$$$CLEANUP_AND_EXIT_WITH_FAILURE:$ STATUS = VMI$_FAILURE $ GOTO CAE10$$$CLEANUP_AND_EXIT:$ STATUS = VMI$_SUCCESS$$CAE10$: $ EXIT STATUS $ doubleQuote: $ yyy = ""$ i = f$locate("""",xxx)9$ 23016: if (.not.(i .ne. f$length(xxx))) then goto 23018)$ yyy = yyy + f$extract(0,i+1,xxx) + """"$ xxx = f$extract(i+1,999,xxx)$ 23017: i = f$locate("""",xxx) $ goto 23016 $ 23018: $ yyy = yyy + xxx$ return $ dialhome: subroutine$ exit$ endsubroutine*[VLT00A.GCE]ZMENU.CLD;5+,e./ 4P->0123KPWO56}B'˖7Ze89GHJDefine Verb ZMENU Image "sys$system:ZMENU"0 Qualifier SCROLLING , Syntax=ZMENU_SCROLLING1 Parameter P1 , Value( Default="SYS$INPUT:" )' Qualifier SYMBOLS , NonnegatableI Qualifier POINTER , Default, Nonnegatable , Value( Default="-->" )C Qualifier ITEM , Default, Nonnegatable, Value( Default="^" )P Qualifier INITIAL , Default , Nonnegatable, Value(Type=$NUMBER,Default=1)$ Qualifier WIDE , Nonnegatable+ Qualifier NOINTERRUPT , Nonnegatable+ Qualifier TEXT , Nonnegatable, Value& Qualifier START0 , Nonnegatable% Qualifier BOUND , Nonnegatable% Qualifier DEBUG , Nonnegatable' Qualifier VERSION , NonnegatableDefine Syntax ZMENU_SCROLLING" Image "sys$system:ZMENU_SCROLL"0 Parameter P1 , Value(Required,Type=$INFILE)C Qualifier ITEM , Default, Nonnegatable, Value( Default="^" )$ Qualifier WIDE , Nonnegatable' Qualifier SYMBOLS , Nonnegatable*[VLT00A.GCE]ZMENU.EXE;4+,f.(/ 4()->0123 KPWO)56x?7)e89GHJ.0DX0205(-%ilFZMENU01-%i05-05  !#6 ( ?B!d FORRTL_001! LIBRTL_001[JP1.MENU)[22;132HVERSIONNSWC ZMENU Rev 1.005 Created 7-JAN-1992 12:00DEBUGSYMBOLSWIDETEXTNOINTERRUPTSTART0BOUNDINITIALPOINTERITEMMENU TEXT[!2UL;!2ULH[!UL;!ULH[2D 00:00:00ZMENU_TEXT[20H[J[20;24r[24H[K------------------------------------------------------------------------------E [7m H E L P [m Use arrow keys to move the pointer to the desired item.E Type RETURN, ENTER, DO, or SELECT to select the item.E Type CONTROL-W to refresh the screen.E [5;7m Type a blank to return to the menu. [m[H[2K[1;24rNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than two selectable itemsBADQUAL, invalid /TEXT qualifierTEXT, missing or invalid text areaITEMCOL, the menu contains an item marker too close to the left marginCHOICE[?25h[1;24r[23H[m TT TT!UL SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:[?3h[?3lSYS$OUTPUT  MENU ,(@T MENU(|SYMBOLS(qPOINTER$ITEM(INITIAL, NOINTERRUPT$@WIDE$dTEXT(START0$ BOUNDp  (   `D(/| d +  / `  `   `  D l $2W @D`DD .L @{ / "     ( 8 H /X ` "x E  p C SA GcA RWcA Y2Y\0cA RW1WA cX2XX\XRWRW1SPRWw1eD1d1;WdPUdRPS>C SB 7cB PWB cX2X\ WcB Q2QQ\QPWPWSPWWdX 1eM ceQC 1K[Ы\Rm( BV, <Ɣ @L3#m~ +#?f#ȫpƔ tp##fƔ !fiG/ G P2PPPPQ,n Q@bˀkL!1N22fPPˌƔ ː22PďP@Ɣ ˘˜d22WkGfŏWXkkPkXQ,n PAƔ kˬHƔ ˰ďWG˸˼zkkP22WďWkWX,n PH\PPkkPP\21!2  W\122XkX1WYŏkTYTP@b2]PWP  2 PPPk@ W@ *.YTP @ŏkTDƔ w!PPTQ AƔ Xk\Wi  a 2 P~Pt&  \|Hȿ[Cԫ P0 8P@ PPRdP2PPPPQ,n~FAV020.Af>[VLT00A.GCE]ZMENU.EXE;4(1r" Q@ `P\2hPP^(Pn^SV^(nVVlV\^ptL\^ˈ{P˘hP˨UP˸BP/P9P* P'@2PP,P.< 20PPL(P\ktP ˄H﬿[A\ լ0KlAlClKll8Ѭ @HVѬW,W  WH LPѬ`լ 32PѬP&֬ŏP@lpP լ |ŏWGˈˌWPffPPTTPUTWP-U@ TWP, U@{Ь˰Ь ˴ˠP PPPP ˸,n PԬI[}PQPk}PQ PԼ V ^ H0[k1k2c\Rb\1>S2PŏbQPA  P\bL$JPPzPP{PPPP~^0,^ŏbPRRPSC@<@ HHм[8ŏPQQP\L ?A D$$ O[V2Wռ1}է PPX ^( nu^(nmnbZ ZYH~Y^(nYYYX^ X^קg1=g11Ѽ1sѧէ fkkѧPg,_֧P@X ^( n^(n~^(nH~^(n8X^< PP~^H@X^g1g1hէkf2XX]>YZ2ZZˠˤ2iPďP˨ZPQA=ˬ˰)ЫfYXFէkf2ˌː˔OP ¦2OPѫPЫfkf1ѼFV^(n§^(nЧXXY^(nY}~YYLYV^PTV^QѼ*gdhlP P|x"Ѽէˀ,n PԧH[XP H0@@8P0`(  h2 p ˄=˘||H[Ѽ5V<^(<ɮn ^( nEkEV^V^1Ѽ.V1^(1ʮn ^( n::V^V^1Ѽ6V9^(9Ǯn ^( nB BV^$(MV^1Ѽ.V ^( Įn ^( n)0)V^48V^qѼ.V"^("ﰮn ^( n+@+V^DHV^=Ѽ6VF^(Fn ^( nOPOV^TXV^`HH[!H[4A~^^$H[PP P  2,޼@$P P\X 2d`2Lp޼˄hPPˠ˜2˨ˤ޼PˬX ˴cPR˼ FPRRRVO[}PQP}PQP k<PP PQPQ ,  $NPQPQVzVR{RRRRWW RRX< RXRPQ P8+T|PT  PyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTKݏlPެQ.T1}a ( f2f0P PLH 2TP"H[}PQPk0123KPWO56N37 e89GHJXh-%i0!mOZMENU_TV01V1.1$n $ $:$F $J6d FORRTL_TV_0016 LIBRTL_TV_0016 TIE$SHARE_001[JP1.MENU)[22;132HVERSIONNSWC ZMENU Rev 1.005 Created 7-JAN-1992 12:00DEBUGSYMBOLSWIDETEXTNOINTERRUPTSTART0BOUNDINITIALPOINTERITEMMENU TEXT[!2UL;!2ULH[!UL;!ULH[2D 00:00:00ZMENU_TEXT[20H[J[20;24r[24H[K------------------------------------------------------------------------------E [7m H E L P [m Use arrow keys to move the pointer to the desired item.E Type RETURN, ENTER, DO, or SELECT to select the item.E Type CONTROL-W to refresh the screen.E [5;7m Type a blank to return to the menu. [m[H[2K[1;24rNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than two selectable itemsBADQUAL, invalid /TEXT qualifierTEXT, missing or invalid text areaITEMCOL, the menu contains an item marker too close to the left marginCHOICE[?25h[1;24r[23H[m TT TT!UL SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:[?3h[?3lSYS$OUTPUT  MENU ,(@T MENU(|SYMBOLS(qPOINTER$ITEM(INITIAL, NOINTERRUPT$@WIDE$dTEXT(START0$ BOUNDp  (   `D(/| d +  / `  `   `  D l $2W @D`DD .L @{ / "     ( 8 H /X ` "x E  p C SA GcA RWcA Y2Y\0cA RW1WA cX2XX\XRWRW1SPRWw1eD1d1;WdPUdRPS>C SB 7cB PWB cX2X\ WcB Q2QQ\QPWPWSPWWdX 1eM ceQC 1K[Ы\Rm( BV, <Ɣ @L3#m~ +#?f#ȫpƔ tp##fƔ !fiG/ G P2PPPPQ,n Q@bˀkL!1N22fPPˌƔ ː22PďP@Ɣ ˘˜d22WkGfŏWXkkPkXQ,n PAƔ kˬHƔ ˰ďWG˸˼zkkP22WďWkWX,n PH\PPkkPP\21!2  W\122XkX1WYŏkTYTP@b2]PWP  2 PPPk@ W@ *.YTP @ŏkTDƔ w!PPTQ AƔ Xk\Wi  a 2 P~Pt&  \|Hȿ[Cԫ P0 8P@ PPRdP2PPPPQ,n Q@ `P\2hPP^(Pn^SV^(nVVlV\^ptL\^ˈ{P˘hP˨UP˸BP/P9P* P'@2PP,P.< 20PPL(P\ktP ˄H﬿[A\ լ0KlAlClKll8Ѭ @HVѬW,W  WH LPѬ`լ 32PѬP&֬ŏP@lpP լ |ŏWGˈˌWPffPPTTPUTWP-U@ TWP, U@{Ь˰Ь ˴ˠP PPPP ˸,n PԬI[}PQPk}PQ PԼ V ^ H0[k1k2c\Rb\1>S2PŏbQPA  P\bL$JPPzPP{PPPP~^0,^ŏbPRRPSC@<@ HHм[8ŏPQQP\L ?A D$$ O[V2Wռ1}է PPX ^( nu^(nmnbZ ZYH~Y^(nYYYX^ X^קg1=g11Ѽ1sѧէ fkkѧPg,_֧P@X ^( n^(n~^(nH~^(n8X^< PP~^H@X^g1g1hէkf2XX]>YZ2ZZˠˤ2iPďP˨ZPQA=ˬ˰)~FAV020.Ag>[VLT00A.GCE]ZMENU.EXE_A;2|-ЫfYXFէkf2ˌː˔OP ¦2OPѫPЫfkf1ѼFV^(n§^(nЧXXY^(nY}~YYLYV^PTV^QѼ*gdhlP P|x"Ѽէˀ,n PԧH[XP H0@@8P0`(  h2 p ˄=˘||H[Ѽ5V<^(<ɮn ^( nEkEV^V^1Ѽ.V1^(1ʮn ^( n::V^V^1Ѽ6V9^(9Ǯn ^( nB BV^$(MV^1Ѽ.V ^( Įn ^( n)0)V^48V^qѼ.V"^("ﰮn ^( n+@+V^DHV^=Ѽ6VF^(Fn ^( nOPOV^TXV^`HH[!H[4A~^^$H[PP P  2,޼@$P P\X 2d`2Lp޼˄hPPˠ˜2˨ˤ޼PˬX ˴cPR˼ FPRRRVO[}PQP}PQP k<PP PQPQ ,  $NPQPQVzVR{RRRRWW RRX< RXRPQ P8+T|PT  PyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTKݏlPެQ.T1}a ( f2f0P PLH 2TP"H[}PQPkCYGo&s""?"!@Sk%|~!n#aG~CGo&s""?"!@Sk%H~!o&Hs"@ "?"@Sk%,~!%."*_"0JB'`.#JB?e/ #eK\C ."!F>BQFo&s""?"!@Sk%}!."JuB o&\s"H "?"@Sk%}!/= C_Y/e#~"KpC7 e."eJTB #GC8Go&s""?"!@Sk%}!e/#eK\C ."!F>BQFo&Ls""?"!@Sk%|!."JuB .#!G>CYGo&s""?"!@Sk%|!/e# "KpC+ O @o&\s"P "?"@Sk%H|!o=`BU/??#KB @/H"KpC e.h"eJTB #GC8Go&Ls""?"!@Sk%{!e/A#eK\C7$% D5@B`9GFBB37H<7HD@@ R"G .D.D. ;.GT GJGQ ;JU JJPF:GK0FFrC ZC$:1 CD;9 C@ &. # .Q BQFo&Ls""?"!@Sk%t!X#"FB%t!G#.#!G>CYGo&`o!s""?"!@Sk%s!4o`o&s" "?"@Sk%s!O'o'Z"4/"{O"@Zko& s" , "?"@Sk%Ps!+.# .<K"=k.O'Q sKo'<.?"L "TJtF<>@ZLo{@Zk%r!#GC8GO#NO'1o##n_"\oo'N"Z?"!{@Zk%|r!n"aF~BFO'ΰ"Poo'"Z!{?"@Zk%4r!#GC8Gqk/_# KK[ kK "Gqk?{KKO'p/p+"_"\K|Gp?t o'."To?"N!Z{@Zk%q!n"aF~BFO'Xoo'"Z?"!{@Zk%tq!&//Y &KK8G5J f/ F#GFZzK"GK9DC5DC!F5DCFД FG=DCF3DC4GF.f.T JfJF2FJv@///"Y 5KK8G5J"o/O#GZzKFGK"ECEC!FECFД FGECFEC4GFN"AF^BrFo&s""?"!@Sk%Hp!Z0ďJ•5JJB瀢O?#9&KvH:FK"YCfK YC0vKO'F HZo'H."ȃ{D 1@!B5 BA39@B""_""@Zko&s" "?"@Sk%o!.# GF/\J;KKfK9C5CaF5CxCVF"Ҕ`F F=C GzKY KVF3C;gK4 FYGVF/ {C3&/2/2"#U 4KK<KF5JY 4KBJXK tK B9F4?qtK"8F?f. F#.2f# /FfJT JX KF HH H8G ?xH+/Y5KG+?KG3.2/P JKF HHu@TBBRBD@BDDGDGT GGPFo&:GK,s"@ {# ZCk "?"@Sk%m!3&.2.2#KFQ E2C/6FEuSJEXK6FT@FF?6FPF ?G9'K3gJB sB 9C ?#k."": 8CO'AZAo'@ȃ{ "_"" 8C@Zk+.tJGD.FFDDFT FUJ@Fs"PFko&2GJs"@F> # ?" " RB@Sk%(l!B+3.2/2f# GP JKFF'H?#H: 8C4HKDBRB@BD 8CFDDFTG@@O'FPFZ9'Ko'@ȃ{"" 9C_".""@ZkE @ 3f.2F.2&"GS qJQJFrF1&J"&J D#B#BG#BFՔGF#BF#B4FFO'Hoo'Z "?"{@Zk%j!3f/2F/2&#[ yKYKzG9&K o&s" "?"@Sk%j!O'o'0Zo"?"8{@Zk 3&.2#2._"KQ #>//Z XK8KYG HH @`o&s" "?"@Sk%i!O'o'0Zo"8{?"@Zk F. # &."5JP \JyJ1G<> . /P JK;JF HfKHtCDD@87H07H@ " J5/@ #QBY 5K HYG5?yJ GU/;gK {CZUK:GU?<.Q qH\.R\J2F3H\>8ďfJgB F3gJ sB5@@ #Y/{K@GZYKFzGY?O'o'sCRB\BP?BBDDFD@FTF 9#F+PFZo8K "{ C?"@Zk%g!D 1@@@ 1" "Q.sJ;9@CRQJ@rFQ>0B B8BJ?#D@ @ @ C:CGFG1 f. F. &"S qJQJrF1&J&JY Bo&s" "?"@Sk%f!O'o'0ZWo"?"8{@Zk &/ / "OY 5KK8G HH @C`#ŏ ."!F>BQFo&s""?"!@Sk%\f!dį.aď.ao"U JJF`o&4s" "?"@Sk%$f!#GC8Go&s""?"!@Sk%e!Mm8!4m_FCJ0-F, 6@JM$͠Fp`G(nCm `n7J@AGNnCSkO'o'Z{@Zk##GC%\e!\Fho!kO`o&t s" "?"@Sk%e!!O'oo'Z0 "?"{@Zk%d!"FBFO'`oo'"Z?"!{@Zk%d!O'o'0Zo"8{?"@Zko&s"8 "?"@Sk%td!O'o'0Zo"8{?"@Zko&s"@ "?"@Sk%tH Bl. ACt "UJo&Ds"Fl>?"p˱@Sk%b!AEaG{GLCo&t s" "?"@Sk%Xb!01C0o&t s" "?"@Sk%0b!11C4/o&t s" "?"@Sk%b!21COo&t s" "?"@Sk%a! dį.ao"41CU J JGdį>uJa/XKFa?o&t s" "?"@Sk%a!91C/o&t s" "?"@Sk%ha!:1COo&t s" "?"@Sk%@a!%o& s" "?"@Sk% a!.o#/O'+.ܯo"P JKQ +JF Ho'H " HQF+>q HK.RKJ2FK>k?"Zo{@Zk%`!o&t s", "?"@Sk%`!0o& s"< "?"@Sk%l`!<M.L"o& HU JHs" H@/#GM>uH\ "?"L /XKFL ?P+@Sk%`!?ď/>o#K\ K [K1FKF?ď?&J|[K>.:B ?FPJ1'JG>> 1Bo&t s"t "?"@Sk%_!o& s" "?"@Sk%_!O'o'@ZH{@Zk#N"AF^B%p_!Fwo& s"o!ď! "?"@Sk%4_! o&s"0 "?"@Sk%_!O'o'0Zmo"?"8{@ZkL/A#LK;C" L.C"LJ3B",/K_#,KC`# o&s"8 "?"@Sk%x^!O'o'0Zo"?"8{@Zk,Y B @.l" /"JXKyuJ8G ?k/K# #zK\Co&s"@ "?"@Sk%]!O'o'0Zo"?"8{@Zk, y B@O'lo'Z_"ȃ{,"'Q`B4Y`B" ""@Zk/ &/o&IK/s"KY &KZ KK8G J #zGIK?zJP "Hk/?"[kK[GHk?L@Sk%4]! 5B o&s"` "?"@Sk% ]!O'o'0Zo"8{?"@Zk L/@.o". U JJF HH C$ LGF0@Cl8@CO' o'3JpBQ_B BDDFDAFTF09#Fl+PFZo8K{p "?" C@Zk%4\! L@o&s"| "?"@Sk%\!O'o'0Z5o"?"8{@ZklGFr{CQ_B;B\BCDDvFDO'vFTFAvF# PFZo5קJo' B "{?"@Zk%p[!F&"" _"YCYCO'$1@ЃZ%@<9@0 @@o'@A؃{0vH1"@ZkO'o'Z@ȃ{A@""_",""@Zko0`Bŏ8`B O'o' & ,Ps"?" "+Z{@Zk%Z!F lzCD 1@ @zC19B@o&s" "?"@Sk%PZ!O'o'0Zo"?"8{@ZkO'Z#P?" ". _"B@Zk _  M0!m,m_F(CJF 6@JmFpF$͠BM `7J@AFNBSkO'o'Z{@Zk#"FB%xY!G,ȍo! K9Z@K {H+zGKPJ8@B.0"xJUJG>+/k#(CKY/YK;CK.@?"s+JRKJrFK>+D0@/$1@$CKY/8B89@YK;C+~"$BQ.QJ3BD0@8B+k#/(CKY/YK;C +.k"(BJQ.QJ3BD0@8Cy Lz0`C ,8@k8`C 1hB 1 BB.0@/J29 BXKyuJD8G?\#n#aG~C%pV!Ge ؍o!27HA.q.T JqJF&HHO GF4AGE|C[CxCY_C CDDFDFFT FFPF2GJ RBO'o'ZAF{5 fBN"1""@Zk.#!G'>CDФYG."KnEA!FK. I1FR KJDrFK>r ICk. "?"BSkJ@SFk>˱o& /#>O/F G[ yKYKzG HK!1BH59BDB0@K@B[C`CGADD6F@D39@B[D6FT@F 1@6FPFD @3gJ9 C8A sBA@A@EGO'o'ZAG{9 BN"01""@Zkk&n@: n@0AEFO'1 CZo'FN"{+" "@Zk.D"@U J HGBG>o&uHď#1B@B97HDA#vFDx/DX/vFTF[ xKXKvF37HzGPFA8K5קJR"K B >.vH?/...JQ o&qH?"H˱@Sk%N!AEG8OGB@n#aG~CG/0Bo&C%tN!yGpo!볳O."/. O "R PJ0Jb QF,IIÂo .G.FJU J k.|CF H[CHS kJ HxCY_CF k> C!D9DF. Ds HFT FTJO'AFtF>" PFZoo'2GJ?" "{ RBc @Zk%LM!7H0C C8C_kO'doo'Z$ "?"{@Zk%L!n#aG~CGO&o&GFO'Wo'У2أS_""TT1HD= ]!FZ$K{F F= CFT FTF?"FPF5קJ" B@Zko&_#s";@Cn!0˱< @C, "?"@Sk%L!BGFExRBUCBSB`BDD6GD"1C6GT@G@6GPFO'A;gKR"<K {CZo'hoB09C{@A?"@ "@Zk%|K!#M !m_FMCJmFm6@J FpFB`7J@AFNBSkO'o'Z{@Zko&s"H "?"@Sk%J!_#GC8Go&s""Ȏo!?"!@Sk%J! OG$ůFqZCP?BB[C`CD!1BVFD @DVFAT`FZ# KO'hoVFPFZ4ׇJo' B{?" "@89B@Zk% J!po` ŏCO'o'@ZH{@Zko&s" "?"@Sk%I!o&u4J P A/aGXKF?{G0AX CEFO'o'ZF1C{N"'""@Zk.)E A +IT J@BF>o&t+I.˱?" A@Sk%XG!AEaGg{GHCu`B11B'29B3B,95 C@^gŏ|C`_G@fk" C T_C O'oo'Z, "?"{@Zk%F!."!F>BQFgE.1A0`B(o/8`B39ABoKo' 1C@q\K.O'!PJ99C0F>ZN"{ &""@ZkO'o'ZE.qA{N"+""5yB@Zk(//n/N#"/K[zK|KO'Gn?o'Z.B1B{+"N""@Zk.H_"n" SJT JO'F>tSJ#.o'9C'"UJ"F>Z.C{N"@Zk9k/_# KK[ kK"G9k?{KKE8/XB@ "?"\KPA|G8?<˱ Gg./rB81@Y 5K KrBYG.?o&yKpKKJ+. v@I8vJGQ+J  GF+>KFi.*FI.'"G.FIiJT JQJF Hg.HS qJ:HD@CX?CCDDvGDvGTGvGPF0J B.rF +JT J @F>t+JO'.A09#o'UJ @F>+?"Z "o{@Zk%B!/g/G#'"\ KzKO'GZo'K"{@Zk F_)E A@B0B B8B2' KF,./g#K.+"P JKR QJF qKO'rFK>rqK"k.o' "SqJ?"SFk>Zo{@Zk%A! 9C+: C k HH `C  _KFlsU`BY8qAGEGO'o'ZG{9yBN"+""@ZkGE<AG0 zCO'o'ZGN"{'""@Zk3AE pAxAaFO'o'ZsF{4@BN"+""@ZkN#AG'^C)E AؠBzGN"$K.)E !AAFM.Lk" 3IDT JBFM>t3IRFL.@ CT "UJo&?"P˱@Sk%(@!AEaG{GFCT uB5 G5@B`_'/"/dK#ek/"Y 5KK[ zK8G J?"Gek?{Jd/\KO'|Gd?h o'Zl "o{@Zk%|?!O'| oo'Zx "?"{@Zk%L?!O'o'0Zo"8{?"@Zk,1 B@g`j_o&s" "?"@Sk%>!O'Z#P?"". _"B@Zk _  U_##GC%>!8Go&!o&!o&!o&!o&!o&qKK.RPJ2FK>.k".#//O/JU JZ XK8KFYG3fJ8K xB`o&s"p "?"@Sk%2FJ3GFJq>3J \B \BB xB|GGzG_o&C%H;!yGBĐo!5C:."!F>BQFO'o'ZE{.AGN"/""4gB@ZkO'o'ZE{.1AN"+""89B@ZkK/E?# +KDZ KKCzGK?z+K@k/?" "[kK[Gk?O'˱oo'Z{@Zk%L:!AEAFRF&B5UB:#GC8GE;9FCO'o'Z.1A{GN"؄/""@ZkO'o'ZE{.1A09CN"+""@ZkK.:?" +JO'R KJo'rFK>r+JDk.P@?" "SkJXBSFk>˱Zo{@Zk%T9!AE!G9GCl{u`C:"FB0FO'o'ZE{.1A39GBGN" /""@ZkO'o'ZE{.1AN"+""59B@Zk!+/B# KDY +KXhCYG!+?y Ko' K/P@?"( "ZKK:G K?O'$˱Zo{@Zk%\8!AE!F1FBls`B:"FBGE:$CO'o'Z.A{GN"B/""@ZkO'EZ<9aCo'.1AN"+"{"@Zk1+.)" JO'Q +JDQF1+>q J8eB0K.o'0@8 "RKJ2F0K>?"4˱Zo{@Zk%d7!AEGGB{LZ@C:`#GCFO'o'ZE{.QA2Y$BGN"b/""@ZkO'o'ZE{.1AN"+""49aB@ZkA /+" JDX KxEC8GA ?xJO'@+/o'p@?"Y+KH "G@+?D˱Zo{@Zk%l6!AEFFC=LR@B9`"FBFO'o'ZE{.AGN"/""9C@ZkE;9ACO'o'Z.1A{N"+""@ZkQ .O# KO'P JD0FQ >pKIBP+.o'@Q+JFP+>T˱?"ZX "o{@Zk%t5!AEFFBO'`oo'Z` "{?"@Zk%85!O'o'0Zo"?"8{@Zk#.#!G>C%5!yGSŏ0o! 5B J_o&ﳌs"0o!4 "?"@Sk%4!"FBGO/o&s"?"YCn!˱ "YC@Sk%t4!o&\s"EBA "?"@Sk%L4!o&$ "++?"@Sk%.!D 1CN_&1 @ H@9dH@H?"YG0C9G0G Cw`K"0CG .59 @DH@F0@B@F9F@@`G3CG / F k#'BKP J5 BC1'J(1@@:9@@F 1B AC G _ E B)vH8 B:AAGZG+O'; )CZo'N"!B"{@Zk0AEFO'o'ZF1 C{N"+""@ZkO'4 Ao'Z)E Dȃ{ AJB"B_"."" *A@Zk @F ,F @KGCkGCx#N"AF^B%,!Foo&s"o!qB_ "?"@Sk%,!   B_  @ LDG*ŏ/*o#\K*ŏ?0/1&J: O'loo'Z "{?"@Zk%@,!O'( o'Z$ "o?"{@Zk%,!O'o'0Zo"?"8{@ZkO'oo'Z, "?"{@Zk%+!O'8 oo'Z4 "?"{@Zk%+!O'o'0Zo"8{?"@ZkK"KhoO'o'< "@k&0ŏs"`k?"HK4JJDZ{@Zk%,+!O't oo'Zp "?"{@Zk%*!O'o'0Zo"8{?"@Zk_0o!O'8Ko'K| Z?"ox "{@Zk%*!0/O'o'9&K?"&K+Z "o{@Zk%d*!O'o'0Zo"8{?"@ZkO'o'@ZH{@Zk#n#aG~C%,*!G To!O'o'+0rHQ J+ "QF+l?"s,kZ&Ps"{@Zk%)!o&s"0 "?"@Sk%)! /.k#9+/?"X KJY +KG J@ "YG9+?yJ8K/ZKK:G8K?O'<ko' LZo{@Zk% )! +.O'K."Qk.o'+JR KJS kJQF J?"FQk>s JX "P.TJtFP>TZo{@Zk%(! :_O'o'Zؓo!"ȃ{/"_"""@Zk!O'o'Zؓo!ȃ{"(/"_"""@Zk!#.#!G>C%0(!yGfO'o'Zؓo!"{3/"K"@Zk!o&s"G, "?"@Sk%'!O'o'Z&s"{< "?"@Zk%'!D#@O'E0Zo'Ahs"?"8{@Zk%l'!O'o'0Zo"8{?"@ZkO'd o'Z` "o?"{@Zk% '!O'o'0Zo"?"8{@Zk+GU(B@D 1@49`BO'D0ZEo'Ahs"8{?"@Zk%&!O'o'0Z o"?"8{@ZkO'o'@Z BDH{E@Zko&$s"ؓo! "?"@Sk%`&!<"GGBD"1@@:9 CO'o'@ZBDH{@Zko&$s"ؓo!$ "?"@Sk%&!<ŏ'{#GGBD"1@@19BO'o'@ZBDH{@Zk#N"AF^B%%!F ؕo!G,+8zHY K0+YG,+X#n#aG~C%t%!Gs ؕo!4+0 krHQ J8+QF4+"`O'h" Zo'&s" "{?"@Zk%$!O' o'Z "o?"{@Zk%$!O'o'0Zo"?"8{@Zk51C 5K/4+/4 #o'8+Z XK8K؃{ _"YGO'"ЃZG@Zk5 .4/4k#O'8+P JK"Fko'Zk"ȃ{_"4 "@Zk O' ?"+Zo'"L/"K"{@Zko&s" "?"@Sk%#!LRK_#"FB%#!G,ؕo!_"<K9Z@K${H@+zG<K@< 0vJ + 2B`O'oo'Z  "?"{@Zk%$#!O'o'0Z>o"8{?"@Zkg_#"FB%"!Gؕo!+ K@$k`W_+ 01C $KB@BD_" @` + H.8HO'T JKF>tHC.+# G8KUJo'F>,+&Zs" C{( "?"@Zk%"!O'4 oo'Z0 "?"{@Zk%!!O'o'0Zo"8{?"@Zk + "_#BD@!"Z@< zC@kkK_ K 51C$KB@BD?# 9@@? H`/0&HO'J[ `KBG`?{ H+"/ F0J&\Ks"|G?<+o'Z B?"{8 "@Zk% !O'D o'Z@ "o?"{@Zk% !O'o'0ZBo"?"8{@Zk + "_"BD@"R@4 rB@O'o'K@ZH{@ZkLؕo!&1C,k:[`K|H0+G,k O'o'@ZH{@Zk K11C+@hK ".ubJP#TJk#F>iK zK"/"@#Y"KYG"?K ?#bK .qK2KPJGJ0F>~K ubJ.\B _FTJ2GJF>lK  RBK {"KB/ZBKzGB?K "".rJQ"JQF">O'hk"PkZo'&s"L "{?"@Zk%!O'X o'ZT "o?"{@Zk%!O'o'0Zo"?"8{@Zk ".xJD?#UJh#G> { K@/ "&s"Z@K?"zG@? O'o'` \ "Z{@Zk%!O'h ~FAV020.Ag>[VLT00A.GCE]ZMENU.EXE_A;2}V|koo'Zd "?"{@Zk%!O'o'0Z0o"8{?"@Zk -k.,K.O',+"ZS qJQJo'0+rFȃ{_""", "@Zk/m.l" HU JO'Gm>uH+#l /o'| "?"XKFl ?p+Zo{@Zk% ! D 1@`A"#0.rK;9@CQ0JQF0>"k. HO'T J #F>tHo'. "?"UJF> Zo{@Zk%!D+o&s" "0 CK8 C?"@Sk%T!O'oo'Z "{?"@Zk%(!O'o'0Zo"?"8{@Zko&Ps" "?"@Sk%!DYA"FB0F.An"TJuH"1@F>!bA{#N/A/89@NK\Kp;K!F?ñ Ab @4A2 @EFO'o'ZFfA{1"N""5 `B@ZkO'o'Z"{)n@8 n@_"?""AI@Zk#GCD@FCFN.."sHRQJ#rFN>)E 0 AGO'o'pZGx{8B_"?""@Zkn#aG~CD@&CG.."rH"Q0J)EQF.> 0 AF 0@ 1@: @AO'o'Z8`Bȃ{`AF!@A"_"".""99@8@@Zk @aG{G @JEJO' o'Z&Ps"{ "?"@Zk%! @2A0 @EAFO'o'Z3 BfA{RF1"N""@Zk*n@4 n@9AE!G: CO'o'Z9G "{+"N"@Zk  O'JEZ@DhCo'&1@ HA(1@ȃ{49`BfA29@ A@5 A""_".""@Zk @GG @EK5@ !k#h ! H1H/O'&JK"\ K'BF?|H ?F.1'Jo'&PJs"G>K 1BZ?"{ "@Zk%4!O' oo'Z "?"{@Zk%!O'o'0Zo"8{?"@Zkf$k gB @gBK+ $KKkC` # @ ! H(.3HO'Q (JfJQF(>`BqHH. F3gJ"RHJo'2FH> sBZ&s"{?" "@Zk%$!O' oo'Z "?"{@Zk%!O'o'0Z o"8{?"@Zk " !9C+#: C@@$KO'$+o' "QB QBZo?"{@Zk%`!$B$BO'o'@ZH{@Zk#.#!G>C%(!yG h ,o!.JD7KG ."!F>BQFo&(s""?"!@Sk%!j K/+#..Z YKU JJvHF`F8Hp@K .Q JF >L.r.T JrJFUB O'o'Z"\/"{K"@ZkO'o'Z"{a/"K"@Zk/O'o'9&K?"&K+Z "o{@Zk%!O'8 oo'Z4 "?"{@Zk%!O'o'0Zo"8{?"@Zkď/o#K`O."/.O'o'R PJ0JQF0J?"J@ Z< "o{@Zk%$!O'o'0Zo"8{?"@Zko&s"D "?"@Sk%! n"aF~BFo&s""?"!@Sk%!+/ /"Y 5KK8G@[_##GC%!\F l|o!3uH+TJ+F Y K8TJ zH +YG+O'l /. vHKP JDF"FHo'FH "#1@@ @uHC F3 CBZo19@@?"{@Zk%!7H +BDY@<1@@YC09@@ _#N"AF^B%l!FW #GC8Go!o& s" E<;ACqHPJ+.A0F 4 "?"@Sk%! .O"o."T JrJF@BKo&ts"< "?"@Sk%!D#GC8Go&ts"0AN!8AT˱L "?"@Sk%\!E DAC ]. 1 A+D @\" HU JO'G]>uH(C\ /3 HBo'19 AXK?"F\ ?`+d "Zo{@Zk%!)E k (AKD0@4`B0@Ck8@C+/K/ #5 `B8KZ XK8 BYG 0 (AEm iC*vH< iC1A!FO'1F+o'Z2 BN"{)B"@Zk kE5AFO'o'ZF{8 BN"+" "@Zk JE E'CO'<9`CZo'(1A Bȃ{1 B."B"_"" GA@Zk @AFk/+#K/ @RF[ yKYKBzG @B =O.:":/.R PJ0JQFB k)E 3A0 A B8 ATo&s"t "?"@Sk% !Kl[o&s"| "?"@Sk% ! M8!m4m_F0MCJ,-FM6@J$( Fp F.Bm `.7J@A?FN.BSkO'o'Z{@Zk#N"AF^B%( !Fj #GC8GL0o! "?"Z;C< CnO'!˱o'Zo{@Zk% !o&s"EBA "?"@Sk% ! LRk0`B8`BK O'8Ko'4 Z( "o?"{@Zk%8 !O'@ o'Z< "o?"{@Zk% !O'o'0Zo"?"8{@ZkBD_#n#aG~C% !GQ  @o!+0rHQ J+QF+.J; /o&s"4 "X K ?O?"@Sk%d !O'Oo'Z "o?"{@Zk%8 !O' o'Z "o?"{@Zk% !O'o'0Z-o"?"8{@Zko& s" "?"@Sk% !<HlO{HKZ@KCzGlO G1"8K"@Zk5O'o'`Z?"h{"1F@Zk@GG`朆4H5$HHJG4CBGGJ C$KúB@GGGGG9J C$K/KFC8`G;gK {CDGGD$1@19BD_G_##GC% !8GMz/zKMm!_FCJ F6@JFpGC`7J@AGNCSkO'o'Z{@Zk#N"AF^B%x!F 8/8K mD/K[C-Q@1  _G_##GC%!8GLz/zK  D0.0JC@mS@_G_##GC%!8GL#!zC < 0.0JmD.JSB X@Y @_,A;@#v@HC@-_DQ.QJB2`_#TT@4!//"Y 5KK8GB&` @#@#v@HC@-_DQ.QJB`_#TT@ //"Y 5KK8GB`O'oo' Z?"({@Zk%X!O'o'@ZH{@ZkO'o'@ZGH{@Zk-.a.JaJ1H2GJ 2B U@O'o'@ZH{@ZkO' o'@ZH{@Zk, O'o'9 @ZH{@Zk#n#aG~C%!Go! ?  0B @8B@D+GFl "k?"usBTBBADTDG@Do&GT G\K@GPF:GK|s" ZC@Sk%! ? @DQK@RK@SK@1rs=`BUK@?#u# #C@DK@ o&s" "?"@Sk%!k 0`Ck cC8`CO'QK@1"(+o'Z&s"{?"$ "@Zk%,! K@kO'o', "0k?"Zo{@Zk%!O'o'0Zo"?"8{@Zk_#"FB%!GLo! K1@$ %$C$@O'e#8kZo'&s"4 "{?"@Zk%X!  O'o'@ < "Z?"o{@Zk%!O'o'0Z]o"8{?"@ZkcD0`@D b@@&B8`BG @$ DD0@D @@&C8`Ck\_O'oo'Z(o!{ "?"@Zk%l!O' oo'Z "?"{@Zk%<!O'o'0Zo"8{?"@ZkO'o'@ZH{@Zk#N"AF^B%!F@o!P!L/LK) /,? l/\ KlKG HH@<? @ ,? @@.O'.o'?"JU J "F3fJfJkZo{@Zk%P!O'o'0Zo"?"8{@Zk#GC8G/l/L#n.N"\ KzKSrJG&H( H"A # .;gK# J1CtJ'JFn>'/sJ4 C/Y'KKzJ"YG'?K#G.R\JrFG>,/ /k//Y 5KKzK\ K8GGBl.L.," /.S qJQJX KJrFG4B /L#l/ "+.K.zK\ KR PJ0JGQFPCR`/.""yJXK~#8G?g/gK\CEg.~?"G"At2JSrJ"Fg>/KD @:&C$=@"`A#"Q@1BD5/B'.GDFA8KVFDD'HVFT`FD@VFD @PFQ'JrH4ׇJQF'>AC0C BA"/0".3gJDJ\K4J8BK; B?GFGpHF?-l.,"L.S qJQJrF1&J&J$B,/" /Y 5KK8G5JJB@ .l#/P JKF;fKfKtC .*_"g"uSJTJF>G/ #'#{KZYKzGG?x "FB0Fo&d s""?"!@Sk%!M !m_F͠CJmF6@J FpFB`7J@AFNBSkO'o'Z{@Zk#"FB%8!G,/, ,K 1@ Q@a! `/c/A! \ KcKv`HGCGD@B.""."R PJ0JQFBP5fH$/# KY $Kd#YG$?yK {HD/ZDK:GD?/\ KF?|{H.PJG>D V 1@s$.#Q $J$>D.RDJD>..$/U JJY 8KF xJYG$?yxJD/ZXK:GD?a! {d 7/$" qH\ K?.PJ>D.R QJrFD>rqHd.SqJSFd> " 1@?./d#$/ {HJX KY $KG JYG$?yJD/ZDK:GD?/\ KF?|{H.PJG>"$A! D uHM !m_FMCJFm6@J FpFB`7J@AFNBSkO'o'Z{@Zk"FBG?#.;$KGaGFVG`G#VGO'o'pZ o"x{"_"!?"@Zk%!PF,., H,J5#N"AF^B%!FҀPo!8KO'o'Z&Ps"{ "?"@Zk%!O' oo'Z "?"{@Zk%T!O'o'0ZHo"8{?"@Zk/hO#@KO'o'9&K?"&K,+$ "Z\o{@Zk%!O'\ o'ZX "o?"{@Zk%!O'o'0Zoo"?"8{@Zk.ď#Jo.O./"O'S qJQJo'rF1&J` "&Jd+?"Zo{@Zk%P!O'o'0Zo"?"8{@ZkO'o'Z"{h/"tO"@Zk_#"FB%!Gro&s"o!h "?"@Sk%!%&  .`/!.@/JQ !J@K[ `Kv HvHzG0F GG2vH3v HSB o&s"& + "?"@Sk%T!O'o'Z"{ &"F"@Zk&//O'0˰o'Y &KK&8G5Js"JZ "{?"@Zk%!O'L oo'ZH "?"{@Zk%!O'o'0Zo"8{?"@Zk/f#K`F."&.O'o'R PJ0JQF0J?"JT ZP "o{@Zk%C%!yG#<Ko."2CGJSpJt0JHo!Fo>o&hs"5 C "?"@Sk%!_#.#!G>C%!yGP#GCFO'Z#`!?" ". GB@Zkm.P?"M"t2JSrJM#Fm>쯢-##"_ |?" NO'.lno'xoZ!{@Zk%!"FB0FO'α"N"Nm"nZo'&s""{?"!@Zk%\!Mm$!_FCJMF 6@JmFpF B`7J@AFNBSkO'o'Z{@Zk##GC%!8G0HN#AG^CzGO'xϠZ# "X!?"GB. @Zk-.Q# "rKQ0J #QF->o"O'#mf"|쏢"_ ?"  ,no'.Z!{@Zk%!#GCFO'α .".M"N"Too'Z"!{?"@Zk%!"FBG-#.L#"DNO'to?"no'Z!{@Zk%X! .?" JCA@ l?`"FBF#.#.#Lf"no'"NO'{!Z?"@Zk%!..#.MQ qKP.RPJ2FP>BDMm(!$͠_FCJF6@Jm FpFMB `7J@AFNBSkO'o'Z{@Zk#"FB%!GgD.#!G>CYGO'Z#xϠ "D!?"GB. @Zk/S#pmK\K_ F?/ -|OM.J3gJ`#GC8GM#m#NnO'_"No'f"Z"?"{!@Zk%!m"m?# / KB@ l` .?" JC@l`O'Z#?" ". GB@Zk"" _ ,/_#,KC`  L."LJ3B L/#LK;C ."!F>BQFm""nO'#o'f"Z"?"{!@Zk%x!.#!G>CYGO'α_"Nn#n#Zo'&s""{?"!@Zk%!7_`"FBGO'Z#`!?" ". GB@Zkm/M#T?#|:K[zK_ Gm?  |/-l.lJ2GJ@#GC8GN#NO'αm#n#Zo'&s""{?"!@Zk%,!O'o'@ZH{@ZkP"FB0FO'Z#`!?" ". GB@Zk.U_"m"uSJTJm#F>M#_""_ ?"|/ -nNO'o'xoN!Z{@Zk%\!n"aF~BFO'?#α". #o'Z&s"{"?"!@Zk%!O'o'@ZH{@ZkpE;7`KqE!;F;cK "N4Gn F EkpE27@JqE2F2CJ!R& " E FN4GNnNkpE87KqE8F8K!<' E F4G"n NNkpE;7`KqE;F!;cK "|{'N4GN Fn E $ΰnkpE27@JqE2F!2CJ "R&n4GN FN EkpE87KqE8F!8K "' EN F4GNnkpE;7`KqE;F;cK! {' " E FN4GnnnNkpE27@JqE2F!2CJ R& "N E FN4GnkpE87KqE8F!8K "<'N4GN Fn E $nkpE;7`KqE;F!;cK E|{' FN4G "(nnN$ΰ nkpE27@JqE2F2CJ!R& " E Fΰ4GNnNkpE87KqE8F!8K'  EN F4G ",nN($ΰ nkpE;7`KqE;F!;cK {'N "4Gΰ F E $nnkpE27@JqE2F!2CJ R& N EN F4G ",0nn($ΰ NkpE87KqE8F!8K " '4G F ENNn $ΰ(,0.4nkpE;7`KqE;F!;cK "{'n4G F ENNn $(,.0N4nkpE27@JqE2F!2CJ FR& E4G "N8n4N0.,($ΰNNnk3AJ> 1!BrF3BJ /FrF3DJ;BrFG`QK`[K2F;F0>k0.\KS[JGQ;J?3F0>krFF3DJ`qCp/[pKrFSPJ1$B{Fp?#F  F `P>B;bC`P>BG`P>B p/RQJ[qKrGp?kP>1$BP>P> P>B? 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p 0$$FV1.1May 18 1993 12:51:35ZMENU01-%iCGOCGO@@ACGOCGO@@A[H[2K@jqFF")Fj,Fj4F?F@FHFLFTF\F dF&kFZlFZsFzFFFF FFRFfFFFFFFFF:FNFFFFFGGG GGG GF$GJ*G^.Gf3Gr6GvEGHGLGOGXG:^GNgGvlGoG~GG G&G.G2GFGJGvGzGGGZGGGFGNGRHHH HHHHH H&H )H .H 1H 9H. HH QH YH: hH lH {H ~H H H H H2 H6 H: H> HZ H^ Hb Hv H H H H H H HV H^ Hz H I I. I. 1I :I OIVVIZIaIeImI>vI}IIIIIVIrIII&J*J*NJWJvJ~JJJJJ>J^JJJJJJJJBJjJK1Kf=KAKGKNKWK>eKjlKrsKzzKKKKKKKKKKKzKKKKLILLLULXL_LhLkLrL{L~LLL*L.L^LzL~LLLLLLLLbL~LM$M+MB 4M^ 7Mb @M~ HM JM `M eM mM!vM.!yM6!MJ!MR!Mf!Mn!Mv!M!M!M!M!M."M>"Mv"M"M"M#M"#NN#N#(N#-N#5N$QN$TN$sN$N>%Nz%N%N%N&N&N'N'N'N'O'O'O'$O"((O:(,O>(4Ob(9Oz(@T>>GTV>TTn>XTv>\Tz>`Tz>hT>nT>T?T?T @T@T@T@T@T@T@T@T@T@TAUJAULA UnA UA(UA0UA8UA@UBHU"BOUVBPUVBWUB`UBiUBqUBxUCUBCU^CUbCU~CUCUDUNDUDUDUDUEUEVE*VF0VF6VFcVGlVGrVGVHVHVHVIVIVI WJWJWJWK(WK1W&K4W*KIWNKaWKlWKtWKW4LWVLWfLWLWLWLW"MW&MWnMWzMWMWNW"NXjN XvNXNXN(XN1X&O8X.OAXJOJXrOMXvOPXzO^XO`X,PbXNPXPXPXPXZQXbQXjQXRX"R(YS*Y2S=YVS@YZSNYrSRYzSXYSZYShYSpYSsYSYTY>TYBTYTYTYTY*UY.UYjUYnUYUZUZU"ZVV*ZrV-ZvVCZVLZV]Z^WaZbWjZjWZWZWZWZXZ:XZfXZrXZXZXZYZYZ"Y [nY[Y)[Y;[Y=[YC[YR[Zd[Zf[&Zp[\]?\]A\&]L\2]Q\:]V\B]X\F]l\^]p\b]|\r]\v]\]\]\:^\j^\^]^]^]^]^1]*_4]._B]v_`]_j]_]_]_] `]`]`]`]`]2a]6a]~a!^a$^a0^Bb3^FbD^bG^bH^bZ^b^^bh^cl^&c^~c^c^c^c^c^c^d^&d^d^d _f._Nfp_Fgt_Jgy_Rg_g_g_"h_&h_>h_Rh_Zh_jh_nh_h_h `2i,`fi/`jiF`iM`iX`iZ`im`jt`Nj`j`Zk`k`k`l`>l`Bl`l`l`m`m`"maVmatm amHafnNarnWan`anbanaoaFoaboajoanoaoaoaoa:pa>paFp8bqHbqXbq`brcbrgb"rob>rrbBrwbNrbrbrbRsbzsb~sbsbsbsbsbtb$tbFtbzt ctctct-cu6c:u=cfuPcubcuqcv{cNvcvcvcvcvcvcwcwcwcwcwcwcwcwcxc"xc:xcJxcPxcrxcxcxcxcxcxcxdxdxdx#d.y,d:y4dFy:d^yGdyMdyNdySdy`dzfdzjd*zqdFzdhzdzdzdzd{d"{d&{dF{db{dj{d{d{e{ e{e6|e8|eZ|/ej|8er|=e~|Je|Pe|]e }_e}fe.}oe:}te>}xeF}{eJ}ej}er}e}e}e}e}e~e2~eZ~ef~er~e~fff"'fR6f;fPfYff\fjbfjfrfxf|ff&fZfȂfffff:f^fff΃fփfJfff&f*f g g g("gJ1gZ9g[VLT00A.GCE]ZMENU.EXE_A;2Zwgngևggg>gBgggֈg&g*grg hhh. h"hʊ8h=hIh.PhJXh`h‹jhʋhhhNhdhhhhhh&hrhthiRii iBIiXiZhimiƐriΐ~i*iRiiʑiDifiiiJiRiniviijғj jjj j j%j.*j66jEjHjmjrrjzwjjޕjjj  @0FF!@=:p` G`  0? @@VP  8( $@ 8] R@ 60@$  !  P@p`,;h00P  @ ̐`A f" ` ,@0 8 ((d H0$T0@{ $H0R0@) A2{W 0 H@$ @@&x0ms av8| X  1 H@20a L & „ H@20a X` `p(H@($ !CW Q1Sp٣ T` 0P( 0@:68 qp,``P{@8@<= 3,``Ap`@L(G` $ U((P"D ` &C`KD C `D<20 pfHp@`.<@dae  ;&H+ L'< 0< H` @X;( lp y `̐ / @+p *` **T</^+ Py PUTT|  Hl0Ll0PlTlXl \l`ldlphltlPxl|lplll`lllllll0 lpl l ll 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p          0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV*[VLT00A.GCE]ZMENU.EXE_A2;2+,h./ 4->0123KPWO562\|7C#e89GHJbh-%i0!mOZMENU_TV01V1.1$n $ $:$F $J6d FORRTL_TV_0016 LIBRTL_TV_0016 TIE$SHARE_001[JP1.MENU)[22;132HVERSIONNSWC ZMENU Rev 1.005 Created 7-JAN-1992 12:00DEBUGSYMBOLSWIDETEXTNOINTERRUPTSTART0BOUNDINITIALPOINTERITEMMENU TEXT[!2UL;!2ULH[!UL;!ULH[2D 00:00:00ZMENU_TEXT[20H[J[20;24r[24H[K------------------------------------------------------------------------------E [7m H E L P [m Use arrow keys to move the pointer to the desired item.E Type RETURN, ENTER, DO, or SELECT to select the item.E Type CONTROL-W to refresh the screen.E [5;7m Type a blank to return to the menu. [m[H[2K[1;24rNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than two selectable itemsBADQUAL, invalid /TEXT qualifierTEXT, missing or invalid text areaITEMCOL, the menu contains an item marker too close to the left marginCHOICE[?25h[1;24r[23H[m TT TT!UL SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:[?3h[?3lSYS$OUTPUT  MENU ,(@T MENU(|SYMBOLS(qPOINTER$ITEM(INITIAL, NOINTERRUPT$@WIDE$dTEXT(START0$ BOUNDp  (   `D(/| d +  / `  `   `  D l $2W @D`DD .L @{ / "     ( 8 H /X ` "x E  p C SA GcA RWcA Y2Y\0cA RW1WA cX2XX\XRWRW1SPRWw1eD1d1;WdPUdRPS>C SB 7cB PWB cX2X\ WcB Q2QQ\QPWPWSPWWdX 1eM ceQC 1K[Ы\Rm( BV, <Ɣ @L3#m~ +#?f#ȫpƔ tp##fƔ !fiG/ G P2PPPPQ,n Q@bˀkL!1N22fPPˌƔ ː22PďP@Ɣ ˘˜d22WkGfŏWXkkPkXQ,n PAƔ kˬHƔ ˰ďWG˸˼zkkP22WďWkWX,n PH\PPkkPP\21!2  W\122XkX1WYŏkTYTP@b2]PWP  2 PPPk@ W@ *.YTP @ŏkTDƔ w!PPTQ AƔ Xk\Wi  a 2 P~Pt&  \|Hȿ[Cԫ P0 8P@ PPRdP2PPPPQ,n Q@ `P\2hPP^(Pn^SV^(nVVlV\^ptL\^ˈ{P˘hP˨UP˸BP/P9P* P'@2PP,P.< 20PPL(P\ktP ˄H﬿[A\ լ0KlAlClKll8Ѭ @HVѬW,W  WH LPѬ`լ 32PѬP&֬ŏP@lpP լ |ŏWGˈˌWPffPPTTPUTWP-U@ TWP, U@{Ь˰Ь ˴ˠP PPPP ˸,n PԬI[}PQPk}PQ PԼ V ^ H0[k1k2c\Rb\1>S2PŏbQPA  P\bL$JPPzPP{PPPP~^0,^ŏbPRRPSC@<@ HHм[8ŏPQQP\L ?A D$$ O[V2Wռ1}է PPX ^( nu^(nmnbZ ZYH~Y^(nYYYX^ X^קg1=g11Ѽ1sѧէ fkkѧPg,_֧P@X ^( n^(n~^(nH~^(n8X^< PP~^H@X^g1g1hէkf2XX]>YZ2ZZˠˤ2iPďP˨ZPQA=ˬ˰)ЫfYXFէkf2ˌː˔OP ¦2OPѫPЫfkf1ѼFV^(n§^(nЧXXY^(nY}~YYLYV^PTV^QѼ*gdhlP P|x"Ѽէˀ,n PԧH[XP H0@@8P0`(  h2 p ˄=˘||H[Ѽ5V<^(<ɮn ^( nEkEV^V^1Ѽ.V1^(1ʮn ^( n::V^V^1Ѽ6V9^(9Ǯn ^( nB BV^$(MV^1Ѽ.V ^( Įn ^( n)0)V^48V^qѼ.V"^("ﰮn ^( n+@+V^DHV^=Ѽ6VF^(Fn ^( nOPOV^TXV^`HH[!H[4A~^^$H[PP P  2,޼@$P P\X 2d`2Lp޼˄hPPˠ˜2˨ˤ޼PˬX ˴cPR˼ FPRRRVO[}PQP}PQP k<PP PQPQ ,  $NPQPQVzVR{RRRRWW RRX< RXRPQ P[VLT00A.GCE]ZMENU.EXE_A2;2k|2˹PD`Ph`˸`\P Phdԫ <,W,,0 WV1-Wlp|NP P@Wˈˌ˘'PV1֫ˤP ˬ˴/PXX 0XPP~VRB1XdOVWPP^(PFn^SYzXP{ PPP0PP~Y XP0PP~YWZVPPZQ,Yn Q@PQ^ZWQXPVWPP^(PFn^SZ«^(nЫXXZWPPXVVXP,Zn PFPQ^XW1ի7XhXWh˸PP 1W$PP tPЫ`Ы$ի[ЫPP<PXPh˸PP P`PXPhԫ$$XXWkf kWW$ԫWk8+T|PT  PyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTKݏlPެQ.T1}a ( f2f0P PLH 2TP"H[}PQPkCYGo&s""?"!@Sk%|~!n#aG~CGo&s""?"!@Sk%H~!o&Hs"@ "?"@Sk%,~!%."*_"0JB'`.#JB?e/ #eK\C ."!F>BQFo&s""?"!@Sk%}!."JuB o&\s"H "?"@Sk%}!/= C_Y/e#~"KpC7 e."eJTB #GC8Go&s""?"!@Sk%}!e/#eK\C ."!F>BQFo&Ls""?"!@Sk%|!."JuB .#!G>CYGo&s""?"!@Sk%|!/e# "KpC+ O @o&\s"P "?"@Sk%H|!o=`BU/??#KB @/H"KpC e.h"eJTB #GC8Go&Ls""?"!@Sk%{!e/A#eK\C7$% D5@B`9GFBB37H<7HD@@ R"G .D.D. ;.GT GJGQ ;JU JJPF:GK0FFrC ZC$:1 CD;9 C@ &. # .Q BQFo&Ls""?"!@Sk%t!X#"FB%t!G#.#!G>CYGo&`o!s""?"!@Sk%s!4o`o&s" "?"@Sk%s!O'o'Z"4/"{O"@Zko& s" , "?"@Sk%Ps!+.# .<K"=k.O'Q sKo'<.?"L "TJtF<>@ZLo{@Zk%r!#GC8GO#NO'1o##n_"\oo'N"Z?"!{@Zk%|r!n"aF~BFO'ΰ"Poo'"Z!{?"@Zk%4r!#GC8Gqk/_# KK[ kK "Gqk?{KKO'p/p+"_"\K|Gp?t o'."To?"N!Z{@Zk%q!n"aF~BFO'Xoo'"Z?"!{@Zk%tq!&//Y &KK8G5J f/ F#GFZzK"GK9DC5DC!F5DCFД FG=DCF3DC4GF.f.T JfJF2FJv@///"Y 5KK8G5J"o/O#GZzKFGK"ECEC!FECFД FGECFEC4GFN"AF^BrFo&s""?"!@Sk%Hp!Z0ďJ•5JJB瀢O?#9&KvH:FK"YCfK YC0vKO'F HZo'H."ȃ{D 1@!B5 BA39@B""_""@Zko&s" "?"@Sk%o!.# GF/\J;KKfK9C5CaF5CxCVF"Ҕ`F F=C GzKY KVF3C;gK4 FYGVF/ {C3&/2/2"#U 4KK<KF5JY 4KBJXK tK B9F4?qtK"8F?f. F#.2f# /FfJT JX KF HH H8G ?xH+/Y5KG+?KG3.2/P JKF HHu@TBBRBD@BDDGDGT GGPFo&:GK,s"@ {# ZCk "?"@Sk%m!3&.2.2#KFQ E2C/6FEuSJEXK6FT@FF?6FPF ?G9'K3gJB sB 9C ?#k."": 8CO'AZAo'@ȃ{ "_"" 8C@Zk+.tJGD.FFDDFT FUJ@Fs"PFko&2GJs"@F> # ?" " RB@Sk%(l!B+3.2/2f# GP JKFF'H?#H: 8C4HKDBRB@BD 8CFDDFTG@@O'FPFZ9'Ko'@ȃ{"" 9C_".""@ZkE @ 3f.2F.2&"GS qJQJFrF1&J"&J D#B#BG#BFՔGF#BF#B4FFO'Hoo'Z "?"{@Zk%j!3f/2F/2&#[ yKYKzG9&K o&s" "?"@Sk%j!O'o'0Zo"?"8{@Zk 3&.2#2._"KQ #>//Z XK8KYG HH @`o&s" "?"@Sk%i!O'o'0Zo"8{?"@Zk F. # &."5JP \JyJ1G<> . /P JK;JF HfKHtCDD@87H07H@ " J5/@ #QBY 5K HYG5?yJ GU/;gK {CZUK:GU?<.Q qH\.R\J2F3H\>8ďfJgB F3gJ sB5@@ #Y/{K@GZYKFzGY?O'o'sCRB\BP?BBDDFD@FTF 9#F+PFZo8K "{ C?"@Zk%g!D 1@@@ 1" "Q.sJ;9@CRQJ@rFQ>0B B8BJ?#D@ @ @ C:CGFG1 f. F. &"S qJQJrF1&J&JY Bo&s" "?"@Sk%f!O'o'0ZWo"?"8{@Zk &/ / "OY 5KK8G HH @C`#ŏ ."!F>BQFo&s""?"!@Sk%\f!dį.aď.ao"U JJF`o&4s" "?"@Sk%$f!#GC8Go&s""?"!@Sk%e!Mm8!4m_FCJ0-F, 6@JM$͠Fp`G(nCm `n7J@AGNnCSkO'o'Z{@Zk##GC%\e!\Fho!kO`o&t s" "?"@Sk%e!!O'oo'Z0 "?"{@Zk%d!"FBFO'`oo'"Z?"!{@Zk%d!O'o'0Zo"8{?"@Zko&s"8 "?"@Sk%td!O'o'0Zo"8{?"@Zko&s"@ "?"@Sk%tH Bl. ACt "UJo&Ds"Fl>?"p˱@Sk%b!AEaG{GLCo&t s" "?"@Sk%Xb!01C0o&t s" "?"@Sk%0b!11C4/o&t s" "?"@Sk%b!21COo&t s" "?"@Sk%a! dį.ao"41CU J JGdį>uJa/XKFa?o&t s" "?"@Sk%a!91C/o&t s" "?"@Sk%ha!:1COo&t s" "?"@Sk%@a!%o& s" "?"@Sk% a!.o#/O'+.ܯo"P JKQ +JF Ho'H " HQF+>q HK.RKJ2FK>k?"Zo{@Zk%`!o&t s", "?"@Sk%`!0o& s"< "?"@Sk%l`!<M.L"o& HU JHs" H@/#GM>uH\ "?"L /XKFL ?P+@Sk%`!?ď/>o#K\ K [K1FKF?ď?&J|[K>.:B ?FPJ1'JG>> 1Bo&t s"t "?"@Sk%_!o& s" "?"@Sk%_!O'o'@ZH{@Zk#N"AF^B%p_!Fwo& s"o!ď! "?"@Sk%4_! o&s"0 "?"@Sk%_!O'o'0Zmo"?"8{@ZkL/A#LK;C" L.C"LJ3B",/K_#,KC`# o&s"8 "?"@Sk%x^!O'o'0Zo"?"8{@Zk,Y B @.l" /"JXKyuJ8G ?k/K# #zK\Co&s"@ "?"@Sk%]!O'o'0Zo"?"8{@Zk, y B@O'lo'Z_"ȃ{,"'Q`B4Y`B" ""@Zk/ &/o&IK/s"KY &KZ KK8G J #zGIK?zJP "Hk/?"[kK[GHk?L@Sk%4]! 5B o&s"` "?"@Sk% ]!O'o'0Zo"8{?"@Zk L/@.o". U JJF HH C$ LGF0@Cl8@CO' o'3JpBQ_B BDDFDAFTF09#Fl+PFZo8K{p "?" C@Zk%4\! L@o&s"| "?"@Sk%\!O'o'0Z5o"?"8{@ZklGFr{CQ_B;B\BCDDvFDO'vFTFAvF# PFZo5קJo' B "{?"@Zk%p[!F&"" _"YCYCO'$1@ЃZ%@<9@0 @@o'@A؃{0vH1"@ZkO'o'Z@ȃ{A@""_",""@Zko0`Bŏ8`B O'o' & ,Ps"?" "+Z{@Zk%Z!F lzCD 1@ @zC19B@o&s" "?"@Sk%PZ!O'o'0Zo"?"8{@ZkO'Z#P?" ". _"B@Zk _  M0!m,m_F(CJF 6@JmFpF$͠BM `7J@AFNBSkO'o'Z{@Zk#"FB%xY!G,ȍo! K9Z@K {H+zGKPJ8@B.0"xJUJG>+/k#(CKY/YK;CK.@?"s+JRKJrFK>+D0@/$1@$CKY/8B89@YK;C+~"$BQ.QJ3BD0@8B+k#/(CKY/YK;C +.k"(BJQ.QJ3BD0@8Cy Lz0`C ,8@k8`C 1hB 1 BB.0@/J29 BXKyuJD8G?\#n#aG~C%pV!Ge ؍o!27HA.q.T JqJF&HHO GF4AGE|C[CxCY_C CDDFDFFT FFPF2GJ RBO'o'ZAF{5 fBN"1""@Zk.#!G'>CDФYG."KnEA!FK. I1FR KJDrFK>r ICk. "?"BSkJ@SFk>˱o& /#>O/F G[ yKYKzG HK!1BH59BDB0@K@B[C`CGADD6F@D39@B[D6FT@F 1@6FPFD @3gJ9 C8A sBA@A@EGO'o'ZAG{9 BN"01""@Zkk&n@: n@0AEFO'1 CZo'FN"{+" "@Zk.D"@U J HGBG>o&uHď#1B@B97HDA#vFDx/DX/vFTF[ xKXKvF37HzGPFA8K5קJR"K B >.vH?/...JQ o&qH?"H˱@Sk%N!AEG8OGB@n#aG~CG/0Bo&C%tN!yGpo!볳O."/. O "R PJ0Jb QF,IIÂo .G.FJU J k.|CF H[CHS kJ HxCY_CF k> C!D9DF. Ds HFT FTJO'AFtF>" PFZoo'2GJ?" "{ RBc @Zk%LM!7H0C C8C_kO'doo'Z$ "?"{@Zk%L!n#aG~CGO&o&GFO'Wo'У2أS_""TT1HD= ]!FZ$K{F F= CFT FTF?"FPF5קJ" B@Zko&_#s";@Cn!0˱< @C, "?"@Sk%L!BGFExRBUCBSB`BDD6GD"1C6GT@G@6GPFO'A;gKR"<K {CZo'hoB09C{@A?"@ "@Zk%|K!#M !m_FMCJmFm6@J FpFB`7J@AFNBSkO'o'Z{@Zko&s"H "?"@Sk%J!_#GC8Go&s""Ȏo!?"!@Sk%J! OG$ůFqZCP?BB[C`CD!1BVFD @DVFAT`FZ# KO'hoVFPFZ4ׇJo' B{?" "@89B@Zk% J!po` ŏCO'o'@ZH{@Zko&s" "?"@Sk%I!o&u4J P A/aGXKF?{G0AX CEFO'o'ZF1C{N"'""@Zk.)E A +IT J@BF>o&t+I.˱?" A@Sk%XG!AEaGg{GHCu`B11B'29B3B,95 C@^gŏ|C`_G@fk" C T_C O'oo'Z, "?"{@Zk%F!."!F>BQFgE.1A0`B(o/8`B39ABoKo' 1C@q\K.O'!PJ99C0F>ZN"{ &""@ZkO'o'ZE.qA{N"+""5yB@Zk(//n/N#"/K[zK|KO'Gn?o'Z.B1B{+"N""@Zk.H_"n" SJT JO'F>tSJ#.o'9C'"UJ"F>Z.C{N"@Zk9k/_# KK[ kK"G9k?{KKE8/XB@ "?"\KPA|G8?<˱ Gg./rB81@Y 5K KrBYG.?o&yKpKKJ+. v@I8vJGQ+J  GF+>KFi.*FI.'"G.FIiJT JQJF Hg.HS qJ:HD@CX?CCDDvGDvGTGvGPF0J B.rF +JT J @F>t+JO'.A09#o'UJ @F>+?"Z "o{@Zk%B!/g/G#'"\ KzKO'GZo'K"{@Zk F_)E A@B0B B8B2' KF,./g#K.+"P JKR QJF qKO'rFK>rqK"k.o' "SqJ?"SFk>Zo{@Zk%A! 9C+: C k HH `C  _KFlsU`BY8qAGEGO'o'ZG{9yBN"+""@ZkGE<AG0 zCO'o'ZGN"{'""@Zk3AE pAxAaFO'o'ZsF{4@BN"+""@ZkN#AG'^C)E AؠBzGN"$K.)E !AAFM.Lk" 3IDT JBFM>t3IRFL.@ CT "UJo&?"P˱@Sk%(@!AEaG{GFCT uB5 G5@B`_'/"/dK#ek/"Y 5KK[ zK8G J?"Gek?{Jd/\KO'|Gd?h o'Zl "o{@Zk%|?!O'| oo'Zx "?"{@Zk%L?!O'o'0Zo"8{?"@Zk,1 B@g`j_o&s" "?"@Sk%>!O'Z#P?"". _"B@Zk _  U_##GC%>!8Go&!o&!o&!o&!o&!o&qKK.RPJ2FK>.k".#//O/JU JZ XK8KFYG3fJ8K xB`o&s"p "?"@Sk%2FJ3GFJq>3J \B \BB xB|GGzG_o&C%H;!yGBĐo!5C:."!F>BQFO'o'ZE{.AGN"/""4gB@ZkO'o'ZE{.1AN"+""89B@ZkK/E?# +KDZ KKCzGK?z+K@k/?" "[kK[Gk?O'˱oo'Z{@Zk%L:!AEAFRF&B5UB:#GC8GE;9FCO'o'Z.1A{GN"؄/""@ZkO'o'ZE{.1A09CN"+""@ZkK.:?" +JO'R KJo'rFK>r+JDk.P@?" "SkJXBSFk>˱Zo{@Zk%T9!AE!G9GCl{u`C:"FB0FO'o'ZE{.1A39GBGN" /""@ZkO'o'ZE{.1AN"+""59B@Zk!+/B# KDY +KXhCYG!+?y Ko' K/P@?"( "ZKK:G K?O'$˱Zo{@Zk%\8!AE!F1FBls`B:"FBGE:$CO'o'Z.A{GN"B/""@ZkO'EZ<9aCo'.1AN"+"{"@Zk1+.)" JO'Q +JDQF1+>q J8eB0K.o'0@8 "RKJ2F0K>?"4˱Zo{@Zk%d7!AEGGB{LZ@C:`#GCFO'o'ZE{.QA2Y$BGN"b/""@ZkO'o'ZE{.1AN"+""49aB@ZkA /+" JDX KxEC8GA ?xJO'@+/o'p@?"Y+KH "G@+?D˱Zo{@Zk%l6!AEFFC=LR@B9`"FBFO'o'ZE{.AGN"/""9C@ZkE;9ACO'o'Z.1A{N"+""@ZkQ .O# KO'P JD0FQ >pKIBP+.o'@Q+JFP+>T˱?"ZX "o{@Zk%t5!AEFFBO'`oo'Z` "{?"@Zk%85!O'o'0Zo"?"8{@Zk#.#!G>C%5!yGSŏ0o! 5B J_o&ﳌs"0o!4 "?"@Sk%4!"FBGO/o&s"?"YCn!˱ "YC@Sk%t4!o&\s"EBA "?"@Sk%L4!o&$ "++?"@Sk%.!D 1CN_&1 @ H@9dH@H?"YG0C9G0G Cw`K"0CG .59 @DH@F0@B@F9F@@`G3CG / F k#'BKP J5 BC1'J(1@@:9@@F 1B AC G _ E B)vH8 B:AAGZG+O'; )CZo'N"!B"{@Zk0AEFO'o'ZF1 C{N"+""@ZkO'4 Ao'Z)E Dȃ{ AJB"B_"."" *A@Zk @F ,F @KGCkGCx#N"AF^B%,!Foo&s"o!qB_ "?"@Sk%,!   B_  @ LDG*ŏ/*o#\K*ŏ?0/1&J: O'loo'Z "{?"@Zk%@,!O'( o'Z$ "o?"{@Zk%,!O'o'0Zo"?"8{@ZkO'oo'Z, "?"{@Zk%+!O'8 oo'Z4 "?"{@Zk%+!O'o'0Zo"8{?"@ZkK"KhoO'o'< "@k&0ŏs"`k?"HK4JJDZ{@Zk%,+!O't oo'Zp "?"{@Zk%*!O'o'0Zo"8{?"@Zk_0o!O'8Ko'K| Z?"ox "{@Zk%*!0/O'o'9&K?"&K+Z "o{@Zk%d*!O'o'0Zo"8{?"@ZkO'o'@ZH{@Zk#n#aG~C%,*!G To!O'o'+0rHQ J+ "QF+l?"s,kZ&Ps"{@Zk%)!o&s"0 "?"@Sk%)! /.k#9+/?"X KJY +KG J@ "YG9+?yJ8K/ZKK:G8K?O'<ko' LZo{@Zk% )! +.O'K."Qk.o'+JR KJS kJQF J?"FQk>s JX "P.TJtFP>TZo{@Zk%(! :_O'o'Zؓo!"ȃ{/"_"""@Zk!O'o'Zؓo!ȃ{"(/"_"""@Zk!#.#!G>C%0(!yGfO'o'Zؓo!"{3/"K"@Zk!o&s"G, "?"@Sk%'!O'o'Z&s"{< "?"@Zk%'!D#@O'E0Zo'Ahs"?"8{@Zk%l'!O'o'0Zo"8{?"@ZkO'd o'Z` "o?"{@Zk% '!O'o'0Zo"?"8{@Zk+GU(B@D 1@49`BO'D0ZEo'Ahs"8{?"@Zk%&!O'o'0Z o"?"8{@ZkO'o'@Z BDH{E@Zko&$s"ؓo! "?"@Sk%`&!<"GGBD"1@@:9 CO'o'@ZBDH{@Zko&$s"ؓo!$ "?"@Sk%&!<ŏ'{#GGBD"1@@19BO'o'@ZBDH{@Zk#N"AF^B%%!F ؕo!G,+8zHY K0+YG,+X#n#aG~C%t%!Gs ؕo!4+0 krHQ J8+QF4+"`O'h" Zo'&s" "{?"@Zk%$!O' o'Z "o?"{@Zk%$!O'o'0Zo"?"8{@Zk51C 5K/4+/4 #o'8+Z XK8K؃{ _"YGO'"ЃZG@Zk5 .4/4k#O'8+P JK"Fko'Zk"ȃ{_"4 "@Zk O' ?"+Zo'"L/"K"{@Zko&s" "?"@Sk%#!LRK_#"FB%#!G,ؕo!_"<K9Z@K${H@+zG<K@< 0vJ + 2B`O'oo'Z  "?"{@Zk%$#!O'o'0Z>o"8{?"@Zkg_#"FB%"!Gؕo!+ K@$k`W_+ 01C $KB@BD_" @` + H.8HO'T JKF>tHC.+# G8KUJo'F>,+&Zs" C{( "?"@Zk%"!O'4 oo'Z0 "?"{@Zk%!!O'o'0Zo"8{?"@Zk + "_#BD@!"Z@< zC@kkK_ K 51C$KB@BD?# 9@@? H`/0&HO'J[ `KBG`?{ H+"/ F0J&\Ks"|G?<+o'Z B?"{8 "@Zk% !O'D o'Z@ "o?"{@Zk% !O'o'0ZBo"?"8{@Zk + "_"BD@"R@4 rB@O'o'K@ZH{@ZkLؕo!&1C,k:[`K|H0+G,k O'o'@ZH{@Zk K11C+@hK ".ubJP#TJk#F>iK zK"/"@#Y"KYG"?K ?#bK .qK2KPJGJ0F>~K ubJ.\B _FTJ2GJF>lK  RBK {"KB/ZBKzGB?K "".rJQ"JQF">O'hk"PkZo'&s"L "{?"@Zk%!O'X o'ZT "o?"{@Zk%!O'o'0Zo"?"8{@Zk ".xJD?#UJh#G> { K@/ "&s"Z@K?"zG@? O'o'` \ "Z{@Zk%!O'h oo'Zd "?"{@Zk%!O'o'0Z0o"8{?"@Zk -k.,K.O',+"ZS qJQJo'0+rFȃ{_""", "@Zk/m.l" HU JO'Gm>uH+#l /o'| "?"XKFl ?p+Zo{@Zk% ! D 1@`A"#0.rK;9@CQ0JQF0>"k. HO'T J #F>tHo'. "?"UJF> Zo{@Zk%!D+o&s" "0 CK8 C?"@Sk%T!O'oo'Z "{?"@Zk%(!O'o'0Zo"?"8{@Zko&Ps" "?"@Sk%!DYA"FB0F.An"TJuH"1@F>!bA{#N/A/89@NK\Kp;K!F?ñ Ab @4A2 @EFO'o'ZFfA{1"N""5 `B@ZkO'o'Z"{)n@8 n@_"?""AI@Zk#GCD@FCFN.."sHRQJ#rFN>)E 0 AGO'o'pZGx{8B_"?""@Zkn#aG~CD@&CG.."rH"Q0J)EQF.> 0 AF 0@ 1@: @AO'o'Z8`Bȃ{`AF!@A"_"".""99@8@@Zk @aG{G @JEJO' o'Z&Ps"{ "?"@Zk%! @2A0 @EAFO'o'Z3 BfA{RF1"N""@Zk*n@4 n@9AE!G: CO'o'Z9G "{+"N"@Zk  O'JEZ@DhCo'&1@ HA(1@ȃ{49`BfA29@ A@5 A""_".""@Zk @GG @EK5@ !k#h ! H1H/O'&JK"\ K'BF?|H ?F.1'Jo'&PJs"G>K 1BZ?"{ "@Zk%4!O' oo'Z "?"{@Zk%!O'o'0Zo"8{?"@Zkf$k gB @gBK+ $KKkC` # @ ! H(.3HO'Q (JfJQF(>`BqHH. F3gJ"RHJo'2FH> sBZ&s"{?" "@Zk%$!O' oo'Z "?"{@Zk%!O'o'0Z o"8{?"@Zk " !9C+#: C@@$KO'$+o' "QB QBZo?"{@Zk%`!$B$BO'o'@ZH{@Zk#.#!G>C%(!yG h ,o!.JD7KG ."!F>BQFo&(s""?"!@Sk%!j K/+#..Z YKU JJvHF`F8Hp@K .Q JF >L.r.T JrJFUB O'o'Z"\/"{K"@ZkO'o'Z"{a/"K"  x  DH`;7TY~Pl!E9iP4ka}).p{oMF2z̻3MoZuՑ1\ GӉlD diINznDYOuñҍ1EhT2)ԅM3)"PY~abS"{"fc%p)0w{@ (?3D.\2b80|qɇ]1:ŨHӜ`o/2eQ.x{9Zī[qaXC,&nhOmx!5ԋE 9 浱J;]PKrMrxڼ  "?Ͳ0-{Տv`G$L\@x0И:K.F*rq j9Ƒ43 ÝrlĈ'۱k, Ӟ9ON|1=-t@͵ !a̒dGƨ8LR.Lܳ3"#ڈ K\axC}{濗;^zPvLm|ksl)LnVYah1fChZ3Ѿ,L%;\]GbUqguYƜHSP^qh ӂ#F (Mhy }fkH%4LF;G]fׄn;l A[K qZ܏SxtQ0U DE8p4l \aa݂TV%s_\HU_o'Y,,0֙p<ˡV;2e֌F]d7_GՌ" )nlCF HK>]`|_ }ХGxΨD(Ȳ񨠯wPo9C1=pZ$rbŊ(1!"Wl%ޔG->&s>7F$0Ӻ$]ei)9/kJ&7Qf@DWG"c z61&zJ;?('wשrF5=0%f:ev't: DM $.+iS>`X3|;_36cvG$Y+fѡ|jv78 tU ?tV9EAdz'=(B]Dius~1(;bPK ;iqVc$uX($A`j<}Nlȑ3(!S1鉦LCԽ'X/2.Sc\[&qB8.A-'K+GTe&6Y{ȝT=wzA鉧K_'+&WGhK)_}A0Y.$_6F*e9=< #6sOM(0fۆEL!k| B-VmS ]]vc>7SD#,,ASŖ.Rzn\?`.}HkhK[ԶyudG!M0xR3¥~$ ڨ/Ml$IDZH/$A>g3 'SumjB803Cç]%d9P,WO3dTrf-NB߳=,Ơa2|]+.99H ْ-O=KI^&HBW:<G=S33*Z)KsHœo_bu/~MqS*>vɿl\$ 4t_A>4}B_ Cg#Ȱ˂,4}* E #=T9& rm*oCU:1qQfʈ|#l`Q%o2 J/+S GgZ,PV1G@QT6I8.0FY s #QbaIw|NX_|A,[5 > "Nq\7II=$3-ͧ.6TMKof·C*'TbjPNQîEߴ2HFuՕAv ?@V#ME/耤 $M,9_ԝ:[ ]$䎌hogVS5|BbMmD>Ld;N!g~z~)+V%ΗMXhow7>1?P>F}QμhpqQ/tN(H2.7E;(MNވ<10&[faU Y|`U͚6,cmj3ehJ*#ɪ xg1+?V,<;K!D s9 Fl%51Sv0|ZZ&MRdO آOUfݨaRgï+"1^ýpحEQ:04JV5J  ؋5vr08UFd(V50;;T8fZ;j^SbKO;ؽ?:I+:[* w'2PRL_LԪW$-#jKq%:7UhP/lEUm (,΋֡['o-)𰢍*O]Ta)V-ڽHzZz_bZt./AZwS/vQ)H`7m`6Ch. H?>WiF-sEL)۠0 /N |!uL-y )^ːHhctڬ ]6/-;Tgo_ş]^۶+=%->P}PUMyٻC6*VOuWP,[`0qU''t7w!:( h2D/|>3TP΃Y:  ;^t>(UjTɖ].$VZ_-ՄS7N%F'Ve'dɍ)8]]L3K0؉zT]R(]&N_ $s\ّY &{ޥƫ'Hb IY֪k]D Nfhj{OaWM3$m}y] ]!B y2@>AoZQt%dv_B:dj6LL=YiO{% s 'v`I۵7Ig!n$NNV-N0)Brab#@EYyqGGꞢ#/i=[ʑ!xK1qQzeMz*qMENTu [P s)Fi[<ʬuGO]=!צ/*uA~T'(#vlrW%xu]{}P }WAW_- plۍ_U$_kՕOcFmh$H RNm9v,O~!NgΔL=?'*g0kT%!됰BV#Kb"wu}H/\k@Kי.޶ ĤS=0 yFpyfK-r!+HIdv$r0U"94S4x~_!h-!PP^e/€%5|ł͐GNh vf[{ٸ-&tdN2$FDzNuFKDZw8e(pP|ivν8ȋ/FsͩhQ/"I%PjóDx~t"FE 4:hMīRj(w`(l|P砽ou ]r8-SCtL$UN[ʼn(;A )q1eF'Ľu'9&a'J+!m3#J.*"=:,!!QgWbQFe(I]iC)c@^/ܴ671j/|E%C Ǖ[I*$\%w:W*QFPkcpNha#??%[Dyْ=4K獣dVfWZga06RBSo𡬆ԕ醗乲T@KZá ۤҼLsu,  %Bs)A Ӵ#=ČE%Bj00O7Oo{)6-GtEMX2\]ǜui*R'丈Rpy}v;1"'lDKD<9\6`q`WEH(Sj;ѓ'Y  >8P bmh1+I\x!FLW(LzKηF|}R~+ Zc=ϯAfbrU K%{n;]S^_9xRE4^#.<$FDt[P2Ý|.{︡U4̙xJ}ÙrX Z5|Й4m{/p!U1n~ݚx}88/RVJ4R~hYS2Oy+#SoWD<1đwD+2f04K5uiCa[w.~uO$"+"9yqbr`BZb]NiW ]h+I=ܜ3GLӂal;l*;8ͣdE"XTrHkis?:*@7p!Ŗq@~_9{"zm1^`@FPK$WtX)hEOK@)1OT\|wu6)>}f8"^A McZ)'V[@o ÆUM"v)vQ}T(9«|Zlg)(-cl?t{Uc\~XƇ4IzMu$V]'!G]zF!x~AW 2~eeD}yfPzSo9r,^d6GPB c~nu 4q!/F&ģQK}8~dj@5Ĭ.*KRɟHdjIyC:q# |1TZx{!(\m0IRpm'fJi6T9:Z~@[uTl"D l)"(_>0r T}gaVVuX_ac(B۾::^Xbn8 vx?" $O$H:O=+.|`7-W |#BdApHUS{ C" '9ix3`\4oʉw9V3`"9&e\y fQ՗HOVSѵ*mDco!l5KnMYBȣv-ڧHK# rݿLϳj q:B74) MMv3Z@`oǕ0~Xu~MĂQQf? 2ʥ]6h2-#G{\I /2-`M5VL^9hXCbmf=XL~:7B:[ |עMSu p.MD'[!gp;3tʲܥ?wmcTODr= |*vZKid 2`OmkrGݧt= }0ERk#4St^MhCztH^ bp{UURv0w u̽PϭlѫI]b0d᫥5Њ<9v: &2zi^Hzڤ"-ao}=N+X,n%e< (vWFƻ^L04p9?ع.:j5NeT|yDTuD q:[̻Zu3zhd;D /vtEăt)ـJ0`|daĻɠi<ؚ'aֺ?:}Fs?7(}qx_j+ht e8}P6 -N整pK|6PXvA\/5mr{bY1,,Z}!eAoԦo^PXD׻߹GnS` |\(ɚ2֑R!ߺfY2juw85 /Ub]OY6Y^y~7)tܢ`~ojא40ìƛ xV*9{f3-O>-;ˢ1Ny3Ee~ұi ~\"WcMk0Hk Xt> Qpt.39=sT#\|z9Tlb/n2\tPWףX=B~^ǐnWd"d>OKM44p5XRx_xbUDR0.~e+-.0tǢizԮDdR`8F}`:B(*XkDKsw$g(@˝-[w0iœ_~ pErAzr ^I6GD䌦t D^;I(MK}Lp&7>buEҩ#{HA_H-gHD!H^](5n8q))r_aƋnX\ey:LtkZ<6?j4xN#X'4DlV)Ƿ8: 5l"{q;dQ![ѯ׆-qx!zȄ92|8HLu6xIxZoEhN21_bgiM|.ws_9Yf2J}X-Z\~=BOL+h7bggPvV&㯀ئ»A>]}"G1F*z]7bM ud[tՌE $Zۇ~nWjdsҫ X}m$88狓Yf*4 +uux$R+qGo]£iZF_t~`R](%U2ksGi K4f'+ _ԭo#Max`%8P#+ʕgpTT?>C6Tv/i?VM'Xwr Ѭc?*!S ![$ cjmg#S/*WkF??;3ƪS ghG0b4:uO^G+|ZV3F@!F3|OKXf9'*]ӭ87DR"_יˑ ~ p&o C>1ͣ:LYSGePë\Q-~ot3@5[;T'K`u>P.d^nX—<C"ΰbQ/8O" \N "0Ō*u,yi͑ gix#ŔfjOSdy[M )cœsŴ}ViR^@|YR38\9ceW)=7R煻_9 cnAA>jrlU|i7q= ;-EҳAMKς/bx("|!d`@ /ȉ]ы*\w}dA5l@aKlW7&%?*EvF41chCf.3)ģNlmŎ=%LdHp=QE!E8`=~S,1q~I}"D;s^ NOurKKI;2+O8~E=R"?%1Fcm:uv-B5v_Cqwk{aMǡ)z񖆾4" FI^ N$0]Wm4Nk@H8 ˊF!5+[4F"%٬ԋ~j],W#pʵ>?Gck'߄CwSj\Uv=BZVfJ͜HPEh ="J;^(O}M2GN^_bp|^^0\|W&{zͬ<"<oK%dGD(cB!U\uGn(j[X[Bq$%mORdZ73v)5QL@BF4a']>w$nKy+I&|8M6Z|u+Lz}~ A%dp&V9O0{V^k]׿<biR#g# zwW[&WBjࣸ}VE=_a`7DĸmRwdco AHn>D ~Rp8tsުTc%lFx)_[Ɖ6}e{}>IysHMjѐ \B}ѡNwӈS*+!c)h #{eX V*zx 1k<cɥ-V6^9;f,ˁT sR=a;(dcvren_;6ܢQ.#h'KTFaJ 60(kS$2녾drnOWWo0ů% ,ʿ7pGuB=K|v^P\i].&@R(@jq@ls?Vq>ܪUa|]` 3XVcc~0NiyzЮ\^zBҝŭ?FEJ-ѲR%@ }ܥ}ApE:fװUZSLiQB*'Dm yrk`G+SF&(0]mZ!< L >xR#F$p`&AY\ Ƴki !BMYF䕱1;N'a]Xc`ms( B Z,5`Jf OF9M?#?ks,hs%gdPt-W{ ëDL#frfb0]if$ _D~NĤ?c lGӇ{Ē' ,ph5r\;Ee 3HWhCio@>B$dA}4B#/'q9beXo\YDAlKOD)>UA\,$9LbW&k)8[4ܢ&؈4eL}85_Zjo"@Im}aZ:]w2e/Ɨ7-ږq[tH1)X aF+i4BΟB3i(z_¯3 SNzDf{>gQ7\ޢA6gnс#@j_֛}72H "P;}RI;Yi _.0 mV$n׽AjucKa1}lLksi{ 0'p_a~qC /M2/Av E/oশd 4)dN9Z@:WV6Q9tFNDʡ+ZrU_8,3DSst>B?N$r3kOLq(X}P49p\eRC@HY'?pZԅ 0 KTRZO4tU[( Dhd|?f^Í8؉3zVLPCshN=-փ~]Z t JuK_-v{07~8gx7nu7E9X[ ޷bT)7Kp<)`f1)$V"*>%7P*$/VAermڏ_ec(sj7 @7D3dbb {O1%B8R_"z:rFm'<`5zGow+܅:F;T/o V;ԍYJCBwe[K(8)>krr{Qojn$iT6YHѾ D8]<(kE讗_t+߆c$ U]4KlkpzG.9,^(o9H} W]'#`hl- \ 1y@FiYn M΁o^1-^\G4-5VVe#R)2*2D6P/QKhsGhqUygcՉ5?o'.xXf>öaw 2^"HPXkP3U*ڻ\T!g1 (N{ RNVYev+m,gˤFG1g/`K`Qr,wf]$Ƒy)CXo-WO͌F%VMgCM_A6%Qi[D&4-s'3j2d)]nD"h!Ճ8芠yc/g!SiRASDhjwj[4gfQCoF9CںA%TXL`4aU(/FXHL;$BU`mi!C0d'E}yTr{[gbQDDJ GX2f1u{8"O3%1~HH(TOVEE Nbqιy@3ZoWFt-I$jp_"81?恁;'*\L&Dji%#CJknI=y{njT)_9n$PfOr=mtD>́v/nkȸX?\g_h _=X  4 Ƴh5Q} SS ~7]ԫHZ+3C;O$: ƨQ Hn Axt, Y+eDF,dq<<0a3&̳?HڿXo)6T9]T><4qoar1{"EDGDVJ^9L*ͺ7Ci+U{ A%0fQ )jIhJJn恃-]uEAIY>'Z,jIae:KAyS2v1C/ĿPn4YLyNF׈\55A0 F F #XS~:`@O4i%.?n;*X%[=_q4z$eՒW[%1'Hhyes7jל:QlQLǪI>&h˜ 3&X5S^%V=IZ! M $R:mnYV:=d!h"6)V ^/= *e8=t ޳Ws3M!otok~E7ǽ{Av7vàOvD7:HG[Q~6Q_qNd^ "2r-j9s0r%Xyu' .qvC^W7G@~&HRf4ӆ3 Rt(HؙA֧XPWDO;IJJ.8nMnuH%b>Q)ùv=PNtiStfXr'遾 rH4*K,g2h%YE~dXwe?kr#"#I wc9^ `PEYwbH! .2 ~qLOi/Hͅ'>',ofܟB^}J3 Rt! w DFMVo܂3jkK76?_OrZG fWn!_^ČV-zvU?=!?an5=?Xp@CliIhE+a%L*koi`QӓlWrR- ZXQfO"}(_->Dy`+8}$5O5X{>QҦZIWШ6A|"78 ay0 .~~kjM/-Fּ m= w:dEas^:$@2F: Q5l- 3ƱN,|N&K)X>mSpKQ^ w u7bOx:F7$^v& DOAH EFBKpsԡ+w]K!d[x=, _A0bew"'/3ICYTX&d<8@a[b">2xzlG]Ɨ 2ũ9iW9.U DQQQLxb{m6K^_A Bt73'mHA8.\ej k6UW?g 7Mո BuOmcE~.,d&M*!uə/HG-aTTt1dbI${=NlE8o tac =!hIi}T~+JYj g TYph{l{`C^vVIY]mx:96|{V) r BDfCs H9sR #n6 p`.|ּ'm-wjˆ{ RnrxNDER {>RÓsfHc?KuAw& \J/Z+xLZ[n^B:'5%Yp ]ț9UaXl;Mwd.ngw@+W0Z4R&]ID#ALgyc`o*GtW5B0e]Jd1X0LEc@l /,P1BuY*,`3A`2,XWK70I,BCL x":qQ>dHdwwLpKxW?F$:.Zn<P!<|0^d pKQ~tGFm3ʹ?jUk^&>QH&)bbFC q@~O|˥i yˢqyMux8.fAЕsjT+df!3lX5UbQ^,>Q)Pf5="(1.s(4؈ y{}= G_ rbt\%"Aijw{cAU{KEW^"p!,EO5IBsj8m?Qb|{8tw4x'ȇ-]m9r(!D&; $uW-y~o|r7!,L3Cse^Y7 xaQP(CQM YN}77;*Jar !Z]"{z6B|E' I$.&Q}"pR*OEJ[<ުJx4hKah_3 bD]'pMCKUgca)kC_w x{0O8VG68*d+EIxViY g]pe q$Sa#tfqXD}hT)_gdv0 E&PU_bv)__46rUz+GO?mcHV+\nAs9HaS0ck>!dD,K;+WNd  (L7-v.Y:{X%6Vy+UsC8q AK殍!úRC V:&}(D-+DXI43A@x;]kbץ5e⿖ɉ[d87umNf|A7$miˈHǍ fnͼUJрD('t uA&Yzz kpA>J%ê ^VX}Wgyz֝y6o1rF~'Z^kmOT+xbS Im_SCz,@{ _~R}+ 4aYxa0V1[m KcAuu$V07CWGfg|}38U-qɫw6BqI**e?6v,yE`F~ߟxr'ԽoqmQW.x &랖׹qe4^C`ʗxDꁲDA8ۈOrЄ닫ry<xpF>ZNˆBuˬM Dέ;^$$8ӹ~_$yJ|+iWK4߈%M+G6n?цzn<1mpnJ0im09ON>v|z#`mN1'YlQ*~ <4.bbe#]>YX.n\i@rcYTڬ,..aJܱ.P$lcK*`8#B+$R$Qv*LiJ^%o&Rvb"9>"NKpH+I%)gnb !OyT8877?VQ2L:jeOymBTr4@YBJ*~,5$)5[OQow/)^('MRqkޘ);Э:JERG+-JC>q1|K5eFG|U#6O2oZC HZetEQYh)uJy_SF/,{BX pz@",w$UFIǮHq(PSSP 6S[M,3zmC=8aJY>QrBY$Pb2(:8b$'rCF4NtkL~K"c+(90鼣|4MFD'2Rzż.[_xZ\K&-HJ.#L$^0M$ݸ }}.Zrԅ H)dOq1< XZi)])423o-#Pc/7HH?tP?w "_`+(icGzn-X/&c[@]o?5<<\n#*@I@ٷ 6~C~(AnĨv}cq}bqWh$hR=r2rﲵ%R1x^V X-zw;zU1r̫:'7TŸ)!ho`(w}=O-4kw쪋S~U Tru_[YVz:?˷Kƶ'?UT"8.s|#A#>O9:AIaw(14אF11]fFdyF(b3&M]vg "U>b]s^d`G!d e@Ѥ'Q\=?"!1v2y0_cF;B&65G5 (? ][#A*#ɎqD FQ>{BX.Q#l9]E*b@taq8hgbY&*oW Xk($m#u ALMZRae-`BׅwZ` ZػR:[\&tLD%C?.5z18ߞ[SS5WFoȓrF9b}p[VJ4 8@b{Sq+ vUAIEcNLFFfB%r(H^Dֹ)l?0Xy;L@&]SUQLVcF]iC4iX/ߟ?1JQE f\3$NcL \|h`4 [U#P"+'{qm2 0>f( Gy^1_3cL@|#,d|Wg!C) BwŞ!O S/b\W*b:9. VGryycu{VУkd)zssLߊu0$_u5-bU(?-@ubL,f ^H %4IzE˒>$Ν]h FQttP6`.H!^i?{f>^6pKF~7{:~>zR! oxG`j(ewh{Ekb8.> 7j. o97Gp wom9 Ze ๟;\%I;CH?&E\}Ct/VLPuB6~>|=gGmFq{kp:[Ghh1mdIs Nyn:= ;o|zUxR"= #f8L0aKA@AyuH@W;xB9:&m*Ԁ:#`+GֵQgn&r(nRjJ¾A5 -N`Gh]LVgx0HX D S\Άvr:[0 oN L EbM  .9UF wog`m*u\6)I$cҫ|fQ vptR9~pKc8LΨToqP+~ Y_\26 X?e5_;46sH\&Mvpֽb"Qn=:2WHYl-73H0slDHn6Zc _S vD3^t;1 bT34 ?ݫxʆz7D;|[Dg_}J)BWD}d)—݊O$,'"ף*'g2gф۪iM37bQ?#خ wIZ E@Y3Ȟ.4%qljBM_OM z@<=dfTUo. ={m'~.Ui;Ib.jU6bʁeU~\J7TaޙUvˉdMfN'9a59bz&L8@(9! ,L}aXo.Uk\*%nX,ΣXaHIѹ>}aw_kD@ؘ|Ksҷs5}*&pP2XBa]B ?(&G2326WZlf+/#o/- "epA~>*XC;VmC% u'_ %*t$:gis_Қ]-@E5&k6߁~FWEix b߈Ekiz7C3D4rBд.SGo|Dov7 a`WiW+trb#rN6.{;}Oe5g;#3)ޯv8p,Sa $٢R(O0vkqeZ~ 2.5_v&X?_X^[w7UR96Hm ;{0OT{9"M(v_k;e 6=Nw cNU`)!8;巁W K' A4P^9N:d{<{ kLEU:[pJk1Xah\qz#5d.Ji4~] Co-+L*OZK'ڍ~0R+V$zH*d$Q|3/ZX_S>6YleH< {:!w8BI@tp ~"w]9dA3j?~YxGk_I]x;~jJtW:}O4U ;I{\}"93eBo.xΫVֹA 14- OG\)y]gj#ifV~{|!!kWe)>/JcKI4C-q̩X45l  ;f5B>5&ep䉅&WLd!2#ˉ6 ,Pj=]5xU bzYI"ϾLX[whݝ.*X4b*Se*` uHv&xAaJwo>r|.şؚ~a+UQb9E_юSr_H 㜜ʙU58tW!ͷ8YT]FOS$ڣۦ_5yKcő0JIYE?8Dxj?F8NqGZ[R[Htd;4#b)/KeGKky"pm5I w!S6PNQ Qd<= h 7K 1D ZgyJ3AGCcpٸM!%PM) "Po3 LDB`{UT^aUQiC녎6|X/i&@> J@hNR4[(Mñ;2@i6e,I&pn \jf~ 9h'+HGA kUM5*v0%%xc o~Iv98,{ Q2uQ3i,{Zg]G6gXG3>T1|$E6Utg[9` Y蛤coߴ f=Kl} `ˑ%VkF5bk1%EA>jaTJ 6PHo, 䛄זͧ5(j >| Am'a1BLСPA VÜ7IX3&@a%7-Ķ68?.*AHꬎu.]lwیo,0Xau=X s!]=sg ~v/d9 ~MCtV6"| 찾?Cɡ KU81 q`Xu3wXv+2J? w &3d.Bb i\%TJ/E_Ų3CFb}6T OWtQv%+?ŘCɐo*}dMYkN\J9;K߾zC< +[/AN'MXsw|x lU4`p. lZu>Q;`uq *xO@ۚzt!ʜ  YZۆ-+TM\ Ŵ(%ۖ0;#Zy^KlޥI]ẍ0EF{& Qśt}9{Ȓ=+ܭB>I_ajb/%im/kL$ =&3Bc?  :?qyꬽ;%{RzŅANL"{żT0Is!b+Q%xQdPMitѡR72|ZsLWb{kfp|+/#V(6$3E[L 6枤pW>yD݆Lӥf%{wyG8wv$8n;\>=eV~}w-z.0_ſ~u`Z\OdIy*$s>Sߣ;2r2&@s%{>쓢/z^m QYM){Tmg[Z-e=WYj /:U|OQ}'_>q ބm<0 RGiᵛMXѽl*ʐOtTC^2h TK:Uq_;܎lB#{ Vqv-j4}Pts.Zw[4m, 5=ubV.=Iؤ\`HaەzX"E=S 1&,Zj鵿IsE?Dlb~Nc׻>wmX+Ucq쯓a}Th.=aVе5" 5^ ҂3$n:J/t酖`X!ߴ y=k>M> ^| ~F,mr6AP{irN;>rÜs]&ʹΏ0jE(L1毈U}xnVM vqB}9e,ʺR'l!1RL^yZ]̋gY8!s0XX@3f0ǑvuȰ+:?AW6N]wSBg7ᗎc"HUéVIQY\_t#zD)Z Yne6,,vwB͋DZCXfGc" %Uİh\Qņ;/mcSe1V^P较}O6UN?RS;p qOT0HvQe^dn9E䕈P4f :zmtBHz?NE \VL9;Hh@$p({hJd}ZOY TȣSY2SIj:ޑ鏄a SF^ V*ek.)mЮ;p =U!OBAwa:bn9ݾH./p)4.5*9|ݐ5( p8aYɻa`S31g`OP%V`: "]\E!ǭK D~ɖzo*30g%gZs"N&dGLjM̌k2[$z2{J]Z{] K6B&8|58*rs˲& JCSQ nd NP$cS5`.kM;4s@[DYs0Z5I ѕ\=1S!m,? ER!Iss3x6*%P)-$ 0_ 9\+oJm{Mԅr"!?r]RҦ,k&)c}=ssqeh7dV(֑@iPH_>zw]<D ݯA:)F(EZ<2>{C/5MW(?8z ^m" 085[_X @]7X(ДsWӹͥb+?hC鍐i ˓ݴ\lW,!YimEu'-TLaTM׵OFُKa}k_u!SȔ.3ti̟PϰUZ%Qi.[1& P`KEZ'5# pHǾ) {}޸Ndu}m]d}B(lOL_ ͼGzA;f폸Uvˍe\!Iz<4hp":s╰UHv}N?a;)TTOpFdJ4du)o4>dp,ІCX 7 wrC!ZרYP03p}"\ʾQK [)z8<U۽Saz?..**ɾαEi@7>gܔS]3nrU?ꮔ15zZ܀b,׳!˛־-@ahe￉v{|KˈhF#dnsճyG'R E3 w2t[ُcYAMX,۞l)/ {UASwl˥yՑ|mW<;p#BΒ=Yx*{<_b`>0ГJG{rai.|ٿ;-fQZ6- sC'nɨJ9xdh 5T%n?˯*0m *E5K, VQUKE/H@5 T& ! f00S7q[ݮp&Z;("[fnQ:MTwAW#pmdh2)qhi5 YI)TQ_%͐TB QO 2@u{WZ+lᢩ"Yf") Lq+ T"v*gL ORUԀ/4X%T088w7 R*xSQQ2htj,҅<j)6!@ڔ;eD)"/I+A+IhgL_`cl_q]S0MI|}-XdR /gXy6.Uewu46XU4(^@~]) y?r)U¿G#E\?1z}߭j 8k] ܗ$]sW?}!iZebE, Nx[D4P< u e4/MG.M7ro#0~j ĭ~1_ 5#1j%=9Ȅ*oLĖnFJs[6m7k" !K2s3KC"8j恻,>Բepqcs)׮ZsΡ/u.t@w#;PI{? T#8 o+XBCka6i핅"Dv'7{k r/H9Xl?bJY#^k>p8E=h~ rrv14;L0LlʩMv#M"ѽD9 `EV&H:PJgQ6YzOA7*b*A<\z$JwM1D7os > 1ߺʙn&!{L/ԏ8,4~rW_tSKc6{3Zq1"pG[rJub+%2fŚQ8:Ϙh~*U`O 1>Vc֝/6_tuhO\NX7vGǬ6y)FPtss! C*,hgnéȥ, EާcvO)N3Ty05B8Ut!Ka33YѼ"D= $IEv@cɗU}(8}@yP~SyRym =eD= oL/&t\Ez|.X /ʼnrqQ4{NRu\"&vS%t;'uJ[2;F^Fd+a l-\~NFdpC-}=2&1CGi6v@_iun# JuUIWoFe G|*Y:Ka9ܝ9My ׷)x:v4}n]mWeA\4k5Oб;?57QWe m 32SPC.Q ,fsm @{Q5s'>)gcBmh ڜj Ȑɠeі066$ g8p1+"#Zrm \@kޣ%ssq WHnco͎սLROX+e#$Xs,` LqR/o@.^OuA Jce1+5;rNڈ@-'fg]vLub2"zm\ZգJ,@pՎwL@>`.9B%TeH#0ܴL!U7|AObBk4}0#k/h ېRqW- l4r}D)%?{vx[{Dlk<yU!]\-m93_ߤ -fˀ)F9p(½|ÒEAQT[[;A s?5#}$G޻'fթ;>"]x@xQ#NL=7 ]ѷg,<="jFd}7o_#ҶO>ffK^t? b(KT9)e&8|7y``D~FAV020.Ah>[VLT00A.GCE]ZMENU.EXE_A2;2Rd|p@Zk/O'o'9&K?"&K+Z "o{@Zk%!O'8 oo'Z4 "?"{@Zk%!O'o'0Zo"8{?"@Zkď/o#K`O."/.O'o'R PJ0JQF0J?"J@ Z< "o{@Zk%$!O'o'0Zo"8{?"@Zko&s"D "?"@Sk%! n"aF~BFo&s""?"!@Sk%!+/ /"Y 5KK8G@[_##GC%!\F l|o!3uH+TJ+F Y K8TJ zH +YG+O'l /. vHKP JDF"FHo'FH "#1@@ @uHC F3 CBZo19@@?"{@Zk%!7H +BDY@<1@@YC09@@ _#N"AF^B%l!FW #GC8Go!o& s" E<;ACqHPJ+.A0F 4 "?"@Sk%! .O"o."T JrJF@BKo&ts"< "?"@Sk%!D#GC8Go&ts"0AN!8AT˱L "?"@Sk%\!E DAC ]. 1 A+D @\" HU JO'G]>uH(C\ /3 HBo'19 AXK?"F\ ?`+d "Zo{@Zk%!)E k (AKD0@4`B0@Ck8@C+/K/ #5 `B8KZ XK8 BYG 0 (AEm iC*vH< iC1A!FO'1F+o'Z2 BN"{)B"@Zk kE5AFO'o'ZF{8 BN"+" "@Zk JE E'CO'<9`CZo'(1A Bȃ{1 B."B"_"" GA@Zk @AFk/+#K/ @RF[ yKYKBzG @B =O.:":/.R PJ0JQFB k)E 3A0 A B8 ATo&s"t "?"@Sk% !Kl[o&s"| "?"@Sk% ! M8!m4m_F0MCJ,-FM6@J$( Fp F.Bm `.7J@A?FN.BSkO'o'Z{@Zk#N"AF^B%( !Fj #GC8GL0o! "?"Z;C< CnO'!˱o'Zo{@Zk% !o&s"EBA "?"@Sk% ! LRk0`B8`BK O'8Ko'4 Z( "o?"{@Zk%8 !O'@ o'Z< "o?"{@Zk% !O'o'0Zo"?"8{@ZkBD_#n#aG~C% !GQ  @o!+0rHQ J+QF+.J; /o&s"4 "X K ?O?"@Sk%d !O'Oo'Z "o?"{@Zk%8 !O' o'Z "o?"{@Zk% !O'o'0Z-o"?"8{@Zko& s" "?"@Sk% !<HlO{HKZ@KCzGlO G1"8K"@Zk5O'o'`Z?"h{"1F@Zk@GG`朆4H5$HHJG4CBGGJ C$KúB@GGGGG9J C$K/KFC8`G;gK {CDGGD$1@19BD_G_##GC% !8GMz/zKMm!_FCJ F6@JFpGC`7J@AGNCSkO'o'Z{@Zk#N"AF^B%x!F 8/8K mD/K[C-Q@1  _G_##GC%!8GLz/zK  D0.0JC@mS@_G_##GC%!8GL#!zC < 0.0JmD.JSB X@Y @_,A;@#v@HC@-_DQ.QJB2`_#TT@4!//"Y 5KK8GB&` @#@#v@HC@-_DQ.QJB`_#TT@ //"Y 5KK8GB`O'oo' Z?"({@Zk%X!O'o'@ZH{@ZkO'o'@ZGH{@Zk-.a.JaJ1H2GJ 2B U@O'o'@ZH{@ZkO' o'@ZH{@Zk, O'o'9 @ZH{@Zk#n#aG~C%!Go! ?  0B @8B@D+GFl "k?"usBTBBADTDG@Do&GT G\K@GPF:GK|s" ZC@Sk%! ? @DQK@RK@SK@1rs=`BUK@?#u# #C@DK@ o&s" "?"@Sk%!k 0`Ck cC8`CO'QK@1"(+o'Z&s"{?"$ "@Zk%,! K@kO'o', "0k?"Zo{@Zk%!O'o'0Zo"?"8{@Zk_#"FB%!GLo! K1@$ %$C$@O'e#8kZo'&s"4 "{?"@Zk%X!  O'o'@ < "Z?"o{@Zk%!O'o'0Z]o"8{?"@ZkcD0`@D b@@&B8`BG @$ DD0@D @@&C8`Ck\_O'oo'Z(o!{ "?"@Zk%l!O' oo'Z "?"{@Zk%<!O'o'0Zo"8{?"@ZkO'o'@ZH{@Zk#N"AF^B%!F@o!P!L/LK) /,? l/\ KlKG HH@<? @ ,? @@.O'.o'?"JU J "F3fJfJkZo{@Zk%P!O'o'0Zo"?"8{@Zk#GC8G/l/L#n.N"\ KzKSrJG&H( H"A # .;gK# J1CtJ'JFn>'/sJ4 C/Y'KKzJ"YG'?K#G.R\JrFG>,/ /k//Y 5KKzK\ K8GGBl.L.," /.S qJQJX KJrFG4B /L#l/ "+.K.zK\ KR PJ0JGQFPCR`/.""yJXK~#8G?g/gK\CEg.~?"G"At2JSrJ"Fg>/KD @:&C$=@"`A#"Q@1BD5/B'.GDFA8KVFDD'HVFT`FD@VFD @PFQ'JrH4ׇJQF'>AC0C BA"/0".3gJDJ\K4J8BK; B?GFGpHF?-l.,"L.S qJQJrF1&J&J$B,/" /Y 5KK8G5JJB@ .l#/P JKF;fKfKtC .*_"g"uSJTJF>G/ #'#{KZYKzGG?x "FB0Fo&d s""?"!@Sk%!M !m_F͠CJmF6@J FpFB`7J@AFNBSkO'o'Z{@Zk#"FB%8!G,/, ,K 1@ Q@a! `/c/A! \ KcKv`HGCGD@B.""."R PJ0JQFBP5fH$/# KY $Kd#YG$?yK {HD/ZDK:GD?/\ KF?|{H.PJG>D V 1@s$.#Q $J$>D.RDJD>..$/U JJY 8KF xJYG$?yxJD/ZXK:GD?a! {d 7/$" qH\ K?.PJ>D.R QJrFD>rqHd.SqJSFd> " 1@?./d#$/ {HJX KY $KG JYG$?yJD/ZDK:GD?/\ KF?|{H.PJG>"$A! D uHM !m_FMCJFm6@J FpFB`7J@AFNBSkO'o'Z{@Zk"FBG?#.;$KGaGFVG`G#VGO'o'pZ o"x{"_"!?"@Zk%!PF,., H,J5#N"AF^B%!FҀPo!8KO'o'Z&Ps"{ "?"@Zk%!O' oo'Z "?"{@Zk%T!O'o'0ZHo"8{?"@Zk/hO#@KO'o'9&K?"&K,+$ "Z\o{@Zk%!O'\ o'ZX "o?"{@Zk%!O'o'0Zoo"?"8{@Zk.ď#Jo.O./"O'S qJQJo'rF1&J` "&Jd+?"Zo{@Zk%P!O'o'0Zo"?"8{@ZkO'o'Z"{h/"tO"@Zk_#"FB%!Gro&s"o!h "?"@Sk%!%&  .`/!.@/JQ !J@K[ `Kv HvHzG0F GG2vH3v HSB o&s"& + "?"@Sk%T!O'o'Z"{ &"F"@Zk&//O'0˰o'Y &KK&8G5Js"JZ "{?"@Zk%!O'L oo'ZH "?"{@Zk%!O'o'0Zo"8{?"@Zk/f#K`F."&.O'o'R PJ0JQF0J?"JT ZP "o{@Zk%C%!yG#<Ko."2CGJSpJt0JHo!Fo>o&hs"5 C "?"@Sk%!_#.#!G>C%!yGP#GCFO'Z#`!?" ". GB@Zkm.P?"M"t2JSrJM#Fm>쯢-##"_ |?" NO'.lno'xoZ!{@Zk%!"FB0FO'α"N"Nm"nZo'&s""{?"!@Zk%\!Mm$!_FCJMF 6@JmFpF B`7J@AFNBSkO'o'Z{@Zk##GC%!8G0HN#AG^CzGO'xϠZ# "X!?"GB. @Zk-.Q# "rKQ0J #QF->o"O'#mf"|쏢"_ ?"  ,no'.Z!{@Zk%!#GCFO'α .".M"N"Too'Z"!{?"@Zk%!"FBG-#.L#"DNO'to?"no'Z!{@Zk%X! .?" JCA@ l?`"FBF#.#.#Lf"no'"NO'{!Z?"@Zk%!..#.MQ qKP.RPJ2FP>BDMm(!$͠_FCJF6@Jm FpFMB `7J@AFNBSkO'o'Z{@Zk#"FB%!GgD.#!G>CYGO'Z#xϠ "D!?"GB. @Zk/S#pmK\K_ F?/ -|OM.J3gJ`#GC8GM#m#NnO'_"No'f"Z"?"{!@Zk%!m"m?# / KB@ l` .?" JC@l`O'Z#?" ". GB@Zk"" _ ,/_#,KC`  L."LJ3B L/#LK;C ."!F>BQFm""nO'#o'f"Z"?"{!@Zk%x!.#!G>CYGO'α_"Nn#n#Zo'&s""{?"!@Zk%!7_`"FBGO'Z#`!?" ". GB@Zkm/M#T?#|:K[zK_ Gm?  |/-l.lJ2GJ@#GC8GN#NO'αm#n#Zo'&s""{?"!@Zk%,!O'o'@ZH{@ZkP"FB0FO'Z#`!?" ". GB@Zk.U_"m"uSJTJm#F>M#_""_ ?"|/ -nNO'o'xoN!Z{@Zk%\!n"aF~BFO'?#α". #o'Z&s"{"?"!@Zk%!O'o'@ZH{@ZkpE;7`KqE!;F;cK "N4Gn F EkpE27@JqE2F2CJ!R& " E FN4GNnNkpE87KqE8F8K!<' E F4G"n NNkpE;7`KqE;F!;cK "|{'N4GN Fn E $ΰnkpE27@JqE2F!2CJ "R&n4GN FN EkpE87KqE8F!8K "' EN F4GNnkpE;7`KqE;F;cK! {' " E FN4GnnnNkpE27@JqE2F!2CJ R& "N E FN4GnkpE87KqE8F!8K "<'N4GN Fn E $nkpE;7`KqE;F!;cK E|{' FN4G "(nnN$ΰ nkpE27@JqE2F2CJ!R& " E Fΰ4GNnNkpE87KqE8F!8K'  EN F4G ",nN($ΰ nkpE;7`KqE;F!;cK {'N "4Gΰ F E $nnkpE27@JqE2F!2CJ R& N EN F4G ",0nn($ΰ NkpE87KqE8F!8K " '4G F ENNn $ΰ(,0.4nkpE;7`KqE;F!;cK "{'n4G F ENNn $(,.0N4nkpE27@JqE2F!2CJ FR& E4G "N8n4N0.,($ΰNNnk3AJ> 1!BrF3BJ /FrF3DJ;BrFG`QK`[K2F;F0>k0.\KS[JGQ;J?3F0>krFF3DJ`qCp/[pKrFSPJ1$B{Fp?#F  F `P>B;bC`P>BG`P>B p/RQJ[qKrGp?kP>1$BP>P> P>B? 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p 0$$FV1.1May 18 1993 12:51:35ZMENU01-%iCGOCGO@@ACGOCGO@@A[H[2K@jqFF")Fj,Fj4F?F@FHFLFTF\F dF&kFZlFZsFzFFFF FFRFfFFFFFFFF:FNFFFFFGGG GGG GF$GJ*G^.Gf3Gr6GvEGHGLGOGXG:^GNgGvlGoG~GG G&G.G2GFGJGvGzGGGZGGGFGNGRHHH HHHHH H&H )H .H 1H 9H. HH QH YH: hH lH {H ~H H H H H2 H6 H: H> HZ H^ Hb Hv H H H H H H HV H^ Hz H I I. I. 1I :I OIVVIZIaIeImI>vI}IIIIIVIrIII&J*J*NJWJvJ~JJJJJ>J^JJJJJJJJBJjJK1Kf=KAKGKNKWK>eKjlKrsKzzKKKKKKKKKKKzKKKKLILLLULXL_LhLkLrL{L~LLL*L.L^LzL~LLLLLLLLbL~LM$M+MB 4M^ 7Mb @M~ HM JM `M eM mM!vM.!yM6!MJ!MR!Mf!Mn!Mv!M!M!M!M!M."M>"Mv"M"M"M#M"#NN#N#(N#-N#5N$QN$TN$sN$N>%Nz%N%N%N&N&N'N'N'N'O'O'O'$O"((O:(,O>(4Ob(9Oz(@T>>GTV>TTn>XTv>\Tz>`Tz>hT>nT>T?T?T @T@T@T@T@T@T@T@T@T@TAUJAULA UnA UA(UA0UA8UA@UBHU"BOUVBPUVBWUB`UBiUBqUBxUCUBCU^CUbCU~CUCUDUNDUDUDUDUEUEVE*VF0VF6VFcVGlVGrVGVHVHVHVIVIVI WJWJWJWK(WK1W&K4W*KIWNKaWKlWKtWKW4LWVLWfLWLWLWLW"MW&MWnMWzMWMWNW"NXjN XvNXNXN(XN1X&O8X.OAXJOJXrOMXvOPXzO^XO`X,PbXNPXPXPXPXZQXbQXjQXRX"R(YS*Y2S=YVS@YZSNYrSRYzSXYSZYShYSpYSsYSYTY>TYBTYTYTYTY*UY.UYjUYnUYUZUZU"ZVV*ZrV-ZvVCZVLZV]Z^WaZbWjZjWZWZWZWZXZ:XZfXZrXZXZXZYZYZ"Y [nY[Y)[Y;[Y=[YC[YR[Zd[Zf[&Zp[\]?\]A\&]L\2]Q\:]V\B]X\F]l\^]p\b]|\r]\v]\]\]\:^\j^\^]^]^]^]^1]*_4]._B]v_`]_j]_]_]_] `]`]`]`]`]2a]6a]~a!^a$^a0^Bb3^FbD^bG^bH^bZ^b^^bh^cl^&c^~c^c^c^c^c^c^d^&d^d^d _f._Nfp_Fgt_Jgy_Rg_g_g_"h_&h_>h_Rh_Zh_jh_nh_h_h `2i,`fi/`jiF`iM`iX`iZ`im`jt`Nj`j`Zk`k`k`l`>l`Bl`l`l`m`m`"maVmatm amHafnNarnWan`anbanaoaFoaboajoanoaoaoaoa:pa>paFp8bqHbqXbq`brcbrgb"rob>rrbBrwbNrbrbrbRsbzsb~sbsbsbsbsbtb$tbFtbzt ctctct-cu6c:u=cfuPcubcuqcv{cNvcvcvcvcvcvcwcwcwcwcwcwcwcwcxc"xc:xcJxcPxcrxcxcxcxcxcxcxdxdxdx#d.y,d:y4dFy:d^yGdyMdyNdySdy`dzfdzjd*zqdFzdhzdzdzdzd{d"{d&{dF{db{dj{d{d{e{ e{e6|e8|eZ|/ej|8er|=e~|Je|Pe|]e }_e}fe.}oe:}te>}xeF}{eJ}ej}er}e}e}e}e}e~e2~eZ~ef~er~e~fff"'fR6f;fPfYff\fjbfjfrfxf|ff&fZfȂfffff:f^fff΃fփfJfff&f*f g g g("gJ1gZ9ggBgggֈg&g*grg hhh. h"hʊ8h=hIh.PhJXh`h‹jhʋhhhNhdhhhhhh&hrhthiRii iBIiXiZhimiƐriΐ~i*iRiiʑiDifiiiJiRiniviijғj jjj j j%j.*j66jEjHjmjrrjzwjjޕjjj  @0FF!@=:p` G`  0? @@VP  8( $@ 8] R@ 60@$  !  P@p`,;h00P  @ ̐`A f" ` ,@0 8 ((d H0$T0@{ $H0R0@) A2{W 0 H@$ @@&x0ms av8| X  1 H@20a L & „ H@20a X` `p(H@($ !CW Q1Sp٣ T` 0P( 0@:68 qp,``P{@8@<= 3,``Ap`@L(G` $ U((P"D ` &C`KD C `D<20 pfHp@`.<@dae  ;&H+ L'< 0< H` @X;( lp y `̐ / @+p *` **T</^+ Py PUTT| ~FAV020.Ah>[VLT00A.GCE]ZMENU.EXE_A2;2c Hl0Ll0PlTlXl \l`ldlphltlPxl|lplll`lllllll0 lpl l ll 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p          0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV*[VLT00A.GCE]ZMENU_SCROLL.EXE;4+,i. / 4 ->0123 KPWO 56x?72:e89GHJ>0DX0205(E)ij ZMENU_SCROLL01 E)i05-05   # $  ?B!d FORRTL_001! LIBRTL_001[2J Currently on item !UL of !UL [m [24;1H[7m Type H for help. [m[;1H[;1H[K[K[24;1H[K[46C[7m[m[;1H[7m[1;24r[1;1H[1;23rM[1;23r[23;1HDWIDESYMBOLSP1.MENUITEM[?25l)[18H[J[18;24r[24H[K-------------------------------- [7m H E L P [m ---------------------------------E Use CONTROL-W to refresh the screen. Use the up- and down-arrow keys to moveE to the desired selection. Use the prev- and next-screen keys to move faster.E When the desired selection is highlighted, press RETURN or ENTER or SELECT or E DO. If you want to quit without making a selection, press E or Q.EE[5;7m Type a blank to return to the menu. [mNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than one selectable itemCHOICE_LINE!ULCHOICE[24;1H[?25h TT TT SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:SYS$OUTPUT[?3h[?3l (h$@Xhg" |H ,Mggggg88g@ g4 D gq   ` \    h   \ ` X L o` QPp Q R FG 2 %ZMENU-F-    x  g$ G, H P d t  0h  # xx  t  0h   h   X x | X SYS$OUTPUT: t||4xt h 'h  #h  0h h!h (0`  $CMKRNLCMEXECSYSNAMGRPNAMALLSPODETACHDIAGNOLOG_IOGROUP ACNT PRMCEBPRMMBXPSWAPMALTPRISETPRVTMPMBXWORLD MOUNT OPER EXQUOTNETMBXVOLPROPHY_IOBUGCHKPRMGBLSYSGBLPFNMAPSHMEM SYSPRVBYPASSSYSLCKDhTh \hph(8h,lhh0P4V^7Ѽ0V8^(8Ón ^( nA AV^$(V^0HX[мRHI[RtRBP@QPQďPQ@= R<,PPPHLP`d%HP[PP P @2,޼@$P P\X 2d` 2p޼˄hPPˠ˜2˨ˤ޼Pˬ ˴PR˼ ~PRRROT[}PQP}PQP k<PP PQPQ ,  $PQPQVzVR{RRRRWW RRX< RXRPQ Pa K( f2f0P PLH  2TP "p8+T|PT  ӇPyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTkݏlPެQNT1}HH[kIH<[}PQPk0123KPWO)5 6 37eKe89GHJ.hE)i0!OZMENU_SCROLL_TV01V1.1$ $ $ $ $x$< $J!6d FORRTL_TV_0016 LIBRTL_TV_0016 TIE$SHARE_001[2J Currently on item !UL of !UL [m [24;1H[7m Type H for help. [m[;1H[;1H[K[K[24;1H[K[46C[7m[m[;1H[7m[1;24r[1;1H[1;23rM[1;23r[23;1HDWIDESYMBOLSP1.MENUITEM[?25l)[18H[J[18;24r[24H[K-------------------------------- [7m H E L P [m ---------------------------------E Use CONTROL-W to refresh the screen. Use the up- and down-arrow keys to moveE to the desired selection. Use the prev- and next-screen keys to move faster.E When the desired selection is highlighted, press RETURN or ENTER or SELECT or E DO. If you want to quit without making a selection, press E or Q.EE[5;7m Type a blank to return to the menu. [mNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than one selectable itemCHOICE_LINE!ULCHOICE[24;1H[?25h TT TT SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:SYS$OUTPUT[?3h[?3l (h$@Xhg" |H ,Mggggg88g@ g4 D gq   ` \    h   \ ` X L o` QPp Q R FG 2 %ZMENU-F-    x  g$ G, H P d t  0h  # xx  t  0h   h   X x | X SYS$OUTPUT: t||4xt h 'h  #h  0h h!h (0`  $CMKRNLCMEXECSYSNAMGRPNAMALLSPODETACHDIAGNOLOG_IOGROUP ACNT PRMCEBPRMMBXPSWAPMALTPRISETPRVTMPMBXWORLD MOUNT OPER EXQUOTNETMBXVOLPROPHY_IOBUGCHKPRMGBLSYSGBLPFNMAPSHMEM SYSPRVBYPASSSYSLCKDhTh \hph(8h,lhh0P4 [VLT00A.GCE]ZMENU_SCROLL.EXE_A;2(;i|~FAV020.Aj> [VLT00A.GCE]ZMENU_SCROLL.EXE_A;2(|V~FAV020.Aj> [VLT00A.GCE]ZMENU_SCROLL.EXE_A;2(|''O[^,: < YZUJWЇPXŏZQP^(PAn^SV ^( ݗn VVDVX^HL2 X^VYZ3VЦ pt`P\^(n$^($n^(n:x:\^|ˀ \^ ː ԫЦ P@æ PPի ˠ SY^(;nŏ P«^(@nЫXX\ ^( n \\ˬ\Y^˰˴D Y^Y IЦ *i1ji  ~1i i i P"i/Ѧ Ц P@\| XX1P P1i?Ѧ 1VPЦ \Ѧ {LrXæ QQ{\ P\q1! :iEiQ iHi? Pj1iAѦ 1צ iB1Ѧ 1֦ Ц P@c իDXŏ P«^(@$nЫ\^(.n\\\X^X^æ PPXPXkX1Ѧ 1Ѧ1Ѧ|צPPZZQIZZZ^(nŏPЦQA#QQ^(Q@{n^SWW\^(ﻔn\\\Z^Z^vѦoѦe֦֦ԭ^(qnŏPЦWGWW^(W@nWZZ\^(Tn\\ \^$(c^XkЦ 19iM)iQ P1Iﰚ[AP 4 (m+P`PˏPQ\Q\\\ÏPl" 8P@ PP\`Vpftˀ Wˬ~~߫ի ggP@g1f!˸f˼fj\)ëPЫQ,n PAf kf!1vgf*ݷ׷Pg@ηXP,X PfXŏgX,f HdPPЫPgXPHgg1 g q PPggPPeN^4Hș[(8HX L B P|Hԙ[Ѽ1V<^(V^7Ѽ0V8^(8Ón ^( nA AV^$(V^0HX[мRHI[RtRBP@QPQďPQ@= R<,PPPHLP`d%HP[PP P @2,޼@$P P\X 2d` 2p޼˄hPPˠ˜2˨ˤ޼Pˬ ˴PR˼ ~PRRROT[}PQP}PQP k<PP PQPQ ,  $PQPQVzVR{RRRRWW RRX< RXRPQ Pa K( f2f0P PLH  2TP "p8+T|PT  ӇPyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTkݏlPެQNT1}HH[kIH<[}PQPkqK{#P.'#RPJ2FP>./&.1"/U JJQ..Kq. FX/QJ8/P JS qJZ XK8KFrF`C B YG qC  A @AeGOA XJA5KGB!DF6G D5D6GT@G0A6GPF;gKEG {C FO'o'Z1 C{AF41"N""@Zk41A&n@2 n@EFO'o'ZF{59aBN"T/""@ZkEk/D0@DK# H[ zKo&GEk?{Hs"D/EBA\KL "|GD?H˱?"8C@Sk%h}!AEaF&"HBU/JE5/ 0@A IAX UK5KZ UKG0C KY5KFU?pKsFF5?8C8@B$51C F/ &/ #&Z XK8KPs"YGp ȧoO'` "?"tko'Z{@Zk%|!#GCFO'o'ZE{.qA2y B]/" G"N"@ZkO'o'ZE{.A4dB"+"N"@ZkO'o'ZE.qA{N"`/""8yB@ZkyK/:?# +KZ KKo&zGyK?z+Ks"xk/EXC "[kK?"[Gxk?|˱ PA@Sk%{!AEAFRF,Bo&s" "?"@Sk%t{! &/ " /f# &"Y 5KK"8G@Z@ZK./ f. F.P JK&/S qJQJFrF ;B0@ KY 5K4 ;BYG&?yK8@F/ZUK:GF?o&s" "?"@Sk%z!a1qA GE!FO'o'Z1F{2yBN"s/""@Zk . . f"G U JJFF`BYsB8 K2ACDDVGDEVGT`GAFVGPF<ׇK CO'o'Z3 0B{ARF41"N" "@Zk 8QAEG pAxAO'o'ZG{9YBN"v/""@Zk .E PA# IP J)E0F >LBo&pI+.s" ,AXACQ "˱?"@Sk%Dy!AEFFB.#!G>CYGo&ضs"/%"()!?"!@Sk%x!n#aG~CGo&s""?"!@Sk%x! F. " &.f". #R PJ0JT JQF J*_#F>tJ.UJF>)/8KC` .?" JC@2. "JuBo&̣s"?" "@Sk%x!O'o'0Zo&8{s"?"@ZkI/)#~#YK;C)._")JB`o&̣s"?" "@Sk%w!O'o'0Zo&8{s"?"@Zk.#JB o&̣s"?" "@Sk%\w!O'o'0Zo&8{s"?"@Zki/#iK\C."!F>BQFo&s""?"!@Sk%v!31@`B 3aJ3W`JAs&DsAs&Ds"k@ /?# KB0@. / f#P JKF`C5`Ce?. F" f.T JrJF@L@̧! F/ # &/Z XK8K!YG(CA; C&. " HQ 0JDQF&>qH 1@ F.49`BRPJ2F F> /?# KB<@. f# /ȧ/P JKF`CqC@.F/ &/ #. f" .Z XK8KȧoU JȧJYGC F C AHAȧ! F. &. "h!R PJ0JQF!pB"@4 pB&/ # IY 8KEYG&?yI 0A F/ A8`CZXK:G F?I.)" "QJ3BIO'&Z|uo' "?"{@Zk%t!)/E_#)KC` .Q?" JC@o&̣s"?" "@Sk%\t!O'o'0Zo&8{s"?"@Zk.H"JuBI/?#IK;C"FB0Fo&s""?"!@Sk%s!21@@B `2AJ2W@JAR&XRAR&XR"k,.A#JB / f/ F#\ KzKG@C5@C. f. &"R JqJT JUF81@B KSqJ4GyK>:9@B3Gq>!/B"KpC . F" f.ȧT JrJF@BUB|/ f/ &#Z KyK\ KPG0@C 9J[yK\Fr9J?8@C[Fy?/ . "f/F#X KJ[ zKG@Y@o&ȧ9s" " :K?"Gf?{:K/\K|G?@Sk%8r! R f. &" F.GFkS qJQJ0ArF BU1B4JGBDDGDEGT GFGPF:GK ZCO'1 CZo'AF{41"N" "@Zk3AEaFO'o'ZsF4@B{N"M/""@ZkK/E ЀA+# IZ YKo&zGK?zIs"Ek/C A "[yK?"[Gk?˱ؠB@Sk%p!AEAFRF(BF/&# / "f/ .X K[ yKJYKGzG 4CD< 4C(C0 C?"+`.F"f. " / &/rJT JY 5KKF8G@BB UB@./f#P JKF`CaC .f.F"T JrJF@B5@Bf/#F/f"Y xKXK[ xKO'o'ZRF3 B{"/"N"@Zk/".&"F.GX Kf.JQJGBZB9@KS qJ CDFvGDrF @DvGTGT/@vG4PF0J8A BEGO'o'ZAG{9 BN"41""@Zk'n@0A: n@ @@EFO'o'ZF1C{N"/""@Zk.E A IT JABF>o&tI.s"JE CUJ "F>˱?" LA@Sk%m!AEaG{GJCF."&.R PJ0JQFBB`/."/X KJGBB@&..f##\ ;JJQ ;JG0C {JPJF;>t{J8CF>F/4Af/EFXKY xK[ xKuIo&  /s"( "?"X KF  ?-,CM,C$˱@Sk%\k!EA!F1FB"`BFB B B:GXG8GuB.f#/ &" F.P JKR QJF qKrF F>rqK f.SqJSF f>w.M#JB o&̣s"?" "@Sk%j!O'o'0Zo&s"8{?"@Zki/Q#iK\C."!F>BQFo&s""?"!@Sk%0j!31@`B 3aJ3W`JAs&sAs&~FAV020.Aj> [VLT00A.GCE]ZMENU_SCROLL.EXE_A;2(2s"k|A#"FB%i!Go&ts"Xo! "?"@Sk%i!O'o'0Zo&s"8{?"@Zko&ls"?" "@Sk%|i!O'o'0Zo&8{s"?"@Zk.#!G>CYGo&s""?"!@Sk%(i!o&s"( "?"@Sk% i!$ #GF GD!D!DG DGE,1AGEF6FE F6FX@F39B6F B6F!"FBF#9@G!GFVG GDVGDGX`G%o&!VG@ls","VG< @?"!@Sk%h!o&(s"8 "?"@Sk%g!o&0s"@ "?"@Sk%g!o&(s"P "?"@Sk%g!o&s" D` "?"@Sk%g!K.+. "qk.O'R PJ0JS kJQF J&Fqk>s J p.o' "?"TJtFp>t˰ZHu{@Zk%(g!o&s" "?"@Sk%g!#GC8GO'DZ#N&O'ڂo#n#_"XtNo'Z"!{?"@Zk%f!"FBG'O'+#.#L|no'Z"!{?"@Zk%Pf!"FB0F&O'K"N"Puo'Z"!{?"@Zk%f!#GC8Go'O'T{o'"Z?"!{@Zk%e!0B'8BS@/"GUKFJ"9B5BaG5BVGڔ`G G=BVG3B4 GVG+. .#K.Q rK?"k.SkJSFk>o&˰0s"@Sk%d!-O'o'+"Z_"8 Bȃ{ B.""@"@Zko&s" "?"@Sk%d!+F#G+F/"[KgK9dC5dCAF5dC6Fє@FF=dC6F3dC4F6FHgO'0`B&/8`Bz/&KzKCȧo'0Bȧ/8Bg_"&"ȧ"T@ȧt"+"ȃ{:9 CO' 1 CZ89B(1B@Zk gGFO'P{C<JZo'CEEȃ{6FE@6FT@Fd"6FPF3gJ_" sBo&s"&" "@Zk @ XA'_#GF :C:CF:CGܔF"`G :CG:C4`GG' o&ls"?" "@Sk%b!O'o'0Zo&Qs"8{?"@ZkȧO@o&ls"?" "@Sk%Tb!O'o'0Zo&8{bs"?"@Zko&s"..U JJF@ @ O'Z# Hz//&1"[ zKGz?{H/\K|G?Q.̧R QJ JrFQ>rJ "q.SqJSFq>o&s"?"@Sk%a!O'o'@ZH{@Zk#"FB%ha!Go&s"`o! "?"@Sk%0a!o&s" "?"@Sk%a!o&s"( "?"@Sk%`!o&s"8 "?"@Sk%`!o&s"H "?"@Sk%`!o&s"X "?"@Sk%`!.#!G>CYGo&ضs""?"!@Sk%p`!n#aG~CGo&s""?"!@Sk%<`!&)" _"0.0JB& #(.JB? Mm!_FCJmF 6@JFp`GnC`7Jn@AGNnCSkO'o'Z{@Zk##GC%_!\Fl̊o!s5`B;"FBGE:'CO'o'Z.AG{"̄/"N"@ZkO'EZ<9aCo'.1AN"{+""@Zk+.E" JQ +JO'QF+>q J&K.DhBo'RKJ@2FK>˱?"Z "u{@Zk%^!AE!G9GC}l{U`C;"FB0FO'o'ZE{.1A39FBG"/"N"@ZkO'o'ZE{.1AN"+""59B@Zk+/:# KO&Y +KDYG+?y KXgCK/o'P@?"ZKK ":GK?O'˱rZ{@Zk%]!AEFFfB> uC: N#AG^CzGO'o'ZE.A{0CG"9/"N"@ZkO'o'ZE.1A{29!BN"+""@Zk!.A" kJT JO'F!>tkJo' .D0@?"UJ( "F >$˱8CZ{o'{@Zk%\!AEFFCO'O&Zo'\r0 "?"{@Zk%\\!O'o'0Zo&8{s"?"@Zk#"FB%4\!G,o!Y o&Ps"o!Gt "?"@Sk%[!@ZO@ȧ[@; G .Q@ +H0 JU JDG >BGD /FVFDDVFT`FX Ku+HO'o'AVFF ?49# +PFZ{o'4ׇJ{ "?" B@Zk%([!O'<Ko'Z&{Ps", "?"@Zk%Z!I/O'O&/"\ K Ho'FI?| HH .P JGH >P "L+?"Zr{@Zk%Z!o&s"d "?"@Sk%|Z!n"aF~BF&O'\uo'Z"?"{!@Zk%8Z!O'o'0Zo&7s"8{?"@Zk##GC%Z!8GO'o!0Z:FK @O'o'Z&{Ps" "?"@Zk%Y!O'o' Z "{o'?"{@Zk%Y!O'o'0Zo&8{`s"?"@Zk'O'0蜣o'&<Ks"K, ?"@ $ "Z{@Zk%Y!O'\ O&Zro'X "?"{@Zk%X!O'o'0Zo&s"8{?"@Zk.J+/K/o'?"+KZ KK` "YG8KO'Kd Z{o'{@Zk%pX!O'o'0Zo&s"8{?"@Zk'O'0蜣O&o'?"<KKp h "Zr{@Zk%X!O'& Zo't "?"{@Zk%W!O'o'0Zo&8{s"?"@Zk+/+Kk/O&/?" "kK\ KG:FKo'FKKO'r{Z@Zk%\W!O'o'0Zo&8{s"?"@Zk o&\s" "?"@Sk%W!O'&Zo't "?"{@Zk%V!Do&4s" "?"@Sk%V!O'&Zo'u "?"{@Zk%V!D@O''KZo'x "?"{@Zk%dV!O'o'0Zo&8{s"?"@ZkMm!_FCJMFm6@J Fp G.C`7J.@A?GN.CSkO'o'Z{@Zk#n#aG~C%U!G to!?#+81C0Q JrH +QF+TJl3+uH +F vH L +@ `O'o'+Z "_" lȃ{@Zk k.K"<..S rJQ sK?".TJtF>o&s"@Sk%T!D$ 1CM<!m, _F8mCJ4MF0-6@JM$͠FpG(Cm `7J@AGNCSkO'o'Z{@Zk&1 @H L@;dH@HZ"G2C{GrG`CwJ#2C2F K.99 @DHF0BF{F@@F5C5F +.`F "'C0JR PJ9 CGC3gJ(1@@<9@@QF sB AGC`G_ E B)vH8 B:AAGZGO'+; )CZo'N"!B{"@Zk0AEFO'o'ZF{1 CN"+""@ZkO'4 AZo')E D Aȃ{JB"B_"."" *A@Zk @F ,F @KGCkGCV#N"AF^B%dR!FEo&xs"Ќo!qB_ "?"@Sk%(R!   B_  @ LDGo'*{#/&/\K?011&J@ O'O&Z$ro' "?"{@Zk%Q!O'&( Zo't$ "?"{@Zk%tQ!O'o'0Zo&8{7s"?"@ZkO'&Zuo', "?"{@Zk%(Q!O''8 Zo'x4 "?"{@Zk%P!O'o'0Zo&8{Ns"?"@Zk+#+o'O&s"< "@KO'0{?"`kHK;fKfKDko'Z{@Zk%|P!O't 'Z|o'p "?"{@Zk%HP!O'o'0Zo&s"8{?"@ZkM !m_FMCJmFm6@J FpFB`7J@AFNBSkO'o'Z{@Zk/&Ќo!01O'O&o'1&Jx "&J|+Z?"r{@Zk%tO!o&O'0s&o' "3fJ?"fJkZt{@Zk%0O!O'o'0Zo&s"8{?"@ZkO'o'@ZH{@ZkO'o'Zxo!ȃ{"/"_"""@Zk!O'o'Zxo!"ȃ{ȅ/"_"""@Zk!#"FB%N!GvO'o'Zxo!{"Ӆ/"K"@Zk!o&s"G, "?"@Sk%,N!O'o'Z&{s"< "?"@Zk%N!D?#@@O'E0ZAo's&s"?"8{@Zk%M!O'o'0Zo&8{0s"?"@ZkO'd o'Z{o'` "?"{@Zk%pM!O'o'0Zo&?s"8{?"@ZkGUCD 1@29 BO'DE0ZAo's&s"8{?"@Zk%M!O'o'0Zo&Ys"8{?"@ZkO'o'@Z BDEH{@Zko&s"xo! "?"@Sk%L!&"<蔢GFBD"1@@89BO'o'@ZBDH{@Zko&s"xo!$ "?"@Sk%HL!O'?'uH ?G/9'Ko'&XKs"F?,KO' 9C{Z( "?"@Zk%HH!O'o'4 Z0 "{o'?"{@Zk%H!O'o'0Zo&8{s"?"@Zk + _"#BD@"\@a1 B@K_KK 91C+B$KD@BD# ;@? H.2&HO'P JFJ0F>p HAB .k" _F2GJQ Jo'F ><k&Zs" RB{8 "?"@Zk%G!O'D &Zto'@ "?"{@Zk%F!O'o'0Zo&s"8{?"@Zk + _#"BD@a"U@9 C@O'Ko'@ZH{@Zk xo!&1C,+0rHQ J0+QF,+k`O'o'@ZH{@Zk 41ChK #"/zKP#+"Y"K#YG"?iK pbK/@#\KF?K #"K Kb.tBJ5GJSbJJFb>~K zKB"/ F5JY"K BYG"?lK bK qK.PJ0F>K@K ".ubJTJF>O'h #P o'Z&s"{L "?"@Zk%D!O'X /'Zyo'T "?"{@Zk%D!O'o'0Zo&Hs"8{?"@Zk _#`/|@KD"O'[`Khk"G`? rJ ."o'\ "Q JQF > ?"``&Zs"{@Zk%(D!O'&h Zo'ud "?"{@Zk%C!O'o'0Zo&8{s"?"@Zk -K/, #,+/o'_"0+Z XKȃ{8K"YGO'"Z, "@Zk3m/lk# HO'\ KO&Fm?|H+"l .PJo'Gl >| "p+?"Zr{@Zk%(C! D 1@`A#"8/zJ49`BY8KYG8?#k/ HO'\ KO&F?|H+" .o'P JG > "+?"Zr{@Zk%B!Dk "?"0`B8`Bo&xs"@Sk%XB!O''Zxo' "?"{@Zk%(B!O'o'0Zo&s"8{?"@Zko&@s" "?"@Sk%A!DYA N#AG^CzG..A"rHQ0J"1@QF.>!bA.#A8/J!zJY8K39@YG8?û Ab` @1A< @E!FO'o'Z1F{fA2 BN"1""@ZkO'o'Z3 n@)n@{?""IA"_"@Zk.#!G>CD@BYG/n#pHn"\K)EF? 0 AaFO'o'pZsF8 Bx{_"?""@Zk#GCD@B8Gn/N#|H[zKN"Gn?)E 0 AAFO' 1@Zo' 0@49@ȃ{`ARF!@A8B8@_""".""5 @A@Zk @GG @JEJO' o'Z&{Ps" "?"@Zk%?! @<A: @EGO'0 `CZo'fAG{1"N""@ZkK*n@1 n@E4AFO'o'ZF5 rB{ "+"N"@ZkKJE D&1@@@O'o'ZCȃ{ HA(1@fA<9@ A2 A19B"_"".""@Zk @aFsF @E7 ! # ! H(/;H#fKY (KgCYG(?yH GH/;gK& {CZHKo':GH?O's"{Z "?"@Zk%0>!O'O& Zo'r "?"{@Zk%=!O'o'0Zo&8{s"?"@Zki$k gB @gBM+ $KKkE` # @ ! H(.3HO'fJQ (J`BQF(>qH FH.3gJ"o'RHJ sB2FH>&Zs"?"{ "@Zk%=!O'& Zo'u "?"{@Zk%tSJ.UJF>,y/Y/[ yKYKzGCK.+. "R PJ0JQF@_$ 5/_"/@/Y 5KKZ @K8G JzG@?zJ`/[`K[G`?<..Q CYG o!o&+s"0EQ JrH+4 "QF+?"<aC.A@Sk%1!o& s"#..U JJ F`Bko&s"< "?"@Sk%1!D.#!G>CYGo&s"0An!8AT˱L "?"@Sk%D1!E DAB ] / 1 AKD @\"X K HHC8G] ?xHo'\+/4 hB29 A?"Y5Kd "G\+?`KO'{o'Z{@Zk%0!)E (AD0@8B 0C8C K#k//9 B8`BzK\ K2 (AGME  B*vH1 B3AaFO'+o'ZsF4 JB{N")B"@Zk E9A!G: CO'o'Z9G{ "+"N"@Zk O'MJEEZgCo'(1A HBȃ{3 HB19B."B"_"" GA@Zk @F ./k#  @+P JKF8CF @8C O&R".r.T JrJF@BK )E 5A0 AKC8 ARo&xs"t "?"@Sk%.! o&xs"| "?"@Sk%.!+ L2 M8!m4m_F0MCJ,-FM6@J$( FpFBm `7J@AFNBSkO'o'Z{@Zk#"FB%.!GU,Po!K9Z@K{H+zGK+.+JAK.o&&s"RKJK>4 "T?"@Sk%-!&O''Uo'Z "x?"{@Zk%X-!O'/' Zo'y "?"{@Zk%$-!O'o'0Zo&8{s"?"@Zko&s" "?"@Sk%,!0HO'JlzB|H F[`K0JGlz BO'+o'Z "ȃ{8""_"@ZkO'O&Zo'r "?"{@Zk%d,!O'o'ZD{@H"_"?""@Zk5@AO' 1@Zo'`A59@{">1"8K"@Zk5O'o'`Z?"h{"1F@Zk@GGD9H:$HH'KzG 9C'CFYKCKð'CGFGG<YKCKKQG?B8 F1'J 1BKDG@FD$1@49`BDE_GC_#.#!G>C%+!yG.JMm!_FCJ F6@JFp F.B`7J.@A?FN.BSkO'o'Z{@Zk#N"AF^B%*!F 8/8K mD/K[C-Q@1  _G_##GC% *!8GLz/zK  D0.0JC@mS@_G_##GC%)!8GL#!zC < 0.0JmD.JSB X@Y @_,A<@#v@HC@-_DQ.QJB3`_#TT@4!//"Y 5KK8GB'` @$@#v@HC@-_DQ.QJB`_#TT@ //"Y 5KK8GB`O'' Zx|o'?"({@Zk%d(!O'o'@ZH{@ZkO'o'@ZGH{@Zk -0..0JJ2H3gJ SB X@O'o'@ZH{@ZkO',o'@ZH{@ZkLo' Z@O'H{@Z@Zk#n#aG~C%'!Go! ?  0B @8B@D+GlFk "?"usBTBBADTDG@Do&GT G\K@GPF|:GKs" ZC@Sk%'! ? @DQK@RK@SK@1rs=`BUK@?#u# #C@DK@ o&s" "?"@Sk%&! k0`C cCk8`CO'QK@1"(+Zo'&s"?"{$ "@Zk%8&! K@kO'&0ko'Z, "t?"{@Zk%%!O'o'0Zo& s"8{?"@Zk_##GC%%!8GFo! K3@$ EDC&`O'#8o'Z&s"{4 "?"@Zk%\%! +O'O&o'@+< "Z?"r{@Zk%%!O'o'0Zo&8{Ms"?"@ZkcD0`@D b@@fB8B?G @$ E@DD0@D @@fC8B_k_O'&Zuo'8o! "?"{@Zk%d$!O' 'Zxo' "?"{@Zk%0$!O'o'0Zo&s"8{?"@ZkO'o'@ZH{@Zk#.#!G>C%#!yGPo!!,.,J+l.,? L.S lJLJrF HH@!<? @,? @L/'l/?" "LK[ lKzG9&KO'&K+Zo'|{@Zk%<#!O'o'0Zo&8{s"?"@Zk"FB0F.l.L"N/.#T JrJZYKF&H$H( A #/"3gJK8C{JKzGN?'."zJ.Q'J; CJrK#QF'>K"'/Y4KYG'?,. .k..JQ g.gJTBEG/~#'#A{KZYK#zGG?.JD @2&B$=@"`A"#X@C<.D/BGDFA0J6GDD'H6GT@GD@6GD @PFXKyH;gK8G?AB5B {CA.{#0_#/:GKDTJK;gK0zCJ3 zC?FFFuHF>-L/,/ #Z XK8KYG8KKC`,. .#Q "FBGo&s""?"!@Sk%!Mm !_FCJ͠Fm6@J Fp G.C`7J.@A?GN.CSkO'o'Z{@Zk#n#aG~C%!G .,  J 1@ Q@a! `c.C.AS cJCJv`HrF#F! D@/."?#X KJGBP@;fH`.# KD"P J rH0F>pK$.Q$JF$>d.S rJFd>srH.TJtF>D V 1@s.#U J>/XK?b/B/.[ bKBKP JzG pA! RD 7d." uHS dJd>.TJ>/X K8G?xuH$/Y5KG$? " 1@?b/D"/ rH.bK\ KP JG DK0F>pDK$.Q$JF$>d.S rJFd>srH.TJtF>!  uXMm !_FCJMF6@Jm Fp G.C`7J.@A?GN.CSkO'o'Z{@ZkN#AG^CzG#1KG!FO'F_"NFpZ Fo'o&s"Fx{"?"!_"@Zk%!PF`., XJ4#"FB%!Gu?#O'9'KZ#<C.Ko&qzKPJ\s"`o!0F>2 C "?"@Sk%P!_#"FB%D!G,lo!K9{HZ@K+zGKo&tR""O'M?#pso'"_ mf"?"  . !Z{@Zk%<!N#AG^CzG&O'α # "_"DtNo'Z"!{?"@Zk%!"FBG-#.L'#"NO'h|Dno'Z!?"{@Zk%!,._",JBA` ?"FBG.#.N#NlO'#f"nZo'"?"!{@Zk% !N..."mR PJ0J3v`JQFB.//" LY 5KKz/8G J[ zKGz?{J/\K|G? , Q. JR QJrFQ>rJq.SqJSFq>BDM(!m$͠_FCJFm6@J MFpF B`7J@AFNBSkO'o'Z{@ZkD"FBGO'/'Z#D!?"l٠ ". GB@Zkm/S_#|MK[mK&Gm?t/&_  p1 -l.lJ2GJ@"FBG-#M#.NO'l#f""nZo'?"!{@Zk%! " ,"-l.lJTB L/#LK;C O'Z#?" ". GB@Zk?"-M"M _ ."JuB , LM/"KpC L@lm.#JB L@n#aG~CG "-".O'L"o'f"NZ"?"{!@Zk%!"FBGM#NO'α.#.#nZo'&s""{?"!@Zk%\!O'o'@ZH{@Zk`#GCFO'Z#?" "`!. GB@Zkm.T?"M"t2JSrJ&Fm>'t_  p L/LK9'K l`"FB0FO'α"N"Nm"nZo'&s""{?"!@Zk%T!O'o'@ZH{@ZkP"FBGO'Z#`!?" ". BG@Zkm/U?#M#[zK|:K&Gm?/&tm"M"' O'p1"o'"-_ n?"N  lxZ!{@Zk%x!.#!G>CYGO'α_"Nn#n#Zo'&s""{?"!@Zk%!O'o'@ZH{@ZkpE57JqE!5F 5JN"4G F EkpE97 KqE9F9#K!9' " EN F4G.nNkpE<7KqE 1!BrF3BJ /FrF3DJ;BrFG`QK`[K2F;F0>k0.\KS[JGQ;J?3F0>krFF3DJ`qCp/[pKrFSPJ1$B{Fp?#F  F `P>B;bC`P>BG`P>B p/RQJ[qKrGp?kP>1$BP>P> P>B? 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p~FAV020.Aj> [VLT00A.GCE]ZMENU_SCROLL.EXE_A;2(I2 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p 0$v$jV1.1May 18 1993 12:51:35 ZMENU_SCROLL01 E)iCGOCGO@@ACGOCGO@@A@jgjj"jj$jFjzPjjjjjnj^jzkk!k6*kR,kV|kkkkkJkkkkkkk*k.kBk~kkkk kJ k^ k l l l l $l (l -l2 7lZ :l^ Ol Xl bl jl ll" pl& vl> lj l~ l l l l l* l^ lb lv l l l l l l" l& lf l l 9mx>y*>y>!y>py"@~yR@yJAyNAyVAyAyAy.Bz2B zJBz^B!zfB.zvB3zzBKzBNzB\zFC|zzCz~CzCzCzCzDz&DzRDzVDzDzDzDzFEzZE{E {lF"{F7{F:{FM{ G]{.Gb{NGs{Gv{G{G{H{rH{H{H{0I{RI{vI{I{&J{FJ{J|J |J|6K|:K'|K/|K?|LG|.LJ|2LQ|fLX|LZ|L|zM|M|M|M|M|*N|^N|zN|N|N}N }N}N(}VO+}ZO0}bO}P}P}Q}2Q}6Q}BQ}^Q}bQ}nQ}Q}R}NR}~R ~R~R~S&~"S-~RS@~SR~Sa~Tk~>Tv~T~T~T~T~T~ U~xU~U~U~U~U~U~U~V~V~*V~:V~@V~bV~rV~zV~V~V~V~V~VVVW*W$6W*NW7~W=W>WCWPWVXZXa:Xp\Xr~XXX YYY:YVY^YzYYYY 2Z 4Z VZfZ(nZ-zZ:Z@ZM[O[V2[_>[dB[hJ[kN[rn[zv[[[[ \.\B\j\ǀv\Ӏ\ހ\]^ >^n^&^+^@:_I_L_R_Z_b_h`l:`sB`zv`|`~aa"a.aVazaaaaƁfbρbӁbBcFcc.d6dHdjd'd(d*d@eEeQBeX^e`ehereffjfffff&g(g‚Jghnhhi9iH*jXj]jbjnju&k|nkklllă mɃmӃ.m؃6m݃JmRmmmmmm mmmm&Rn5n8n]JobRogZovoyopp0` !@@ H@P` @8p  @  Ā 1q 0$u @B@@0! ,$@1!@060 00@@86 I{>p  @  0 @ L &L@$00pB8 @( 8x0C @!@E2 80`@`t  3 0C``r ~{( P@<fX` +`( #0CAt!@HA@PP0) ~ p80pBpB X@  0 fP@ "d !Q"!@0I"<20 Ip@ $@Y?L?La |e@oXOx@8 @@ D$a 0@ ,d @r p$U+$U P 4$*T</^+0I $U+TTTD \ H0L`PT X\hPlpptx|`p   0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p          0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV!*[VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2+,k.(/ 4()->0123KPWO)562\|7Vje89GHJHhE)i0!OZMENU_SCROLL_TV01V1.1$ $ $ $ $x$< $J!6d FORRTL_TV_0016 LIBRTL_TV_0016 TIE$SHARE_001[2J Currently on item !UL of !UL [m [24;1H[7m Type H for help. [m[;1H[;1H[K[K[24;1H[K[46C[7m[m[;1H[7m[1;24r[1;1H[1;23rM[1;23r[23;1HDWIDESYMBOLSP1.MENUITEM[?25l)[18H[J[18;24r[24H[K-------------------------------- [7m H E L P [m ---------------------------------E Use CONTROL-W to refresh the screen. Use the up- and down-arrow keys to moveE to the desired selection. Use the prev- and next-screen keys to move faster.E When the desired selection is highlighted, press RETURN or ENTER or SELECT or E DO. If you want to quit without making a selection, press E or Q.EE[5;7m Type a blank to return to the menu. [mNONINT, ZMENU must be called only from INTERACTIVE processesEMPTY, the menu file contains no lines to displayINSUFF, the menu contains fewer than one selectable itemCHOICE_LINE!ULCHOICE[24;1H[?25h TT TT SYS$INPUT:SYS$OUTPUT:SYS$COMMAND:!ULSYS$OUTPUT:SYS$OUTPUT[?3h[?3l (h$@Xhg" |H ,Mggggg88g@ g4 D gq   ` \    h   \ ` X L o` QPp Q R FG 2 %ZMENU-F-    x  g$ G, H P d t  0h  # xx  t  0h   h   X x | X SYS$OUTPUT: t||4xt h 'h  #h  0h h!h (0`  $CMKRNLCMEXECSYSNAMGRPNAMALLSPODETACHDIAGNOLOG_IOGROUP ACNT PRMCEBPRMMBXPSWAPMALTPRISETPRVTMPMBXWORLD MOUNT OPER EXQUOTNETMBXVOLPROPHY_IOBUGCHKPRMGBLSYSGBLPFNMAPSHMEM SYSPRVBYPASSSYSLCKDhTh \hph(8h,lhh0P4![VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2(2|%~FAV020.Ak>![VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2(|c ~FAV020.Ak>![VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2(|''O[^,: < YZUJWЇPXŏZQP^(PAn^SV ^( ݗn VVDVX^HL2 X^VYZ3VЦ pt`P\^(n$^($n^(n:x:\^|ˀ \^ ː ԫЦ P@æ PPի ˠ SY^(;nŏ P«^(@nЫXX\ ^( n \\ˬ\Y^˰˴D Y^Y IЦ *i1ji  ~1i i i P"i/Ѧ Ц P@\| XX1P P1i?Ѧ 1VPЦ \Ѧ {LrXæ QQ{\ P\q1! :iEiQ iHi? Pj1iAѦ 1צ iB1Ѧ 1֦ Ц P@c իDXŏ P«^(@$nЫ\^(.n\\\X^X^æ PPXPXkX1Ѧ 1Ѧ1Ѧ|צPPZZQIZZZ^(nŏPЦQA#QQ^(Q@{n^SWW\^(ﻔn\\\Z^Z^vѦoѦe֦֦ԭ^(qnŏPЦWGWW^(W@nWZZ\^(Tn\\ \^$(c^XkЦ 19iM)iQ P1Iﰚ[AP 4 (m+P`PˏPQ\Q\\\ÏPl" 8P@ PP\`Vpftˀ Wˬ~~߫ի ggP@g1f!˸f˼fj\)ëPЫQ,n PAf kf!1vgf*ݷ׷Pg@ηXP,X PfXŏgX,f HdPPЫPgXPHgg1 g q PPggPPeN^4Hș[(8HX L B P|Hԙ[Ѽ1V<^(V^7Ѽ0V8^(8Ón ^( nA AV^$(V^0HX[мRHI[RtRBP@QPQďPQ@= R<,PPPHLP`d%HP[PP P @2,޼@$P P\X 2d` 2p޼˄hPPˠ˜2˨ˤ޼Pˬ ˴PR˼ ~PRRROT[}PQP}PQP k<PP PQPQ ,  $PQPQVzVR{RRRRWW RRX< RXRPQ Pa K( f2f0P PLH  2TP "p8+T|PT  ӇPyTPPPPPkPTPTTPPPPP @PPP P@PPlQмQPP@PA`PЬQaRFSYcSޑR)*S SRԄ*P4bБԄS|PbSТޑPdTkݏlPެQNT1}HH[kIH<[}PQPkqK{#P.'#RPJ2FP>./&.1"/U JJQ..Kq. FX/QJ8/P JS qJZ XK8KFrF`C B YG qC  A @AeGOA XJA5KGB!DF6G D5D6GT@G0A6GPF;gKEG {C FO'o'Z1 C{AF41"N""@Zk41A&n@2 n@EFO'o'ZF{59aBN"T/""@ZkEk/D0@DK# H[ zKo&GEk?{Hs"D/EBA\KL "|GD?H˱?"8C@Sk%h}!AEaF&"HBU/JE5/ 0@A IAX UK5KZ UKG0C KY5KFU?pKsFF5?8C8@B$51C F/ &/ #&Z XK8KPs"YGp ȧoO'` "?"tko'Z{@Zk%|!#GCFO'o'ZE{.qA2y B]/" G"N"@ZkO'o'ZE{.A4dB"+"N"@ZkO'o'ZE.qA{N"`/""8yB@ZkyK/:?# +KZ KKo&zGyK?z+Ks"xk/EXC "[kK?"[Gxk?|˱ PA@Sk%{!AEAFRF,Bo&s" "?"@Sk%t{! &/ " /f# &"Y 5KK"8G@Z@ZK./ f. F.P JK&/S qJQJFrF ;B0@ KY 5K4 ;BYG&?yK8@F/ZUK:GF?o&s" "?"@Sk%z!a1qA GE!FO'o'Z1F{2yBN"s/""@Zk . . f"G U JJFF`BYsB8 K2ACDDVGDEVGT`GAFVGPF<ׇK CO'o'Z3 0B{ARF41"N" "@Zk 8QAEG pAxAO'o'ZG{9YBN"v/""@Zk .E PA# IP J)E0F >LBo&pI+.s" ,AXACQ "˱?"@Sk%Dy!AEFFB.#!G>CYGo&ضs"/%"()!?"!@Sk%x!n#aG~CGo&s""?"!@Sk%x! F. " &.f". #R PJ0JT JQF J*_#F>tJ.UJF>)/8KC` .?" JC@2. "JuBo&̣s"?" "@Sk%x!O'o'0Zo&8{s"?"@ZkI/)#~#YK;C)._")JB`o&̣s"?" "@Sk%w!O'o'0Zo&8{s"?"@Zk.#JB o&̣s"?" "@Sk%\w!O'o'0Zo&8{s"?"@Zki/#iK\C."!F>BQFo&s""?"!@Sk%v!31@`B 3aJ3W`JAs&DsAs&Ds"k@ /?# KB0@. / f#P JKF`C5`Ce?. F" f.T JrJF@L@̧! F/ # &/Z XK8K!YG(CA; C&. " HQ 0JDQF&>qH 1@ F.49`BRPJ2F F> /?# KB<@. f# /ȧ/P JKF`CqC@.F/ &/ #. f" .Z XK8KȧoU JȧJYGC F C AHAȧ! F. &. "h!R PJ0JQF!pB"@4 pB&/ # IY 8KEYG&?yI 0A F/ A8`CZXK:G F?I.)" "QJ3BIO'&Z|uo' "?"{@Zk%t!)/E_#)KC` .Q?" JC@o&̣s"?" "@Sk%\t!O'o'0Zo&8{s"?"@Zk.H"JuBI/?#IK;C"FB0Fo&s""?"!@Sk%s!21@@B `2AJ2W@JAR&XRAR&XR"k,.A#JB / f/ F#\ KzKG@C5@C. f. &"R JqJT JUF81@B KSqJ4GyK>:9@B3Gq>!/B"KpC . F" f.ȧT JrJF@BUB|/ f/ &#Z KyK\ KPG0@C 9J[yK\Fr9J?8@C[Fy?/ . "f/F#X KJ[ zKG@Y@o&ȧ9s" " :K?"Gf?{:K/\K|G?@Sk%8r! R f. &" F.GFkS qJQJ0ArF BU1B4JGBDDGDEGT GFGPF:GK ZCO'1 CZo'AF{41"N" "@Zk3AEaFO'o'ZsF4@B{N"M/""@ZkK/E ЀA+# IZ YKo&zGK?zIs"Ek/C A "[yK?"[Gk?˱ؠB@Sk%p!AEAFRF(BF/&# / "f/ .X K[ yKJYKGzG 4CD< 4C(C0 C?"+`.F"f. " / &/rJT JY 5KKF8G@BB UB@./f#P JKF`CaC .f.F"T JrJF@B5@Bf/#F/f"Y xKXK[ xKO'o'ZRF3 B{"/"N"@Zk/".&"F.GX Kf.JQJGBZB9@KS qJ CDFvGDrF @DvGTGT/@vG4PF0J8A BEGO'o'ZAG{9 BN"41""@Zk'n@0A: n@ @@EFO'o'ZF1C{N"/""@Zk.E A IT JABF>o&tI.s"JE CUJ "F>˱?" LA@Sk%m!AEaG{GJCF."&.R PJ0JQFBB`/."/X KJGBB@&..f##\ ;JJQ ;JG0C {JPJF;>t{J8CF>F/4Af/EFXKY xK[ xKuIo&  /s"( "?"X KF  ?-,CM,C$˱@Sk%\k!EA!F1FB"`BFB B B:GXG8GuB.f#/ &" F.P JKR QJF qKrF F>rqK f.SqJSF f>w.M#JB o&̣s"?" "@Sk%j!O'o'0Zo&s"8{?"@Zki/Q#iK\C."!F>BQFo&s""?"!@Sk%0j!31@`B 3aJ3W`JAs&sAs&s"k|A#"FB%i!Go&ts"Xo! "?"@Sk%i!O'o'0Zo&s"8{?"@Zko&ls"?" "@Sk%|i!O'o'0Zo&8{s"?"@Zk.#!G>CYGo&s""?"!@Sk%(i!o&s"( "?"@Sk% i!$ #GF GD!D!DG DGE,1AGEF6FE F6FX@F39B6F B6F!"FBF#9@G!GFVG GDVGDGX`G%o&!VG@ls","VG< @?"!@Sk%h!o&(s"8 "?"@Sk%g!o&0s"@ "?"@Sk%g!o&(s"P "?"@Sk%g!o&s" D` "?"@Sk%g!K.+. "qk.O'R PJ0JS kJQF J&Fqk>s J p.o' "?"TJtFp>t˰ZHu{@Zk%(g!o&s" "?"@Sk%g!#GC8GO'DZ#N&O'ڂo#n#_"XtNo'Z"!{?"@Zk%f!"FBG'O'+#.#L|no'Z"!{?"@Zk%Pf!"FB0F&O'K"N"Puo'Z"!{?"@Zk%f!#GC8Go'O'T{o'"Z?"!{@Zk%e!0B'8BS@/"GUKFJ"9B5BaG5BVGڔ`G G=BVG3B4 GVG+. .#K.Q rK?"k.SkJSFk>o&˰0s"@Sk%d!-O'o'+"Z_"8 Bȃ{ B.""@"@Zko&s" "?"@Sk%d!+F#G+F/"[KgK9dC5dCAF5dC6Fє@FF=dC6F3dC4F6FHgO'0`B&/8`Bz/&KzKCȧo'0Bȧ/8Bg_"&"ȧ"T@ȧt"+"ȃ{:9 CO' 1 CZ89B(1B@Zk gGFO'P{C<JZo'CEEȃ{6FE@6FT@Fd"6FPF3gJ_" sBo&s"&" "@Zk @ XA'_#GF :C:CF:CGܔF"`G :CG:C4`GG' o&ls"?" "@Sk%b!O'o'0Zo&Qs"8{?"@ZkȧO@o&ls"?" "@Sk%Tb!O'o'0Zo&8{bs"?"@Zko&s"..U JJF@ @ O'Z# Hz//&1"[ zKGz?{H/\K|G?Q.̧R QJ JrFQ>rJ "q.SqJSFq>o&s"?"@Sk%a!O'o'@ZH{@Zk#"FB%ha!Go&s"`o! "?"@Sk%0a!o&s" "?"@Sk%a!o&s"( "?"@Sk%`!o&s"8 "?"@Sk%`!o&s"H "?"@Sk%`!o&s"X "?"@Sk%`!.#!G>CYGo&ضs""?"!@Sk%p`!n#aG~CGo&s""?"!@Sk%<`!&)" _"0.0JB& #(.JB? Mm!_FCJmF 6@JFp`GnC`7Jn@AGNnCSkO'o'Z{@Zk##GC%_!\Fl̊o!s5`B;"FBGE:'CO'o'Z.AG{"̄/"N"@ZkO'EZ<9aCo'.1AN"{+""@Zk+.E" JQ +JO'QF+>q J&K.DhBo'RKJ@2FK>˱?"Z "u{@Zk%^!AE!G9GC}l{U`C;"FB0FO'o'ZE{.1A39FBG"/"N"@ZkO'o'ZE{.1AN"+""59B@Zk+/:# KO&Y +KDYG+?y KXgCK/o'P@?"ZKK ":GK?O'˱rZ{@Zk%]!AEFFfB> uC: N#AG^CzGO'o'ZE.A{0CG"9/"N"@ZkO'o'ZE.1A{29!BN"+""@Zk!.A" kJT JO'F!>tkJo' .D0@?"UJ( "F >$˱8CZ{o'{@Zk%\!AEFFCO'O&Zo'\r0 "?"{@Zk%\\!O'o'0Zo&8{s"?"@Zk#"FB%4\!G,o!Y o&Ps"o!Gt "?"@Sk%[!@ZO@ȧ[@; G .Q@ +H0 JU JDG >BGD /FVFDDVFT`FX Ku+HO'o'AVFF ?49# +PFZ{o'4ׇJ{ "?" B@Zk%([!O'<Ko'Z&{Ps", "?"@Zk%Z!I/O'O&/"\ K Ho'FI?| HH .P JGH >P "L+?"Zr{@Zk%Z!o&s"d "?"@Sk%|Z!n"aF~BF&O'\uo'Z"?"{!@Zk%8Z!O'o'0Zo&7s"8{?"@Zk##GC%Z!8GO'o!0Z:FK @O'o'Z&{Ps" "?"@Zk%Y!O'o' Z "{o'?"{@Zk%Y!O'o'0Zo&8{`s"?"@Zk'O'0蜣o'&<Ks"K, ?"@ $ "Z{@Zk%Y!O'\ O&Zro'X "?"{@Zk%X!O'o'0Zo&s"8{?"@Zk.J+/K/o'?"+KZ KK` "YG8KO'Kd Z{o'{@Zk%pX!O'o'0Zo&s"8{?"@Zk'O'0蜣O&o'?"<KKp h "Zr{@Zk%X!O'& Zo't "?"{@Zk%W!O'o'0Zo&8{s"?"@Zk+/+Kk/O&/?" "kK\ KG:FKo'FKKO'r{Z@Zk%\W!O'o'0Zo&8{s"?"@Zk o&\s" "?"@Sk%W!O'&Zo't "?"{@Zk%V!Do&4s" "?"@Sk%V!O'&Zo'u "?"{@Zk%V!D@O''KZo'x "?"{@Zk%dV!O'o'0Zo&8{s"?"@ZkMm!_FCJMFm6@J Fp G.C`7J.@A?GN.CSkO'o'Z{@Zk#n#aG~C%U!G to!?#+81C0Q JrH +QF+TJl3+uH +F vH L +@ `O'o'+Z "_" lȃ{@Zk k.K"<..S rJQ sK?".TJtF>o&s"@Sk%T!D$ 1CM<!m, _F8mCJ4MF0-6@JM$͠FpG(Cm `7J@AGNCSkO'o'Z{@Zk&1 @H L@;dH@HZ"G2C{GrG`CwJ#2C2F K.99 @DHF0BF{F@@F5C5F +.`F "'C0JR PJ9 CGC3gJ(1@@<9@@QF sB AGC`G_ E B)vH8 B:AAGZGO'+; )CZo'N"!B{"@Zk0AEFO'o'ZF{1 CN"+""@ZkO'4 AZo')E D Aȃ{JB"B_"."" *A@Zk @F ,F @KGCkGCV#N"AF^B%dR!FEo&xs"Ќo!qB_ "?"@Sk%(R!   B_  @ LDGo'*{#/&/\K?011&J@ O'O&Z$ro' "?"{@Zk%Q!O'&( Zo't$ "?"{@Zk%tQ!O'o'0Zo&8{7s"?"@ZkO'&Zuo', "?"{@Zk%(Q!O''8 Zo'x4 "?"{@Zk%P!O'o'0Zo&8{Ns"?"@Zk+#+o'O&s"< "@KO'0{?"`kHK;fKfKDko'Z{@Zk%|P!O't 'Z|o'p "?"{@Zk%HP!O'o'0Zo&s"8{?"@ZkM !m_FMCJm! 2+r!)I~C) h eiz列q6Z5MN Bp8@XNiG3d0eѴ)I@Lt\ )PpZlIN`u Ll*:P Dt0\ p@5L~ix o_ PuhT=4 (Nז <*d0eEڜ6 $` ND gk))6h;3,kT& 6GˇT`?< 4 ;`jEw#lTG `l$!h@JD!h =( *Fa9l< Fl 'hzd bfV7M0 ";gX\q`8mf /lj7 F+cPGv&Y W>S BAb%:c  MfV60dMb  KDe$pfN{Q * >pwhbS, Q_)mjialh9Td r 7S!f??''i  F΂H#E F44T5 d@ /i-GiHK(qPd-mǑ=IPA5Y- . /(27NIe#p.qT9Trro?OT5?B!$ ȃ +tk xo? nH +Vb {jVc }@g6!AeՐ7@ P~I IFCbeM4js b8";ed1Fyg3a;as_1ni)+f[`35acw"4ʃ~M"b3І/RZI*x0J!iC)!a#}`[Vtc8)+"ci끳rBS>L./Fg-x#[bTX"!zj 14hEX+Ve)2JG"rKwjpG VqiI:LƄ+vkhbwip_|kr`wx# jSdXX$h;ZD|tsFfliSS6WgIWH_Lgze-v>Ma  NHHXSIXSJղy2fS`6d>Y7MR2rBY>LfuR- YSIRS"I yY>MR, ;jLȱmmkj -mܫa2serS,fvnvqb>cL`RfR.g%syJb[L"{|d6 he Ca[7MaCحlkkla nYD_o3 -hb)YR?=ɑa e(Ykb#aFp?;|iRҷk^IyZSSo bh`fӂ8YlBAJ]hrNu#O2o3 mղY䋬(ZzaV4zC*J&ý%n.ՙ~q=M*|igZ S~C "`(TN}Vv纆Dz“`d/gP :N`͘j|sd/eaլN n"eW-3+D3_n. `icdjÏ;d.eĆ Ă &ty k@Bq(Rm0@ 6,{fJMffobhw}GNZ(k$?qC:l}o9qmkRl2\Go濋i$^U;<9ԑ6>2?ċݟĝКn ug]Jqrhz|@1 |V ^rSO0{rU]v礛-Ϟhaj ƒokU#ũ2d Ft;-Z+>j2`l˓.Ed"ȡFmdm  j0'ם^`S,ltg~c o.baeoK>Pj1hoAkiEboP+j  {7Rg~0auz|gYZ s>OR/|bݩ\o%[q?J'fXl),C-1!q/MW(!ХNkQD.k*F.y*f9l"g(RŎ}궦hl  p1xp12|4E>5֣KF$P(".HJJ0]Iy4Jb*B5fy&egXpXtgc\Q'=Em0L bK=WB&;?~5TcoAG $Q AhVCIr2WQs|pQjJ|:׊&GkMdwuI3l V _#M`,꿸`,3=" io i?W)LidP`-rE dFPNF>cP 0Sr !a}{\dZ:[ڡ;'Ko$J( q9();(V=-8HrQXsypJFt] zt_zam"MST*86E diJ-~ 9Fjq0+n1 F & Pe_x|E{ +t0l} G4x|,$ z`1CMH8nCKyHg?A{1esOvV|z 6MeֶOEo5nI_cs ?Wm3mWnMʊ{bD\IWP#gf(l1 L0&>BKD6Go#_"W~=&N/s<_;Jm3g}homo|d# 䟉b? |3:T3-~^Z=94`5oO1xG)Y+Al-d#eN4Zmqh+Pk/Yc7 5>rw=c|df"`VQ odSK# J= u4ll`m0>9i,gųb,-k?@Zy_qy$rAy$1Jz EH`VmMAWaOie>B zď|  wF'm U-냃hBW z~Bǂ0z*IyFZ{ u gNuzz WC68.:!vmFvC`joT}kwnbkiEEz#i'D|:YrhaB Ga{1@[`v= 3OjQdKc-2c|a&HyC)b]F:FD wD[ +NM ]ҥfK O{%9 UkI"IZI jo@(Q`&FLF+LkZxk6If"v] WH[`j`:| \?j|ͺ= |>cxX v ex~Iyw! ROd=IL zTGF|ŋ~&Dbh%Wdy=| ~ 0-k N$dN#S7p~c:YqEtpk}/PN^jDXnTbZm_>@T_ q3`OY~Rl`S2xpNA} R2}z89NR~ R!r&u%SM+~(Y\B#bD-{ 4l 3|Kh.h>;Uh /%~f\~jjߍt OV]>uE\2oC|l^\rZS|`Lth3X`eZ!_ jz1W ~]C,\r|_ } h?YUЩن,Γ?V6wK~/)b_9˶>ɪC_M) 4"5hVV$>V&b rAUA\Ma,ҫ{gWJ(]Ic+W64ف\a|`Y,eOArؖnfg%aaF  aѤDrVJ{le|M'ؑ^OpTdY' ?N}ˀjSa@"v5ݡFn^u~i| .^,5 s\$ApIdV K:hߘE|^%x,Ÿ˖fs5 lwomOdc> saAsI덽ճJ*a~,}iu~~V~aEg0z{_~ug'S:[#2%,IRBIWc.Wc_aPgc/V`Y}PJBlIC"JuhO-k LKM&;$@ ~i~00lM":+P$@B%LJ9ZB7X)OO%%KPb} @ȴPEJU @tV'N#FDuh$P~Ѽ40& !Q rKE?,Ɋq@!M@(ǃX%!¨k$5R8a_e_%$S+_=3 8p>`R0hhH Aԁ'6ԍ|od?@}s @Htd50|D@vq%P88v2hqؽpE>9@ށo #h*e!aED/Lc" ̰`&$%WqpZI^ˎaD59̓ӚU G6[')"jopoA}~N6pKӧvE`ME#GAЁ! \uAL"䃗ЮbG(t4D/"M @<gl2l 6`@&r10>Dbp!|4dd骯gb:gaAIa 8`s@!UL~D=y =BP t BǑOzWfD )7E>ҎqY@0}:G0hIpOׇ0@:@ڇv)_e,mgRQm)X k p{N՞D̙=BVN 'QH/DSK`%XEgD ݦSnOg,]C!V@"WƹKMM^O]߿-TPW JĶ7d+CGOSSSdBXTTNELMYQyNI٠xNB$=zHGBLcSGH'&yO+7YR}8z7QQS#\+րV&X΁n@e]4`@5Hxnx abahzmElB0xց:(L+sdNYaL%0oO{:jD4ZEcE5~Ue\ٞ@S׆dl P0d  i1elj$ BLdL~0@xc賈 a }w yi.|4 il aAXi6`xKqnXPddtF'= a a%8q@L!ZSpX@QnWP rIGBF!ȉo@gd] TM, dR+i!RMOdez^ee#x  w>xIr|, _ ֌i |a{ko ք5w*Hg;ƒJN>2gCdžn`膃鿆Pdsd 6@)^C1mAÆgmp`bkIr@L 5w@vD 7}nKjeQޕfYecUe:La&b = j` fFA-kAi`e0CjktaXx|#}p:4}1CE9xo;Wk'gWi2ib d"aNh&i| aeq10p/t`'"jƔFm$d"i\vI xah$p3P 4 QnJX`eHZRB,g8JgcŕqPy`7|PGH2nFb3(KbDidiy0GqG![dtGXI- xgPQJ nJ YSe~h?XdFzjqh>Ʃfe; zbpLgcqhDs aM,/6o%b{FgMyds v3Vev;he/u6*E & wȌeea|#` pd ~N7J +ec #(T)z3hK V| &$i k Hvy?Y(f elrY"5Klhxđ򔀂MݍkH`i+* qd'hK'H dopt>Hfq9`;`b &W)aw+7s(`, a(f] 㯰Inyd! 7`(df0SHa9ee `i7PLp7o0n+l̐,0pdT0H[/ b<a:gR GW`cƒEib*3Hﺁ&2a13+S*uc `<:{*33sAC2cdfH͎b3fAbybh&Eda.f*hg[zz!m])ěg8iSg#dxTڨD di$ pIEdkH2eLkn/ Cii(B3maz6!h;i6#vW&J,xfzO!HlRgLLd!|i$R.z<-gC0#`5bDS{pBvȫ'.ߔn"[(dsa/ />ƗK@X,@"Gb$ i.,{hZ>tVX }GlJ^ZA: q a!UYi k$x ^kkKX ,Bkl`-a1Be6M/ef| UゐGkqM`m =q) ǝLmhc*lbM v ,jhx2j,~ẕ&gnF'L+o,;={[f-6;W hʧQĽoUvxF-/ȀœS+iE!VYG l&y!]욯oG3ꇗDCdXjX͒ Q„0Е[<?=0.#; (YUcQμH?KoG(Zc;DTĤV+Z,82^>uQXaئ}nvu(%=v(}DmAj9|@ON%d/<,>?ϑ+ۦƠODz8 Nv< ?{o;쉕ܝП?S7 6CM,ɁE~LUV;@.fR0S`})]u`v$B\|JU_=j'txj˞smsL@[!u?W `O$YliZ7&F?{ݱ+a8<fR =^͍w!Mq'+oPP`;KZߩsCV{c8wj%NaG ? r]slJ /kdk>I7 IJ.+)Zs?RY^iPl/=x ev1|ѧ#q祶K\ :^\ $^ c4)m6Kٯw| )K%$Lj 5酧䀘T_~E׋  HX"TYpi4xΉʟJ䀑Zer)0] /K $4h:v#?c# p " yC87Nj) %<  >o 0r?=I0)J,zaց:xBB " ԍjcc6|=+f{v%L5OOFOB$7_z$,xh5tTEODRg 5T_ qڇzN> W4qE$%"Z'bQ9Bl IE+W84Yta,F ^[@aIY}W O(1U)އ]{ﶧ$VKd/ar)>1mԣ56o,LgO*W.3~?W n ןmmH,8=%G.LL-K+FIl'8z.2RYcZU,Ks)vuSbV "@7/u_^t./if5" Į5[0nIWPx6F3xȆugdauMk(Y 5gߢO`7Uǵm.B~Ө@gZJZCĢFQdKI1L !ى2.BkL(sAq!׆-/l5@JEҼMd'%.2@5Y*BxJ|S懍9I{g{'(疫3"Qjy\^`3Rk/VI>vn R 2V,I,Qm_׌MȥXY7eo,`} hlfӆn&2#X 23{d—CY<~^7IolxkGԾ2+y'It5pË?Y#H$xOs}Nz!\ IqIqR 7CNˑ;O3R4)z-*Lބe< Ʀ=NS9O_FIP*4H|ɶ2o jWK28 z6 ߵ7tDt,efyDvW`Y9*Eg!T`=R  '=/DIkܽ?ps3ՄBdL T}?-4]]1 "Q%w[88c9ݱ W|&[!7+;?5B*m"A +Wo,9 c *I{T"|rLr# knL=P.Ž#WU?EMWWSrA3U¦Hcl{ -lF7%g:m6$NU?QXv4`(EcXrn\ruiKYy2GV\fB<͕Jj&rh<_#ps/0U;!}ZWottbPPlǛ<:~rn:Hp}P$ٺ#;1L33j(yt]K\+'ax`bl?"TPqz'yPKT/^+}jZ&-{ Ej?r-pL.ofiݘRSoDTop`ַpN.h )~] sd.wIJn#IX ҈lSŅ*?66CBkb[Yǘ;[gzVU %19Y1% 7"aQ#y#9H*&(+VQ5egvR ./P$cI\‡Dl:Z5(uJqخyR^K|G\,JKf]}/mQUWs\`6!ne 2.~t&$ spVaŪ$OE b{bB֩b4;ę^q3 ]W͆%b4CX4ؿ""RɚHLٓne6ti•i̯hNXp@]gN~8E6WնP|^0D9!)~O&QbWS{+n&RդeホrQ Ӗ@-zcϼ݄<~6#(T ;wn[ UY'1m@Ƚ &ΗxHrCࡀ;p&:\ -栰F}G4Z1@@t>_H]\8/_DH2d .0ȕ#S9IӑnAgK9_v״L~^Q_,j8V:(A1ɵv QV\m䂴nj X;*UxqnA=`e V%&/A=BHZF "#q&^lcJ tBE! U!N7 \CP>}%##Tj"P.Tr 7W#}EufVbJoRW #lv4,^Ӡ #$2JPoAg¼8 ^-USBT IA?Th ;m$M ? _ ^ {Ӕ9cC枠jϾƫoK}ં0 Q867 hM+o xR=} DQ+Y`\KׁKas鎻BԹ.5h,Ւ$+iȵz{'V\\\hJ[1ȵzJc CPQUP/ɸ:CMfKjM4;>,OՁap"-wQ>EZS =EE]NUW'.SҪlDAX9&D='g%NfSkPXCNTZź-0*32uS(Pb 0 夋I'Lʛ Z0WF! +x3'&y ZJV{nD>}ʶkwYbWH<7ג- 4XQS԰qJ3ޘ\DTkZ>[=ϱ{%Ifa9dKv?QOV$_q7yY8%E5F]vƆ8xp<J;sA<^~q@uG+ q3'Dn}d}A#jLYJN K:@nVҘk-OʁBUH%^lZ'ͤ7* kC@3ϖn EuY3_A@r8`,q8]ҟIJ0@%6(U$NSUIq["U\mn,T.vY:7혠 *O|.!Waf < ^Шy#]:̐8$$r&?^ ,4~ls?A33EU[\ź<g| CUٜЁ]F|Rϕ\I/N}^_ƆIK[tv:5q,gɒkhyoK-ι,Tm O,ܾXy౳YDfâG6lECV|۟uPF1[iW@$燏),6,ǽ5I CBGE*GYI:=Uj /S8 c}}QgiZh [x.ҟaS&:"2SqhN\\79m^x)KMcj-gt'8tq&_?('êq EW;zWŚ]>n_HBּ %>1ô*50F~YMIFџ.*rEkX<K25 6_4f.j*3Kj6˫0g>i>#$J}3.4X<ܙGwʧDWamz@bS#04{F]2$-@dX΍#+;e _Muy{RjwE}X"b {"S5&GLX_K~ *r"ި@$BŋA%  T16HQjC;A25A54KV?r^XӲP'zgh+;87PKOiRl wRU <=h*"%&JM[S1s #M]TΗeܿjDy&Y ;;=oV> OkԚj;A1(~=_n }\,hW ASL#Uzj((LPڧe`fd)Av!H꓅#POovѺ\UP`<:J_Pq[/]W_g˃Upo 4JKο`ג7fC}߲ZRq2% \_Ʋ"fbk8{d(o YF`E.:mRܫ`fmhpt`LOKR`>7KcցMU&ӒkɖOB=K<yDW֐^J N,Q~tnQÌ_|ɦZ5Q+ 6QڶJAP/6^ޙ_??%g( p;}/ 9|C!-8g=C,gS{Qۋ]դ87".L'jsfV"(C+ 'S~. x*? bie`br&`"snǬĬ@e=r:Tũ8yf9@s쳦goN=0B'%W|;Q ieIY5)mwNkc3I?mz߸~5沐&rCĤ| P&<|gfr`(rYųT9"]zU2Pa{Zo ?Ͽ2GLBuՑjiq=^XŬ U:0! %[vguWO>A9]AOw?G0teoWcW8.U]< q6\tλTZtqDjGMRS!!]56DdhJpVc%{1i:grS+#}RU_;! i*Eڔ<0~8bif+̌K&I }gp5 dNj *kxX$&?+1Mdt?b+4]7jpoW?m:q%XXHW[Q~`giU&kc6VY_(M#x%&$z Q*'E{E&TטN9cĉ`H]vSZ˹A5+ Cs9MR՘cγsc S:^<wZmu}73bwvګS nK3~_@U6NS R~ʒks kmԭ[*:;vK4rVOQ+g.36$Lb+~/PQ!~mFR Ѻv+RV>@FCe`LrbsM;srR%i|И1OQ*H~ۗcz|2!H\o(V7#dGpwTBKs# ȟ>%hlm̏5QLUd!B_fb$݋ ab,Mnέ2-dmC}Ƴ|Vߓ [`P\ KL Ng5;,_6-RN0WGQHtXMJd_ o\_ҩ{U^3XY4a=ScYH/wH\o`<w]8џ e vC ӂLWC,{4< vM4WJ Z0, (eG>z)5 7C;:rև,x3 :ó\}oH;RBV I:N0SCg*J51X@߸2[Cr ԘRza!@)߃uʽj쉮pYgQ6`|\ܨpVLrJΌ/3ʳŽN X SPN1ߞTVޣ9[Lm6rJ ,$NXۼj2 R͗y{6 KmyHdYpp ]'[no7c%dLަA7qH# Qޔedkup/):g0hZѫKsC"%^DIK΃V c3 `gSRLgNX/JWw#ʐUm_xHH‹G+ˌjFni5OdnmG9QHv i櫨>(^M_V֢-]kV&w{$r ||[7FmnjU$t4DOlsl ʅ)ƪV] !Dr t㬡u8v8'l3"ud"L3O1 $\deZ-&r6}"˅ާqQZ>~ "ͱȷ*!n6'Q?f}K _ #9Z'}q*:' fV,ж/vy:>}qب)o܄4t'6{xp!\`YX [\s eБ5or { cfUfW_sc?ofX0bGݎm:kR▘[}jQƽevAN|n?du8 N%PݲpCo<Oƒ$kQRZ~充#CE?ɃƟICb#FךGGJ(}7-cS*2S DȎb)kVH*j _WS}NFtd_Jtxw]D]~V&;)V/B].18<)6>i>3!-zIN"F LB[Ƙ1 Y[[>2`A6"N~?*ٿwvBk&"OZ}p"q4N')ʻ["*Ow#85d')GD(RYG<7n& s"ﳭ"]6>"o!~vRk%_!Ra'r"XR "b&>"zVk%;!8$е ~#Rn&0s"/ "HV?"v~Rk%Y!FVo&Rr"8T ">>"XSkm%3!?n&s";DT " @>"Sk%\3!@J.V+.@ "Rk.@N']PJ B1J^kJDPF\ J@&PF@j>U J: T.An'%"KA3"\WJXEuFW>AʰpZGt{[kʪ%&!Wo& r" B "W?""Rk%^%!L#NGVCTF9Gcu飳-Z#JOdV&BN'o#oV#UQ#EuP@eQn'T "7b3U?"[k%1!L"FaUBSGU'WN'V%"B/U#P}ZnVn';Zn"Y!z7V?"&rily]{A 4N Ip i f+k}3ޒ s J`l*[ooF;H_C~U( J F(s1$v!%%沨^{5-e (lI#Y@F򐅓w$G:2 2Whg̨ZSrHdN ah`8(ԗbDb?)H: yMxCStX"hOEἓh Knhg0\h%M:t@\hOEY]Q  !^`o LTl]TaXs DhJbţEh\"}X qU3dmdBR_`(,TeRcLKcWSz*|k<`ZS-zFhzSLNGikeǺLSdR2%1InbS~ $& LmQMgcÙSPxaYB(`ZUS5iP ?m/`Ae } m QuPaeNe@F[X)%cG`@!0b.3V oXb Zߠ|oZ_W!Zo0yfz B`DSTaS[ WE\buMّ=XQ\tS.>`ҦuX9髉\`sdvN`^ci RecZ:3T;mFiUri5_e)[(QG]+kRYX]u_Z,e' ja`5bd_vf_}lXh\eۀ"C9 Ce\cojX[I_[\KEg[{)EQQIN؇``_dF8\!"$%Xg.nW%ao@eC ]D=\ 9XXb^ ʫg6DSlIC4M<Y]i#wY\k q .a_d.bb$l]ˎ]Me=X0^1di^A KeR0tuR  XqgZjx 2ZveB_t^o TS;uQ0 Uo0&_oxUϪ][<`_`_c兰ceL^#YI`DJNWc,|<`g`0N`teVhs`+!!gJ'Eu Jd=kX ,h `ѓ[`|`i`nS( a7e}lXa*flg[figb|~E`XMnf5 ce x8dPkyMw&ukǡ}G ǣ]}N=1}tefd} ak7AA -d oyAꄇ}{&myd%}j}l ӚGht 8~b (nGc7ysH{OdozaFhhjxo8~~&1l8h]`!fJ6bZdN`Zy+)S&hIjWlad&a\Ckchy R*fܶj/mh^Vpe}l"jcmM }eE kl`~Eeyi :f!) ƷJ< ٱtiFmm2hafkJ7 )lI{o-9~bU{/e`^% `*bd˅i)L|!5U$gP{IdIةNbghRm/ኆnѯ: gvi`(hjggVcx݁Ke7koaaAi QVp  eVog;3hcwmD dмR-Lӓws߉xnTejx (7bЀy o"HfV{ LP~ Fsgß)A#XɣunVbADdPN?p"bU.VCL*IZ UX AU~ۜn?vm @ A=V< !{^v(KR#~e P@q p)*hh=SIXLIL "mfA|uҬu%%:d9LRỀl5\ MATʹVwӗ)3"I0}R}돛 Ç TV X%v\0GL H8yioMbٍ+ 'LEnf eCjlUej|u |zCfAwSx6E̤o`l)q2$gz >Pg~Wv$͓t 1ڀg5F B+c u Qwp˵q@U= $QM9}j-ĉݩaWa7eM{, $EJtGZEYz"$pw؇7aW*{e倛>XUB$ I [ ]b0#!4̰UmUb *q}n;@> =@G!%.k TB!7cc!=A"$ajD46&] 3zH]?u7l?~kF-_Em-efne6`;.0=ש`ˌ*J Ijghe+y߾/a7L Mf(lfi1[Vo#Yv *+ 扡hF*ۍma2C6xhG8? dS6g]<9g"PphWSI?5 0]Ն" .UZeb٩eYP_ L *F+ %k a}4m8gq8Cn12cg}FOL i CG= Nom+)j 5 8{NdG硰>93ʇ參If)cȃ5S_)9 mYU yS r @E JHf+' z MA-mmt}=#Pj:M٩J"8}|| F:s|DZ/ 2= /f6;bAcil{kk R"#4zum@5L1 gT8B"ZoIcQ&po.dPQ$4(4i AQTކIbCdX "~FAV020.Ak>![VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2(߲|Fm6@J FpFB`7J@AFNBSkO'o'Z{@Zk/&Ќo!01O'O&o'1&Jx "&J|+Z?"r{@Zk%tO!o&O'0s&o' "3fJ?"fJkZt{@Zk%0O!O'o'0Zo&s"8{?"@ZkO'o'@ZH{@ZkO'o'Zxo!ȃ{"/"_"""@Zk!O'o'Zxo!"ȃ{ȅ/"_"""@Zk!#"FB%N!GvO'o'Zxo!{"Ӆ/"K"@Zk!o&s"G, "?"@Sk%,N!O'o'Z&{s"< "?"@Zk%N!D?#@@O'E0ZAo's&s"?"8{@Zk%M!O'o'0Zo&8{0s"?"@ZkO'd o'Z{o'` "?"{@Zk%pM!O'o'0Zo&?s"8{?"@ZkGUCD 1@29 BO'DE0ZAo's&s"8{?"@Zk%M!O'o'0Zo&Ys"8{?"@ZkO'o'@Z BDEH{@Zko&s"xo! "?"@Sk%L!&"<蔢GFBD"1@@89BO'o'@ZBDH{@Zko&s"xo!$ "?"@Sk%HL!O'?'uH ?G/9'Ko'&XKs"F?,KO' 9C{Z( "?"@Zk%HH!O'o'4 Z0 "{o'?"{@Zk%H!O'o'0Zo&8{s"?"@Zk + _"#BD@"\@a1 B@K_KK 91C+B$KD@BD# ;@? H.2&HO'P JFJ0F>p HAB .k" _F2GJQ Jo'F ><k&Zs" RB{8 "?"@Zk%G!O'D &Zto'@ "?"{@Zk%F!O'o'0Zo&s"8{?"@Zk + _#"BD@a"U@9 C@O'Ko'@ZH{@Zk xo!&1C,+0rHQ J0+QF,+k`O'o'@ZH{@Zk 41ChK #"/zKP#+"Y"K#YG"?iK pbK/@#\KF?K #"K Kb.tBJ5GJSbJJFb>~K zKB"/ F5JY"K BYG"?lK bK qK.PJ0F>K@K ".ubJTJF>O'h #P o'Z&s"{L "?"@Zk%D!O'X /'Zyo'T "?"{@Zk%D!O'o'0Zo&Hs"8{?"@Zk _#`/|@KD"O'[`Khk"G`? rJ ."o'\ "Q JQF > ?"``&Zs"{@Zk%(D!O'&h Zo'ud "?"{@Zk%C!O'o'0Zo&8{s"?"@Zk -K/, #,+/o'_"0+Z XKȃ{8K"YGO'"Z, "@Zk3m/lk# HO'\ KO&Fm?|H+"l .PJo'Gl >| "p+?"Zr{@Zk%(C! D 1@`A#"8/zJ49`BY8KYG8?#k/ HO'\ KO&F?|H+" .o'P JG > "+?"Zr{@Zk%B!Dk "?"0`B8`Bo&xs"@Sk%XB!O''Zxo' "?"{@Zk%(B!O'o'0Zo&s"8{?"@Zko&@s" "?"@Sk%A!DYA N#AG^CzG..A"rHQ0J"1@QF.>!bA.#A8/J!zJY8K39@YG8?û Ab` @1A< @E!FO'o'Z1F{fA2 BN"1""@ZkO'o'Z3 n@)n@{?""IA"_"@Zk.#!G>CD@BYG/n#pHn"\K)EF? 0 AaFO'o'pZsF8 Bx{_"?""@Zk#GCD@B8Gn/N#|H[zKN"Gn?)E 0 AAFO' 1@Zo' 0@49@ȃ{`ARF!@A8B8@_""".""5 @A@Zk @GG @JEJO' o'Z&{Ps" "?"@Zk%?! @<A: @EGO'0 `CZo'fAG{1"N""@ZkK*n@1 n@E4AFO'o'ZF5 rB{ "+"N"@ZkKJE D&1@@@O'o'ZCȃ{ HA(1@fA<9@ A2 A19B"_"".""@Zk @aFsF @E7 ! # ! H(/;H#fKY (KgCYG(?yH GH/;gK& {CZHKo':GH?O's"{Z "?"@Zk%0>!O'O& Zo'r "?"{@Zk%=!O'o'0Zo&8{s"?"@Zki$k gB @gBM+ $KKkE` # @ ! H(.3HO'fJQ (J`BQF(>qH FH.3gJ"o'RHJ sB2FH>&Zs"?"{ "@Zk%=!O'& Zo'u "?"{@Zk%tSJ.UJF>,y/Y/[ yKYKzGCK.+. "R PJ0JQF@_$ 5/_"/@/Y 5KKZ @K8G JzG@?zJ`/[`K[G`?<..Q CYG o!o&+s"0EQ JrH+4 "QF+?"<aC.A@Sk%1!o& s"#..U JJ F`Bko&s"< "?"@Sk%1!D.#!G>CYGo&s"0An!8AT˱L "?"@Sk%D1!E DAB ] / 1 AKD @\"X K HHC8G] ?xHo'\+/4 hB29 A?"Y5Kd "G\+?`KO'{o'Z{@Zk%0!)E (AD0@8B 0C8C K#k//9 B8`BzK\ K2 (AGME  B*vH1 B3AaFO'+o'ZsF4 JB{N")B"@Zk E9A!G: CO'o'Z9G{ "+"N"@Zk O'MJEEZgCo'(1A HBȃ{3 HB19B."B"_"" GA@Zk @F ./k#  @+P JKF8CF @8C O&R".r.T JrJF@BK )E 5A0 AKC8 ARo&xs"t "?"@Sk%.! o&xs"| "?"@Sk%.!+ L2 M8!m4m_F0MCJ,-FM6@J$( FpFBm `7J@AFNBSkO'o'Z{@Zk#"FB%.!GU,Po!K9Z@K{H+zGK+.+JAK.o&&s"RKJK>4 "T?"@Sk%-!&O''Uo'Z "x?"{@Zk%X-!O'/' Zo'y "?"{@Zk%$-!O'o'0Zo&8{s"?"@Zko&s" "?"@Sk%,!0HO'JlzB|H F[`K0JGlz BO'+o'Z "ȃ{8""_"@ZkO'O&Zo'r "?"{@Zk%d,!O'o'ZD{@H"_"?""@Zk5@AO' 1@Zo'`A59@{">1"8K"@Zk5O'o'`Z?"h{"1F@Zk@GGD9H:$HH'KzG 9C'CFYKCKð'CGFGG<YKCKKQG?B8 F1'J 1BKDG@FD$1@49`BDE_GC_#.#!G>C%+!yG.JMm!_FCJ F6@JFp F.B`7J.@A?FN.BSkO'o'Z{@Zk#N"AF^B%*!F 8/8K mD/K[C-Q@1  _G_##GC% *!8GLz/zK  D0.0JC@mS@_G_##GC%)!8GL#!zC < 0.0JmD.JSB X@Y @_,A<@#v@HC@-_DQ.QJB3`_#TT@4!//"Y 5KK8GB'` @$@#v@HC@-_DQ.QJB`_#TT@ //"Y 5KK8GB`O'' Zx|o'?"({@Zk%d(!O'o'@ZH{@ZkO'o'@ZGH{@Zk -0..0JJ2H3gJ SB X@O'o'@ZH{@ZkO',o'@ZH{@ZkLo' Z@O'H{@Z@Zk#n#aG~C%'!Go! ?  0B @8B@D+GlFk "?"usBTBBADTDG@Do&GT G\K@GPF|:GKs" ZC@Sk%'! ? @DQK@RK@SK@1rs=`BUK@?#u# #C@DK@ o&s" "?"@Sk%&! k0`C cCk8`CO'QK@1"(+Zo'&s"?"{$ "@Zk%8&! K@kO'&0ko'Z, "t?"{@Zk%%!O'o'0Zo& s"8{?"@Zk_##GC%%!8GFo! K3@$ EDC&`O'#8o'Z&s"{4 "?"@Zk%\%! +O'O&o'@+< "Z?"r{@Zk%%!O'o'0Zo&8{Ms"?"@ZkcD0`@D b@@fB8B?G @$ E@DD0@D @@fC8B_k_O'&Zuo'8o! "?"{@Zk%d$!O' 'Zxo' "?"{@Zk%0$!O'o'0Zo&s"8{?"@ZkO'o'@ZH{@Zk#.#!G>C%#!yGPo!!,.,J+l.,? L.S lJLJrF HH@!<? @,? @L/'l/?" "LK[ lKzG9&KO'&K+Zo'|{@Zk%<#!O'o'0Zo&8{s"?"@Zk"FB0F.l.L"N/.#T JrJZYKF&H$H( A #/"3gJK8C{JKzGN?'."zJ.Q'J; CJrK#QF'>K"'/Y4KYG'?,. .k..JQ g.gJTBEG/~#'#A{KZYK#zGG?.JD @2&B$=@"`A"#X@C<.D/BGDFA0J6GDD'H6GT@GD@6GD @PFXKyH;gK8G?AB5B {CA.{#0_#/:GKDTJK;gK0zCJ3 zC?FFFuHF>-L/,/ #Z XK8KYG8KKC`,. .#Q "FBGo&s""?"!@Sk%!Mm !_FCJ͠Fm6@J Fp G.C`7J.@A?GN.CSkO'o'Z{@Zk#n#aG~C%!G .,  J 1@ Q@a! `c.C.AS cJCJv`HrF#F! D@/."?#X KJGBP@;fH`.# KD"P J rH0F>pK$.Q$JF$>d.S rJFd>srH.TJtF>D V 1@s.#U J>/XK?b/B/.[ bKBKP JzG pA! RD 7d." uHS dJd>.TJ>/X K8G?xuH$/Y5KG$? " 1@?b/D"/ rH.bK\ KP JG DK0F>pDK$.Q$JF$>d.S rJFd>srH.TJtF>!  uXMm !_FCJMF6@Jm Fp G.C`7J.@A?GN.CSkO'o'Z{@ZkN#AG^CzG#1KG!FO'F_"NFpZ Fo'o&s"Fx{"?"!_"@Zk%!PF`., XJ4#"FB%!Gu?#O'9'KZ#<C.Ko&qzKPJ\s"`o!0F>2 C "?"@Sk%P!_#"FB%D!G,lo!K9{HZ@K+zGKo&tR""O'M?#pso'"_ mf"?"  . !Z{@Zk%<!N#AG^CzG&O'α # "_"DtNo'Z"!{?"@Zk%!"FBG-#.L'#"NO'h|Dno'Z!?"{@Zk%!,._",JBA` ?"FBG.#.N#NlO'#f"nZo'"?"!{@Zk% !N..."mR PJ0J3v`JQFB.//" LY 5KKz/8G J[ zKGz?{J/\K|G? , Q. JR QJrFQ>rJq.SqJSFq>BDM(!m$͠_FCJFm6@J MFpF B`7J@AFNBSkO'o'Z{@ZkD"FBGO'/'Z#D!?"l٠ ". GB@Zkm/S_#|MK[mK&Gm?t/&_  p1 -l.lJ2GJ@"FBG-#M#.NO'l#f""nZo'?"!{@Zk%! " ,"-l.lJTB L/#LK;C O'Z#?" ". GB@Zk?"-M"M _ ."JuB , LM/"KpC L@lm.#JB L@n#aG~CG "-".O'L"o'f"NZ"?"{!@Zk%!"FBGM#NO'α.#.#nZo'&s""{?"!@Zk%\!O'o'@ZH{@Zk`#GCFO'Z#?" "`!. GB@Zkm.T?"M"t2JSrJ&Fm>'t_  p L/LK9'K l`"FB0FO'α"N"Nm"nZo'&s""{?"!@Zk%T!O'o'@ZH{@ZkP"FBGO'Z#`!?" ". BG@Zkm/U?#M#[zK|:K&Gm?/&tm"M"' O'p1"o'"-_ n?"N  lxZ!{@Zk%x!.#!G>CYGO'α_"Nn#n#Zo'&s""{?"!@Zk%!O'o'@ZH{@ZkpE57JqE!5F 5JN"4G F EkpE97 KqE9F9#K!9' " EN F4G.nNkpE<7KqE 1!BrF3BJ /FrF3DJ;BrFG`QK`[K2F;F0>k0.\KS[JGQ;J?3F0>krFF3DJ`qCp/[pKrFSPJ1$B{Fp?#F  F `P>B;bC`P>BG`P>B p/RQJ[qKrGp?kP>1$BP>P> P>B? 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p 0$v$jV1.1May 18 1993 12:51:35 ZMENU_SCROLL01 E)iCGOCGO@@ACGOCGO@@A@jgjj"jj$jFjzPjjjjjnj^jzkk!k6*kR,kV|kkkkkJkkkkkkk*k.kBk~kkkk kJ k^ k l l l l $l (l -l2 7lZ :l^ Ol Xl bl jl ll" pl& vl> lj l~ l l l l l* l^ lb lv l l l l l l" l& lf l l 9mx>y*>y>!y>py"@~yR@yJAyNAyVAyAyAy.Bz2B zJBz^B!zfB.zvB3zzBKzBNzB\zFC|zzCz~CzCzCzCzDz&DzRDzVDzDzDzDzFEzZE{E {lF"{F7{F:{FM{ G]{.Gb{NGs{Gv{G{G{H{rH{H{H{0I{RI{vI{I{&J{FJ{J|J |J|6K|:K'|K/|K?|LG|.LJ|2LQ|fLX|LZ|L|zM|M|M|M|M|*N|^N|zN|N|N}N }N}N(}VO+}ZO0}bO}P}P}Q}2Q}6Q}BQ}^Q}bQ}nQ}Q}R}NR}~R ~R~R~S&~"S-~RS@~SR~Sa~Tk~>Tv~T~T~T~T~T~ U~xU~U~U~U~U~U~U~V~V~*V~:V~@V~bV~rV~zV~V~V~V~V~VVVW*W$6W*NW7~W=W>WCWPWVXZXa:Xp\Xr~XXX YY#~FAV020.Ak>![VLT00A.GCE]ZMENU_SCROLL.EXE_A2;2(B+Y:YVY^YzYYYY 2Z 4Z VZfZ(nZ-zZ:Z@ZM[O[V2[_>[dB[hJ[kN[rn[zv[[[[ \.\B\j\ǀv\Ӏ\ހ\]^ >^n^&^+^@:_I_L_R_Z_b_h`l:`sB`zv`|`~aa"a.aVazaaaaƁfbρbӁbBcFcc.d6dHdjd'd(d*d@eEeQBeX^e`ehereffjfffff&g(g‚Jghnhhi9iH*jXj]jbjnju&k|nkklllă mɃmӃ.m؃6m݃JmRmmmmmm mmmm&Rn5n8n]JobRogZovoyopp0` !@@ H@P` @8p  @  Ā 1q 0$u @B@@0! ,$@1!@060 00@@86 I{>p  @  0 @ L &L@$00pB8 @( 8x0C @!@E2 80`@`t  3 0C``r ~{( P@<fX` +`( #0CAt!@HA@PP0) ~ p80pBpB X@  0 fP@ "d !Q"!@0I"<20 Ip@ $@Y?L?La |e@oXOx@8 @@ D$a 0@ ,d @r p$U+$U P 4$*T</^+0I $U+TTTD \ H0L`PT X\hPlpptx|`p   0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p            0 @ P ` p          0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TV   0 @ P ` p         @ TIE$SHARE@ FORRTL_TV@ LIBRTL_TVd$dFYkPIEJ6YFF)F BYYfJzYEAFYBVkYI' j'\~4\k*&i!/h4aZI'-J&iZi'#JZ "#JZ-P_Z9"tw}O_k%"!*[Zj&9[I'ThvG[&oj'[ "XcJN[9"cJ[mj_]r~\kq%!J'[i'_ \i&+tv"}:"B\kJ'm\i'_>}_k\I'ـj'.\ j!}~")"~Z"ݡy"~"n\k!^,J'^i'_Bi!~"J}*"IY"~z"^"Z_k~_!p_#~" FԂB%!dG q`I'{j'd\ j!}h~")"`~N""!\k4!(ai&yav"TeG"za9"Vkx%!aI'j'\9z&~}ev"b "Ӂ:""\k~%B-!:#f@EcI'E\A1di'v&u":"R}'_k@%!dI'-j'\Ej&*}uwv"e9"Q_kVe_J':e ej'\Ȅ~ei'"e9"~&\kp}%j+!J'mfi'_fi&wv"}:"&\kbG ׍C%gцDV@%BMgI'DlE2_}hAj'hu&wv":}::")\k|%*'!_J'ji'm_ji&;vv"}m:"*\krJ'!ki'<_boDDE}_kli&KRv"i!"l9"Vk%m!m&,Z1u{'P3<" z @zv=[Zq'wO3Z/w8s%?"p[b0qc@1 h?Lk!6J'!_"9$+k{[ZYK#GF{F/@G'׃zكCC[5m4@)Ooӄ ؚZ~60A #8k#ȃK_b (T"t@Ze I.3GD'Z!P[cD"(@]k&v3gS9`Un)a&` (lyb30kԾt!&b F|J i"F—.%.x8" ;B{[Hk{H|+^#zW=KP [>8n0j$ )3@fG F'OBc&5 *b0v":x2pr%EpO'g0 n&8@s"C"Z2$`?=B3@JFhK_#(W YK8 k#jdP_K->m1?.HU '(lC{Z( "?"@Zk%HH!O'o'4 Z0 "_]\ \o&8{s"?"@Zk + _"#BDW@"\@ a1 BH@KXKK 91C+B$KD@BD# ;@? H.2&HO'P JFJ0F>p HAB .k" _F2GJQ Jo'F ><k&Zs" RB{8 "?"@Zk%G!O'D &Zto'@ "?"{@Zk%F!O'o'0Zo&s"8{?"OZk + _#"BD@a"U@9 C@O'Ko'@ZH{@Zk xo!&1C,+0rHQ J0+QF,+k`O'o'@ZH{@Zk 41ChK #"/zKP#+"Y"K#YG"?iK pbK/@#\KF?K #"K Kb.tBJ5GJbJJFb>~K zKB"/ F5JY"K BYG"?lK bK qK.PJ0F>K@K ".ubJTJF>O'h #P o'Z&s"{L "?"@Zk%D!O'X /'Zyo'T "?"{@Zk%D!O'Oj'ZIj&(s"h~?"T_k YZ#`/ EKD"O'Y`Kxn"KGle?I Jp .x"o'$"Q JmTF` >tx ?"ewz&ZLgv"{_kj%!dJ' &0Zj'pu"?"{@Zk%C!H'h']5h&x|t"c8"p@]k쳽L/ #,/h'X", _KȂ|?K"7^GGH'x"]\ "A]k/l# HH' KH& FM?LH,"< .0Jwh'G > ",8"]tu|C]k%@!<SDp2@xgA#"?/J:gB?K^G??+x#l/HGH' KeH&lF ?H\,"8 .h' JGx > ", 8" ]uH|`E]k%G!DBlt "8"5gB>gB&h&Ht"@FTk%8D!cH'']h'| "8"|G]k%E!7H'Gh'`]eh&t"|8"G]kh&t"d "8"GTk%I!( DQAZ'I#zFG YC^ }Go).AO " H7J9@ VF)>!8 eA0 .#LA` ?/ J !J ?K0@ ^G ??N K Ab g0 @ A @PEN&Fg H'w h']6F(| aAB I"6""K]k H'' h']si@y i@؃|8"e"IAOx"?X"K]k)#&G9CD @(B^G/i# Hi" K.EF??<'AfF H' h'`]. tF"5'B8|X"8""M]ko #G C D@B. ?Gi/I#\Hk}KI"K Gi?` .E>'AFFH'?@]h'>@7@Ȍ|gA. UFGAQ7BC7@X""~x")"V"GAO]k'@G G'@MEj7H' Wh'p]ox&|t"d "8"P]k*%X/!@<A*@;E.GGH'`gC]wh'aAG(|L6"I"/"Q]kL*i@!i@3EA^FWH'gh']FuB(| "<,"I"R]kLME 0D"@[@P@gH'wh'@]Ch|OA"@aA*@A2A!-Bx"X""P)""pT]k'@fFtF'@E$ ! #  !HQ//[H#aK/K`C^G/?HxGO/;`Kix&;|CjOKGh'J=G`O?wH'\t"|] "8"V]k %0)!'H'5H& @]gh'u` "8"|W]k:%,*!H'h'0]h&|t"C8"PX]k Tl`B@`B, '$LL(lugH #@qL J !RH/.HH'saJ/JgBVF!/>AHSxFPO.S`J"h'OJtB5FO><ex&]t"8"8| "@[]k%x&!dH'&T ]h'pr "8"|\]k% !GH'Wh'P]uh&|t"8"\]k,0 ,#?CL !#{?C@@`a@9ô쳄LlH'&h'uB 4uB ] "r`8"h|^]kj%"! C,CH''h'0]|`_]kp#i#fGyCJ%#!G7&h!7J G H'W h'p]_x&|t" " 8"`]k*%X! O'O& Zo'r\ "?"2$*%;!O'o'0Zo&8{s"?"@Zko&O'Ps& FtaC*"fJ@,ko'Z?"u$ "{@Zk%X;!LeWTCxV Zo'xX "?"{@Zk \\% pcخõ/ϹycytL\_]\ ڣ\\|\w|\]]2ޔjXFBDJF GJ8 j WFDPFt J~ B gꗷJ GްAИF BSkO'o'Z{@Zk@#"P%9!GN o&xs"(o!$ "?"@Sk%T9!,FO\TjVV .`/!.@/JQ !J@K[ `Kv HvHzG\0F GH`"Lg HSB o&0s"& + " #|\w|\4Oئٴ'ǸY!jYTM\\ ړسO\_]ط\ \}\/ϵ d.F"f.O'&T JrJo'F2FJP "FJTK?"Zu{@Zk%7!O'o'0Zo&s"8{?"@Zk"F/"&#YK n#aG~CGo&Hs""?"!@Sk%T7!Mm,!$͠_FCJ(mF6@JmFpF BM `7J@AFNBSkO'o'Z{@Zk#N"AF^B%6!F $ o! / KD7KG N#AG^CzGo&s""?"!@Sk%`6!$. k" .T J.Q JJvH0FG2H8vHFJ SJF>tSJ.UJF>,y/Y/[ yKYKzGCK.+. "R PJ0JQF@_$ 5/_"/@/Y 5KKZ @K8G JzG@?zJ`/[`K[G`?<..Q CYG o!o&+s"0EQ JrH+4 "QF+?"<aC.A@Sk%1!o& s"#..U JJ F`Bko&s"< "?"@Sk%1!D.#!G>CYGo&s"0An!8AT˱L "?"@Sk%D1!E DAB ] / 1 AKD @\"X K HHC8G] ?xHo'\+/4 hB29 A?"Y5Kd "G\+?`KO'{o'Z{@Zk%0!)E (AD0@8B 0C8C K#k//9 B8`BzK\ K2 (AGME  B*vH1 B3AaFO'+o'ZsF4 JB{N")B"@Zk E9A!G: CO'o'Z9G{ "+"N"@Zk O'MJEEZgCo'(1A HBȃ{3 HB19B."B"_"" GA@Zk @F ./k#  @+P JKF8CF @8C O&R".r.T JrJF@BK )E 5A0 AKC8 ARo&xs"t "?"@Sk%.! o&xs"| "?"@Sk%.!+ L2 M8!m4m_F0MCJ,-FM6@J$( FpFBm `7J@AFNBSkO'o'Z{@Zk#"FB%.!GU,Po!K9Z@K{H+zGK+.+JAK.o&&s"RKJK>4 "T?"@Sk%-!&O''Uo'Z "x?"{@Zk%X-!O'/' Zo'y "?"{@Zk%$-!O'o'0Zo&8{s"?"@Zko&s" "?"@Sk%,!0HO'JlzB|H F[`K0JGlz BO'+o'Z "ȃ{8""_"@ZkO'O&Zo'r "?"{@Zk%d,!O'o'ZD{@H"_"?""@Zk5@AO' 1@Zo'`A59@{">1"8K"@Zk5O'o'`Z?"h{"1F@Zk@GGD9H:$HH'KzG 9C'CFYKCKð'CGFGG<YKCKKQG?B8 F1'J 1BKDG@FD$1@49`BDE_GC_#.#!G>C%+!yG.JMm!_FCJ F6@JFp F.B`7J.@A?FN.BSkO'o'Z{@Zk#N"AF^B%*!F 8/8K mD/K[C-Q@1  _G_##GC% *!8GLz/zK  D0.0JC@mS@_G_##GC%)!8GL#!zC < 0.0JmD.JSB X@Y @_,A<@#v@HC@-_DQ.QJB3`_#TT@4!//"Y 5KK8GB'` @$@#v@HC@-_DQ.QJB`_#TT@ //"Y 5KK8GB`O'' Zx|o'?"({@Zk%d(!O'o'@ZH{@ZkO'o'@ZGH{@Zk -0..0JJ2H3gJ SB X@O'o'@ZH{@ZkO',o'@ZH{@ZkLo' Z@O'H{@Z@Zk#n#aG~C%'!Go! ?  0B @8B@D+GlFk "?"usBTBBADTDG@Do&GT G\K@GPF|:GKs" ZC@Sk%'! ? @DQK@RK@SK@1rs=`BUK@?#u# #C@DK@ o&s" "?"@Sk%&! k0`C cCk8`CO'QK@1"(+Zo'&s"?"{$ "@Zk%8&! K@kO'&0ko'Z, "t?"{@Zk%%!O'o'0Zo& s"8{?"@Zk_##GC%%!8GFo! K3@$ EDC&`O'#8o'Z&s"{4 "?"@Zk%\%! +O'O&o'@+< "Z?"r{@Zk%%!O'o'0Zo&8{Ms"?"@ZkcD0`@D b@@fB8B?G @$ E@DD0@D @@fC8B_k_O'&Zuo'8o! "?"{@Zk%d$!O' 'Zxo' "?"{@Zk%0$!O'o'0Zo&s"8{?"@ZkO'o'@ZH{@Zk#.#!G>C%#!yGPo!!,.,J+l.,? L.S lJLJrF HH@!<? @,? @L/'l/?" "LK[ lKzG9&KO'&K+Zo'|{@Zk%<#!O'o'0Zo&8{s"?"@Zk"FB0F.l.L"N/.#T JrJZYKF&H$H( A #/"3gJK8C{JKzGN?'."zJ.Q'J; CJrK#QF'>K"'/Y4KYG'?,. .k..JQ g.gJTBEG/~#'#A{KZYK#zGG?.JD @2&B$=@"`A"#X@C<.D/BGDFA0J6GDD'H6GT@GD@6GD @PFXKyH;gK8G?AB5B {CA.{#0_#/:GKDTJK;gK0zCJ3 zC?FFFuHF>-L/,/ #Z XK8KYG8KKC`,. .#Q "FBGo&s""?"!@Sk%!Mm !_FCJ͠Fm6@J Fp G.C`7J.@A?GN.CSkO'o'Z{@Zk#n#aG~C%!G .,  J 1@ Q@a! `c.C.AS cJCJv`HrF#F! D@/."?#X KJGBP@;fH`.# KD"P J rH0F>pK$.Q$JF$>d.S rJFd>srH.TJtF>D V 1@s.#U J>/XK?b/B/.[ bKBKP JzG pA! RD 7d." uHS dJd>.TJ>/X K8G?xuH$/Y5KG$? " 1@?b/D"/ rH.bK\ KP JG DK0F>pDK$.Q$JF$>d.S rJFd>srH.TJtF>!  uXMm !_FCJMF6@Jm Fp G.C`7J.@A?GN.CSkO'o'Z{@ZkN#AG^CzG#1KG!FO'F_"NFpZ Fo'o&s"Fx{"?"!_"@Zk%!PF`., XJ4#"FB%!Gu?#O'9'KZ#<C.Ko&qzKPJ\s"`o!0F>2 C "?"@Sk%P!_#"FB%D!G,lo!K9{HZ@K+zGKo&tR""O'M?#pso'"_ mf"?"  . !Z{@Zk%<!N#AG^CzG&O'α # "_"DtNo'Z"!{?"@Zk%!"FBG-#.L'#"NO'h|Dno'Z!?"{@Zk%!,._",JBA` ?"FBG.#.N#NlO'#f"nZo'"?"!{@Zk% !N..."mR PJ0J3v`JQFB.//" LY 5KKz/8G J[ zKGz?{J/\K|G? , Q. JR QJrFQ>rJq.SqJSFq>BDM(!m$͠_FCJFm6@J MFpF B`7J@AFNBSkO'o'Z{@ZkD"FBGO'/'Z#D!?"l٠ ". GB@Zkm/S_#|MK[mK&Gm?t/&_  p1 -l.lJ2GJ@"FBG-#M#.NO'l#f""nZo'?"!{@Zk%! " ,"-l.lJTB L/#LK;C O'Z#?" ". GB@Zk?"-M"M _ ."JuB , LM/"KpC L@lm.#JB L@n#aG~CG "-".O'L"o'f"NZ"?"{!@Zk%!"FBGM#NO'α.#.#nZo'&s""{?"!@Zk%\!O'o'@ZH{@Zk`#GCFO'Z#?" "`!. GB@Zkm.T?"M"t2JSrJ&Fm>'t_  p L/LK9'K l`"FB0FO'α"N"Nm"nZo'&s""{?"!@Zk%T!O'o'@ZH{@ZkP"FBGO'Z#`!?" ". BG@Zkm/U?#M#[zK|:K&Gm?/&tm"M"' O'p1"o'"-_ n?"N  lxZ!{@Zk%x!.#!G>CYGO'α_"Nn#n#Zo'&s""{?"!@Zk%!O'o'@ZH{@ZkpE57JqE!5F 5JN"4G F EkpE97 KqE9F9#K!9' " EN F4G.nNkpE<7KqE 1!BrF3BJ /FrF3DJ;BrFG`QK`[K2F;F0>k0.\KS[JGQ;J?3F0>krFF3DJ`qCp/[pKrFSPJ1$B{Fp?#F  F `P>B;bC`P>BG`P>B p/RQJ[qKrGp?kP>1$BP>P> P>B? 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0 @ P ` p  0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p 0@P`p  0 @ P ` p 0$v$jV1.1May 18 1993 12:51:35 ZMENU_SCROLL01 E)iCGOCGO@@ACGOCGO@@A@jgjj"jj$jFjzPjjjjjnj^jzkk!k6*kR,kV|kkkkkJkkkkkkk*k.kBk~kkkk kJ k^ k l l l l $l (l -l2 7lZ :l^ Ol Xl bl jl ll" pl& vl> lj l~ l l l l l* l^ lb lv l l l l l l" l& lf l l 9mx>y*>y>!y>py"@~yR@yJAyNAyVAyAyAy.Bz2B zJBz^B!zfB.zvB3zzBKzBNzB\zFC|zzCz~CzCzCzCzDz&DzRDzVDzDzDzDzFEzZE{E {lF"{F7{F:{FM{ G]{.Gb{NGs{Gv{G{G{H{rH{H{H{0I{RI{vI{I{&J{FJ{J|J |J|6K|:K'|K/|K?|LG|.LJ|2LQ|fLX|LZ|L|zM|M|M|M|M|*N|^N|zN|N|N}N }N}N(}VO+}ZO0}bO}P}P}Q}2Q}6Q}BQ}^Q}bQ}nQ}Q}R}NR}~R ~R~R~S&~"S-~RS@~SR~Sa~Tk~>Tv~T~T~T~T~T~ U~xU~U~U~U~U~U~U~V~V~*V~:V~@V~bV~rV~zV~V~V~V~V~VVVW*W$6W*NW7~W=W>WCWPWVXZXa:Xp\Xr~XXX YY