From: SMTP%"marshall@nebula.decnet.lockheed.com" 19-JUL-1993 15:04:28.84 To: EVERHART CC: Subj: Re: request for free network backup software Date: Mon, 19 Jul 93 11:50:28 -0700 Message-Id: <9307191850.AA24503@eagle.is.lmsc.lockheed.com> From: marshall@nebula.decnet.lockheed.com (Bob Marshall Org 6791 Bldg 561 x65737) To: "EVERHART@arisia.gce.com"@eagle.decnet.lockheed.com Subject: Re: request for free network backup software OK, let's try it again, with the meaty parts included. By the way, the routines I changed were ZT2.C and ZTNS2.C; search for the string "Marshall". I added a $QIOW write in ZTNS2 and a corresponding $QIOW read in ZT2. Should be simple for a C programmer, but not for a FORTRAN programmer (since handling strings in FORTRAN is trivial, but not so in C, at least for me). Also, I changed the variable maxunits from 1 to 4 in ZTDRIVER.MAR, and I fixed a few typos in ZTSERVER.MAR (you had "DCS" instead of "DSC" in a few places, I think). Bob Marshall marshall@nebula.ssd.lmsc.lockheed.com $! ................... Cut between dotted lines and save. ................... $!........................................................................... $! VAX/VMS archive file created by VMS_SHARE V06.10 7-FEB-1989. $! $! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from $! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au). $! $! To unpack, simply save, concatinate all parts into one file and $! execute (@) that file. $! $! This archive was created by user MARSHALL $! on 19-JUL-1993 11:47:49.61. $! $! ATTENTION: To keep each article below 31 blocks (15872 bytes), this $! program has been transmitted in 10 parts. You should $! concatenate ALL parts to ONE file and execute (@) that file. $! $! It contains the following 22 files: $! AAAREADME.TXT $! BUILD.COM $! FEHLER.MAR $! INSTALL.TXT $! IODEF.H $! MTDEF.H $! REDIRECT.C $! RMT.COM $! RMT.DOC $! RMT_OBJECT.COM $! RMT_STARTUP.COM $! UCBDEF.H $! ZT.WRITEUP $! ZT2.C $! ZT2.COM $! ZT2_FORCEX.FOR $! ZTDEF.MAR $! ZTDRIVER.MAR $! ZTDRIVER.OPT $! ZTNS.H $! ZTNS2.C $! ZTSERVER.MAR $! $!============================================================================ $ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL ) $ VERSION = F$GETSYI( "VERSION" ) $ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK $ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", - "VMS_SHARE V06.10 7-FEB-1989 requires VMS V4.4 or higher." $ EXIT 44 ! SS$_ABORT $VERSION_OK: $ GOTO START $! $UNPACK_FILE: $ WRITE SYS$OUTPUT "Creating ''FILE_IS'" $ DEFINE/USER_MODE SYS$OUTPUT NL: $ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION - VMS_SHARE_DUMMY.DUMMY b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) ) ; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE , b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors := 0; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN & "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION ( BEGINNING_OF( b_part ) ); LOOP EXITIF SEARCH( SPAN( ' ' )@r_trail & LINE_END, FORWARD) = 0; POSITION( r_trail ); ERASE( r_trail ); ENDLOOP ; POSITION( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK ( NONE ) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 ) ; IF s_x = '+' THEN r_skip := SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip <> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF ; ENDIF; IF s_x = '-' THEN r_skip := SEARCH( pat_end, FORWARD, EXACT ) ; IF r_skip <> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip := MARK( NONE ); r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip <> 0 THEN POSITION( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET ) ; MOVE_VERTICAL( 1 ); MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part ) ); ENDIF; ERASE( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF ; IF s_x = 'V' THEN s_x := ''; IF i_append_line <> 0 THEN APPEND_LINE ; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1 ; MOVE_VERTICAL( 1 ); ENDIF; IF s_x = 'X' THEN s_x := ''; IF i_append_line <> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF ; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> '' THEN i_errors := i_errors + 1; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT ( "The following line could not be unpacked properly:" ); SPLIT_LINE ; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL ( 1 ); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH ( "`", FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER( 1 ); COPY_TEXT( ASCII( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDLOOP ; IF i_errors = 0 THEN SET( NO_WRITE, b_errors, ON ); ELSE POSITION ( BEGINNING_OF( b_errors ) ); COPY_TEXT( FAO ( "The following !UL errors were detected while unpacking !AS", i_errors , s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors, "SYS$COMMAND" ) ; ENDIF; EXIT; $ DELETE VMS_SHARE_DUMMY.DUMMY;* $ CHECKSUM 'FILE_IS $ WRITE SYS$OUTPUT " CHECKSUM ", - F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!!,passed." ) $ RETURN $! $START: $ FILE_IS = "AAAREADME.TXT" $ CHECKSUM_IS = 1262437492 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY XThis area contains Wolfgang Moeller's remote magtape driver with Xmods for VMS 5.4 and up. This allows you to have a tape somewhere Xacross your DECnet acting as though it were locally connected, so Xthat you can perform copies, backups, etc., over the network. A Xdriver, local control program that talks to the driver, and remote Xnetwork server that talks to the magtape and the local control Xprogram (across the net) are present. X My update to Moeller's driver is in ztdriverm.mar and ztserverm.mar Xwhich are attempts at a multi-unit driver. The server expects to Xtranslate a logical ZTAPE which must contain the name of the ZTAn: Xunit that it is expected to get to. The remote program that accesses Xthe tape still does not get into kernel mode to read the tape Xposition for the real tape. What I expect is that a DECnet object Xthat runs each ZT unit on a machine does an assign to logical ZTAPE Xbefore running the ztns2 program so the server will find the correct Xzt unit on the machine that needs remote tapes. X ZTdriver works nicely on VMS 5.4 and 5.5. XGlenn Everhart X X6/7/93 : Additional mods added by Bob Marshall : X Xo Added RMT.COM to be run by the user on the "ZT" side (i.e., the side X without the tape drive). Automates use of the software. Xo Added RMT_OBJECT.COM, and DECNET object that resides on the side with X the real tape. RMT.COM communicates with RMT_OBJECT.COM. RMT_OBJECT X does everything on the real-tape side, obviating the need for the X user to log into the real-tape side. Xo Modified ZT2.C and ZTNS2.C to pass the name of the ZT device, since X this is a variable piece of information (ZTA0, ZTA1, ZTA2, or ZTA3). Xo Added the FORTRAN (sorry) program ZT2_FORCEX which finds the process X that is running ZT2 and does a $FORCEX on it. X XInstallation instructions in INSTALL.TXT. X $ GOSUB UNPACK_FILE $ FILE_IS = "BUILD.COM" $ CHECKSUM_IS = 135852538 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X$ set noon X$ write sys$output "" X$! X$! Create ZT.MLB X$! X$ write sys$output "Creating ZT.MLB..." X$ lib/macro/create zt.mlb ztdef X$! X$! Create ZTDRIVER X$! X$ write sys$output "" X$ write sys$output - V"Creating multi-unit ZTDRIVER.EXE (ignore 'no user transfer address' message) X" X$ macro ztdriver X$ link ztdriver/opt X$ copy ztdriver.exe sys$common:[sys$ldr] X$! X$! Create ZT2 X$! X$ write sys$output "" X$ write sys$output "Creating ZT2.EXE..." X$ macro ztserver X$ macro fehler X$ if f$search("sys$system:vaxc.exe") .nes. "" then cc redirect X$ if f$search("sys$system:vaxc.exe") .nes. "" then cc zt2 X$ link/nodebug/notrace zt2,ztserver,fehler,redirect,sys$input/opt Xsys$library:vaxcrtl/share X$! X$! Create ZTNS2 X$! X$ write sys$output "" X$ write sys$output "Creating ZTNS2.EXE..." X$ if f$search("sys$system:vaxc.exe") .nes. "" then cc ztns2 X$ link ztns2,fehler,redirect,sys$input/opt Xsys$library:vaxcrtl/share X$! X$! Create ZT2_FORCEX X$! X$ write sys$output "" X$ write sys$output "Creating ZT2_FORCEX.EXE..." X$ if f$search("sys$system:fortran.exe") .nes. "" then fortran zt2_forcex X$ link/notrace/nodebug zt2_forcex X$ type sys$input X XNow edit RMT_STARTUP.COM to specify site-specific information. Then execute XRMT_STARTUP.COM, and remember to also execute IT from SYS$SYSTARTUP. Read`032 XINSTALL.TXT for more information about the steps that need to be taken`032 Xon the ZT-node and on the real-tape node. X $ GOSUB UNPACK_FILE $ FILE_IS = "FEHLER.MAR" $ CHECKSUM_IS = 87885753 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X`009.title`009FEHLER`009abort a program with message & status X; X;`009w.j.m. ??? (FORTRAN version) X;`009change apr 85: do not rely on own msg definition, X;`009`009`009use "shared" msg instead. X;`009`009`009disadvantage: unwinding become unwieldy, X;`009`009`009`009message is output in any case X; X;`009entry:`009FEHLER(string) X; X; X;`009note: this program had to written in MACRO to allow X;`009`009access to the address of the stringdescriptor X;`009`009passed by the calling routine! X;`009 the FORTRAN program included does not work since X;`009 literal strings are passed to it without descriptor!! X; X; X;***** X; X`009.psect`009$LOCAL,pic,usr,con,rel,lcl,noshr,noexe,rd,wrt,novec X; Xfehler_name:`009.ascid`009"FEHLER"`009;.ADDRESS is not (PIC,SHR) !! X; X; X`009.psect`009$CODE,pic,usr,con,rel,lcl,shr,exe,rd,nowrt,novec X; X`009.entry`009fehler,`094m<> X; X;=`009`009subroutine fehler(strdsc) X;=`009`009implicit none X;=`009`009integer*4 strdsc(2)`009! actual argument is character*(*) ! X;=`009c X;=`009`009integer*4 msgvec(4) X;=`009`009external shr$_text X;=`009c X; Xmsgvec=-<4*4>`009;(fp) X; X`009moval`009msgvec(fp),sp X; X;=`009c X;=`009`009msgvec(1)=3 X;=`009`009msgvec(2)=(%loc(shr$_text).and.'0000fff8'x) + 4 + '08000000'x X;=`009c`009`009! # force fatal status X;=`009c`009`009! # fake (user) facility other than "ss$_" X;=`009c`009`009! to allow for $fao argument X;=`009`009msgvec(3)=1`009`009`009! # fao X;=`009`009msgvec(4)=%loc(strdsc)`009`009! need %loc of descriptor here X; X`009movl`009#3,msgvec(fp) X`009movl`009#<!`094x08000004>,msgvec+<1*4>(fp) X`009movl`009#1,msgvec+<2*4>(fp) X`009moval`009@1*4(ap),msgvec+<3*4>(fp) X; X;=`009`009call sys$putmsg(msgvec,,'FEHLER',) X; X`009$putmsg_s`009msgvec=msgvec(fp),- X`009`009`009facnam=fehler_name X; X;=`009`009call lib$stop(%val(msgvec(2).or.'10000000'x))`009! no more output, X;=`009c`009`009`009`009`009`009`009! but ggf. trace X; X`009bisl3`009msgvec+<1*4>(fp),#`094x10000000,-(sp) X`009calls`009#1,g`094lib$stop X; X;=`009`009end X; X`009ret X; X`009.end $ GOSUB UNPACK_FILE $ FILE_IS = "INSTALL.TXT" $ CHECKSUM_IS = 1060396136 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY XIn the discussion below, the node with the actual mag tape device is Xreferred to as the "real-tape" side; the remote node wishing to use the Xdrive is referred to as the "ZT-side". X XBuilding the software (do this on the ZT-side) X---------------------------------------------- X X $ @BUILD X XThings to do on the ZT-side X--------------------------- X X o $ COPY ZTDRIVER.EXE SYS$COMMON:[SYS$LDR] X X o In SYSTARTUP.COM, add these lines somewhere (use RMT_STARTUP.COM X as a template if you wish) : X X $ RUN SYS$SYSTEM:SYSGEN X CONNECT ZTA0/NOADAPTER X CONNECT ZTA1/NOADAPTER X CONNECT ZTA2/NOADAPTER X CONNECT ZTA3/NOADAPTER X EXIT X $ DEFINE/SYSTEM RMT$DIR dev:[dir] X $ INSTALL ADD RMT$DIR:ZT2.EXE/OPEN/HEADER/SHARED/PRIV=CMKRNL X $ INSTALL ADD RMT$DIR:ZT2_FORCEX.EXE/OPEN/HEADER/SHARED/PRIV=WORLD V $ DEFINE/SYSTEM RMT_REMOTE_NODE nodename ! Default Nodename with real-ta Xpe device X $ DEFINE/SYSTEM RMT_REMOTE_TAPE device ! Default remote drive name X X (The two logical names are just used for prompt defaults; the user X can easily override them when prompted) X X o In NCP, define the ZT2 network object : X X $ RUN SYS$SYSTEM:NCP X NCP> SET/DEFINE OBJECT ZT2 NUMBER 141 FILE RMT$DIR:ZT2.COM - X [USER username PASSWORD password] X X (Note : The number 141 is arbitrary; to use a different number just X edit RMT_OBJECT.COM and replace "141" with the desired number) X X o Define a global symbol in SYLOGIN.COM to run RMT.COM : X X $ RMT :== @RMT$DIR:RMT X X XThings to do on the real-tape side X---------------------------------- X X o Copy RMT_OBJECT.COM and ZTNS2.EXE to an appropriate place. Make sure X they have W:RE access or are owned by the username which will run X the RMT_OBJECT DECNET object. X X o In SYS$STARTUP : X X $ DEFINE/SYSTEM RMT$DIR dev:[dir] X X o Add NCP object : X X $ RUN SYS$SYSTEM:NCP X NCP> SET/DEFINE OBJECT RMT_OBJECT NUMBER 142 - X FILE RMT$DIR:RMT_OBJECT.COM - X USER username PASSWORD password X X Notes : X X - The number 142 is arbitrary. To use a different number just edit X the file RMT.COM and specify a different number. X - The username specified for the object must have VOLPRO privilege X in order to make the MOUNT/FOREIGN/MULTI_VOLUME command in`032 X RMT_OBJECT.COM work. For example : X X $ SET DEFAULT SYS$COMMON:[SYSEXE] X $ RUN SYS$SYSTEM:AUTHORIZE X UAF> ADD username/UIC=[g,m]/PASSWORD=password/DEVICE=device- X /DIRECT=[directory]/PRIV=VOLPRO/DEFPRIV=VOLPRO- X /NOBATCH/NOLOCAL/NODIALUP/NOREMOTE/NETWORK X UAF> EXIT X X (The username/password combination must match that specified X in the NCP SET/DEFINE object command) $ GOSUB UNPACK_FILE $ FILE_IS = "IODEF.H" $ CHECKSUM_IS = 242363424 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* X * definitions created by C_GBLINI at 28-DEC-1990 13:48:30.59 X */ X#define`009IO$_NOP`0090 X#define`009IO$_UNLOAD`0091 X#define`009IO$_LOADMCODE`0091 X#define`009IO$_SEEK`0092 X#define`009IO$_SPACEFILE`0092 X#define`009IO$_STARTMPROC`0092 X#define`009IO$_RECAL`0093 X#define`009IO$_DUPLEX`0093 X#define`009IO$_STOP`0093 X#define`009IO$_DRVCLR`0094 X#define`009IO$_INITIALIZE`0094 X#define`009IO$_MIMIC`0094 X#define`009IO$_RELEASE`0095 X#define`009IO$_SETCLOCKP`0095 X#define`009IO$_OFFSET`0096 X#define`009IO$_ERASETAPE`0096 X#define`009IO$_STARTDATAP`0096 X#define`009IO$_RETCENTER`0097 X#define`009IO$_QSTOP`0097 X#define`009IO$_PACKACK`0098 X#define`009IO$_SEARCH`0099 X#define`009IO$_SPACERECORD`0099 X#define`009IO$_READRCT`0099 X#define`009IO$_WRITECHECK`00910 X#define`009IO$_WRITEPBLK`00911 X#define`009IO$_READPBLK`00912 X#define`009IO$_WRITEHEAD`00913 X#define`009IO$_RDSTATS`00913 X#define`009IO$_CRESHAD`00913 X#define`009IO$_READHEAD`00914 X#define`009IO$_ADDSHAD`00914 X#define`009IO$_WRITETRACKD`00915 X#define`009IO$_COPYSHAD`00915 X#define`009IO$_READTRACKD`00916 X#define`009IO$_REMSHAD`00916 X#define`009IO$_AVAILABLE`00917 X#define`009IO$_SETPRFPATH`00918 X#define`009IO$_DISPLAY`00919 X#define`009IO$_DSE`00921 X#define`009IO$_REREADN`00922 X#define`009IO$_REREADP`00923 X#define`009IO$_WRITERET`00924 X#define`009IO$_WRITECHECKH`00924 X#define`009IO$_READPRESET`00925 X#define`009IO$_STARTSPNDL`00925 X#define`009IO$_SETCHAR`00926 X#define`009IO$_SENSECHAR`00927 X#define`009IO$_WRITEMARK`00928 X#define`009IO$_COPYMEM`00928 X#define`009IO$_WRTTMKR`00929 X#define`009IO$_DIAGNOSE`00929 X#define`009IO$_SHADMV`00929 X#define`009IO$_FORMAT`00930 X#define`009IO$_CLEAN`00930 X#define`009IO$_PHYSICAL`00931 X#define`009IO$_WRITELBLK`00932 X#define`009IO$_READLBLK`00933 X#define`009IO$_REWINDOFF`00934 X#define`009IO$_READRCTL`00934 X#define`009IO$_SETMODE`00935 X#define`009IO$_REWIND`00936 X#define`009IO$_SKIPFILE`00937 X#define`009IO$_SKIPRECORD`00938 X#define`009IO$_SENSEMODE`00939 X#define`009IO$_WRITEOF`00940 X#define`009IO$_TTY_PORT`00941 -+-+-+-+-+ End of part 1 +-+-+-+-+- +-+-+-+ Beginning of part 2 +-+-+-+ X#define`009IO$_FREECAP`00941 X#define`009IO$_FLUSH`00942 X#define`009IO$_READLCHUNK`00943 X#define`009IO$_WRITELCHUNK`00944 X#define`009IO$_LOGICAL`00947 X#define`009IO$_WRITEVBLK`00948 X#define`009IO$_READVBLK`00949 X#define`009IO$_ACCESS`00950 X#define`009IO$_CREATE`00951 X#define`009IO$_DEACCESS`00952 X#define`009IO$_DELETE`00953 X#define`009IO$_MODIFY`00954 X#define`009IO$_NETCONTROL`00954 X#define`009IO$_READPROMPT`00955 X#define`009IO$_SETCLOCK`00955 X#define`009IO$_ACPCONTROL`00956 X#define`009IO$_STARTDATA`00956 X#define`009IO$_MOUNT`00957 X#define`009IO$_TTYREADALL`00958 X#define`009IO$_TTYREADPALL`00959 X#define`009IO$_CONINTREAD`00960 X#define`009IO$_CONINTWRITE`00961 X#define`009IO$_VIRTUAL`00963 X#define`009IO$M_FCODE`00963 X#define`009IO$M_FMODIFIERS`00965472 X#define`009IO$M_INHERLOG`0092048 X#define`009IO$M_ERASE`0091024 X#define`009IO$M_ENCRYPT`0098192 X#define`009IO$M_DATACHECK`00916384 X#define`009IO$M_INHRETRY`00932768 X#define`009IO$M_INHSEEK`0094096 X#define`009IO$M_REVERSE`00964 X#define`009IO$M_NOWAIT`009128 X#define`009IO$M_INHEXTGAP`0094096 X#define`009IO$M_MSCPMODIFS`009256 X#define`009IO$M_SHADOW`00964 X#define`009IO$M_LOCATE`009128 X#define`009IO$M_MSCP_FORMAT`00964 X#define`009IO$M_ALLHOSTS`00964 X#define`009IO$M_DISSOLVE`009128 X#define`009IO$M_NOCLEANUP`009256 X#define`009IO$M_SPINDOWN`00964 X#define`009IO$M_FORCEPATH`00964 X#define`009IO$M_STEPOVER`00964 X#define`009IO$M_COPYOP`009256 X#define`009IO$M_EXISTS`00964 X#define`009IO$M_CBS`009128 X#define`009IO$M_BOOTING`009256 X#define`009IO$M_VUEX_FC`009512 X#define`009IO$M_COMMOD`00964 X#define`009IO$M_MOVETRACKD`009128 X#define`009IO$M_DIAGNOSTIC`009256 X#define`009IO$M_SKPSECINH`009512 X#define`009IO$M_DELDATA`00964 X#define`009IO$M_NOMRSP`00964 X#define`009IO$M_SWAP`009256 X#define`009IO$M_OPPOSITE`009512 X#define`009IO$M_CLSEREXCP`009512 X#define`009IO$M_CHUNKDIAG`00964 X#define`009IO$M_TBC`0091024 X#define`009IO$M_ENAREP`00964 X#define`009IO$M_ACCESS`00964 X#define`009IO$M_CREATE`009128 X#define`009IO$M_DELETE`009256 X#define`009IO$M_MOUNT`009512 X#define`009IO$M_DMOUNT`0091024 X#define`009IO$M_REMOUNT`0092048 X#define`009IO$M_MOVEFILE`0094096 X#define`009IO$M_BINARY`00964 X#define`009IO$M_PACKED`009128 X#define`009IO$M_NOW`00964 X#define`009IO$M_READATTN`009128 X#define`009IO$M_WRTATTN`009256 X#define`009IO$M_SETPROT`009512 X#define`009IO$M_NORSWAIT`0091024 X#define`009IO$M_NOECHO`00964 X#define`009IO$M_TIMED`009128 X#define`009IO$M_CVTLOW`009256 X#define`009IO$M_NOFILTR`009512 X#define`009IO$M_DSABLMBX`0091024 X#define`009IO$M_PURGE`0092048 X#define`009IO$M_TRMNOECHO`0094096 X#define`009IO$M_REFRESH`0098192 X#define`009IO$M_ESCAPE`00916384 X#define`009IO$M_EXTEND`00932768 X#define`009IO$M_CANCTRLO`00964 X#define`009IO$M_ENABLMBX`009128 X#define`009IO$M_NOFORMAT`009256 X#define`009IO$M_BREAKTHRU`009512 X#define`009IO$M_NEWLINE`0091024 X#define`009IO$M_TYPEAHDCNT`00964 X#define`009IO$M_MAINT`00964 X#define`009IO$M_CTRLYAST`009128 X#define`009IO$M_CTRLCAST`009256 X#define`009IO$M_HANGUP`009512 X#define`009IO$M_OUTBAND`0091024 X#define`009IO$M_TT_CONNECT`0092048 X#define`009IO$M_TT_DISCON`0094096 X#define`009IO$M_TT_PROCESS`0098192 X#define`009IO$M_BRDCST`00916384 X#define`009IO$M_LOOP`009128 X#define`009IO$M_UNLOOP`009256 X#define`009IO$M_LINE_OFF`009512 X#define`009IO$M_SET_MODEM`0091024 X#define`009IO$M_LINE_ON`0092048 X#define`009IO$M_LOOP_EXT`0094096 X#define`009IO$M_AUTXOF_ENA`0098192 X#define`009IO$M_AUTXOF_DIS`00916384 X#define`009IO$M_INCLUDE`0092048 X#define`009IO$M_TT_ABORT`0094096 X#define`009IO$M_INTERRUPT`00964 X#define`009IO$M_MULTIPLE`009128 X#define`009IO$M_LOCKBUF`009256 X#define`009IO$M_NOBLOCK`009512 X#define`009IO$M_ABORT`009256 X#define`009IO$M_SYNCH`009512 X#define`009IO$M_RESPONSE`00964 X#define`009IO$M_STARTUP`00964 X#define`009IO$M_SHUTDOWN`009128 X#define`009IO$M_ATTNAST`009256 X#define`009IO$M_CTRL`009512 X#define`009IO$M_RD_MEM`00964 X#define`009IO$M_RD_MODEM`009128 X#define`009IO$M_RD_COUNT`009256 X#define`009IO$M_CLR_COUNT`0091024 X#define`009IO$K_SRRUNOUT`0090 X#define`009IO$K_PTPBSC`0098192 X#define`009IO$K_LOOPTEST`00957344 X#define`009IO$M_MORE`00964 X#define`009IO$M_QUALIFIED`009128 X#define`009IO$M_REDIRECT`00964 X#define`009IO$M_ACCEPT`009128 X#define`009IO$M_SETEVF`00964 X#define`009IO$M_WORD`00964 X#define`009IO$M_SETFNCT`009512 X#define`009IO$M_DATAPATH`0091024 X#define`009IO$M_CYCLE`0094096 X#define`009IO$M_RESET`0098192 X#define`009IO$M_SETCUADR`009256 X#define`009IO$M_SETBSIZE`009512 X#define`009IO$M_SETPOOLSZ`0091024 X#define`009IO$M_SETENQCNT`0092048 X#define`009IO$M_CLEAR`0094096 X#define`009IO$M_LPBEXT`0098192 X#define`009IO$M_LPBINT`00916384 X#define`009IO$M_READCSR`00932768 X#define`009IO$M_NOCTSWAIT`00964 X#define`009IO$M_SLAVLOOP`009128 X#define`009IO$M_NODSRWAIT`009256 X#define`009IO$M_MAINTLOOP`009512 X#define`009IO$M_LASTBLOCK`0091024 X#define`009IO$M_INTCLOCK`0094096 X#define`009IO$M_LT_CONNECT`00964 X#define`009IO$M_LT_DISCON`009128 X#define`009IO$M_LT_READPORT`009256 X#define`009IO$M_LT_MAP_PORT`009512 X#define`009IO$M_LT_RATING`0091024 X#define`009IO$M_LT_SOL_INFO`0092048 X#define`009IO$M_LT_RCV_INFO`0094096 X#define`009IO$M_LT_MAP_FILLER`0091 X#define`009IO$M_LT_MAP_NODNAM`0092 X#define`009IO$M_LT_MAP_PORNAM`0094 X#define`009IO$M_LT_MAP_SRVNAM`0098 X#define`009IO$M_LT_MAP_LNKNAM`00916 X#define`009IO$M_LT_MAP_NETADR`00932 X#define`009IO$S_IODEF`0092 X#define`009IO$S_FCODE`0096 X#define`009IO$V_FCODE`0090 X#define`009IO$S_FMODIFIERS`00910 X#define`009IO$V_FMODIFIERS`0096 X#define`009IO$V_INHERLOG`00911 X#define`009IO$V_ERASE`00910 X#define`009IO$V_ENCRYPT`00913 X#define`009IO$V_DATACHECK`00914 X#define`009IO$V_INHRETRY`00915 X#define`009IO$V_INHSEEK`00912 X#define`009IO$V_REVERSE`0096 X#define`009IO$V_NOWAIT`0097 X#define`009IO$V_INHEXTGAP`00912 X#define`009IO$V_MSCPMODIFS`0098 X#define`009IO$V_SHADOW`0096 X#define`009IO$V_LOCATE`0097 X#define`009IO$V_MSCP_FORMAT`0096 X#define`009IO$V_ALLHOSTS`0096 X#define`009IO$V_DISSOLVE`0097 X#define`009IO$V_NOCLEANUP`0098 X#define`009IO$V_SPINDOWN`0096 X#define`009IO$V_FORCEPATH`0096 X#define`009IO$V_STEPOVER`0096 X#define`009IO$V_COPYOP`0098 X#define`009IO$V_EXISTS`0096 X#define`009IO$V_CBS`0097 X#define`009IO$V_BOOTING`0098 X#define`009IO$V_VUEX_FC`0099 X#define`009IO$V_COMMOD`0096 X#define`009IO$V_MOVETRACKD`0097 X#define`009IO$V_DIAGNOSTIC`0098 X#define`009IO$V_SKPSECINH`0099 X#define`009IO$V_DELDATA`0096 X#define`009IO$V_NOMRSP`0096 X#define`009IO$V_SWAP`0098 X#define`009IO$V_OPPOSITE`0099 X#define`009IO$V_CLSEREXCP`0099 X#define`009IO$V_CHUNKDIAG`0096 X#define`009IO$V_TBC`00910 X#define`009IO$V_ENAREP`0096 X#define`009IO$V_ACCESS`0096 X#define`009IO$V_CREATE`0097 X#define`009IO$V_DELETE`0098 X#define`009IO$V_MOUNT`0099 X#define`009IO$V_DMOUNT`00910 X#define`009IO$V_REMOUNT`00911 X#define`009IO$V_MOVEFILE`00912 X#define`009IO$V_BINARY`0096 X#define`009IO$V_PACKED`0097 X#define`009IO$V_NOW`0096 X#define`009IO$V_READATTN`0097 X#define`009IO$V_WRTATTN`0098 X#define`009IO$V_SETPROT`0099 X#define`009IO$V_NORSWAIT`00910 X#define`009IO$V_NOECHO`0096 X#define`009IO$V_TIMED`0097 X#define`009IO$V_CVTLOW`0098 X#define`009IO$V_NOFILTR`0099 X#define`009IO$V_DSABLMBX`00910 X#define`009IO$V_PURGE`00911 X#define`009IO$V_TRMNOECHO`00912 X#define`009IO$V_REFRESH`00913 X#define`009IO$V_ESCAPE`00914 X#define`009IO$V_EXTEND`00915 X#define`009IO$V_CANCTRLO`0096 X#define`009IO$V_ENABLMBX`0097 X#define`009IO$V_NOFORMAT`0098 X#define`009IO$V_BREAKTHRU`0099 X#define`009IO$V_NEWLINE`00910 X#define`009IO$V_TYPEAHDCNT`0096 X#define`009IO$V_MAINT`0096 X#define`009IO$V_CTRLYAST`0097 X#define`009IO$V_CTRLCAST`0098 X#define`009IO$V_HANGUP`0099 X#define`009IO$V_OUTBAND`00910 X#define`009IO$V_TT_CONNECT`00911 X#define`009IO$V_TT_DISCON`00912 X#define`009IO$V_TT_PROCESS`00913 X#define`009IO$V_BRDCST`00914 X#define`009IO$V_LOOP`0097 X#define`009IO$V_UNLOOP`0098 X#define`009IO$V_LINE_OFF`0099 X#define`009IO$V_SET_MODEM`00910 X#define`009IO$V_LINE_ON`00911 X#define`009IO$V_LOOP_EXT`00912 X#define`009IO$V_AUTXOF_ENA`00913 X#define`009IO$V_AUTXOF_DIS`00914 X#define`009IO$V_INCLUDE`00911 X#define`009IO$V_TT_ABORT`00912 X#define`009IO$V_INTERRUPT`0096 X#define`009IO$V_MULTIPLE`0097 X#define`009IO$V_LOCKBUF`0098 X#define`009IO$V_NOBLOCK`0099 X#define`009IO$V_ABORT`0098 X#define`009IO$V_SYNCH`0099 X#define`009IO$V_RESPONSE`0096 X#define`009IO$V_STARTUP`0096 X#define`009IO$V_SHUTDOWN`0097 X#define`009IO$V_ATTNAST`0098 X#define`009IO$V_CTRL`0099 X#define`009IO$V_RD_MEM`0096 X#define`009IO$V_RD_MODEM`0097 X#define`009IO$V_RD_COUNT`0098 X#define`009IO$V_CLR_COUNT`00910 X#define`009IO$V_MORE`0096 X#define`009IO$V_QUALIFIED`0097 X#define`009IO$V_REDIRECT`0096 X#define`009IO$V_ACCEPT`0097 X#define`009IO$V_SETEVF`0096 X#define`009IO$V_WORD`0096 X#define`009IO$V_SETFNCT`0099 X#define`009IO$V_DATAPATH`00910 X#define`009IO$V_CYCLE`00912 X#define`009IO$V_RESET`00913 X#define`009IO$V_SETCUADR`0098 X#define`009IO$V_SETBSIZE`0099 X#define`009IO$V_SETPOOLSZ`00910 X#define`009IO$V_SETENQCNT`00911 X#define`009IO$V_CLEAR`00912 X#define`009IO$V_LPBEXT`00913 X#define`009IO$V_LPBINT`00914 X#define`009IO$V_READCSR`00915 X#define`009IO$V_NOCTSWAIT`0096 X#define`009IO$V_SLAVLOOP`0097 X#define`009IO$V_NODSRWAIT`0098 X#define`009IO$V_MAINTLOOP`0099 X#define`009IO$V_LASTBLOCK`00910 X#define`009IO$V_INTCLOCK`00912 X#define`009IO$V_LT_CONNECT`0096 X#define`009IO$V_LT_DISCON`0097 X#define`009IO$V_LT_READPORT`0098 X#define`009IO$V_LT_MAP_PORT`0099 X#define`009IO$V_LT_RATING`00910 X#define`009IO$V_LT_SOL_INFO`00911 X#define`009IO$V_LT_RCV_INFO`00912 X#define`009IO$V_LT_MAP_FILLER`0090 X#define`009IO$V_LT_MAP_NODNAM`0091 X#define`009IO$V_LT_MAP_PORNAM`0092 X#define`009IO$V_LT_MAP_SRVNAM`0093 X#define`009IO$V_LT_MAP_LNKNAM`0094 X#define`009IO$V_LT_MAP_NETADR`0095 X/* X * end of C_GBLINI definitions X */ $ GOSUB UNPACK_FILE $ FILE_IS = "MTDEF.H" $ CHECKSUM_IS = 1443239590 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* X * definitions created by C_GBLINI at 28-DEC-1990 13:49:01.31 X */ X#define`009MT$M_SEREXCP`0091 X#define`009MT$M_ENAUTOPACK`0092 X#define`009MT$M_ENSEREXCP`0094 X#define`009MT$M_PARITY`0098 X#define`009MT$M_FORMAT`009240 X#define`009MT$M_DENSITY`0097936 X#define`009MT$M_LOGSOFT`00916384 X#define`009MT$M_LOGSOFTOG`00932768 X#define`009MT$M_BOT`00965536 X#define`009MT$M_EOF`009131072 X#define`009MT$M_EOT`009262144 X#define`009MT$M_HWL`009524288 X#define`009MT$M_LOST`0091048576 X#define`009MT$M_SUP_NRZI`0092097152 X#define`009MT$M_SUP_PE`0094194304 X#define`009MT$M_SUP_GCR`0098388608 X#define`009MT$M_SPEED`009(-16777216) X#define`009MT$K_DEFAULT`0090 X#define`009MT$K_NORMAL11`00912 X#define`009MT$K_CORDMP11`00913 X#define`009MT$K_NORMAL15`00914 X#define`009MT$K_NRZI_800`0093 X#define`009MT$K_PE_1600`0094 X#define`009MT$K_GCR_6250`0095 X#define`009MT$K_WOD_6250`0098 X#define`009MT$K_HPC_40K`00912 X#define`009MT$K_HPC_COMP`00913 X#define`009MT$K_XPC_80K`00914 X#define`009MT$K_XPC_COMP`00915 X#define`009MT$K_BLK_833`00917 X#define`009MT$K_BLK_1250`00918 X#define`009MT$K_SPEED_DEF`0090 X#define`009MT$K_SPEED_25`00925 X#define`009MT$K_SPEED_75`00975 X#define`009MT$S_MTDEF`0094 X#define`009MT$V_SEREXCP`0090 X#define`009MT$V_ENAUTOPACK`0091 X#define`009MT$V_ENSEREXCP`0092 X#define`009MT$V_PARITY`0093 X#define`009MT$S_FORMAT`0094 X#define`009MT$V_FORMAT`0094 X#define`009MT$S_DENSITY`0095 X#define`009MT$V_DENSITY`0098 X#define`009MT$V_LOGSOFT`00914 X#define`009MT$V_LOGSOFTOG`00915 X#define`009MT$V_BOT`00916 X#define`009MT$V_EOF`00917 X#define`009MT$V_EOT`00918 X#define`009MT$V_HWL`00919 X#define`009MT$V_LOST`00920 X#define`009MT$V_SUP_NRZI`00921 X#define`009MT$V_SUP_PE`00922 X#define`009MT$V_SUP_GCR`00923 X#define`009MT$S_SPEED`0098 X#define`009MT$V_SPEED`00924 X/* X * end of C_GBLINI definitions X */ $ GOSUB UNPACK_FILE $ FILE_IS = "REDIRECT.C" $ CHECKSUM_IS = 336937157 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/*`009simulate SHELL redirection for VAXC X`009w.j.m. feb 86 X`009fix aug 86 wjm X`009mod apr 87 wjm: allow for ">>" X`009mod 26-may-1990 wjm: use "mbc=16" for efficiency (seq. I/O only!) X Xusage: X X`009main(argc,argv) X`009int argc; char **argv; X`009`123 X`009#ifdef VAXC X`009`009redirect(&argc,&argv); X`009#endif X`009`009... X Xbugs: X`009does not handle redirection of stderr. X X`009overwrites argument vector (*argv). X X*/ X X#include stdio X#include perror X Xstatic myerr(str,flag) Xchar *str; int flag; X`123 X`009extern noshare int vaxc$errno; X X`009fprintf(stderr,"%%-F-REDIRECT, %s\n",str); X`009if(flag) `123 X`009`009exit(vaxc$errno); X`009`125 else`009exit(0x10000004); X`125 X Xredirect(argcp,argvp) Xint *argcp; char ***argvp; X`123 X`009char **av,**nav; X`009int ac,nac; X`009int inx = 0, outx = 0; X X`009av = nav = *argvp; X`009ac = *argcp; X X`009if(ac <= 0) return;`009`009/* no arg, no action */ X X`009av++; nav++; ac--; nac = 1;`009/* 1st arg untouched */ X X`009for( ; ac > 0; av++, ac--) `123 X`009`009switch(**av) `123 X`009`009 case '<': X`009`009`009if(inx++) myerr("double input redirection",0); X`009`009`009if((stdin=freopen(*av+1,"r",stdin,"mbc=16"))==NULL) X`009`009`009`009myerr("cannot redirect stdin",1); X`009`009`009break; X`009`009 case '>': X`009`009`009if(outx++) myerr("double output redirection",0); X`009`009`009if(*(*av+1) == '>') `123 X`009`009`009`009if((stdout=freopen(*av+2,"a",stdout,"mbc=16"))==NULL) X`009`009`009`009`009myerr("cannot redirect stdout",1); X`009`009`009`125 else `123 X`009`009`009`009if((stdout=freopen(*av+1,"w",stdout,"mbc=16"))==NULL) X`009`009`009`009`009myerr("cannot redirect stdout",1); X`009`009`009`125 X`009`009`009break; X`009`009 default: X`009`009`009*nav++ = *av; nac++; X`009`009`125 X`009`125 X X`009/* note: K&R does not say that argv[argc] == NULL */ X X`009*argcp = nac; X`125 $ GOSUB UNPACK_FILE $ FILE_IS = "RMT.COM" $ CHECKSUM_IS = 72105995 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X$! This procedure is used to implement the remote mag tape utility for X$! using a mag tape on the node defined by default by the logical name`032 X$! RMT_REMOTE_NODE. The default remote tape drive to be used is defined`032 X$! by the logical name RMT_REMOTE_TAPE, but the user is given the`032 X$! opportunity to override this. X$! X$! Usage : X$! X$! o Mount the tape on the remote node and put the drive on-line X$! o @dev:[dir]RMT X$! X$! (Gory details at end of procedure) X$! X$! Written by : Bob Marshall X$! 17 May 1993 X$!************************************************************************** X$! X$ set noon X$! X$! First find out if there is a ZT device available; if not, we're out X$! of luck anyway. X$! X$ n = 0 X$! X$ look_for_zt: X$! X$ zt_device = "ZTA" + f$string(n) X$ zt_status = f$getdvi(ZT_DEVICE,"STS") X$ if (zt_status .and. %X10) .eq. %X10 X$ then X$ n = n + 1 X$ if n .le. 3 then goto look_for_zt X$ type sys$input X XAll of the ZT devices are in used at present. Try again later. X X$ exit X$ endif X$! X$ default_remote_node = f$trnlnm("RMT_REMOTE_NODE") X$ write sys$output "" X$ if default_remote_node .eqs. "" X$ then -+-+-+-+-+ End of part 2 +-+-+-+-+- +-+-+-+ Beginning of part 3 +-+-+-+ X$ read/prompt="Name of node with tape drive : " sys$command remote_node X$ if remote_node .eqs. "" then exit X$ else X$ read/prompt="Name of node with tape drive [''default_remote_node'] : " - X sys$command remote_node X$ if remote_node .eqs. "" then remote_node = default_remote_node X$ endif X$ remote_node = remote_node - "_" - "::" ! Strip off "::" just in case X$ remote_node = f$edit(remote_node,"UPCASE") X$! X$ default_remote_tape = f$trnlnm("RMT_REMOTE_TAPE") X$ if default_remote_tape .eqs. "" then default_remote_tape = "MUA0:" X$! X$ write sys$output "" X$ read/prompt="Name of remote tape device [''default_remote_tape'] : " - X sys$command remote_tape X$ if remote_tape .eqs. "" then remote_tape = default_remote_tape X$! X$ write sys$output "" X$ write sys$output - X "Make sure the tape is mounted and ready to go. Then press " X$ read/prompt="when you are ready to continue..." sys$command dummy X$! X$! Open the network link to the remote node X$! X$! (Note : to use an object number other than 142, specify that number here) X$! X$ write sys$output "" X$ write sys$output "Attempting to create network link to ''remote_node'..." X$ open/read/write/err=err_openlink netline 'remote_node'::"142=" X$! X$ this_node = f$trnlnm("sys$node") - "::" - "_" X$ write netline this_node X$ write netline remote_tape X$ write netline zt_device X$ on control_y then goto done X$! X$ write sys$output "" V$ write sys$output "Stand by, ''remote_node' is attempting to mount the tape. X.." X$! X$ k = 0 X$ not_loaded = "FALSE" X$! X$ readloop: X$! V$! Read any output from the remote side, looking for the string "**CONTINUE** X" X$! X$ read/err=err_start_server netline message X$ if f$locate("not software enabled",message) .ne. f$length(message) then - X not_loaded = "TRUE" X$ if message .eqs. "**ERROR**" then goto close X$ if message .nes. "**CONTINUE**" X$ then X$ if message .nes. "" then - X write sys$output "%''remote_node'-I-MESSAGE, ",message X$ k = k + 1 X$! if k .gt. 10 then goto err_start_server X$ goto readloop X$ endif X$! V$! At this point things seem to be OK on the remote side; now just wait for`0 X32 X$! ZTAn: to come on-line. X$! X$ kwait = 0 X$ write sys$output "" X$! X$ wait_for_ztan: X$! X$ write sys$output "Stand by, waiting for ''zt_device' to come on-line..." X$ tape_status = f$getdvi(ZT_DEVICE,"STS") X$ if (tape_status .and. %X10) .ne. %X10 X$ then X$ wait 00:00:05.00 X$ kwait = kwait + 1 X$ if kwait .lt. 20 then goto wait_for_ztan X$ type sys$input X XSomething appears to have gone haywire; bailing out... X X$ goto err_start_server X$ endif X$! X$! OK, ZTAn: is on-line X$! X$ prompt = f$environment("PROMPT") X$ write sys$output "" X$ write sys$output - V"The local drive ''zt_device' is now on-line and ready to use. Please refer t Xo" X$ write sys$output - X"device ''zt_device' in your subsequent commands." X$ write sys$output "" X$ write sys$output - X"A subprocess will be spawned to allow you to use ''zt_device'. You may issue X$ type sys$input Xany necessary commands, e.g., MOUNT, BACKUP, COPY, etc. When you are done Xwith the drive, simply LOGOUT to terminate the subprocess and return control Xto this procedure. X XIMPORTANT : Due to a VMS bug, you should first ALLOCATE the device by issuing X$ write sys$output "the command $ ALLOCATE ''zt_device'." X$ write sys$output "" X$ pid = f$getjpi("","pid") ! Generate a useful process name X$ spawn/prompt="RMT_''prompt'"/process="RMT_''pid'" ! SPAWN X$! X$ done: X$! X$! Clean up (dismount tape, zap ZT2, close the link) X$! X$ set noon X$ write sys$output "" X$ write sys$output "Cleaning up..." X$ if f$getdvi(ZT_DEVICE,"MNT") X$ then X$ write sys$output "Dismounting ''zt_device'..." V$ dismount/nounload 'ZT_DEVICE' ! Remove the /NOUNLOAD after testin Xg`032 X$ endif X$ write sys$output "Terminating the ZT2 program..." X$ zt2_forcex := $rmt$dir:zt2_forcex X$ zt2_forcex RMT_'zt_device' X$ write sys$output "Telling remote node that we are done..." X$ write netline "**DONE**" X$ read/err=continue netline message X$ continue: X$ wait 00:00:05.00 ! Give remote process time to die X$! X$ close: X$! X$ if not_loaded`032 X$ then X$ write sys$output "" X$ write sys$output - X"The message 'Volume is not software enabled' means that the tape was not" X$ write sys$output - X"mounted on ''remote_tape', or the drive was not placed on-line. Please" X$ write sys$output - X"correct the condition and try again." X$ write sys$output "" X$ endif X$ write sys$output "Closing network link..." X$ close netline X$ write sys$output "" X$ exit X$! X$ err_openlink: X$! X$ error_message = f$message($status) X$ write sys$output "" X$ write sys$output - X"%RMT-F-OPENLINK, Error opening network link to ''remote_node'" X$ write sys$output "''error_message'" X$ write sys$output "" X$ exit X$! X$ err_start_server: X$! X$ write sys$output "" X$ write sys$output - X"%RMT-F-NOSTART, Error starting remote tape server on ''remote_node'" X$ write sys$output "" X$ write netline "**DONE**" X$ close netline X$ exit X$!********************************************************************* X$! X$! Gory details : X$! X$! This procedure performs the following tasks in cooperation with a X$! network object on the remote node : X$! X$! o Prompts the user for the name of the remote node, and the name of X$! the remote tape device. X$! o Opens a network link to network object #142 on the node with the X$! tape drive. Object #142 is just a command procedure that does X$! various things, described below. X$! o Waits for the command procedure on the remote side to take the steps X$! necessary to put ZTAn: on-line. X$! o Spawns a subprocess to allow the user to use ZTAn: as he pleases. When X$! the user logs out of the subprocess control is returned to this X$! procedure to allow things to be cleaned up neatly (hopefully). X$! o Cleanup involves dismounting ZTAn if necessary, $FORCEX'ing the process X$! which is running the ZT2 image, telling the other side that we are X$! all done, and then closing the network link. X$! X$! Network object #142 is a command procedure on the remote that performs X$! the following tasks : X$! X$! o Opens a channel on SYS$NET to communicate with this procedure X$! o Checks on the availability of the requested device, i.e., does it exist, X$! and is it unallocated? Bail out if not. X$! o MOUNTs the tape X$! o Runs the server image ZTNS2 as a subprocess. ZTNS2 starts up a network X$! object back on this side that fires up the ZT2 image. When all of this X$! happens, ZTAn: magically comes on-line (hopefully)! X$! o Now the procedure issues a READ on SYS$NET, waiting for a control string X$! that indicates that the other side is done with the drive. It also can X$! detect whether the other side has closed the network link abnormally. X$! o Dismounts the tape, and closes the network link X$! o Logs out, thus killing the subprocess running ZTNS2. $ GOSUB UNPACK_FILE $ FILE_IS = "RMT.DOC" $ CHECKSUM_IS = 91711494 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X(Preliminary documentation for RMT remote magtape utility) X XThe RMT utility allows a user to access a mag tape drive located on a Xcooperating remote DECNET node as if the drive were local. By "cooperating", Xwe mean that the remote node must have the server portion of the RMT Xsoftware installed and operational. In other words, it is not possible to Xaccess tape drives on arbirtrary DECNET nodes, only on DECNET nodes Xthat have the RMT server software installed. X XUsage is fairly straightforward : X V1. Determine the DECNET node name of the remote node (e.g., LSDC), and the`03 X2 X physical name of the tape device you wish to use (e.g., MUA0:) X X2. Physically mount the tape on the drive, and make sure the drive is X on-line and ready to use (or, have an operator do this for you and X let you know when the drive is ready to use). FAILURE TO PREPARE THE X DRIVE BEFORE RUNNING RMT WILL CAUSE RMT TO FAIL. X X3. On the cluster, issue the command RMT at the DCL prompt, e.g., X X $ RMT X X4. You will be prompted for the DECNET node name and the tape device X name. The default values are in brackets, and if you press X at these prompts the default values are taken. X X5. You will be asked to confirm that the tape drive is indeed ready to use. X X6. If all goes well, within about 30 seconds you should get a message like X the following : X X %LSDC-I-MESSAGE, %MOUNT-I-MOUNTED, TEST mounted on MUA0: X X This indicates that the tape was successfully mounted at the remote X node side. This does *not* mean that the tape is mounted on your side; X you will do that manually in the next step. X X7. A subprocess will be spawned and you will be returned to DCL level. At X this point you can issue any commands you'd like, for example, MOUNT, X COPY, BACKUP, etc. IMPORTANT : NOTE THE NAME OF THE TAPE DRIVE; IT IS X USUALLY ZTA0, BUT IF MAY BE ZTA1, ZTA2, ETC. When you are done using`032 V the drive simply log out of the subprocess by issuing a LOGOUT command.`03 X2 X This will return control to the RMT command procedure so that things`032 X can terminate cleanly. X XSample session : X X$ RMT X XName of node with tape drive [LSDC] :`032 X XName of remote tape device [MUA0:] :`032 X XMake sure the tape is mounted and ready to go. Then press Xwhen you are ready to continue... X XStand by, LSDC is attempting to mount the tape... X%LSDC-I-MESSAGE, %MOUNT-I-MOUNTED, TEST mounted on MUA0: X XThe local drive ZTA0: is now on-line and ready to use. Please refer to XZTA0: in your subsequent commands. X XA subprocess will be spawned to allow you to use ZTA0. You may issue Xany necessary commands, e.g., MOUNT, BACKUP, COPY, etc. When you are done Xwith the drive, simply LOGOUT to terminate the subprocess and return control Xto this procedure. X X%DCL-S-SPAWNED, process RMT_20804D4C spawned X%DCL-S-ATTACHED, terminal now attached to process RMT_20804D4C X XRMT_$ SHOW DEVICE ZTA0 X VDevice Device Error Volume Free Trans X Mnt V Name Status Count Label Blocks Count X Cnt XZTA0: (NEBULA) Online 0 X XRMT_NEBULA$ MOUNT ZTA0 X%MOUNT-I-MOUNTED, TEST mounted on _ZTA0: (NEBULA) XRMT_NEBULA$ COPY A.COM ZTA0:[]/LOG X%COPY-S-COPIED, A.COM;7 copied to ZTA0:[]A.COM;7 (6 records) XRMT_NEBULA$ LOGOUT X Process RMT_20804D4C logged out at 19-MAY-1993 14:11:25.28 X%DCL-S-RETURNED, control returned to process ttttrrrrrrrrr X XCleaning up... XDismounting ZTA0... XTerminating the ZT2 program... XTelling remote node that we are done... XClosing network link... X X XNote : To change the default values in the initial prompts, add the X following lines to your LOGIN.COM file : X X$ DEFINE RMT_REMOTE_NODE nodename X$ DEFINE RMT_REMOTE_TAPE device X XFor example : X X$ DEFINE RMT_REMOTE_NODE LSDC X$ DEFINE RMT_REMOTE_TAPE MUA0: X $ GOSUB UNPACK_FILE $ FILE_IS = "RMT_OBJECT.COM" $ CHECKSUM_IS = 325598358 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X$! This procedure is run as a network object to allow a remote DECNET node V$! to use a tape drive located on this node. The following tasks are performe Xd : X$! X$! o Opens a channel on SYS$NET to communicate with an inbound network X$! object request. X$! o Checks on the availability of the requested device, i.e., does it exist, X$! and is it unallocated? Bail out if not. X$! o MOUNTs the tape. X$! o Runs the server image ZTNS2 as a subprocess. ZTNS2 starts up a network X$! object on the other side that fires up the ZT2 image. When all of this X$! happens, ZTAn: magically comes on-line on the other side (hopefully)! V$! o Then the procedure issues a READ on SYS$NET, waiting for a control strin Xg X$! that indicates that the other side is done with the drive. It also can X$! detect whether the other side has closed the network link abnormally, X$! in which case it cleans up neatly. X$! o Dismounts the tape, and closes the network link X$! o Logs out, thus killing the subprocess running ZTNS2. X$!`032 X$! Written by : Bob Marshall X$! 18 May 1993 X$!************************************************************************ X$! X$ set noon X$! X$! Open a channel to SYS$NET X$! X$ open/read/write/err=oh_well netline sys$net X$! X$ define/nolog sys$output netline X$ define/nolog sys$error netline X$! X$! Read three messsages from the remote procedure. The first should be the X$! the name of the remote node, the second should be the name of X$! the tape drive to use, and the third should be the name of the "ZT" X$! device X$! X$ read/end=oops/err=oops netline remote_node X$ read/end=oops/err=oops netline local_tape X$ read/end=oops/err=oops netline zt_device X$! X$ local_tape = local_tape - ":" + ":" ! Add a colon, if necessary X$ zt_device = zt_device - ":" + ":" ! Add a colon, if necessary X$! X$! Make sure the device exists!`032 X$! X$ if .not. f$getdvi(local_tape,"EXISTS") X$ then X$ write sys$output "" X$ write sys$output "%RMT-F-NOSUCHDEV, device ''local_tape' does not exist" X$ write sys$output "" X$ write netline "**ERROR**" X$ goto oops X$ endif X$! X$! Make sure it's not allocated to someone else X$! X$ if f$getdvi(local_tape,"ALL") X$ then X$ write sys$output "" X$ write sys$output - X"%RMT-F-ALLOCATED, device ''local_tape' is allocated to another process" X$ write sys$output "" X$ write netline "**ERROR**" X$ goto oops X$ endif X$! X$! OK, looks like we're cleared for take-off X$! X$ define zt_tape 'local_tape' ! Used by ZTNS2 X$ define zt_device 'zt_device' ! Used by ZT2 on the other side X$! X$! MOUNT the tape; use /NOASSIST so that if the user forgot to physically X$! prepare the drive, even after being warned, then he loses and has to X$! start all over. X$! X$! Note : Remove the /nounload switch when done with testing X$! X$ mount/for/noassist/nounload/multi_volume zt_tape ! Requires VOLPRO priv X$! X$! If the MOUNT failed for any reason, bail out X$! X$ if .not. $status X$ then X$ write/err=oops netline "**ERROR**" X$ goto oops X$ endif X$! X$! Change the next line if a network object number other than 141 is desired. X$! X$ define/nolog zt_netobject "''remote_node'::""141=""" ! Used by ZTNS2 X$! X$! Run the ZTNS2 program as a subprocess. ZTNS2 will create a link to X$! object #141 on the ZT-side, which runs a command procedure to run X$! the ZT2 program. Once this happens, ZTAn: comes on-line on the ZT-side. X$! By running ZTNS2 in a subprocess, we can have control return to this X$! command procedure to communicate via SYS$NET. X$! X$ define/nolog ztape 'zt_device' X$ spawn/nowait/nolog/output=nla0: run rmt$dir:ztns2 X$! X$ wait 00:00:05.00 ! Wait a bit V$ write/err=link_gone netline "**CONTINUE**" ! Tell the other side we're rea Xdy X$! X$! Now just sit and wait for a message to come from the ZT-side indicating -+-+-+-+-+ End of part 3 +-+-+-+-+- +-+-+-+ Beginning of part 4 +-+-+-+ X$! that they are done. If for some reason we never get a "**DONE**" message, X$! then the READ statement below will return an EOF error, and we can just X$! clean things up. X$! X$ loop: X$! X$ read/end=link_gone/err=done netline message X$ if message .nes. "**DONE**" then goto loop X$! X$ done: X$! X$ write/err=link_gone netline "**CLOSE**" X$! X$ link_gone: X$! X$! REMINDER : Remove /NOUNLOAD after testing X$! X$ if f$getdvi(local_tape,"MNT") then dismount/nounload zt_tape`032 X$! X$ oops: X$! X$ close netline X$ deassign sys$output X$ deassign sys$error X$! X$ oh_well: X$! X$ purge/keep=3 netserver.log X$ logout/brief X$ exit $ GOSUB UNPACK_FILE $ FILE_IS = "RMT_STARTUP.COM" $ CHECKSUM_IS = 276442157 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X$ set noon X$ run sys$system:sysgen Xconnect zta0/noadapt Xconnect zta1/noadapt Xconnect zta2/noadapt Xconnect zta3/noadapt Xexit X$ define/system rmt$dir sys$sysp:[rmt] X$ install add rmt$dir:zt2/open/header/share/priv=cmkrnl X$ install add rmt$dir:zt2_forcex/open/header/share/priv=world X$ define/system rmt_remote_node LSDC X$ define/system rmt_remote_tape MUE0: $ GOSUB UNPACK_FILE $ FILE_IS = "UCBDEF.H" $ CHECKSUM_IS = 1346593642 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* X * This is a stub - the .C programs only refer to a single flag. X * X * This definition is valid at least for VMS versions 4.0 .. 5.4 X */ X#define`009UCB$M_VALID`0092048 $ GOSUB UNPACK_FILE $ FILE_IS = "ZT.WRITEUP" $ CHECKSUM_IS = 1310779530 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY V============================================================================= X=== X XNote: ZTDRIVER is NOT public domain. COPYRIGHT (c) 1989,1991 W.J.Moeller, X`009all rights reserved ... X V============================================================================= X=== X X Note to the January 1991 distribution: X X`009The programs as "described" below assume VMS V5.4 (and up?). X X`009Due to a change in the documented behaviour of magtape drivers, X`009you'll have have to compile ZT1.C and ZT2.C with X`009`009/DEFINE="PRE_V54=1" X`009in order to generate programs that correctly support X`009earlier VMS versions. For VMS 4.7, you also have to`032 X`009re-assemble the .MAR programs on a 4.7 system. X X`009If you have an older distribution, the only changes are in X`009ZT1.C and ZT2.C - no need to rebuild the driver. X`009(Also, the writeup below did *not* change - sorry.) X X`009`009w.j.m. 21-jan-1991 X V============================================================================= X=== X X ZTDRIVER has been tested & used under VMS V4.7, V5.1-1 and V5.4 . X X I myself hardly use it for "production"; in fact I mainly did it`032 X`009(a) as an exercise to port a driver from V4 to V5 X`009(b) to test VMS V5's great new magtape (BACKUP) features - X`009`009we had tapes only on the 8650 X X Be warned: In my experience DECnet/Ethernet (around 50kb/s) is just SLOW, Xcompared to the speed of 'real' tapes. Anyway I think that ZT won't be faster Vthan BACKUP to a remote disk file. So there is no point in tying up a 'served X'`032 Vreal tape for the duration of DECnet data transfer, unless you're really shor Xt`032 Xof disk space. X V=============== A little description/technical note, made up in a hurry ===== X=== X V ZTDRIVER owes most of its size to my (essentially) copying of MTDRIVER's`0 X32 XFDT stuff, since I didn't know at the outset which I/O functions`032 Xare in actual use (MTAACP/RMS/BACKUP). Now I know - it's indeed only`032 Vthe documented ones plus IO$_NOP, sometimes also represented as a SKIP 0 bloc Xks X(if I remember correctly), with the ACP adding an apparently un-named Xmodifier bit 1@9. X It handles a request in its STARTIO routine the following way: Xcopy pertinent data into its UCB extension, send that as a mailbox msg to Vthe server (which indicates its presence by storing its mailbox into the UCB) X. XIt then WFIKPCH's where the timeout is not only very long, but the timeout Xroutine itself is a NOP (Same for CANCEL!).`032 VAt this point the server process is supposed to do just everything on its own X, Xexcept for modifying externally visible UCB fields. Currently, the server Xneed not go into kernel mode initially; only when it has figured out what Xis actually to be done, it possibly calls IOC$MOVxxUSER to transfer data. XFinally the server into kernel mode, copies back its results into the XUCB extension, and does a fake 'interrupt' to wake the driver. X When awake, the driver just updates the 'real' UCB fields from the data Xit finds in the UCB extension and completes the I/O request. X Currently this description is not completely correct, since there are Va few error paths where the driver decides on its own to reject a request;`03 X2 XI don't like them anymore. X The driver starts out as OFFLINE, the server will set it ONLINE (when Xstoring its mailbox address) and turn it off again in its exit handler - Xnote that there is currently no EXEC mode exit handler! X`009*** CAUTION: don't STOP the server, always $FORCEX it! *** X Actually, the worst that can happen is that the driver gets stuck,`032 Vand as far as I know this should block just 1 process (and possibly its ACP - X`032 XMTAACP is not shared). The server initialization, is intended to clear this Xcondition in any case: it just overwrites the UCB extension fields that`032 Xmay be left from an earlier instance and also triggers a pseudo-interrupt`032 X(which will normally be ignored). So if the server dies, just re-start it! X`009*** CAUTION: the server does not check if it is the only one! X`009`009Once I had 3 servers running by mistake - just "force"d X`009`009all of them (ZTA0 went offline) and started a new one`032 X`009`009(ZTA0 online again) - my first chance to experience`032 X`009`009VMS V5's new mount verification stuff ... X X Files: ZTDEF.MAR (defines message area / 'shared' UCB extension) X`009`009must be made into ZT.MLB, since the .MAR use '.include "ZT"' X`009ZTDRIVER.MAR is the driver (VMS 4.7 .. 5.4), to make: X`009`009$ MAC ZTDRIVER X`009`009$ LINK ZTDRIVER/OPT X`009ZTSERVER.MAR encapsulated the server's kernel mode stuff`032 X`009`009in a few simple-minded subroutines. X`009`009(needs just CMKRNL privilege to run, by the way). X`009*** CAUTION: ZTSERVER and ZTDRIVER have to be generated and *used* X`009`009*together* for a particular VMS version,`032 X`009`009there is no built-in version check!`032 X`009`009(I think the fact that both link with SYS.STB`032 X`009`009will make it impossible to run a wrong server) X X Now for the server: what could it do??? XA first 'test' version (ZT1 + ZT1T) tried to make up a 'memory tape'.`032 XI think such a thing is utterly useless, and as it stands, it can serve Xas a rudimentary test device only since it won't switch reels. X[Just for fun: naturally I included EOT detection, but no way to simulate Xan unloaded tape. The ACP bravely asks the operator, but silly old BACKUP Xindeed initiates UNLOAD, then immediately tests if the tape is loaded; Vif that succeeds - as in my case, and allegedly for some initial V5 TUDRIVER X - Xit happily continues without asking anyone!] X If desired, I might include this program for completeness ... X V The second program (and the only one mentioned above) is a DECnet tape ser Xver Xpair. The program serving the pseudo-tape is called ZT2 Xand the real server, which serves a real tape, is called ZTNS2.`032 V There is quite a bit of black magic involved in getting a real tape served X, Xthe biggest problem being that there is nowhere a documentation for Xthe 'correct' behaviour of a tape driver - in fact different DEC drivers Xdo return different status codes on identical conditions. The second trouble Xcomes with hard errors: if the real-tape-server (ZTNS2, for short) receives Xa media/hardware related error status, it does not know what exactly happened Xand in particular, where the tape is positioned (and of course ZTNS2 ought Xto be device-independent)! X Here comes a horrible thing with VMS: apparently the author(s) Xof MTAACP noted this problem, and so there was created a cell UCB$L_RECORD Xwhere a magtape driver has to put the current block number (0 at BOT, XEOF marks are counted as blocks). I know that the ACP looks at this cell, Xbut normal programs can't, since it's not on the list of $GETDVI! X Currently, ZTNS2 (intended to be a harmless, unprivileged program)`032 Vdoes not go into kernel mode to find out about UCB$L_RECORD, so it has to gue Xss Xand also return "tape position lost" status. There are actually 2 ways to do Xjust that, the first is to say so (SS$_TAPEPOSLOST) and the second is to Xset a status bit MT$V_LOST (does anyone look at this status word, anyway?? - Xthere is a bit MT$V_EOF allegedly indicating "end of file mark passed",`032 XMTDRIVER sets it from some hardware register, newer drivers apparently Xnever set it (?)). ZTNS2 has a conditional of which behaviour is preferred. X X I have to admit that all of the code has not yet been sufficiently tested, Xbecause I was too lazy to implement "error insertion" in my memory tape, Xand with real tapes you have to wait and see - and that takes time...! X The 'protocol' used between ZT2 and ZTNS2 is strictly half-duplex: VZT2 sends (sort of) I/O function, ZTNS2 finally replies with status & some mo Xre Xinformation. In between, ZTNS2 may send at most a single 'DMA request': X - on tape read, this is immediately followed by data (split into X`009reasonably-sized packets) , upon which ZT2 replies`032 X`009(with a 'DMA status', always good so far) X - on tape write, ZT2 replies with the data requested XI unnecessarily wrote ZTNS2 such that it would support full-duplex operation Xof the DECnet link; on the other hand, ZT2 is completely synchronous. X X ZT2/ZTNS2 is not complete. Both programs conspire to ignore Xmost of the I/O function modifier bits, notably IO$M_INHRETRY; Xthey do not implement read backward (I don't even know in what direction Xand where data would have to be placed in the user buffer);`032 XDATACHECK is not end-to-end, but only done on the ZTNS2 end. XAlso, IO$_SETMODE/CHAR is not propagated to ZTNS2 at all, and neither are the Xreal tape "characteristics" to ZT2 - this is truly a shortcoming in the Xtask-to-task protocol. The virtual ZT defaults to "TE16 at 1600bpi"; Xin fact this can be changed with IO$_SETCHAR without any influence on the Xdriver's behaviour. X I did implement the IO$_WRITECHECK function from MTDRIVER, Xwhich actually means "compare tape data to memory". Unfortunately, Xno program uses it, so it's completely untested. X X Files: X`009ZT1.C + ZT1T.C make up the memory tapes (ZT1 is the "driver" part, X`009`009`009ZT1T is just subroutines for in-core storage X`009`009`009of tape blocks and EOF marks). X`009ZT2.C is the ZT-server for the task-to-task design X`009*** CAUTION: ZT1.C *and* ZT2.C each carry their own definition X`009`009`009of the message area defined in ZTDEF.MAR *** X`009`009Both ZT1 and ZT2 have an options to log all I/O operations; X`009`009so far I had that always enabled. X`009ZTNS2.C is the real-tape-server X`009`009ZT1, ZT2 and ZTNS2 include: X`009IODEF.H, MTDEF.H, UCBDEF.H which I created with my 'C_DEFS' X`009`009procedure (recently re-posted on info-vax by Jerry Leichter). X`009`009Note: IODEF.H from VAXC (VMS V4 version) won't do. X`009`009By silly design, UCBDEF is currently *only* required to define X`009`009a single bit position, UCB$M_VALID (this bit did *not* change X`009`009from VMS V4 to V5 - UCBDEF changed a lot). X`009ZTNS.H is included by ZT2.C and ZTNS2.C, it defines`032 X`009`009the task-to-task messages. X X First: $ MACRO ZTSERVER X`009`009$ MACRO FEHLER X`009`009$ CC REDIRECT X`009To make ZT1: X`009`009$ CC ZT1,ZT1T X`009`009$ LINK ZT1,ZT1T,ZTSERVER,FEHLER,REDIRECT ! links with SYS X`009To make ZT2 and ZTNS2: X`009`009$ CC ZT2 X`009`009$ LINK ZT2,ZTSERVER,FEHLER,REDIRECT`009! links with SYS X`009`009$ CC ZTNS2 X`009`009$ LINK ZTNS2,FEHLER,REDIRECT X X To use the programs,`032 X`009(a)`009$ SYSGEN CONNECT ZTA0/noadapter X`009*** BUG: ZTSERVER.MAR has _ZTA0 hard-coded. *** X`009(b1)`009$ run ZT1`009! from anywhere: terminal, batch, detached ... X`009(c1)`009when you are done, somehow stop ZT1 by $FORCEX, X`009`009CTRL-Y, or STOP/QUE/ENTRY when in batch. X`009(b2a)`009on the ZT-side, make up a Network object, e.g. ZT2.COM, X`009`009`009like:`009$ set proc/priv=cmkrnl X`009`009`009`009$ run ZT2 X`009(b2b)`009on the real tape side: X`009`009`009$ define ZT_TAPE X`009`009`009$ mount/foreign ZT_TAPE/multi_volume X`009`009`009`009`009 `094-- for V5, I guess X`009`009`009`009`009`009(my tapes are still with V4) X`009`009`009$ define ZT_NETOBJECT "node::""task=ZT2/" X`009`009`009`009`009`009 `094---------`094 wierd (sorry), X`009`009`009`009`009`009task spec starts with quotation X`009`009`009`009`009`009mark and ends with slash. X`009`009`009$ run ZTNS2 X`009(c2)`009when done, either kill ZT2 with $FORCEX (ZT-side), X`009`009or stop ZTNS2 (by any means). X`009*** BUG: ZT2 will *not* instantly notice that ZTNS2 has gone, X`009`009but only on the next I/O.`032 X`009`009MOUNT/FOREIGN is ok to force an I/O (=> SS$_DEVOFFLINE). X V============================================================================= X== X X XEnjoy, X`009-wjm X XWolfgang J. Moeller, GWDG, D-3400 Goettingen, F.R.Germany `124 Disclaimer ... VBitnet/Earn: U0012@DGOGWDG5 Phone: +49 551 201516 `124 No claim inten Xded! VInternet: Moeller@gwdgv1.dnet.gwdg.de `124 This space intentionally left bl Xank. $ GOSUB UNPACK_FILE $ FILE_IS = "ZT2.C" $ CHECKSUM_IS = 2105360321 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/*`009ZTserver (network object) for ZTNS & ZTDRIVER ... X`009w.j.m. jun 1989 X`009mod 3-jul-1989 wjm: unless UNSAFE_AFTER_ERROR is defined as 1, X`009`009`009don't take unknown position that serious, X`009`009`009just set MT$M_LOST bit. X`009fix 19-sep-1989 wjm: properly set/clear MT$M_LOST in ZT's iosb X`009mod 28-dec-1990 wjm: VMS V5.4 *always* does end-of-volume recognition, X`009`009`009`009no longer dependent upon FOREIGN MOUNT. X`009`009`009 Old behaviour now only with PRE_V54 defined. X`009fix 14-jan-1991 wjm: fix(?) file count returned when reverse X`009`009`009`009SKIPFILE hits BOT (required for 5.4 MTAAACP) X mod 13-jun-1993 ram: read ZTAn device name sent by ZTNS2 on the X real-tape side X*/ X X#ifndef TRACE X#define TRACE 1 X#endif X X#ifndef UNSAFE_AFTER_ERROR X#define UNSAFE_AFTER_ERROR 0 X#endif X X#ifndef PRE_V54`009`009/* might be conditional on UCBDEF or IODEF;`009 */ X#define PRE_V54 0`009/* e.g. UCB$L_SHAD & IO$V_MOVEFILE are new in V5.4 */ X#endif X X#include "ztns.h"`009/* includes IOSB */ X V/* NOTE: following ZT definitions must match ZTDEF.MAR & ZTSERVER.MAR ******* X**/ X Xtypedef struct ZTmsg `123 X`009IOSB iosb;`009/* i.e. status, count, devdep */ X`009long record; X`009unsigned short ucbsts; X`009unsigned short fill1; X`009unsigned long devchar; X`009unsigned short func; X`009unsigned short bcnt; X`009union `123 X`009`009short w[4]; X`009`009unsigned short uw[4]; X`009`009unsigned long ul[2]; X`009`125 media; X`125 ZTmsg; -+-+-+-+-+ End of part 4 +-+-+-+-+- +-+-+-+ Beginning of part 5 +-+-+-+ Xglobalref struct `123 X`009unsigned short l; X`009unsigned short fill1; X`009ZTmsg *p; X`125 ZT_MSGDSC; X Xglobalref struct `123 X`009unsigned long bct; X`009unsigned char *addr; X`125 ZT_BUFDSC; X Xextern unsigned ZT_INIT(),ZT_WAIT(),ZT_TOUSER(),ZT_FRUSER(),ZT_REQCOM(); X V/******* end of ZT definitions ********************************************** X**/ X X X#include ssdef X#include lnmdef X X#include "mtdef.h" X#include "iodef.h"`009/* my own! */ X#include "ucbdef.h"`009/* note VMS version dependency */ X#if PRE_V54 X#include devdef X#endif X X#include stdio X#include stddef X#include string X#include descrip Xtypedef struct dsc$descriptor DESCR; X Xtypedef struct VMS_ITEM `123 X`009unsigned short size; X`009unsigned short code; X`009void *bufp; X`009int *lenp; X`125 VMS_ITEM; X X#define CHECK(x) do `123unsigned s=x; if(!(s&1)) lib$stop(s);`125 while(0) X#define FEHLER(m) do `123$DESCRIPTOR(d,m); Fehler(&d);`125 while(0) X#define MIN(a,b) ((a) < (b)) ? (a) : (b) X Xextern void lib$stop(); Xextern unsigned sys$assign(),sys$trnlnm(); Xextern unsigned sys$qiow(int,int,int, X`009`009`009IOSB*,void*,int, X`009`009`009void*,int,int,int,int,int); X X Xstatic void ns_init(void);`009/* forward */ Xstatic void ns_req(int,int);`009/* forward */ Xstatic IOSB ns_iosb; X Xstatic unsigned char *bufp; Xstatic unsigned long *bufbctp; X Xstatic ZTmsg *msgp; X Xstatic unsigned short fcode; Xstatic unsigned short fmodif; X Xstatic enum `123no,yes,dunno`125 aftertm;`009/* tape positioned after mark? - X`009`009`009`009`009shortcut to save tape movement */ X Xstatic int/*logical*/ pos_unsafe;`009/* set after (hard) error, X`009`009`009`009`009/* #if UNSAFE_AFTER_ERROR: X`009`009`009`009`009/* inhibits all operations X`009`009`009`009`009/* that move the tape forward, X`009`009`009`009`009/* since UCB$L_RECORD may be wrong*/ X X/*****/ X Xstatic void do_init() X`123 X`009ns_init();`009/* must set up ns_iosb.devdep */ X X`009aftertm = (ns_iosb.devdep & MT$M_BOT) ? no: dunno; X`009pos_unsafe = !(ns_iosb.devdep & MT$M_BOT); X`125 X X Xstatic void do_nop() X`123 X`009/* all modifiers ignored */ X X`009/* give 'ns' a chance to update 'devdep' */ X`009ns_req(IO$_SKIPRECORD,0);`009/* skip 0 blocks */ X`009if((ns_iosb.status & 1) `124`124 X`009 (ns_iosb.status == SS$_ENDOFTAPE) `124`124 X`009 (ns_iosb.status == SS$_BEGOFTAPE)) `123 X`009`009`009/* o.k. */ X`009`125 else `123 X`009`009pos_unsafe = 1; X`009`125 X`009/* 'aftertm' did not change, I hope ... */ X`125 X X Xstatic void do_rewind(int unload) X`123 X`009/* fmodif: IO$M_NOWAIT, others ignored */ X`009unsigned short nsfct; X X X`009if(unload) `123 X`009`009nsfct = IO$_REWINDOFF; X`009`125 else `123 X`009`009nsfct = IO$_REWIND; X`009`125 X`009nsfct `124= (fmodif & IO$M_NOWAIT); X`009ns_req(nsfct,0); X`009 X`009msgp->record = 0;`009/* always */ X`009aftertm = no; X X`009if((ns_iosb.status & 1) `124`124 X`009 (ns_iosb.status == SS$_BEGOFTAPE)) `123 X`009`009/* o.k. */ X`009`125 else `123 X`009`009pos_unsafe = 1; X`009`125 X X#if 0`009/* this works together with a VMS V.5 addition: X`009 if tape is mounted foreign & MT$M_ENAUTOPACK is set, X`009 then set UCB$M_VALID on "medium online" interrupt */ X`009/*...................................................*/ X`009if(!hw_medonline) `123 X`009`009msgp->ucbsts &= `126UCB$M_VALID; X`009`125 X#endif`009/*...................................................*/ X`125 X X Xstatic unsigned set_aftertm()`009/* ggf. find out if tape is positioned X`009`009`009`009`009after a tape mark */ X`123 X`009if(aftertm != dunno) return SS$_NORMAL;`009/* nothing to be done */ X X`009ns_req(IO$_SKIPRECORD,-1); X`009msgp->record -= ns_iosb.count; X`009if(ns_iosb.count != 1) `123 X`009`009if((ns_iosb.devdep & MT$M_BOT) == 0) `123 X`009`009`009pos_unsafe = 1; X`009`009`009return SS$_TAPEPOSLOST; X`009`009`125 else `123 X`009`009`009pos_unsafe = 0;`009/* we're at BOT! */ X`009`009`009aftertm = no; X`009`009`009return SS$_NORMAL; X`009`009`125 X`009`125 X`009aftertm = (ns_iosb.status == SS$_ENDOFFILE) ? yes : no; X X`009ns_req(IO$_SKIPRECORD,1); X`009msgp->record += ns_iosb.count; X`009if(ns_iosb.count != 1) `123 X`009`009pos_unsafe = 1; X`009`009return SS$_TAPEPOSLOST; X`009`125 X`009return SS$_NORMAL; X`125 X Xstatic void`009/* "end of volume" recognized */ Vset_eov(sca)`009/* backspace over 2nd eof mark, decrement spacing count etc. X */ Xint sca;`009`009/* spacing count so far (>0) */ X`123 X`009ns_req(IO$_SKIPRECORD,-1); X`009if(ns_iosb.count == 1 && ns_iosb.status == SS$_ENDOFFILE) `123 /* o.k. */ X`009`009msgp->record --; X`009`009ns_iosb.status = SS$_ENDOFVOLUME; X`009`009/* aftertm remains == yes */ X`009`125 else `123 X`009`009pos_unsafe = 1; X`009`009ns_iosb.status = SS$_TAPEPOSLOST; X`009`009aftertm = dunno; X`009`125 X`009ns_iosb.count = sca - 1;`009/* final count */ X`125 X X Xstatic void do_skiprec() X`123 X`009/* all modifiers ignored */ X`009int sc; X X X`009sc = msgp->media.w[0]; X X`009if(sc == 0) `123 X`009`009do_nop(); X`009`009return; X X`009`125 else if(sc > 0) `123`009`009`009`009`009/* FORWARD */ X#if PRE_V54 X`009`009int/*logical*/ no_acp; X#endif X X#if UNSAFE_AFTER_ERROR X`009`009if(pos_unsafe) return; X#endif X X#if PRE_V54 X`009`009no_acp =`009/* not mounted, or mounted foreign */ X`009`009`009((msgp->devchar & DEV$M_MNT) == 0) `124`124 X`009`009`009((msgp->devchar & DEV$M_FOR) != 0); X`009`009if(no_acp) `123 X#endif X`009`009`009if((set_aftertm() & 1) == 0) `123 X`009`009`009`009ns_iosb.status = SS$_TAPEPOSLOST; X`009`009`009`009ns_iosb.count = 0; X`009`009`009`009pos_unsafe = 1; X`009`009`009`009return; X`009`009`009`125 X#if PRE_V54 X`009`009`125 X#endif X X`009`009ns_req(IO$_SKIPRECORD,sc); X`009`009msgp->record += ns_iosb.count; X X`009`009if((ns_iosb.status & 1) `124`124 X`009`009 ns_iosb.status == SS$_ENDOFTAPE) `123 X`009`009`009aftertm = no; X`009`009`125 else if(ns_iosb.status == SS$_ENDOFFILE) `123 X`009`009`009aftertm = yes; X`009`009`009if( X#if PRE_V54 X`009`009`009 no_acp &&`032 X#endif X`009`009`009`009 (ns_iosb.count == 1)) `123 X`009`009`009`009/* "end of volume recognition" */ X`009`009`009`009set_eov(1); X`009`009`009`125 X`009`009`125 else `123 X`009`009`009aftertm = dunno; X`009`009`009pos_unsafe = 1; X`009`009`125 X X`009`125 else `123`009`009`009`009`009`009/* BACKWARD */ X`009`009ns_req(IO$_SKIPRECORD,sc); X`009`009msgp->record -= ns_iosb.count; X X`009`009aftertm = dunno; X`009`009if(ns_iosb.status == SS$_ENDOFFILE) `123 X`009`009`009`009`009/* o.k. */ X`009`009`125 else if((ns_iosb.status & 1) `124`124 X`009`009`009 ns_iosb.status == SS$_BEGOFTAPE) `123 X`009`009`009if(sc + ns_iosb.count == 0) `123 X`009`009`009`009`009/* o.k. */ X`009`009`009 ns_iosb.status = SS$_NORMAL; X`009`009`009`125 else `123 X`009`009`009`009if(ns_iosb.devdep & MT$M_BOT) `123 X`009`009`009`009`009/* terminated due to B.O.T. */ X`009`009`009`009`009ns_iosb.status = SS$_BEGOFTAPE; X`009`009`009`009`125 else `123 X`009`009`009`009`009/* must not happen! */ X`009`009`009`009`009/* ??? */ X`009`009`009`009`125 X`009`009`009`125 X`009`009`125 else `123`009`009/* error */ X`009`009`009pos_unsafe = 1; X`009`009`125 X`009`125 X`125 X X Xstatic void do_skipfile() X`123 X`009/* all modifiers ignored */ X`009int sc,sca; X`009 X X`009sc = msgp->media.w[0]; X`009if(sc == 0) `123 X`009`009do_nop(); X`009`009return; X`009`125 else if(sc > 0) `123`009`009`009`009`009/* FORWARD */ X#if PRE_V54 X`009`009int/*logical*/ no_acp; X#endif X`009`009int prevtm;`009`009/* 'record' after tape mark, or -2 */ X X#if UNSAFE_AFTER_ERROR X`009`009if(pos_unsafe) return; X#endif X X#if PRE_V54 X`009`009no_acp =`009/* not mounted, or mounted foreign */ X`009`009`009((msgp->devchar & DEV$M_MNT) == 0) `124`124 X`009`009`009((msgp->devchar & DEV$M_FOR) != 0); X`009`009if(no_acp) `123 X#endif X`009`009`009if((set_aftertm() & 1) == 0) `123 X`009`009`009`009ns_iosb.status = SS$_TAPEPOSLOST; X`009`009`009`009pos_unsafe = 1; X`009`009`009`009return; X`009`009`009`125 X`009`009`009if(aftertm == yes) `123 X`009`009`009`009prevtm = msgp->record; X`009`009`009`125 else `123 X`009`009`009`009prevtm = -2; X`009`009`009`125 X#if PRE_V54 X`009`009`125 X#endif X X`009`009sca = 0; X`009`009do `123 X`009`009`009do `123 X`009`009`009`009ns_req(IO$_SKIPRECORD,0x7FFF); X`009`009`009`009msgp->record += ns_iosb.count; X`009`009`009`125 while((ns_iosb.status & 1) `124`124 X`009`009`009`009(ns_iosb.status == SS$_ENDOFTAPE)); X X`009`009`009if((ns_iosb.status == SS$_ENDOFFILE)) `123 X`009`009`009`009`009/* o.k. */ X`009`009`009`009sca ++; X`009`009`009`009sc --; X X#if PRE_V54 X`009`009`009`009if(no_acp) `123 X#endif X`009`009`009`009`009if(msgp->record == prevtm+1) `123 X`009`009`009`009`009`009aftertm = yes; X`009`009`009`009`009`009set_eov(sca); X`009`009`009`009`009`009return; X`009`009`009`009`009`125 else `123 X`009`009`009`009`009`009prevtm = msgp->record; X`009`009`009`009`009`125 X#if PRE_V54 X`009`009`009`009`125 X#endif X`009`009`009`125 X`009`009`125 while((sc > 0) && X`009`009`009(ns_iosb.status == SS$_ENDOFFILE)); X X`009`009if(ns_iosb.status == SS$_ENDOFFILE) `123 X`009`009`009`009/* o.k. */ X`009`009`009ns_iosb.status = SS$_NORMAL; X`009`009`125 else `123`009/* error */ X`009`009`009aftertm = dunno; X`009`009`009pos_unsafe = 1; X`009`009`125 X`009`009ns_iosb.count = sca; X X`009`125 else `123`009`009`009`009`009`009/* BACKWARD */ X`009`009`009/* NOTE: It is not clear what status is returned X`009`009`009/* on the attempt to skip backward over B.O.T. X`009`009`009/* We allow for both success and SS$_BEGOFTAPE, and X`009`009`009/* we do return SS$_BEGOFTAPE on skip beyond B.O.T. */ X`009`009int scb;`009/* count of blocks skipped w/i file */ X X`009`009aftertm = dunno; X`009`009sca = 0; X`009`009do `123 X`009`009`009scb = 0; X`009`009`009do `123 X`009`009`009`009ns_req(IO$_SKIPRECORD,-0x7FFF); X`009`009`009`009msgp->record -= ns_iosb.count; X`009`009`009`009scb += ns_iosb.count; X`009`009`009`125 while((ns_iosb.status & 1) && X`009`009`009`009(ns_iosb.count > 0)); X X`009`009`009if((scb > 0) &&`009`009/* anything skipped ? */ X`009`009`009 ((ns_iosb.status & 1) `124`124 X`009`009`009 (ns_iosb.status == SS$_ENDOFFILE) `124`124 X`009`009`009 (ns_iosb.status == SS$_BEGOFTAPE))) `123 X#if 0`009/* I had this in the pre-5.4 version, `009`009*/ X`009/* but TMDRIVER has always counted differently`009*/ X`009`009`009`009sca ++; X#else X`009`009`009`009if(!(ns_iosb.devdep & MT$M_BOT)) sca ++; X`009`009`009`009/** don't count BOT (from TMDRIVER) **/ X#endif X`009`009`009`009sc ++; X`009`009`009`125 X`009`009`125 while((sc < 0) && X`009`009`009(scb > 0) &&`009/* stop if nothing was skipped */ X`009`009`009((ns_iosb.status & 1) `124`124 X`009`009`009 (ns_iosb.status == SS$_ENDOFFILE))); X X`009`009if(ns_iosb.status == SS$_ENDOFFILE) `123 X`009`009`009`009`009/* all files skipped */ X`009`009`009ns_iosb.status = SS$_NORMAL; X`009`009`125 else if((ns_iosb.status & 1) `124`124 X`009`009`009 (ns_iosb.status == SS$_BEGOFTAPE)) `123 X`009`009`009if(sc == 0) `123`009/* all files skipped */ X`009`009`009`009ns_iosb.status = SS$_NORMAL; X`009`009`009`125 else if(ns_iosb.devdep & MT$M_BOT) `123 X`009`009`009`009`009/* stopped due to BOT */ X`009`009`009`009ns_iosb.status = SS$_BEGOFTAPE; X`009`009`009`125 else `123 X`009`009`009`009`009/* must not happen! */ X`009`009`009`009`009/* ??? */ X`009`009`009`125 X`009`009`125 else `123`009`009/* error */ X`009`009`009ns_iosb.status = SS$_TAPEPOSLOST; X`009`009`009pos_unsafe = 1; X`009`009`125 X`009`009ns_iosb.count = sca; X`009`125 X`125 X X Xstatic void do_writecheck() X`123 X`009/* modifiers: IO$M_REVERSE rejected, others ignored */ X X X`009if((fmodif & IO$M_REVERSE) != 0) `123`009/* not supported so far */ X`009`009ns_iosb.status = SS$_BADPARAM; X`009`009return; X`009`125 X X#if UNSAFE_AFTER_ERROR X`009if(pos_unsafe) return; X#endif X X`009CHECK(ZT_FRUSER()); X X`009ns_req(IO$_WRITECHECK,msgp->bcnt); X`009if((ns_iosb.status & 1) `124`124 X`009 (ns_iosb.status == SS$_DATAOVERUN) `124`124 X`009 (ns_iosb.status == SS$_ENDOFFILE) `124`124 X`009 (ns_iosb.status == SS$_DATACHECK)) `123 X`009`009`009`009/* tape moved */ X`009`009msgp->record ++; X`009`009aftertm = (ns_iosb.status == SS$_ENDOFFILE) ? yes : no; X`009`125 else `123 X`009`009`009`009/* tape may have moved */ X`009`009pos_unsafe = 1; X`009`009/* msgp->record ++; /* better don't count it */ X`009`009aftertm = dunno; X`009`125 X`125 X X Xstatic void do_read() X`123 X`009/* modifiers: IO$M_REVERSE rejected, X`009`009`009IO$M_DATACHECK o.k., X`009`009`009others ignores */ X X`009if((fmodif & IO$M_REVERSE) != 0) `123`009/* not supported so far */ X`009`009ns_iosb.status = SS$_BADPARAM; X`009`009return; X`009`125 X X#if UNSAFE_AFTER_ERROR X`009if(pos_unsafe) return; X#endif X X`009ns_req(IO$_READLBLK `124 (fmodif & IO$M_DATACHECK),msgp->bcnt); X`009if((ns_iosb.status & 1) `124`124 X`009 (ns_iosb.status == SS$_DATAOVERUN) `124`124 X`009 (ns_iosb.status == SS$_ENDOFFILE)) `123 X`009`009`009`009/* tape moved */ X`009`009msgp->record ++; X`009`009aftertm = (ns_iosb.status == SS$_ENDOFFILE) ? yes : no; X`009`125 else `123 X`009`009`009`009/* tape may have moved */ X`009`009pos_unsafe = 1; X`009`009/* msgp->record ++; /* better don't count it */ X`009`009aftertm = dunno; X`009`125 X X`009*bufbctp = MIN(ns_iosb.count,msgp->bcnt); X`009CHECK(ZT_TOUSER()); X`125 X`009`009 Xstatic void do_writemark() X`123 X`009/* all modifiers ignored */ X X#if UNSAFE_AFTER_ERROR X`009if(pos_unsafe) return; X#endif X X`009ns_req(IO$_WRITEOF,0); X`009if((ns_iosb.status & 1) `124`124 X`009 ns_iosb.status == SS$_ENDOFTAPE) `123 X`009`009msgp->record ++; X`009`009aftertm = yes; X`009`125 else `123 X`009`009/* assume NO tape movement */ X`009`009pos_unsafe = 1; X`009`009aftertm = dunno; X`009`125 X`125 X X Xstatic void do_write() X`123 X`009/* modifiers: IO$M_DATACHECK o.k., others ignored X`009`009(in particular mysterious IO$M_ERASE flag, X`009`009`009and IO$M_NOWAIT ("TU81plus only")) */ X X X#if UNSAFE_AFTER_ERROR X`009if(pos_unsafe) return; X#endif X X`009CHECK(ZT_FRUSER()); X X`009ns_req(IO$_WRITELBLK `124 (fmodif & IO$M_DATACHECK),msgp->bcnt); X`009if((ns_iosb.status & 1) `124`124 X`009 (ns_iosb.status == SS$_ENDOFTAPE)) `123 X`009`009`009/* tape moved */ X`009`009msgp->record ++; X`009`009aftertm = no; X`009`125 else `123 X`009`009`009/* assume NO tape movement */ X`009`009pos_unsafe = 1; X`009`009aftertm = dunno; X`009`125 X`125 X X X/*****/ X X#if TRACE Xstatic void trace_func();`009/* forward */ Xstatic void trace_result();`009/* forward */ X#endif X Xstatic void dispatch() X`123 X`009fcode = msgp->func & IO$M_FCODE; X`009fmodif = msgp->func & IO$M_FMODIFIERS; X X#if TRACE X`009trace_func(); X#endif X X`009/* set defaults */ X`009ns_iosb.count = 0; X`009ns_iosb.status = SS$_UNSAFE; X X X`009switch(fcode) `123 X X`009 case IO$_WRITEMARK: -+-+-+-+-+ End of part 5 +-+-+-+-+- +-+-+-+ Beginning of part 6 +-+-+-+ X`009 case IO$_WRITEOF: X`009`009do_writemark(); X`009`009break; X X`009 case IO$_UNLOAD: X`009 case IO$_REWINDOFF: X`009`009do_rewind(1); X`009`009break; X X`009 case IO$_RECAL: X`009 case IO$_REWIND: X`009 case IO$_AVAILABLE:`009`009/* NOTE: driver cleared VALID */ X`009`009do_rewind(0); X`009`009break; X`009`009 X`009 case IO$_PACKACK: X`009`009do_nop(); X`009`009if((ns_iosb.status & 1)) `123 X`009`009`009msgp->ucbsts `124= UCB$M_VALID; X`009`009`125 X`009`009break; X`009`009 X`009 case IO$_SPACEFILE: X`009 case IO$_SKIPFILE: X`009`009do_skipfile(); X`009`009break; X X`009 case IO$_SPACERECORD: X`009 case IO$_SKIPRECORD: X`009`009do_skiprec(); X`009`009break; X X`009 case IO$_WRITECHECK: X`009`009do_writecheck(); X`009`009break; X X`009 case IO$_WRITEPBLK: X`009 case IO$_WRITELBLK: X`009`009do_write(); X`009`009break; X X`009 case IO$_READPBLK: X`009 case IO$_READLBLK: X`009`009do_read(); X`009`009break; X X`009 case IO$_NOP: X`009 case IO$_SENSECHAR: X`009 case IO$_SENSEMODE: X`009 case IO$_SETCHAR:`009`009/* treat as no-op */ X`009 case IO$_SETMODE:`009`009/* treat as no-op */ X`009 case IO$_DRVCLR:`009`009/* treat as no-op */ X`009 case IO$_ERASETAPE:`009`009/* treat as no-op */ Xnoop: X`009`009do_nop(); X`009`009break; X X`009 default: X`009`009ns_iosb.status = SS$_ILLIOFUNC; X`009`009break; X`009`125 X X/* final processing: X`009must copy status & count from ns_iosb to msgp->iosb, X`009`009`009also 5 devdepend bits X`009record`009`009- has been updated (if changed) X`009ucbsts`009`009- v_valid has been modified (if changed) X*/ X X`009/* fake 'LOST' BIT */ X`009if(pos_unsafe `124`124 ns_iosb.status == SS$_TAPEPOSLOST) `123 X`009`009ns_iosb.devdep `124= MT$M_LOST; X`009`125 X X`009if(ns_iosb.devdep & MT$M_BOT) `123`009`009`009/* at "BOT" */ X`009`009ns_iosb.devdep &= `126MT$M_LOST;`009`009/* clear pos. lost */ X`009`009aftertm = no; X`009`009pos_unsafe = 0; X`009`125 X X`009msgp->iosb.status = ns_iosb.status; X`009msgp->iosb.count = ns_iosb.count; X`009`123 V`009`009unsigned mask = MT$M_BOT `124 MT$M_EOF `124 MT$M_EOT `124 MT$M_HWL `1 X24 X`009`009`009`009MT$M_LOST; X X`009`009msgp->iosb.devdep = (msgp->iosb.devdep & (`126mask)) `124 X`009`009`009`009 (ns_iosb.devdep & mask); X`009`125 X X#if TRACE X`009trace_result(); X#endif X`125 X X X/*****/ X Xmain(argc,argv) Xint argc; char **argv; X`123 X X#ifdef VAXC X`009redirect(&argc,&argv); X#endif X X`009bufp = ZT_BUFDSC.addr; X`009bufbctp = &(ZT_BUFDSC.bct); X X`009if(ZT_MSGDSC.l != sizeof(ZTmsg)) FEHLER("bad MSGDSC.len"); X`009msgp = ZT_MSGDSC.p; X X X`009do_init(); X`009CHECK(ZT_INIT()); X X X`009do `123 X`009`009CHECK(ZT_WAIT()); X X`009`009dispatch(); X X`009`009CHECK(ZT_REQCOM()); X`009`125 while(1); X`125 X X X/*****/ X X#if TRACE X Xtypedef enum `123zeroparm,oneparm,transfer,setchar`125 TRACE_FTYPE; X Xstatic void trace_f(char *fname,TRACE_FTYPE ftype) X`123 X`009int i,fm; X X`009fprintf(stdout,"***** %s",fname); X X`009for(fm = fmodif>>IO$V_FMODIFIERS, i = IO$V_FMODIFIERS; X`009 (fm != 0) && i < 16; X`009 fm >>= 1, i++) `123 X`009`009if(fm & 1) switch(i) `123 X`009`009 case IO$V_REVERSE: X`009`009`009fprintf(stdout,",REVERSE"); break; X`009`009 case IO$V_NOWAIT: X`009`009`009fprintf(stdout,",NOWAIT"); break; X`009`009 case IO$V_ERASE: X`009`009`009fprintf(stdout,",ERASE"); break; X`009`009 case IO$V_INHERLOG: X`009`009`009fprintf(stdout,",INHERLOG"); break; X`009`009 case IO$V_INHEXTGAP: X`009`009`009fprintf(stdout,",INHEXTGAP"); break; X`009`009 case IO$V_DATACHECK: X`009`009`009fprintf(stdout,",DATACHECK"); break; X`009`009 case IO$V_INHRETRY: X`009`009`009fprintf(stdout,",INHRETRY"); break; X`009`009 default: X`009`009`009fprintf(stdout,",1@%d",i); X`009`009`009break; X`009`009`125 X`009`125 X X`009switch(ftype) `123 X`009 case zeroparm: X`009`009break; X`009 case oneparm: X`009`009fprintf(stdout," media=%d",msgp->media.w[0]); X`009`009break; X`009 case transfer: X`009`009fprintf(stdout," bcnt=%d",msgp->bcnt); X`009`009break; X`009 case setchar: X`009`009fprintf(stdout," media: %04X %04X %04X", X`009`009`009`009msgp->media.uw[0], X`009`009`009`009msgp->media.uw[1], X`009`009`009`009msgp->media.uw[2]); X`009`009break; X`009`125 X`009fprintf(stdout," record=%d\n",msgp->record);`009 `032 X`125 X Xstatic void trace_func() X`123 X`009switch(fcode) `123 X`009 case IO$_NOP: X`009`009trace_f("IO$_NOP",zeroparm); break; X`009 case IO$_UNLOAD: X`009`009trace_f("IO$_UNLOAD",zeroparm); break; X`009 case IO$_RECAL: X`009`009trace_f("IO$_RECAL",zeroparm); break; X`009 case IO$_DRVCLR: X`009`009trace_f("IO$_DRVCLR",zeroparm); break; X`009 case IO$_ERASETAPE: X`009`009trace_f("IO$_ERASETAPE",zeroparm); break; X`009 case IO$_PACKACK: X`009`009trace_f("IO$_PACKACK",zeroparm); break; X`009 case IO$_AVAILABLE: X`009`009trace_f("IO$_AVAILABLE",zeroparm); break; X`009 case IO$_WRITEMARK: X`009`009trace_f("IO$_WRITEMARK",zeroparm); break; X`009 case IO$_REWINDOFF: X`009`009trace_f("IO$_REWINDOFF",zeroparm); break; X`009 case IO$_REWIND: X`009`009trace_f("IO$_REWIND",zeroparm); break; X`009 case IO$_WRITEOF: X`009`009trace_f("IO$_WRITEOF",zeroparm); break; X`009 case IO$_SPACEFILE: X`009`009trace_f("IO$_SPACEFILE",oneparm); break; X`009 case IO$_SPACERECORD: X`009`009trace_f("IO$_SPACERECORD",oneparm); break; X`009 case IO$_SKIPFILE: X`009`009trace_f("IO$_SKIPFILE",oneparm); break; X`009 case IO$_SKIPRECORD: X`009`009trace_f("IO$_SKIPRECORD",oneparm); break; X`009 case IO$_SENSECHAR: X`009`009trace_f("IO$_SENSECHAR",zeroparm); break; X`009 case IO$_SENSEMODE: X`009`009trace_f("IO$_SENSEMODE",zeroparm); break; X`009 case IO$_SETCHAR: X`009`009trace_f("IO$_SETCHAR",setchar); break; X`009 case IO$_SETMODE: X`009`009trace_f("IO$_SETMODE",setchar); break; X`009 case IO$_WRITECHECK: X`009`009trace_f("IO$_WRITECHECK",transfer); break; X`009 case IO$_WRITEPBLK: X`009`009trace_f("IO$_WRITEPBLK",transfer); break; X`009 case IO$_READPBLK: X`009`009trace_f("IO$_READPBLK",transfer); break; X`009 case IO$_WRITELBLK: X`009`009trace_f("IO$_WRITELBLK",transfer); break; X`009 case IO$_READLBLK: X`009`009trace_f("IO$_READLBLK",transfer); break; X`009 default: X`009`009`123`009char name[16]; X X`009`009`009sprintf(name,"?%d?",fcode); X`009`009`009trace_f(name,zeroparm); X`009`009`125 X`009`009break; X`009`125 X`125 X Xstatic void trace_result() X`123 X`009fprintf(stdout,"\tiosts="); X`009switch(msgp->iosb.status) `123 X`009 case SS$_NORMAL: X`009`009fprintf(stdout,"SS$_NORMAL"); break; X`009 case SS$_BADPARAM: X`009`009fprintf(stdout,"SS$_BADPARAM"); break; X`009 case SS$_CTRLERR: X`009`009fprintf(stdout,"SS$_CTRLERR"); break; X`009 case SS$_DATACHECK: X`009`009fprintf(stdout,"SS$_DATACHECK"); break; X`009 case SS$_DEVOFFLINE: X`009`009fprintf(stdout,"SS$_DEVOFFLINE"); break; X`009 case SS$_DRVERR: X`009`009fprintf(stdout,"SS$_DRVERR"); break; X`009 case SS$_FORMAT: X`009`009fprintf(stdout,"SS$_FORMAT"); break; X`009 case SS$_ILLIOFUNC: X`009`009fprintf(stdout,"SS$_ILLIOFUNC"); break; X`009 case SS$_MEDOFL: X`009`009fprintf(stdout,"SS$_MEDOFL"); break; X`009 case SS$_NONEXDRV: X`009`009fprintf(stdout,"SS$_NONEXDRV"); break; X`009 case SS$_PARITY: X`009`009fprintf(stdout,"SS$_PARITY"); break; X`009 case SS$_TAPEPOSLOST: X`009`009fprintf(stdout,"SS$_TAPEPOSLOST"); break; X`009 case SS$_TIMEOUT: X`009`009fprintf(stdout,"SS$_TIMEOUT"); break; X`009 case SS$_UNSAFE: X`009`009fprintf(stdout,"SS$_UNSAFE"); break; X`009 case SS$_VOLINV: X`009`009fprintf(stdout,"SS$_VOLINV"); break; X`009 case SS$_WRITLCK: X`009`009fprintf(stdout,"SS$_WRITLCK"); break; X`009 case SS$_DATAOVERUN: X`009`009fprintf(stdout,"SS$_DATAOVERUN"); break; X`009 case SS$_ENDOFFILE: X`009`009fprintf(stdout,"SS$_ENDOFFILE"); break; X`009 case SS$_ENDOFTAPE: X`009`009fprintf(stdout,"SS$_ENDOFTAPE"); break; X`009 case SS$_ENDOFVOLUME: X`009`009fprintf(stdout,"SS$_ENDOFVOLUME"); break; X`009 case SS$_BEGOFTAPE: X`009`009fprintf(stdout,"SS$_BEGOFTAPE"); break; X`009 default: X`009`009fprintf(stdout,"%04X",msgp->iosb.status); X`009`009break; X`009`125 X X`009if(msgp->iosb.devdep & MT$M_BOT) fprintf(stdout,",M_BOT"); X`009if(msgp->iosb.devdep & MT$M_EOF) fprintf(stdout,",M_EOF"); X`009if(msgp->iosb.devdep & MT$M_EOT) fprintf(stdout,",M_EOT"); X`009if(msgp->iosb.devdep & MT$M_HWL) fprintf(stdout,",M_HWL"); X`009if(msgp->iosb.devdep & MT$M_LOST) fprintf(stdout,",M_LOST"); X X`009if(msgp->iosb.count != 0) `123 X`009`009fprintf(stdout," iocnt=%d",msgp->iosb.count); X`009`125 X X`009fprintf(stdout," atm=%c",(aftertm == yes) ? '1' : X`009`009`009`009`009(aftertm == no) ? '0' : '?'); X`009 `032 X`009fprintf(stdout," record=%d\n",msgp->record);`009 `032 X`125 X X#endif /* TRACE */ X X X/*****/ X Xstatic short n_chan; Xstatic IOSB n_iosb; Xstatic IOSB zt_iosb; X Xstatic int ni_seq = 1; Xstatic int no_seq = 1; X Xstatic ZTNS_MSG n_buf; X X Xstatic void ns_init(void) X`123 X`009char ncb[512]; X`009char ztb[12]; X`009char procname[9]; X`009DESCR ncb_dsc = `1230-0,0,0,ncb`125; X X`009$DESCRIPTOR(ztb_dsc,ztb); X`009$DESCRIPTOR(d_ztape,"ZTAPE"); X`009$DESCRIPTOR(d_procname,procname); X X/* translate SYS$NET */ X X`009`123 X`009`009$DESCRIPTOR(lnmtabdsc,"LNM$FILE_DEV"); X`009`009$DESCRIPTOR(lognamedsc,"SYS$NET"); X`009`009VMS_ITEM lnmlist[] = X`009`009`009`123`123sizeof(ncb),LNM$_STRING,ncb,&ncb_dsc.dsc$w_length`125, X`009`009`009 `1230,0,NULL,NULL`125`125; X X`009`009CHECK(sys$trnlnm(0,&lnmtabdsc,&lognamedsc,0,lnmlist)); X`009`125 X X/* assign channel to NET */ X X`009`123 X`009`009$DESCRIPTOR(netdsc,"_NET:"); X X`009`009CHECK(sys$assign(&netdsc,&n_chan,0,0)); X`009`125 X X/* accept connection */ X X`009CHECK(sys$qiow(0,n_chan,IO$_ACCESS, X`009`009`009&n_iosb,0,0, X`009`009`0090,&ncb_dsc,0,0,0,0)); X`009CHECK(n_iosb.status);`032 X X/* Next section added by Bob Marshall, 6/7/93 to read the name of the X ZT device sent by the remote object on the other side (sent by ZTNS2). X This value is used to set the logical name ZTAPE, used in ZT_INIT.`032 X Also, the process name is changed to RMT_ZTAn so that the program X ZT2_FORCEX can find the right process to $FORCEX */ X X`009sys$qiow(0,n_chan,IO$_READVBLK, X`009`009&zt_iosb,0,0, X`009`009ztb,sizeof(ztb),0,0,0,0); X ztb_dsc.dsc$w_length = zt_iosb.count; X`009lib$set_logical(&d_ztape,&ztb_dsc,0,0,0); X`009strcpy(procname,"RMT_"); X`009strcat(procname,ztb); X`009sys$setprn(&d_procname); X X/* setup initial DEVDEPEND */ X X`009ns_iosb.devdep = MT$M_BOT; X`125 X X Xstatic void ns_req(int iofct,int ct) X`123 X`009int dmafct = 0; X`009unsigned dmasts; X`009int datacnt = 0; X`009unsigned char *datap = NULL; X X X/* send IOREQ */ X X`009n_buf.seq = no_seq++; X`009n_buf.func = ZTNS_F_IOREQ; X`009n_buf.count = ct; X`009n_buf.iofunc = iofct; X X`009CHECK(sys$qiow(0,n_chan,IO$_WRITEVBLK, X`009`009&n_iosb,0,0, X`009`009&n_buf,ZTNS_LEN1,0,0,0,0)); X`009CHECK(n_iosb.status); X X/* read msgs, till IOREPLY */ X X while(1) `123 X`009CHECK(sys$qiow(0,n_chan,IO$_READVBLK, X`009`009&n_iosb,0,0, X`009`009&n_buf,sizeof(n_buf),0,0,0,0)); X`009CHECK(n_iosb.status); X X/* check seq# */ X`009if(n_buf.seq != ni_seq++) FEHLER("prot.error: iseq"); X X/* check minimum length */ X`009if(n_iosb.count < ZTNS_LEN1) FEHLER("prot.error: msg too short"); X X/* process low level function */ X`009switch(n_buf.func) `123 X`009 default: X`009`009FEHLER("prot.error: bad func1"); X`009`009return; X X`009 case ZTNS_F_IOREPLY: X`009`009if(datap != NULL) `123 X`009`009`009FEHLER("prot.error: unexpected IOREPLY"); X`009`009`125 X`009`009ns_iosb = n_buf.iosb; X`009`009return; X X`009 case ZTNS_F_R_DATA: X`009`009if(datap != NULL) `123 X`009`009`009FEHLER("prot.error: unexpected R_DATA command"); X`009`009`125 X`009`009*bufbctp = datacnt = (n_buf.count & 0xFFFF); X`009`009datap = bufp; X`009`009dmafct = n_buf.func; X`009`009dmasts = SS$_NORMAL; X`009`009break; X X`009 case ZTNS_F_C_DATA: X`009`009if(datap != NULL) `123 X`009`009`009FEHLER("prot.error: unexpected C_DATA command"); X`009`009`125 X`009`009datacnt = (n_buf.count & 0xFFFF); X`009`009if(*bufbctp < datacnt) `123 X`009`009`009FEHLER("prot.error: C_DATA count too big"); X`009`009`125 X`009`009datap = bufp; X`009`009dmafct = n_buf.func; X`009`009dmasts = SS$_NORMAL; X`009`009break; X X`009 case ZTNS_F_W_DATA: X`009`009if(datap != NULL) `123 X`009`009`009FEHLER("prot.error: unexpected W_DATA command"); X`009`009`125 X`009`009datacnt = (n_buf.count & 0xFFFF); X`009`009if(datacnt <= 0) FEHLER("prot.error: DATA count .le.0"); X`009`009if(*bufbctp < datacnt) `123 X`009`009`009FEHLER("prot.error: W_DATA count too big"); X`009`009`125 X`009`009datap = bufp; X X`009`009/* send data */ X`009`009do `123 X`009`009`009int c; X X`009`009`009n_buf.seq = no_seq++; X`009`009`009n_buf.func = ZTNS_F_DATA; X`009`009`009n_buf.count = c = MIN(datacnt,ZTNS_DATALEN); X`009`009`009datacnt -= c; X`009`009`009memcpy(n_buf.data,datap,c); X`009`009`009datap += c; X X`009`009`009CHECK(sys$qiow(0,n_chan,IO$_WRITEVBLK, X`009`009`009`009&n_iosb,0,0, X`009`009`009`009&n_buf,c + ZTNS_LEN1,0,0,0,0)); X`009`009`009CHECK(n_iosb.status); X`009`009`125 while(datacnt > 0); X X`009`009datap = NULL; X`009`009break; X X`009 case ZTNS_F_DATA: X`009`009if(datap == NULL) `123 X`009`009`009FEHLER("prot.error: unexpected DATA"); X`009`009`125 X`009`009if(n_iosb.count != ZTNS_LEN1 + n_buf.count) `123 X`009`009`009FEHLER("prot.error: bad DATA msg length"); X`009`009`125 X`009`009if(n_buf.count > datacnt) `123 X`009`009`009FEHLER("prot.error: too much data"); X`009`009`125 X X`009`009switch(dmafct) `123 X`009`009 case ZTNS_F_R_DATA: X`009`009`009memcpy(datap,n_buf.data,n_buf.count); X`009`009`009break; X X`009`009 case ZTNS_F_C_DATA: X`009`009`009if(memcmp(datap,n_buf.data,n_buf.count)) `123 X`009`009`009`009dmasts = SS$_DATACHECK; X`009`009`009`125 X`009`009`009break; X`009`009 default: X`009`009`009FEHLER("prot.error: dmafct bad"); X`009`009`125 X`009`009datacnt -= n_buf.count; X`009`009datap += n_buf.count; X X`009`009if(datacnt == 0) `123`009/* data transfer complete */ X`009`009`009n_buf.seq = no_seq++; X`009`009`009n_buf.func = ZTNS_F_IOREPLY; X`009`009`009n_buf.iosb.status = dmasts; X X`009`009`009CHECK(sys$qiow(0,n_chan,IO$_WRITEVBLK, X`009`009`009`009&n_iosb,0,0, X`009`009`009`009&n_buf,ZTNS_LEN1,0,0,0,0)); X`009`009`009CHECK(n_iosb.status); X X`009`009`009datap = NULL; X`009`009`125 X`009`009break; X`009`125 X `125 X`125 $ GOSUB UNPACK_FILE $ FILE_IS = "ZT2.COM" $ CHECKSUM_IS = 337268944 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X$ set noon X$ run rmt$dir:zt2 X$ logout $ GOSUB UNPACK_FILE $ FILE_IS = "ZT2_FORCEX.FOR" $ CHECKSUM_IS = 308323376 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X`009program zt2_forcex X* X`009implicit integer (A-Z) X`009include '($jpidef)' X`009include '($ssdef)' X* X`009structure /itmlst/ X`009 union X`009 map X`009 integer*2 buflen,itmcod X`009 integer*4 bufadr,retadr -+-+-+-+-+ End of part 6 +-+-+-+-+- +-+-+-+ Beginning of part 7 +-+-+-+ X`009 end map X`009 map X`009 integer*4 end_list X`009 end map X`009 end union X`009end structure X* X`009record /itmlst/jpibuf(3) X* X`009character prcnam*15,target_process*15 X* X`009jpibuf(1).buflen=4 X`009jpibuf(1).itmcod=jpi$_pid X`009jpibuf(1).bufadr=%loc(pid) ! Process ID X`009jpibuf(1).retadr=0 X* X`009jpibuf(2).buflen=15 X`009jpibuf(2).itmcod=jpi$_prcnam X`009jpibuf(2).bufadr=%loc(prcnam) ! Process name X`009jpibuf(2).retadr=%loc(lp) X* X`009jpibuf(3).end_list=0 X* X`009call lib$get_foreign(target_process) X* X`009seedpid = -1 X* X*`009As long as there are processes, keep looping X* X10 continue X* X`009istat=sys$getjpiw(,%ref(seedpid),,%ref(jpibuf),,,) X* X`009if(istat.eq.ss$_nomoreproc)go to 20 ! End of process list...done X* X`009if(prcnam(1:lp) .eq. target_process(1:lp))then X`009 call sys$forcex(pid,,) X`009 call exit X`009endif X`009go to 10 X20`009continue X`009end $ GOSUB UNPACK_FILE $ FILE_IS = "ZTDEF.MAR" $ CHECKSUM_IS = 2098861157 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X.macro`009ztdef X; X; driver/server communication area: X;`009sent to server via MBX, X;`009copied back by server X; X`009$defini`009ZT X$def`009zt_w_iosts`009.blkw`009; IOSB+0`009`009`009[d ->] s -> d X$def`009zt_w_iobct`009.blkw`009; IOSB+2`009`009`009[d ->] s -> d X$def`009zt_l_devdepend`009.blkl`009; UCB$W_DEVDEPEND = IOSB+4 `009d -> s -> d X$def`009zt_l_record`009.blkl`009; UBC$L_RECORD`009`009`009d -> s -> d X$def`009zt_w_ucbsts`009.blkw`009; UCB$W_STS`009`009`009d -> s -> d (*) X`009`009`009`009; `009(*) only UCB$M_VALID to be copied back X$def`009zt_w_fill1`009.blkw`009; "reserved" X$def`009zt_l_devchar`009.blkl`009; UCB$L_DEVCHAR`009`009`009d -> s X$def`009zt_w_func`009.blkw`009; IRP$W_FUNC`009`009`009d -> s X$def`009zt_w_bcnt`009.blkw`009; UCB$W_BCNT`009`009`009d -> s X$def`009zt_l_media`009.blkl`0092 ; IRP$L_MEDIA`009`009`009d -> s X$def`009zt_msglen X`009$defend`009ZT X; X`009$defini`009ZTUCB,dot=ucb$k_lcl_tape_length X;data cells known to server X$def`009ucb_l_inter`009.blkl`009; pointer to pseudo-interrupt routine X$def`009ucb_l_ztmbx`009.blkl`009; pointer to server's mailbox UCB X; X$def`009ucb_a_ztmsg`009.blkb `009zt_msglen`009; above data X$def`009ucb_k_ztend X`009$defend`009ZTUCB X; X.endm`009ztdef $ GOSUB UNPACK_FILE $ FILE_IS = "ZTDRIVER.MAR" $ CHECKSUM_IS = 1999052870 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X`009.title`009ZTdriver`009... pseudo tape ... X; X; gce 7/1992 X;`009w.j.m. jun 1989 (after ZXdriver 0.2 ...) X;`009documentation fixed 3-jul-1989 X;`009mod 18-aug-1989 wjm (0.9): support SMP, i.e. VMS V5 X; X`009.ident`009/v0.1/ X; X;***** X; X;`009This driver attempts to do the minimum necessary; X;`009all the 'real' work, including data transfer, X;`009is done by a (suitably privileged) server process. X; X;`009Communication: X;`009`009driver->server`009- driver activates server via mailbox message, X;`009`009`009`009`009then waits for pseudo-interrupt. X;`009`009server->driver`009- server (possibly) manipulates UCB, X;`009`009`009`009`009in particular copies back the X;`009`009`009`009`009'message' area (*); X;`009`009`009`009`009then it activates the driver via X;`009`009`009`009`009pseudo-interrupt. X; X;`009(*) Only the following fields are taken from the message area: X;`009`009ucb$l_record X;`009`009ucb$v_valid (in ucb$w_sts) X;`009`009ucb$l_devdepend (from 2nd iosb longword) X; X;`009It is the server's responsibility to set the device 'ONLINE' X;`009and to clean up and set the device 'OFFLINE' before terminating. X; X;***** X; X`009.link`009`009"SYS$SYSTEM:SYS.STB"/SELECTIVE_SEARCH X`009.library`009"SYS$LIBRARY:LIB" X`009.library`009"ZT" X; X`009$crbdef X`009$dcdef X`009$ddbdef X`009$devdef X`009$dptdef X`009$dyndef X`009$idbdef X`009$iodef X`009$ipldef X`009$irpdef X`009$mtdef X`009$prdef X`009$ssdef X`009$ucbdef X`009$vecdef X`009$wcbdef X; Xsmp_code=0`009`009`009`009;VMS V4 or earlier X.iif df UCB$L_DLCK, smp_code=1`009`009;VMS V5`032 X; X.if ne smp_code X`009$spldef X.endc X; X`009ztdef`009`009; ZT definitions - need $ucbdef X; X; private UCB fields not in ZTDEF X; X`009$defini`009UCB,dot=ucb_k_ztend X$def`009ucb_q_spare`009.blkq`009`009; reserve for UCB expansion X$def`009ucb_k_size`009`009`009; end of UCB X`009$defend`009UCB X; X`009.page X;*****`009driver prologue table X; X`009dptab`009name=ZTDRIVER,-`009`009; Driver name`009`009<<<<< X`009`009adapter=NULL,- X`009`009flags=dpt$m_svp,-`009; for IOC$MOV[FR/TO]USER X;`009`009maxunits=1,-`009`009; want 1 unit only X`009`009maxunits=4,-`009`009; want 4 units (RAM, 6/3/93) X`009`009ucbsize=ucb_k_size,- X`009`009end=end_of_driver X; X`009dpt_store`009INIT X; X.if eq smp_code X`009dpt_store `009UCB,ucb$b_fipl,B,- X`009`009`009ipl$_synch`009`009; fork IPL X`009dpt_store`009UCB,ucb$b_dipl,B,- X`009`009`009ipl$_synch`009`009; device IPL = same X`009assume`009`009ipl$_synch lt ipl$_mailbox`009;note: writing to MBX X`009`009`009`009`009`009; is done at device IPL X.iff X`009dpt_store `009UCB,ucb$b_flck,B,- X`009`009`009spl$c_iolock8`009`009; fork lock index X`009dpt_store`009UCB,ucb$b_dipl,B,- X`009`009`009ipl$_iolock8`009`009; device IPL = fork IPL X`009assume`009`009ipl$_iolock8 lt ipl$_mailbox`009;note: writing to MBX X`009`009`009`009`009`009; is done at device IPL X.endc X`009dpt_store`009UCB,ucb$b_devclass,B,- X`009`009`009dc$_tape`009`009; device class X`009dpt_store`009UCB,ucb$b_devtype,B,- X`009`009`009dt$_te16`009`009; device type = TE16 X`009dpt_store `009UCB,ucb$l_devchar,L,<-`009; device characteristics X`009`009`009dev$m_avl!-`009`009`009; available X`009`009`009dev$m_idv!-`009`009`009; input device X`009`009`009dev$m_odv!-`009`009`009; output device X`009`009`009dev$m_fod!-`009`009`009; file oriented X`009`009`009dev$m_dir!-`009`009`009; directory structured X`009`009`009dev$m_sdi!-`009`009`009; single directory X`009`009`009dev$m_sqd>`009`009`009; sequential X`009dpt_store`009UCB,ucb$l_devchar2,L,-`009; (cont'd) X`009`009`009dev$m_nnm`009`009`009; "node$" prefix X`009dpt_store`009DDB,ddb$l_acpd,L,-`009; default ACP X`009`009`009<`094a"MTA">`009`009`009; = MTAACP X`009dpt_store`009UCB,ucb$w_devbufsiz,W,-`009; default buffer size X`009`009`0092048`009`009`009`009; = 2048 X`009dpt_store`009UCB,ucb$l_media_id,L,-`009; media i.d. X`009`009`009<`094x6D285010>`009`009`009; media id - TE16 X X`009dpt_store`009REINIT X; X`009dpt_store`009UCB,ucb$l_devdepend,L,<- ; tape characteristics X`009`009`009!-`009; format = normal11 X`009`009`009!-`009; density = 1600 X`009`009`009mt$m_sup_pe!-`009`009`009; support PE only X`009`009`009mt$m_lost>`009`009`009; "position lost" X`009dpt_store`009UCB,ucb$l_record,L,-`009;current tape position X`009`009`0090`009`009`009`009; i.e. BOT X`009dpt_store`009DDB,ddb$l_ddt,D,- X`009`009`009ZT$DDT`009`009`009; address of DDT`009<<<<< X`009dpt_store`009CRB,crb$l_intd+vec$l_initial,D,- X`009`009`009controller_init`009`009; controller initialization X DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,- ;UNIT INIT ADDRESS X D,unit_INIT ;... X ; X; X`009dpt_store`009END X; X; X;*****`009driver dispatch table X; X`009ddtab`009devnam=ZT,-`009`009`009; device name X`009`009functb=fdt_table,- X`009`009start=start_io,- X`009`009cancel=+IOC$CANCELIO`009;cancel: just set flag X; X; X;*****`009function dispatch table X; Xfdt_table: X`009functab`009,<-`009`009`009`009; valid functions X`009`009-`009`009`009;physical: X`009`009nop,-`009`009`009`009;nop (status check only) X`009`009unload,-`009`009`009;unload (=rewindoff) X`009`009spacefile,-`009`009`009;(=skipfile) X`009`009recal,-`009`009`009`009;'recalibrate' (=rewind) X`009`009drvclr,-`009`009`009;'drive clear' X`009`009erasetape,-`009`009`009;write extended gap X`009`009packack,-`009`009`009;set valid X`009`009spacerecord,-`009`009`009;(=skiprecord) X`009`009writecheck,-`009`009`009;compare X`009`009writepblk,-`009`009`009;write X`009`009readpblk,-`009`009`009;read X`009`009available,-`009`009`009;unload & clear valid X`009`009setchar,-`009`009`009; X`009`009sensechar,-`009`009`009; X`009`009writemark,-`009`009`009;(=writeof) X`009`009-`009`009`009;logical: X`009`009writelblk,-`009`009`009;write X`009`009readlblk,-`009`009`009;read X`009`009rewindoff,-`009`009`009;rewind & unload X`009`009setmode,-`009`009`009; X`009`009rewind,-`009`009`009; X`009`009skipfile,-`009`009`009; X`009`009skiprecord,-`009`009`009; X`009`009sensemode,-`009`009`009; X`009`009writeof,-`009`009`009;write tape mark X`009`009-`009`009`009;virtual (ACP only) X`009`009writevblk,-`009`009`009;write X`009`009readvblk,-`009`009`009;read X`009`009access,-`009`009`009; X`009`009create,-`009`009`009; X`009`009deaccess,-`009`009`009; X`009`009delete,-`009`009`009;(???) X`009`009modify,-`009`009`009;(???) X`009`009acpcontrol,-`009`009`009; X`009`009mount>`009`009`009`009; X`009functab`009,<-`009`009`009`009; buffered functions ... X`009`009-`009`009;... all but data transfer & AVAILABLE (WHY???) X`009`009nop,- X`009`009unload,- X`009`009spacefile,- X`009`009recal,- X`009`009drvclr,- X`009`009erasetape,- X`009`009packack,- X`009`009spacerecord,- X`009`009setchar,- X`009`009sensechar,- X`009`009writemark,- X`009`009rewindoff,- X`009`009setmode,- X`009`009rewind,- X`009`009skipfile,- X`009`009skiprecord,- X`009`009sensemode,- X`009`009writeof,- X`009`009access,- X`009`009create,- X`009`009deaccess,- X`009`009delete,- X`009`009modify,- X`009`009acpcontrol,- X`009`009mount> X X`009functab`009+ACP$READBLK,<-`009`009`009; read functions => ACP => ... X`009`009readpblk,- X`009`009readlblk,- X`009`009readvblk> X`009functab`009+ACP$WRITEBLK,<-`009`009; write functions => ACP => ... X`009`009writecheck,- X`009`009writepblk,- X`009`009writelblk,- X`009`009writevblk> X`009functab`009+ACP$ACCESS,<-`009`009`009; access => ACP only X`009`009access,- X`009`009create> X`009functab`009+ACP$DEACCESS,<-`009`009; deaccess => ACP only X`009`009deaccess> X`009functab`009+ACP$MODIFY,<-`009`009`009; control => ACP only X`009`009delete,- X`009`009modify,- X`009`009acpcontrol> X`009functab`009+ACP$MOUNT,<-`009`009`009; mount => ACP only X`009`009mount> X`009functab`009+MT$CHECK_ACCESS,<-`009`009; check access for X`009`009-`009`009`009`009; functions not handled by ACP X`009`009erasetape,- X`009`009writemark,- X`009`009writeof> X X`009functab`009+EXE$ZEROPARM,<-`009`009; (final) functions with 0 par. X`009`009nop,- X`009`009unload,- X`009`009recal,- X`009`009drvclr,- X`009`009erasetape,- X`009`009packack,- X`009`009available,- X`009`009sensechar,-`009`009;(!) X`009`009writemark,- X`009`009rewindoff,- X`009`009rewind,- X`009`009sensemode,-`009`009;(!) X`009`009writeof> X`009functab`009+EXE$ONEPARM,<-`009`009`009; (final) functions with 1 par. X`009`009spacefile,- X`009`009spacerecord,- X`009`009skipfile,- X`009`009skiprecord> X`009functab`009+EXE$SETMODE,<-`009`009`009; (final) set mode X`009`009setchar,- X`009`009setmode> X X; X`009.page X;*****`009controller initialization X; X;`009called`009(1) after loading the driver (not after RELOAD !?) X;`009`009(2) after a power failure X; X;`009r4 - `009csr X;`009r5 -`009idb X;`009r6 -`009ddb X;`009r8 -`009crb X;`009r0..r2 - free for use X; X;`009idb$l_ucblst - ucb (since there is only 1 unit) X; X;`009ipl: ipl$_power X;`009`009 X;***** X; Xcontroller_init: X; X`009movl`009idb$l_ucblst(r5),r0`009; r0 -> ucb (NOTE: maxunits=1) X; X;;; setting device on-line is left to server program! X;;;`009bisw`009#ucb$m_online,-`009`009; set device status "on_line" X;;;`009`009ucb$w_sts(r0) X; X;`009movl`009r0,idb$l_owner(r5)`009; set permanent controller owner X; X`009movab`009pseudo_interrupt,ucb_l_inter(r0)`009; constant UCB field X; X`009rsb X; Xunit_init: X`009movab`009pseudo_interrupt,ucb_l_inter(r5)`009;set pseudo-int. addr X`009rsb`009`009`009;nothing for unit init to do X`009.page X;*****`009start I/O routine X; X;`009r3 - IRP X;`009r5 - UCB X;`009r0..r2, r4 - free (only r3..r5 saved across WFI) X; X;`009ipl: ucb$b_fipl, SMP lock: ucb$b_flck X; X;`009irp$w_func`009- io function (logical or physical) X;`009irp$l_media`009- parameter(s) X;`009ucb$w_bcnt, ucb$w_boff, ucb$l_svapte describe buffer X; X; X;***** X; Xstart_io: X`009movzwl`009irp$w_func(r3),r2`009`009;IO function + modifiers X`009movw`009r2,ucb$w_func(r5)`009`009; save function in UCB X; X; set up mailbox request X; X`009movw`009r2,ucb_a_ztmsg+zt_w_func(r5)`009; fill in 'function' X`009movw`009ucb$w_bcnt(r5),-`009`009; ditto for bytecount X`009`009ucb_a_ztmsg+zt_w_bcnt(r5) X`009movq`009irp$l_media(r3),-`009`009; ditto for parameter(s) X`009`009ucb_a_ztmsg+zt_l_media(r5) X`009movw`009ucb$w_sts(r5),-`009`009`009; ditto for ucb$w_sts X`009`009ucb_a_ztmsg+zt_w_ucbsts(r5) X`009movl`009ucb$l_record(r5),-`009`009; ditto for ucb$l_record X`009`009ucb_a_ztmsg+zt_l_record(r5) X`009movl`009ucb$l_devdepend(r5),-`009`009; ditto for ucb$l_devdepend X`009`009ucb_a_ztmsg+zt_l_devdepend(r5) X`009movl`009ucb$l_devchar(r5),-`009`009; ditto for ucb$l_devchar X`009`009ucb_a_ztmsg+zt_l_devchar(r5) X; X`009movl`009#ss$_devoffline,- X`009`009ucb_a_ztmsg+zt_w_iosts(r5)`009; default 1st iosb longword X; X; server there? X; X`009tstl`009ucb_l_ztmbx(r5)`009`009`009; server mailbox there? X`009blss`0091$`009`009`009`009; br if yes (S0 space!) X`009brw`009io_err_noserver`009`009`009; server disappeared X; X1$: X; X; check for special action(s) X; X`009extzv`009#irp$v_fcode,#irp$s_fcode,-`009;get major function X`009`009irp$w_func(r3),r2 X; X`009cmpw`009r2,#io$_setchar X`009beql`009150$ X`009cmpw`009r2,#io$_setmode X`009beql`009160$ X`009cmpw`009r2,#io$_available X`009beql`009175$ X`009brw`00920$ X; X; set char/mode X; X150$:`009`009`009`009`009`009;io$_setchar X`009movw`009irp$l_media(r3),- X`009`009ucb$b_devclass(r5) X160$:`009`009`009`009`009`009;io$_setmode X`009movw`009irp$l_media+2(r3),- X`009`009ucb$w_devbufsiz(r5) X`009brw`00920$ X; X; available X; X175$: X`009bicw`009#ucb$m_valid,ucb$w_sts(r5)`009;set invalid now X`009bicw`009#ucb$m_valid,- X`009`009ucb_a_ztmsg+zt_w_ucbsts(r5)`009;also update in message (!) X`009brw`00920$ X; X; X; check if i/o is permitted X; X20$: X`009bbs`009#irp$v_physio,irp$w_sts(r3),30$`009; o.k. if physical X`009bbs`009#ucb$v_valid,ucb$w_sts(r5),30$`009; o.k. if volume valid X`009movw`009#ss$_volinv,- X`009`009ucb_a_ztmsg+zt_w_iosts(r5)`009; else error: volume invalid X`009brw`009io_complete X; X; have server do the rest ... X; X30$: X; X; SMP note: postprocessing of the mailbox i/o is done on "this" processor, X;`009`009*** I think ***. X;`009Therefore the mailbox msg will be delivered (by KAST) X;`009only AFTER ipl drops to ASTDEL, i.e. after wfikpch X;`009 X.if eq smp_code X`009dsbint`009ucb$b_dipl(r5)`009`009`009;; X.iff`009`009`009`009`009`009;; X`009devicelock`009-`009`009`009;; X`009`009lockaddr=ucb$l_dlck(r5),-`009;; X`009`009lockipl=ucb$b_dipl(r5),-`009;; X`009`009savipl=-(sp),-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X`009bitw`009#ucb$m_cancel,ucb$w_sts(r5)`009;; I/O to be aborted? X`009beql`00921$`009`009`009`009;; -+-+-+-+-+ End of part 7 +-+-+-+-+- +-+-+-+ Beginning of part 8 +-+-+-+ X`009brw`009io_cancelled`009`009`009;; br if yes, do it now! X21$:`009`009`009`009`009`009;; X`009pushr`009#`094m`009`009`009;; X`009movl`009#zt_msglen,r3`009`009`009;; X`009movab`009ucb_a_ztmsg(r5),r4`009`009;; X`009movl`009ucb_l_ztmbx(r5),r5`009`009;; X`009jsb`009g`094EXE$WRTMAILBOX`009`009;; X`009popr`009#`094m`009`009`009;; X`009blbs`009r0,23$`009`009`009`009;; br if o.k. X`009`009`009`009`009`009;; X.if eq smp_code`009`009`009`009`009;; X`009enbint`009`009`009`009`009;; X.iff`009`009`009`009`009`009;; X`009deviceunlock`009-`009`009`009;; X`009`009lockaddr=ucb$l_dlck(r5),-`009;; X`009`009newipl=(sp)+,-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc X`009brw`009io_err_noserver X23$:`009`009`009`009`009`009;; X`009wfikpch`009io_timeout`009`009`009;; (dummy timeout) X;`009`009`009`009`009;; here with device lock only X`009iofork X`009`009`009`009`009; here with fork lock only X; server replied ... X; X`009brw`009io_complete`009`009`009;o.k., all done X; X; X; i/o cancelled ... X;`009ipl: _dipl with _fipl on stack X; Xio_cancelled:`009`009`009`009`009;; X.if eq smp_code`009`009`009`009`009;; X`009enbint`009`009`009`009`009;; lower IPL (to _fipl) X.iff`009`009`009`009`009`009;; X`009deviceunlock`009-`009`009`009;; X`009`009lockaddr=ucb$l_dlck(r5),-`009;; X`009`009newipl=(sp)+,-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc X; X`009movzwl`009#ss$_cancel,- X`009`009ucb_a_ztmsg+zt_w_iosts(r5)`009; set status X`009brw`009io_complete X; X; X; i/o timeout - we cannot allow for an asynchronous event X;`009ipl: ucb$b_dipl, SMP locks: ucb$l_dlck + ucb$b_flck X; Xio_timeout:`009`009`009`009`009;; X`009bisw`009#,ucb$w_sts(r5)`009;; re-set interrupt expected X`009bicw`009#,ucb$w_sts(r5)`009;;`009and powerfail X`009rsb`009`009`009`009`009;; return! X; X; X; server gone X; Xio_err_noserver: X`009bicw`009#,-`009;clear valid & online X`009`009ucb$w_sts(r5) X`009clrl`009ucb_l_ztmbx(r5)`009`009`009;clear our indicator X`009brb`009io_complete`009`009`009;default values still o.k. X; X; X; i/o completed (normally by server) X; Xio_complete: X`009bicw`009#,- X`009`009ucb$w_sts(r5)`009`009`009; cleanup some UCB flags X; X`009movl`009ucb_a_ztmsg+zt_l_record(r5),-`009;care for ... X`009`009ucb$l_record(r5)`009`009`009; ucb$l_record ... X`009extzv`009#ucb$v_valid,#1,- X`009`009ucb_a_ztmsg+zt_w_ucbsts(r5),r2`009`009; ucb$v_valid ... X`009insv`009r2,#ucb$v_valid,#1,ucb$w_sts(r5) X`009movl`009ucb_a_ztmsg+zt_l_devdepend(r5),r1`009; 2nd iosb longword ... X`009movl`009r1,ucb$l_devdepend(r5)`009`009`009; ucb$l_devdepend ... X`009movl`009ucb_a_ztmsg+zt_w_iosts(r5),r0`009`009; 1st iosb longword X; X; X; special ACP-related cleanup on error (... from DEC ...) X; ... destroys r2 and r4 !! X; X`009blbs`009r0,done`009`009`009`009;br if no error X`009bbc`009#irp$v_virtual,irp$w_sts(r3),-`009;br if not virtual X`009`009done X; X`009movq`009r0,-(sp)`009`009;save r0,r1 X`009movl`009irp$l_wind(r3),r4`009;... X`009clrw`009wcb$w_nmap(r4)`009`009;... X`009movl`009ucb$l_vcb(r5),r4`009;r4=vcb X`009movab`009ucb$l_ioqfl(r5),r2`009;r2=i/o queue listhead (end of list) X`009movl`009r2,r0`009`009`009;r0=IRP pointer X70$: X`009movl`009(r0),r0`009`009`009;get next IRP X`009cmpl`009r0,r2`009`009`009;end of list? X`009beql`00979$`009`009`009;br if yes X`009bbc`009#irp$v_virtual,- X`009`009irp$w_sts(r0),70$`009;skip IRP if not virtual X`009movl`0094(r0),r0`009`009;back up r0 X`009remque`009@0(r0),r1`009`009;remove IRP from I/O queue X`009insque`009(r1),@4(r4)`009`009;insert it into blocked queue (in VCB) X`009brb`00970$ X79$: X`009movq`009(sp)+,r0`009`009;note: r2 & r4 destroyed X; Xdone: X`009reqcom X; X`009.page X;*****`009ZT pseudo-interrupt X; X;`009r0 ... r4 free X;`009r5 -> UCB X;`009ipl = ucb$b_dipl, SMP lock: ucb$l_dlck X; X; function: X;`009on any expected "interrupt", the driver is called back. X;`009we also clear ucb$m_int and ucb$m_tim X;`009`009 X; Xpseudo_interrupt: X; X`009bbc`009#ucb$v_int,ucb$w_sts(r5),90$ X; X`009bicw`009#,- X`009`009ucb$w_sts(r5)`009`009`009; no more interrupts desired X`009assume`009ucb$l_fr4 eq ucb$l_fr3+4 X`009movq`009ucb$l_fr3(r5),r3 X`009jsb`009@ucb$l_fpc(r5)`009`009`009; call driver X90$: X`009rsb X; X; X;*****`009end of driver X; Xend_of_driver: X; X`009.end $ GOSUB UNPACK_FILE $ FILE_IS = "ZTDRIVER.OPT" $ CHECKSUM_IS = 1701995486 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY Xztdriver X Xbase=0 $ GOSUB UNPACK_FILE $ FILE_IS = "ZTNS.H" $ CHECKSUM_IS = 67703244 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* definitions for ZT<->ZTnetserver protocol */ X Xtypedef struct IOSB `123 X`009unsigned short status; X`009unsigned short count; X`009unsigned long devdep; X`125 IOSB; X X X/***** ZTNS function codes *****/ X X#define ZTNS_F_IOREQ`0091`009/* ZT -> NS: iofunc + count`009`009*/ X#define ZTNS_F_IOREPLY`0092`009/* NS -> ZT: iosb,`009`009`009*/ X`009`009`009`009/* ZT -> NS: iosb.status only`009`009*/ X`009`009`009`009/*`009`009(after CMP & PUT)`009*/ X#define ZTNS_F_DATA`0093`009/* 'DMA' data (both directions): count`009*/ X#define ZTNS_F_R_DATA`0094`009/* NS -> ZT: accept 'DMA' data`009*/ X#define ZTNS_F_W_DATA`0095`009/* NS -> ZT: send 'DMA' data`009*/ X#define ZTNS_F_C_DATA`0096`009/* NS -> ZT: rcv.&check 'DMA' data */ X X X/***** ZTNS network messages *****/ X X#define ZTNS_DATALEN 1400`009/* max. #bytes transferred in 1 message */ X`009`009`009`009/* ? ought to be a single Ethernet packet ? */ X Xtypedef struct ZTNS_MSG `123 X`009int seq;`009`009/* sequence number, starts at 1 */ X`009unsigned short func;`009/* ZTNS_F_xxxx */ X`009unsigned short iofunc;`009/* used by:`009IOREQ, IO$_xxx + modifiers */ X`009int count;`009`009/* used by:`009IOREQ (signed!),`032 X`009`009`009`009`009`009xxxDATA (total cnt), X`009`009`009`009`009`009DATA (#bytes in 'data') */ X`009IOSB iosb;`009`009/* used by:`009IOREPLY */ X`009unsigned char data[ZTNS_DATALEN];`009/* used with DATA only */ X`125 ZTNS_MSG; X X#define ZTNS_LEN1 (sizeof(ZTNS_MSG) - ZTNS_DATALEN)`009/* short packet */ X X/* note: length of a DATA packet must be ZTNS_LEN1 + (count) */ $ GOSUB UNPACK_FILE $ FILE_IS = "ZTNS2.C" $ CHECKSUM_IS = 1243149029 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* serve real tape, for ZT2/ZTserver */ X/* w.j.m. jun 1989 */ X/* X/* Mod by Bob Marshall, 6/13/93 : X X Translate the logical name ZT_DEVICE (obtained from the network`032 X object on the "real-tape" side) and pass it back to the ZT2 object. X This is necessary so that ZT2 know which ZTAn device to use in the X case of multiple units. The routine net_send_device was added for X this purpose. X*/ X X/* implicit inputs: X`009logical name ZT_TAPE points to a tape unit mounted foreign X`009logical name ZT_NETOBJECT has equivalence `096node::"0=name/' X`009logical name ZT_DEVICE has equivalence ZTAn X*/ X X#define T_LOGNAME "ZT_TAPE" X#define N_LOGNAME "ZT_NETOBJECT" X#define Z_LOGNAME "ZT_DEVICE" X X X#include "ztns.h"`009/* includes IOSB, VMS_ITEM */ X X#include ssdef X#include lnmdef X#include "iodef.h"`009/* my own! */ X#include "mtdef.h" X X#include stdio X#include stddef X#include string X#include descrip Xtypedef struct dsc$descriptor DESCR; X X#define CHECK(x) do `123unsigned s=x; if(!(s&1)) lib$stop(s);`125 while(0) X#define FEHLER(m) do `123$DESCRIPTOR(d,m); Fehler(&d);`125 while(0) X#define CHECKX(x) do `123unsigned s=x; if(!(s&1)) sys$exit(s);`125 while(0) X#define MIN(a,b) ((a) < (b)) ? (a) : (b) X Xextern unsigned lib$get_foreign(),lib$stop(); Xextern unsigned sys$exit(),sys$assign(),sys$wake(),sys$hiber(),sys$trnlnm(); Xextern unsigned sys$qiow(int,int,int, X`009`009`009IOSB*,void*,int, X`009`009`009void*,int,int,int,int,int); Xextern unsigned sys$qio(int,int,int, X`009`009`009IOSB*,void*,int, X`009`009`009void*,int,int,int,int,int); X Xtypedef struct VMS_ITEM `123 X`009unsigned short size; X`009unsigned short code; X`009void *bufp; X`009int *lenp; X`125 VMS_ITEM; X X X/***** tape data *****/ Xstatic IOSB t_iosb; Xstatic short t_chan; Xstatic unsigned char t_buffer[0xFFFF]; X Vstatic unsigned short ti_iofunc = 0;`009/* request function, !=0 while busy * X/ Xstatic int ti_count;`009`009`009/* request count */ X Xstatic unsigned char *ti_datap = NULL;`009/* input 'DMA' pointer, X`009`009`009`009`009`009==NULL unless data expected */ Xstatic int ti_datacnt = 0;`009`009/* input 'DMA' counter */ X Xstatic int/*logical*/ ti_replyexp = 0;`009/* IOREPLY expected */ Xstatic unsigned short ti_replysts;`009/* status from same */ X X/***** network data *****/ Xstatic short n_chan; X Xstatic IOSB zt_iosb; X X`009/* ZT -> NS */ Xstatic IOSB ni_iosb; Xstatic ZTNS_MSG ni_buf; Xstatic int ni_seq = 1; X X`009/* NS -> ZT (our output) */ Xstatic IOSB no_iosb; Xstatic ZTNS_MSG no_buf; Xstatic int no_seq = 1; X X X/*****/ X Xstatic void net_ast();`009`009/*forward*/ X Xstatic void net_read() X`123 X`009CHECKX(sys$qio(1,n_chan,IO$_READVBLK, X`009`009&ni_iosb,net_ast,0, X`009`009&ni_buf,sizeof(ni_buf),0,0,0,0)); X`125 X Xstatic void net_send_device() X`123 X`009char ztb[12]; X`009DESCR ztb_dsc = `1230-0,0,0,ztb`125; X X X/* translate z_logname */ X X`009`123 X`009`009$DESCRIPTOR(lnmtabdsc,"LNM$FILE_DEV"); X`009`009$DESCRIPTOR(lognamedsc,Z_LOGNAME); X`009`009VMS_ITEM lnmlist[] = X`009`009`009`123`123sizeof(ztb),LNM$_STRING,ztb,&ztb_dsc.dsc$w_length`125, X`009`009`009 `1230,0,NULL,NULL`125`125; X X`009`009CHECK(sys$trnlnm(0,&lnmtabdsc,&lognamedsc,0,lnmlist)); X`009`125 X X/* Next line added by Bob Marshall, 6/7/93, to transmit the name of the X ZT device to the object on the other side (ZT2) */ X X`009`009CHECKX(sys$qiow(1,n_chan,IO$_WRITEVBLK, X`009`009`009&zt_iosb,0,0, X`009`009`009ztb,ztb_dsc.dsc$w_length,0,0,0,0)); X`125 X X Xstatic void net_send(fct) Xint fct;`009/* ZTNS_F_xxxx */ X`123 X`009no_buf.seq = no_seq++; X`009no_buf.func = fct; X X`009CHECKX(sys$qiow(0,n_chan,IO$_WRITEVBLK, X`009`009&no_iosb,0,0, X`009`009&no_buf, X`009`009((fct == ZTNS_F_DATA) ? (ZTNS_LEN1 + no_buf.count) : ZTNS_LEN1), X`009`0090,0,0,0)); X`009CHECKX(no_iosb.status); X`125 X X Xstatic void net_start() X`123 X`009char ncb[512]; X`009DESCR ncb_dsc = `1230-0,0,0,ncb`125; X X X/* translate n_logname */ X X`009`123 X`009`009$DESCRIPTOR(lnmtabdsc,"LNM$FILE_DEV"); X`009`009$DESCRIPTOR(lognamedsc,N_LOGNAME); X`009`009VMS_ITEM lnmlist[] = X`009`009`009`123`123sizeof(ncb),LNM$_STRING,ncb,&ncb_dsc.dsc$w_length`125, X`009`009`009 `1230,0,NULL,NULL`125`125; X X`009`009CHECK(sys$trnlnm(0,&lnmtabdsc,&lognamedsc,0,lnmlist)); X`009`125 X X/* assign channel to NET */ X X`009`123 X`009`009$DESCRIPTOR(netdsc,"_NET:"); X X`009`009CHECK(sys$assign(&netdsc,&n_chan,0,0)); X`009`125 X X/* open connection */ X X`009if(ncb_dsc.dsc$w_length+2+1+16+1 > sizeof(ncb)) `123 X`009`009FEHLER("ncb too small"); X`009`125 X X`009/* clear conn.id & ncb info */ X`009memset(ncb+ncb_dsc.dsc$w_length,0,2+1+16); X`009ncb_dsc.dsc$w_length += 2+1+16; X X`009/* add trailing quotemark */ X`009ncb[ncb_dsc.dsc$w_length] = '\"'; X`009ncb_dsc.dsc$w_length += 1; X X`009CHECK(sys$qiow(0,n_chan,IO$_ACCESS, X`009`009`009&no_iosb,0,0, X`009`009`0090,&ncb_dsc,0,0,0,0)); X`009CHECK(no_iosb.status); X X/* send ZT_DEVICE to remote object */ X X`009net_send_device(); `032 X X/* start async. read from net */ X X`009net_read(); X`125 X X Xstatic void net_ast()`009/* here when we receive net msg */ X`123 X/* check I/O */ X`009CHECKX(ni_iosb.status); X X/* check seq# */ X`009if(ni_buf.seq != ni_seq++) FEHLER("prot.error: iseq"); X X/* check minimum length */ X`009if(ni_iosb.count < ZTNS_LEN1) FEHLER("prot.error: msg too short"); X X/* process low level function */ X`009switch(ni_buf.func) `123 X`009 default: X`009`009FEHLER("prot.error: bad func1"); X`009`009return; X X`009 case ZTNS_F_IOREPLY: X`009`009if(ti_replyexp == 0) `123 X`009`009`009FEHLER("prot.error: unexpected IOREPLY"); X`009`009`125 X`009`009ti_replyexp = 0; X`009`009ti_replysts = ni_buf.iosb.status; X`009`009CHECK(sys$wake(0,0)); X`009`009break; X X`009 case ZTNS_F_IOREQ: X`009`009if(ti_iofunc != 0) `123`009/* still busy ... */ X`009`009`009FEHLER("prot.error: unexpected IOREQ"); X`009`009`125 X`009`009ti_iofunc = ni_buf.iofunc; X`009`009ti_count = ni_buf.count; X`009`009CHECK(sys$wake(0,0)); X`009`009break; X X`009 case ZTNS_F_DATA: X`009`009if(ti_datap == NULL) `123 X`009`009`009FEHLER("prot.error: unexpected DATA"); X`009`009`125 X`009`009if(ni_iosb.count != ZTNS_LEN1 + ni_buf.count) `123 X`009`009`009FEHLER("prot.error: bad DATA msg length"); X`009`009`125 X`009`009if(ni_buf.count > ti_datacnt) `123 X`009`009`009FEHLER("prot.error: too much data"); X`009`009`125 X X`009`009memcpy(ti_datap,ni_buf.data,ni_buf.count); X`009`009ti_datacnt -= ni_buf.count; X`009`009ti_datap += ni_buf.count; X X`009`009if(ti_datacnt == 0) `123`009/* data transfer complete */ X`009`009`009ti_datap = NULL; X`009`009`009CHECK(sys$wake(0,0)); X`009`009`125 X`009`009break; X`009`125 X X/* wait for next msg */ X`009net_read(); X`125 X X X/*****/ X Xstatic void tap_invfun()`009/* unsupported function or modifier */ X`123 X`009t_iosb.status = SS$_ILLIOFUNC; X`009t_iosb.count = 0; X`009/* leave devdepend! */ X`125 X X Xstatic void tap_0par()`009`009/* REWIND, REWINDOFF, WRITEOF */ X`123 X`009CHECK(sys$qiow(0,t_chan,ti_iofunc, X`009`009`009&t_iosb,0,0, X`009`009`0090,0,0,0,0,0)); X`125 X X Xstatic void tap_skiprec()`009/* skip records, forward/backward */ X`123 X`009CHECK(sys$qiow(0,t_chan,IO$_SKIPRECORD, X`009`009`009&t_iosb,0,0, X`009`009`009ti_count,0,0,0,0,0)); X X/* must undo "end-of-volume" recognition */ X`009if(t_iosb.status == SS$_ENDOFVOLUME) `123 X`009`009unsigned char dummybuf[80]; X X`009`009if(t_iosb.count != 0) FEHLER("skipcount !=0 on e.o.v."); X X`009`009CHECK(sys$qiow(0,t_chan,IO$_READVBLK, X`009`009`009`009&t_iosb,0,0, X`009`009`009`009dummybuf,sizeof(dummybuf),0,0,0,0)); X`009`009if(t_iosb.status != SS$_ENDOFFILE) `123 X`009`009`009/* tape position lost since EOF must be next */ X`009`009`009t_iosb.status = SS$_TAPEPOSLOST; X`009`009`125 X`009`009t_iosb.count = 1; X`009`125 X`125 X X Xstatic void tap_read_wchk(wchk)`009/* wchk==0: read, possibly w/datacheck */ Xint wchk;`009`009`009/* wchk==1: simulated writecheck */ X`123 X`009CHECK(sys$qiow(0,t_chan,wchk ? IO$_READLBLK : ti_iofunc, X`009`009`009&t_iosb,0,0, X`009`009`009t_buffer,ti_count,0,0,0,0)); X`009if(t_iosb.count > 0) `123 X`009`009int bcnt,c; X`009`009unsigned char *bpt; X X`009`009no_buf.count = bcnt = MIN(t_iosb.count,ti_count); X`009`009net_send(wchk ? ZTNS_F_C_DATA : ZTNS_F_R_DATA); X`009`009bpt = t_buffer; X`009`009do `123 X`009`009`009no_buf.count = c = MIN(bcnt,ZTNS_DATALEN); X`009`009`009bcnt -= c; X`009`009`009memcpy(no_buf.data,bpt,c); X`009`009`009bpt += c; -+-+-+-+-+ End of part 8 +-+-+-+-+- +-+-+-+ Beginning of part 9 +-+-+-+ X`009`009`009if(bcnt == 0) `123`009/* last message */ X`009`009`009`009ti_replyexp = 1; X`009`009`009`125 X`009`009`009net_send(ZTNS_F_DATA); X`009`009`125 while(bcnt > 0); X`009`009CHECK(sys$hiber());`009/* wait for reply */ X X`009`009if(wchk) `123`009/* CMP may have error = SS$_DATACHECK */ X`009`009`009if((ti_replysts & 1) == 0) `123 X`009`009`009`009t_iosb.status = ti_replysts; X`009`009`009`125 X`009`009`125 else `123`009/* GET must be o.k. */ X`009`009`009CHECKX(ti_replysts); X`009`009`125 X`009`125 X`125 X X Xstatic void tap_write()`009`009/* write, possibly w/datacheck */ X`123 X`009if(ti_count > 0) `123 X`009`009no_buf.count = ti_datacnt = ti_count; X`009`009ti_datap = t_buffer; X`009`009net_send(ZTNS_F_W_DATA); X X`009`009CHECK(sys$hiber());`009/* wait for data */ X`009`125 X X`009CHECK(sys$qiow(0,t_chan,ti_iofunc, X`009`009`009&t_iosb,0,0, X`009`009`009t_buffer,ti_count,0,0,0,0)); X`125 X X Xstatic unsigned ztns()`009`009/* the action routine */ X`123 X`009int/*logical*/ ok = 1; X`009unsigned fcode,fmodif; X X X`009while(ok) `123 X X/* sleep waiting for function */ X`009`009CHECK(sys$hiber()); X X/* check & dispatch function */ X`009`009fcode = ti_iofunc & IO$M_FCODE; X`009`009fmodif = ti_iofunc & IO$M_FMODIFIERS; X`009`009switch(fcode) `123 X X`009`009 case IO$_WRITEOF:`009/* no modifiers */ X`009`009`009if(fmodif != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_0par(); X`009`009`009`125 X`009`009`009break; X X`009`009 case IO$_REWIND:`009/* mod: NOWAIT */ X`009`009 case IO$_REWINDOFF:`009/* mod: NOWAIT */ X`009`009`009if((fmodif & `126IO$M_NOWAIT) != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_0par(); X`009`009`009`125 X`009`009`009break; X X`009`009 case IO$_SKIPRECORD:`009/* no modifiers */ X`009`009`009if(fmodif != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_skiprec(); X`009`009`009`125 X`009`009`009break; X X`009`009 case IO$_READLBLK:`009/* mod: datacheck */ X`009`009`009`009`009/* note: datacheck is not end-to-end */ X`009`009`009if((fmodif & `126IO$M_DATACHECK) != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_read_wchk(0); X`009`009`009`125 X`009`009`009break; X X`009`009 case IO$_WRITELBLK:`009/* mod: datacheck */ X`009`009`009`009`009/* note: datacheck is not end-to-end */ X`009`009`009if((fmodif & `126IO$M_DATACHECK) != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_write(); X`009`009`009`125 X`009`009`009break; X X`009`009 case IO$_WRITECHECK:`009/* no modifiers */ X`009`009`009`009`009/* note: this PHYSICAL I/O,`032 X`009`009`009`009`009simulated as end-to-end check */ X`009`009`009if(fmodif != 0) `123 X`009`009`009`009tap_invfun(); X`009`009`009`125 else `123 X`009`009`009`009tap_read_wchk(1); X`009`009`009`125 X`009`009`009break; X X`009`009 default: X`009`009`009tap_invfun(); X`009`009`125 X X/* fudge */ X`009`009if(t_iosb.status == SS$_VOLINV) `123`009 X`009`009`009/* 'real' VALID bit apparently clear, X`009`009`009/* since we can't change that, X`009`009`009/* say MEDOFL (manual intervention required) */ X`009`009`009t_iosb.status = SS$_MEDOFL; X`009`009`125 X X/* say we're done */ X`009`009ti_iofunc = 0; X X/* return result from t_iosb */ X`009`009no_buf.iosb = t_iosb; X`009`009net_send(ZTNS_F_IOREPLY); X`009`125 X X`009return 1;`009/* not reached */ X`125 X X`009`009 X/*****/ X Xstatic unsigned main() X`123 X`009static $DESCRIPTOR(tape_dsc,T_LOGNAME); X X X/* assign channel to tape */ X`009CHECK(sys$assign(&tape_dsc,&t_chan,0,0)); X X/* rewind tape. this MUST succeed, otherwise something is wrong */ X/* in particular, this checks that the tape is mounted foreign */ X`009CHECK(sys$qiow(0,t_chan,IO$_REWIND, X`009`009`009&t_iosb,0,0, X`009`009`0090,0,0,0,0,0)); X`009CHECK(t_iosb.status); X X/* start the network connection & remote ZTserver */ X`009net_start(); X X/* do our work ... */ X X`009return ztns(); X`125 $ GOSUB UNPACK_FILE $ FILE_IS = "ZTSERVER.MAR" $ CHECKSUM_IS = 1146405095 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X`009.title`009ZTSERVER subroutines X; X; gce 7/1992 X;`009w.j.m. jun 1989 (0.2) X;`009documented 3-jul-1989 wjm X;`009mod 18-aug-1989 wjm (0.9): support VMS V5 X; X`009.ident`009/0.1/`009;this version needs ZTDRIVERM 0.1 X; X;***** X; entries: X;`009status=ZT_INIT()`009- initialize,`032 X;`009`009`009set up communication with ZTDRIVER. X;`009`009`009NOTE: an exit handler is set up, X;`009`009`009`009which MUST be executed eventually! X; X;`009status=ZT_WAIT()`009- wait for message (I/O request) from ZTDRIVER. X;`009`009`009 On return, the 'message buffer' has been filled in. X; X;`009status=ZT_REQCOM()`009- send (part of) 'message buffer' X;`009`009`009to ZTDRIVER and complete I/O. X; X;`009status=ZT_TOUSER()`009- simulates DMA transfer X;`009`009`009from 'data buffer' to ZTDRIVER's user buffer. X;`009`009`009Number of bytes tranferred: X;`009`009`009`009 MIN(UCB$W_BCNT,ZT_BUFDSC.dsc$w_length) X;`009`009`009Can be called at most once per I/O request! X; X;`009status=ZT_FRUSER()`009- simulates DMA transfer X;`009`009`009from ZTDRIVER's user buffer to 'data buffer'. X;`009`009`009Number of bytes transferred: X;`009`009`009`009UCB$W_BCNT X;`009`009`009On return, ZT_BUFDSC.dsc$w_length is set to this number. X;`009`009`009Can be called at most once per I/O request! X;`009`009`009`009`009 X;`009ZT_MSGDSC (globaldef):`032 X;`009`009`009Descriptor of 'message buffer' (see ZTDEF.MAR) X;`009`009`009`009used for communication with ZTDRIVER. X;`009`009`009Both buffer address and length are FIXED. X; X;`009ZT_BUFDSC (globaldef): X;`009`009`009Descriptor of 'data buffer' (see above). X;`009`009`009Buffer address is FIXED, actual size is `094xFFFF . X;`009`009`009ZT_BUFDSC.dsc$w_length is set by ZT_FRUSER(), X;`009`009`009`009and by caller of ZT_TOUSER(). X; X; X;***** X; X`009.link`009`009"SYS$SYSTEM:SYS.STB"/selective_search X`009.library`009"SYS$LIBRARY:LIB" X`009.library`009"ZT" X; X`009$dvidef X`009$iodef X`009$prdef X`009$prvdef X`009$ucbdef X`009$lnmdef ; Added by RAM, 6/3/93 X`009$dscdef ; Added by RAM, 6/3/93 X; Xsmp_code=0`009`009`009`009;VMS V4 or earlier X.iif df UCB$L_DLCK, smp_code=1`009`009;VMS V5`032 X; X`009ztdef`009`009; ZT definitions - need $ucbdef X; X; X;*****`009macros X; X.macro`009chkr0`009?lab X`009blbs`009r0,lab X`009pushl`009r0 X`009calls`009#1,g`094lib$stop Xlab: X.endm`009chkr0 X; X; X;*****`009PSECTs X; X`009.psect`009_data,quad X`009.psect`009_code,nowrt X`009.psect`009_nonpagedcode,page,nowrt Xnonpagedcode:`009`009`009;start of psect X`009.psect`009_nonpageddata,page Xnonpageddata:`009`009`009;start of psect X; X`009.page X;*****`009nonpaged data X; X`009.psect`009_nonpageddata X; Xzt_ucb:`009.long`0090 Xmbx_ucb:.long`0090 X; X`009.align`009quad Xzt_namedsc: Xztns:`009.word`00924 X`009.byte`009dsc$k_dtype_t X`009.byte`009dsc$k_class_s`009;fixed string Xztna:`009.address log`009;point at logical name trans. result. X;`009.ascid`009"_ZTA0:" X;;;;;; Xlogt: .ascid /LNM$PROCESS_TABLE/ ;devname logical in system table Xlogn: .ascid /ZTAPE/ ;the switch logical Xlogitm: .word 24,LNM$_STRING X .address log ;structure of trnlnm(home-made!) X .address ztns ;6 longs X .long 0 ;that's it Xlog: .blkl 6 ;look in here Xlog_l: .word 24 X`009.align long Xatr: .long LNM$M_CASE_BLIND ;be case blinded! X;;;;;; X; Xmbx_name_size=32 Xmbx_name: X`009.blkb`009mbx_name_size X`009.align`009quad Xmbx_namedsc: X`009.long`0090-0 X`009.long`009mbx_name X; X`009.align`009quad Xzt_msgbuf: X`009.byte`0090[zt_msglen] X; X; X;*****`009get ucb from device name X;`009`009called in kernel mode, IPL=0 X;`009`009p1 = addr of descriptor`009`009! must be nonpaged X;`009`009p2 = addr of ucb-address`009! must be nonpaged X; X`009.psect`009_nonpagedcode Xdev_to_ucb:`009.word`009`094m X; X`009movl`009g`094CTL$GL_PCB,r4 X; X`009jsb`009g`094SCH$IOLOCKR`009`009;;***** start IPL2 ********************* X`009movaq`009@1*4(ap),r1`009`009;; X`009jsb`009g`094IOC$SEARCHDEV`009`009;;search for device X`009blbc`009r0,90$`009`009`009;; X`009movl`009r1,@2*4(ap)`009`009;;r1=UCB X90$:`009`009`009`009`009;; X`009pushl`009r0`009`009`009;; X`009jsb`009g`094SCH$IOUNLOCK`009`009;; Unlock the I/O database X`009setipl`009#0`009`009`009;;***** end IPL2 *********************** X`009popl`009r0 X; X`009ret X; X; X;*****`009fake ZT interrupt X;`009`009called in kernel mode, IPL=0 X; X`009.psect`009_nonpagedcode Xzt_int:`009.word`009`094m X; X`009movl`009zt_ucb,r5 X`009beql`00990$ X; X.if eq smp_code X`009dsbint`009ucb$b_dipl(r5)`009`009`009;; X.iff`009`009`009`009`009`009;; X`009devicelock`009-`009`009`009;; X`009`009lockaddr=ucb$l_dlck(r5),-`009;; X`009`009lockipl=ucb$b_dipl(r5),-`009;; X`009`009savipl=-(sp),-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X`009jsb`009@ucb_l_inter(r5)`009`009;; X`009`009`009`009`009`009;; X.if eq smp_code`009`009`009`009`009;; X`009enbint`009`009`009`009`009;; X.iff`009`009`009`009`009`009;; X`009deviceunlock`009-`009`009`009;; X`009`009lockaddr=ucb$l_dlck(r5),-`009;; X`009`009newipl=(sp)+,-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc X; X90$: X`009movl`009#1,r0 X`009ret X; X; X;*****`009kernel mode setup X;`009`009called via $CMKRNL X; X`009.psect`009_nonpagedcode Xk_setup:`009.word`009`094m X; X`009movab`009g`094lib$sig_to_ret,(fp) X; X`009pushal`009mbx_ucb X`009pushaq`009mbx_namedsc X`009calls`009#2,dev_to_ucb X`009blbc`009r0,90$ X; X`009pushal`009zt_ucb X`009pushaq`009zt_namedsc X`009calls`009#2,dev_to_ucb X`009blbc`009r0,90$ X; X`009movl`009zt_ucb,r5 X`009movl`009mbx_ucb,ucb_l_ztmbx(r5) X; X`009bicw`009#ucb$m_valid,ucb$w_sts(r5) X`009bisw`009#ucb$m_online,ucb$w_sts(r5) X; X`009calls`009#0,zt_int`009`009; interrupt unconditionally, X`009`009`009`009`009; to clear potential hang X; X`009movl`009#1,r0 X90$: X`009ret X; X; X;*****`009kernel mode shutdown X;`009`009called via $CMKRNL X; X`009.psect`009_nonpagedcode Xk_shut:`009.word`009`094m X; X`009movab`009g`094lib$sig_to_ret,(fp) X; X`009movl`009zt_ucb,r5 X`009beql`00990$ X; X`009clrl`009ucb_l_ztmbx(r5) X`009bicw`009#,ucb$w_sts(r5) X; X; ggf. terminate i/o X; X`009bicw`009#,- X`009`009zt_msgbuf+zt_w_ucbsts`009`009;just in case ... X; X`009calls`009#0,zt_int`009`009`009;interrupt unconditionally X; X90$: X`009movl`009#1,r0 X`009ret X; X; X;*****`009kernel mode data transfer server -> driver's user X;`009`009called via $CMKRNL X;`009`009implicit inputs:`032 X;`009`009`009- 'zt_ucb' X;`009`009`009- data in 'buffer' X;`009`009`009- byte count in 'bufbct' X;`009`009implicit outputs: X;`009`009`009- ucb$w_bcnt cleared X; X`009.psect`009_nonpagedcode Xk_touser:`009.word`009`094m X; X`009movab`009g`094lib$sig_to_ret,(fp) X; X`009clrl`009r0 X`009movab`009buffer,r1`009`009; 'from' address X`009movzwl`009bufbct,r2`009`009; byte count X`009movl`009zt_ucb,r5 X`009beql`00990$ X`009cmpw`009r2,ucb$w_bcnt(r5)`009;sanity check X`009bgtru`00990$`009`009`009;br if it failed X; X.if eq smp_code X`009dsbint`009ucb$b_fipl(r5)`009`009`009;; X.iff`009`009`009`009`009`009;; X`009forklock`009-`009`009`009;; X`009`009lock=ucb$b_flck(r5),-`009`009;; X`009`009savipl=-(sp),-`009`009`009;; X`009`009preserve=NO,-`009`009`009;; X`009`009fipl=YES`009`009`009;;`032 X.endc`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X`009tstl`009r2`009`009`009`009;; X`009bleq`00928$`009`009`009`009;; br if nothing to be moved! X`009jsb`009ioc$movtouser`009`009`009;; X28$:`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X.if eq smp_code`009`009`009`009`009;; X`009enbint`009`009`009`009`009;; X.iff`009`009`009`009`009`009;; X`009forkunlock`009-`009`009`009;; X`009`009lock=ucb$b_flck(r5),-`009`009;; X`009`009newipl=(sp)+,-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc X; X`009clrw`009ucb$w_bcnt(r5)`009`009;make sure we don't copy twice X; X`009movl`009#1,r0 X90$: X`009ret X; X; X;*****`009kernel mode data transfer, driver's user -> server X;`009`009called via $CMKRNL X;`009`009implicit inputs:`032 X;`009`009`009- 'zt_ucb' X;`009`009`009- byte count in 'zt_msgbuf+zt_w_bnct' X;`009`009implicit outputs: X;`009`009`009- data in 'buffer' X;`009`009`009- byte count in 'bufbct' X;`009`009`009- ucb$w_bcnt cleared X; X`009.psect`009_nonpagedcode Xk_fruser:`009.word`009`094m X; X`009movab`009g`094lib$sig_to_ret,(fp) X; X`009clrl`009r0 X`009clrl`009bufbct X`009movl`009zt_ucb,r5 X`009beql`00990$ X; X`009movab`009buffer,r1`009`009;'to' address X`009movzwl`009zt_msgbuf+zt_w_bcnt,r2`009;byte count X`009cmpw`009r2,ucb$w_bcnt(r5)`009;sanity check X`009bgtru`00990$`009`009`009;br if it failed X`009movl`009r2,bufbct X; X.if eq smp_code X`009dsbint`009ucb$b_fipl(r5)`009`009`009;; X.iff`009`009`009`009`009`009;; X`009forklock`009-`009`009`009;; X`009`009lock=ucb$b_flck(r5),-`009`009;; X`009`009savipl=-(sp),-`009`009`009;; X`009`009preserve=NO,-`009`009`009;; X`009`009fipl=YES`009`009`009;;`032 X.endc`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X`009tstl`009r2`009`009`009`009;; X`009bleq`00928$`009`009`009`009;; br if nothing to be moved! X`009jsb`009ioc$movfruser`009`009`009;; X28$:`009`009`009`009`009`009;; X`009`009`009`009`009`009;; X.if eq smp_code`009`009`009`009`009;; X`009enbint`009`009`009`009`009;; X.iff`009`009`009`009`009`009;; X`009forkunlock`009-`009`009`009;; X`009`009lock=ucb$b_flck(r5),-`009`009;; X`009`009newipl=(sp)+,-`009`009`009;; X`009`009preserve=NO`009`009`009;; X.endc X; X`009clrw`009ucb$w_bcnt(r5)`009`009;make sure we don't copy twice X; X`009movl`009#1,r0 X90$: X`009ret X; X; X;*****`009kernel mode copy of 'result' to driver & activate driver X;`009`009called via $CMKRNL X;`009`009implicit inputs:`032 X;`009`009`009- 'zt_ucb' X;`009`009`009- 'result' X; X`009.psect`009_nonpagedcode Xk_reqcom:`009.word`009`094m X; X`009movab`009g`094lib$sig_to_ret,(fp) X; X`009clrl`009r0 X`009movl`009zt_ucb,r5 X`009beql`00990$ X; X`009movc3`009#zt_msglen,zt_msgbuf,ucb_a_ztmsg(r5)`009;copy back X; X`009calls`009#0,zt_int`009`009`009`009;'interrupt' driver X; X`009movl`009#1,r0 X90$: X`009ret X; X; X;*****`009get mailbox & its name X; X`009.psect`009_data X; Xmbx_dvi_itm: X`009.word`009mbx_name_size X`009.word`009dvi$_fulldevnam X`009.long`009mbx_name X`009.long`009mbx_namedsc X`009.long`0090 X; X`009.align `009quad Xmbxiosb: X`009.blkw`0094 X; Xmbxchan: X`009.blkw X; X; X`009.psect`009_code Xget_mbx:`009.word`009`094m<> X; X`009$crembx_s`009prmflg=#0,- X`009`009`009chan=mbxchan,- X`009`009`009maxmsg=#zt_msglen,- X`009`009`009-;`009???`009`009bufquo=#zt_msglen,- X`009`009`009promsk=#0 -+-+-+-+-+ End of part 9 +-+-+-+-+- +-+-+-+ Beginning of part 10 +-+-+-+ X`009chkr0 X; X`009$getdvi_s`009chan=mbxchan,- X`009`009`009itmlst=mbx_dvi_itm X`009chkr0 X; X`009ret X; X; X;*****`009start mbx read X; X`009.psect`009_code Xread_mbx:`009.word`009`094m<> X; X`009$qio_s`009efn=#1,- X`009`009chan=mbxchan,- X`009`009func=#io$_readvblk,- X`009`009iosb=mbxiosb,- X`009`009p1=zt_msgbuf,- X`009`009p2=#zt_msglen X`009chkr0 X; X`009ret X; X; X;*****`009wait for mbx message X; X`009.psect`009_code Xwait_mbx:`009.word`009`094m<> X; X`009$synch_s`009efn=#1,- X`009`009`009iosb=mbxiosb X`009chkr0 X; X`009movzwl`009mbxiosb,r0 X`009chkr0 X; X`009cmpw`009mbxiosb+2,#zt_msglen X`009beql`00950$ X`009clrl`009r0 X`009chkr0 X50$: X`009ret X; X; X;*****`009exit handler X; X; X`009.psect`009_data Xcurprivs: X`009.quad`0090 X; X; X`009.psect`009_code Xexith:`009.word`009`094m<> X; X`009$setprv_s`009enbflg=#1,-`009`009;establish initial privileges X`009`009`009prvadr=curprivs`009`009;(sometimes removed by rundown) X`009chkr0 X; X`009$cmkrnl_s`009routin=k_shut,- X`009`009`009arglst=(ap) X`009chkr0 X; X`009ret X; X; X;*****`009setup exit handler X; X`009.psect`009_data X; X`009.align`009long Xexstat: X`009.blkl Xexblk: X`009.long`0090-0,exith,1,exstat X; X; X`009.psect`009_code Xsetup_exith:`009.word`009`094m<> X; X`009$dclexh_s`009desblk=exblk X`009chkr0 X; X`009ret X; X`009.page X;*****`009externalized routines & data X; X`009.psect`009_nonpageddata X`009.align`009quad XZT_BUFDSC:: Xbufbct: X`009.long`0090-0,buffer X; X; X`009.psect`009_data X`009.align`009quad XZT_MSGDSC:: X`009.long`009zt_msglen,zt_msgbuf X; X; X;*****`009initialize X; X`009.psect`009_data X; X`009.align`009quad Xlkwdata_inadr: X`009.long`009nonpageddata,nonpageddata_end Xlkwcode_inadr: X`009.long`009nonpagedcode,nonpagedcode_end X; X; X`009.psect`009_code X.entry`009ZT_INIT,`094m<> X; X`009$setprv_s`009prvprv=curprivs`009`009; save current privileges X`009chkr0 X; X;;;;; X; To allow multi-unit use, translate logical ZTAPE to get real device X; name. Use that, whatever it may be. Name is gotten from process X; table to allow its' use. X $trnlnm_s attr=atr,tabnam=logt,- X lognam=logn,- ;is the switch logical there? X itmlst=logitm X`009chkr0 X;;;;; X`009$lkwset_s`009inadr=lkwdata_inadr`009; lock "nonpaged" data X`009chkr0 X; X`009$lkwset_s`009inadr=lkwcode_inadr`009; lock "nonpaged" code X`009chkr0 X; X`009calls`009#0,get_mbx`009`009`009; create mbx etc. X`009chkr0 X; X`009calls`009#0,read_mbx`009`009`009; post read on mbx X`009chkr0 X; X`009calls`009#0,setup_exith`009`009`009; set up exit handler X`009chkr0 X; X`009$cmkrnl_s`009routin=k_setup,-`009; start zt: X`009`009`009arglst=(ap) X`009ret X; X; X;*****`009wait for MBX X; X`009.psect`009_code X.entry`009ZT_WAIT,`094m<> X; X`009calls`009#0,wait_mbx X; X`009ret X; X; X;*****`009move data from 'buffer' to user X; X`009.psect`009_code X.entry`009ZT_TOUSER,`094m<> X; X`009$cmkrnl_s`009routin=k_touser,- X`009`009`009arglst=(ap) X`009ret X; X; X;*****`009move data from user to 'buffer' X; X`009.psect`009_code X.entry`009ZT_FRUSER,`094m<> X; X`009$cmkrnl_s`009routin=k_fruser,- X`009`009`009arglst=(ap) X`009ret X; X; X;*****`009complete I/O X; X`009.psect`009_code X.entry`009ZT_REQCOM,`094m<> X; X`009calls`009#0,read_mbx`009`009`009; post read on mbx X`009chkr0 X; X`009$cmkrnl_s`009routin=k_reqcom,- X`009`009`009arglst=(ap) X`009ret X; X`009.page X;*****`009the end X; X`009.psect`009_nonpageddata X; Xbuffer:`009`009`009`009;the data buffer X`009.blkb`009`094xFFFF`009`009;i.e. 64k-1 X; Xnonpageddata_end: X`009.blkb X; X`009.psect`009_nonpagedcode Xnonpagedcode_end: X`009.blkb X; X`009.end $ GOSUB UNPACK_FILE $ EXIT -+-+-+-+-+ End of part 10 +-+-+-+-+-