From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CUNYVM.CUNY.EDU::U0012%DGOGWDG5.BITNET" 30-AUG-1989 17:36
To:	MRGATE::"ARISIA::EVERHART"
Subj:	preliminary ZTDRIVER (1 of 2)

Message-Id:  <8908302128.AA20516@crdgw1.ge.com>
Received: from DGOGWDG5.BITNET by CUNYVM.CUNY.EDU (IBM VM SMTP R1.2.1MX) with BSMTP id 5949; Wed, 30 Aug 89 17:26:54 EDT
Date:    Wed, 30 Aug 1989 23:17:07  +0200
From: "GWDGV1::MOELLER"  <U0012%DGOGWDG5.BITNET@CUNYVM.CUNY.EDU>
To: Everhart@Arisia.decnet
Subject: preliminary ZTDRIVER (1 of 2)

Glenn,
please make sure that some "copyright" note like the following
accompanies my programs. I am not used to include such a thing
into the source code (not required by German law, as far as I know),
and I have difficulties in coming up with a proper wording.

***********************************************************************
Please understand that this software is not "in the public domain".
All rights to this software are held by
        Wolfgang J. Moeller     (being the author)
and/or
        Gesellschaft fuer wissenschaftliche Datenverarbeitung mbH
        Goettingen, F.R.G.      (paying the bills & my paycheck)

.. This software must not be sold, leased or lent(?) for profit
    or integrated into a commercial product ...
***********************************************************************

This is ZTDRIVER (V0.9) & friends as of 19-aug-1989.

$! ................... 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 MOELLER
$! on 30-AUG-1989 22:32:20.91.
$!
$! ATTENTION: To keep each article below 82 blocks (41984 bytes), this
$!            program has been transmitted in 2 parts.  You should
$!            concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 7 files:
$!        ZTDEF.MAR
$!        ZTDRIVER.MAR
$!        ZTDRIVER.OPT
$!        ZTSERVER.MAR
$!        ZT2.C
$!        ZTNS.H
$!        ZTNS2.C
$!
$!============================================================================
$ 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 = "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 = 373610105
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.title`009ZTdriver`009... pseudo tape ...
X;
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/0.9/
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 (no UNITINIT)
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<mt$k_normal11@mt$v_format>!-`009; format = normal11
X`009`009`009<mt$k_pe_1600@mt$v_density>!-`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;
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;
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;;
X`009brw`009io_cancelled`009`009`009;; br if yes, do it now!
X21$:`009`009`009`009`009`009;;
X`009pushr`009#`094m<r3,r4,r5>`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<r3,r4,r5>`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$m_int>,ucb$w_sts(r5)`009;; re-set interrupt expected
X`009bicw`009#<ucb$m_timout!-`009`009;; clear timout,
X`009`009ucb$m_tim!-`009`009`009;;`009timed,
X`009`009ucb$m_power>,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#<ucb$m_online!ucb$m_valid>,-`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#<ucb$m_tim!ucb$m_int!-
X`009`009ucb$m_timout!ucb$m_power!-
X`009`009ucb$m_cancel>,-
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#<ucb$m_int!ucb$m_tim>,-
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 = "ZTSERVER.MAR"
$ CHECKSUM_IS = 558612985
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.title`009ZTSERVER subroutines
X;
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.9/`009;this version needs ZTDRIVER 0.9
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;
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:
X`009.ascid`009"_ZTA0:"
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<r2,r3,r4,r5>
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<r2,r3,r4,r5>
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<r2,r3,r4,r5>
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<r2,r3,r4,r5>
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$m_online!ucb$m_valid>,ucb$w_sts(r5)
X;
X; ggf. terminate i/o
X;
X`009bicw`009#<ucb$m_online!ucb$m_valid>,-
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<r2,r3,r4,r5>
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<r2,r3,r4,r5>
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<r2,r3,r4,r5>
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
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`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

$ FILE_IS = "ZT2.C"
$ CHECKSUM_IS = 959363830
$ 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*/
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#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;
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#include devdef
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:
-+-+-+-+-+ End of part 1 +-+-+-+-+-

Wolfgang J. Moeller, GWDG, D-3400 Goettingen, F.R.Germany | Disclaimer ...
Bitnet/Earn: U0012@DGOGWDG5         Phone: +49 551 201516 | No claim intended
