+-+-+-+ Beginning of part 5 +-+-+-+ X;*****`009move data from user to 'buffer' X; X`009.psect`009_code X.entry`009ZT_FRUSER,`094m<> X; X.if ne EVAX X`009$cmkrnl_s`009routin=k_fruser X.iff X`009$cmkrnl_s`009routin=k_fruser,- X`009`009`009arglst=(ap) X.endc 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.if ne EVAX X`009$cmkrnl_s`009routin=k_reqcom X.iff X`009$cmkrnl_s`009routin=k_reqcom,- X`009`009`009arglst=(ap) X.endc 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.if ne EVAX X.iff X`009.psect`009_nonpagedcode Xnonpagedcode_end: X`009.blkb X.endc X; X`009.end $ GOSUB UNPACK_FILE $ FILE_IS = "ZT_DRIVER.MAR" $ CHECKSUM_IS = 336793473 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X`009.title`009ZT_driver`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;`009mod 14-oct-1992 wjm (0.99): change driver name ZTDRIVER => ZT_DRIVER X;`009mod 22-oct-1993 wjm (0.99A): port to AXP VMS 1.5 (needs EVAX defined) X;`009mod 29-jan-1994 wjm (0.99B): small fixes, automatically defined EVAX X;`009mod 18-mar-1994 wjm (0.99FT): port to AXP VMS T2.0 (heuristic) X; X`009.ident`009/0.99FT/ 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; X.ntype`009__,R31`009`009`009; set EVAX nonzero if R31 is a register X.if eq <__ & `094xF0> - `094x50 XEVAX = 1 X.iff XEVAX = 0 X.endc X; X; X.if ne EVAX X`009.library`009"SYS$LIBRARY:LIB" X`009.library`009"SYS$DISK:[]ZT" X.iff X`009.link`009`009"SYS$SYSTEM:SYS.STB"/SELECTIVE_SEARCH X`009.library`009"SYS$LIBRARY:LIB" X`009.library`009"ZT" X.endc 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.if ne EVAX`009`009`009`009;AXP ... X;`009`009`009`009`009;... EVAX=1 -> Step1 X.iif ndf WCB$W_NMAP, EVAX=2`009`009;... EVAX=2 -> Step2 (ndf as of T2.0) X.endc X; 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.if ne EVAX X; X`009driver_data X; X.if eq EVAX-2 X`009dptab`009step=2,- X`009`009name=ZT_DRIVER,-`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.iff X`009dptab`009step=1,- X`009`009name=ZT_DRIVER,-`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.endc X.iff X`009dptab`009name=ZT_DRIVER,-`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.endc 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.if ne EVAX X`009dpt_store`009UCB,ucb_l_inter,D,- X`009`009`009pseudo_interrupt`009; (no more controller_init) X.iff X`009dpt_store`009CRB,crb$l_intd+vec$l_initial,D,- X`009`009`009controller_init`009`009; controller initialization X.endc X; X; X`009dpt_store`009END X; X; X;*****`009driver dispatch table X; V;; EVAX note: since we don't need a ctrlinit routine, VAX ddtab is still vali Xd 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; X.if eq EVAX-2 X`009fdt_ini`009fdt=fdt_table X`009fdt_buf`009-`009`009`009`009; buffered functions ... X`009`009-`009`009;... all but data transfer & AVAILABLE (WHY???) X`009`009 X X`009fdt_act`009ACP_STD$READBLK,<-`009`009; read functions => ACP => ... X`009`009readpblk,- X`009`009readlblk,- X`009`009readvblk> X`009fdt_act`009ACP_STD$WRITEBLK,<-`009`009; write functions => ACP => ... X`009`009writecheck,- X`009`009writepblk,- X`009`009writelblk,- X`009`009writevblk> X`009fdt_act`009ACP_STD$ACCESS,<-`009`009; access => ACP only X`009`009access,- X`009`009create> X`009fdt_act`009ACP_STD$DEACCESS,<-`009`009; deaccess => ACP only X`009`009deaccess> X`009fdt_act`009ACP_STD$MODIFY,<-`009`009; control => ACP only X`009`009delete,- X`009`009modify,- X`009`009acpcontrol> X`009fdt_act`009ACP_STD$MOUNT,<-`009`009; mount => ACP only X`009`009mount> X`009fdt_act`009MT_STD$CHECK_ACCESS,-`009`009; ** also does EXE$ZEROPARM ** X`009`009 X`009fdt_act`009EXE_STD$ZEROPARM,<-`009`009; (final) functions with 0 par. X`009`009nop,- X`009`009unload,- X`009`009recal,- X`009`009drvclr,- X`009`009packack,- X`009`009available,- X`009`009sensechar,-`009`009;(!) X`009`009rewindoff,- X`009`009rewind,- X`009`009sensemode>`009`009;(!) X`009fdt_act`009EXE_STD$ONEPARM,<-`009`009; (final) functions with 1 par. X`009`009spacefile,- X`009`009spacerecord,- X`009`009skipfile,- X`009`009skiprecord> X`009fdt_act`009EXE_STD$SETMODE,<-`009`009; (final) set mode X`009`009setchar,- X`009`009setmode> X X.iff 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.endc X; X`009.page X; X.iif ne EVAX,`009driver_code X; X.if eq EVAX X; 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.if ne EVAX*0`009`009`009`009`009`009;; example only X`009.jsb_entry`009input=r5,output=r0`009`009;; X;`009`009`009`009`009`009`009;;`032 X`009movl`009#ss$_normal,r0`009`009; no-op!`009;; X;`009`009`009`009`009`009`009;; X`009rsb`009`009`009`009`009`009;; X.iff 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.endc X; X.endc X; 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.if ne EVAX X`009.jsb_entry`009input=,scratch= X; X`009movl`009irp$l_func(r3),r2`009`009;IO function + modifiers X`009movl`009r2,ucb$l_func(r5)`009`009; save function in UCB X.iff 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.endc X; X; set up mailbox request X; X.if ne EVAX X`009movl`009r2,ucb_a_ztmsg+zt_l_func(r5)`009; fill in 'function' X`009movl`009ucb$l_bcnt(r5),-`009`009; ditto for bytecount X`009`009ucb_a_ztmsg+zt_l_bcnt(r5) X.iff 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.endc X`009movq`009irp$l_media(r3),-`009`009; ditto for parameter(s) X`009`009ucb_a_ztmsg+zt_l_media(r5) X.if ne EVAX X`009movl`009ucb$l_sts(r5),-`009`009`009; ditto for ucb$l_sts X`009`009ucb_a_ztmsg+zt_l_ucbsts(r5) X.iff X`009movw`009ucb$w_sts(r5),-`009`009`009; ditto for ucb$w_sts X`009`009ucb_a_ztmsg+zt_w_ucbsts(r5) X.endc 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.if ne EVAX X`009movl`009#ss$_devoffline,- X`009`009ucb_a_ztmsg+zt_l_iosts(r5) X`009clrl`009ucb_a_ztmsg+zt_l_iobct(r5)`009; default 1st iosb longword X.iff X`009assume`009zt_w_iobct eq zt_w_iosts+2 X`009movl`009#ss$_devoffline,- X`009`009ucb_a_ztmsg+zt_w_iosts(r5)`009; default 1st iosb longword X.endc 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.if ne EVAX X`009extzv`009#irp$v_fcode,#irp$s_fcode,-`009;get major function X`009`009irp$l_func(r3),r2 X.iff X`009extzv`009#irp$v_fcode,#irp$s_fcode,-`009;get major function X`009`009irp$w_func(r3),r2 X.endc 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`009assume`009ucb$b_devtype eq ucb$b_devclass+1 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.if ne EVAX X`009bicl`009#ucb$m_valid,ucb$l_sts(r5)`009;set invalid now X`009bicl`009#ucb$m_valid,- X`009`009ucb_a_ztmsg+zt_l_ucbsts(r5)`009;also update in message (!) X.iff 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.endc X`009brw`00920$ X; X; X; check if i/o is permitted X; X20$: X.if ne EVAX X`009bbs`009#irp$v_physio,irp$l_sts(r3),30$`009; o.k. if physical X`009bbs`009#ucb$v_valid,ucb$l_sts(r5),30$`009; o.k. if volume valid X`009movl`009#ss$_volinv,- X`009`009ucb_a_ztmsg+zt_l_iosts(r5)`009; else error: volume invalid X.iff 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.endc 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.if ne EVAX`009`009`009`009;; X`009bitl`009#ucb$m_cancel,ucb$l_sts(r5)`009;; I/O to be aborted? X.iff`009`009`009`009`009`009;; X`009bitw`009#ucb$m_cancel,ucb$w_sts(r5)`009;; I/O to be aborted? X.endc`009`009`009`009`009`009;; 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`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.if ne EVAX X`009movl`009#ss$_cancel,- X`009`009ucb_a_ztmsg+zt_l_iosts(r5)`009; set status X`009clrl`009ucb_a_ztmsg+zt_l_iobct(r5)`009; clear byte count X.iff X`009assume`009zt_w_iobct eq zt_w_iosts+2 X`009movzwl`009#ss$_cancel,- X`009`009ucb_a_ztmsg+zt_w_iosts(r5)`009; set status X.endc 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.if ne EVAX X`009bisl`009#,ucb$l_sts(r5)`009;; re-set interrupt expected X`009bicl`009#,ucb$l_sts(r5)`009;;`009and powerfail X.iff X`009bisw`009#,ucb$w_sts(r5)`009;; re-set interrupt expected X`009bicw`009#,ucb$w_sts(r5)`009;;`009and powerfail X.endc X`009rsb`009`009`009`009`009;; return! X; X; X; server gone X; Xio_err_noserver: X.if ne EVAX X`009bicl`009#,-`009;clear valid & online X`009`009ucb$l_sts(r5) X.iff X`009bicw`009#,-`009;clear valid & online X`009`009ucb$w_sts(r5) X.endc 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.if ne EVAX X`009bicl`009#,- X`009`009ucb$l_sts(r5)`009`009`009; cleanup some UCB flags X.iff X`009bicw`009#,- X`009`009ucb$w_sts(r5)`009`009`009; cleanup some UCB flags X.endc 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.if ne EVAX X`009extzv`009#ucb$v_valid,#1,- X`009`009ucb_a_ztmsg+zt_l_ucbsts(r5),r2`009`009; ucb$v_valid ... X`009insv`009r2,#ucb$v_valid,#1,ucb$l_sts(r5) X.iff 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.endc 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.if ne EVAX X`009movzwl`009ucb_a_ztmsg+zt_l_iosts(r5),r0 X`009insv`009ucb_a_ztmsg+zt_l_iobct(r5),- X`009`009#16,#16,r0`009`009`009`009; 1st iosb longword X.iff X`009assume`009zt_w_iobct eq zt_w_iosts+2 X`009movl`009ucb_a_ztmsg+zt_w_iosts(r5),r0`009`009; 1st iosb longword X.endc 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.if ne EVAX X`009bbc`009#irp$v_virtual,irp$l_sts(r3),-`009;br if not virtual X`009`009done X.iff X`009bbc`009#irp$v_virtual,irp$w_sts(r3),-`009;br if not virtual X`009`009done X.endc X; X`009movq`009r0,-(sp)`009`009;save r0,r1 X`009movl`009irp$l_wind(r3),r4`009;... X.if eq EVAX-2 X`009clrl`009wcb$l_nmap(r4)`009`009;... X.iff X`009clrw`009wcb$w_nmap(r4)`009`009;... X.endc 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.if ne EVAX X`009bbc`009#irp$v_virtual,- X`009`009irp$l_sts(r0),70$`009;skip IRP if not virtual X.iff X`009bbc`009#irp$v_virtual,- X`009`009irp$w_sts(r0),70$`009;skip IRP if not virtual X.endc 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.if ne EVAX X`009.jsb_entry`009input=r5,output=r5,scratch= X; X`009bbc`009#ucb$v_int,ucb$l_sts(r5),90$ X; X`009bicl`009#,- X`009`009ucb$l_sts(r5)`009`009`009; no more interrupts desired X; X`009evax_ldq`009r3,ucb$q_fr3(r5) X`009evax_ldq`009r4,ucb$q_fr4(r5) X.iff 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.endc 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 $ EXIT -+-+-+-+-+ End of part 5 +-+-+-+-+-