From:	ADVAX::"mcnc!pucc.PRINCETON.EDU!moeller%gwdgv1.dnet.gwdg.de" "GWDGV1::MOELLER" 22-JAN-1991 00:32:43.55
To:	Arisia::Everhart, jim@mango.rsmas.miami.edu, R602MS5U@vb.CC.CMU.EDU, PALTER@UBVMS.BITNET, johnsond@calstate.bitnet, FOX@MSUNSCL.BITNET, awpsys@ultb.isc.rit.edu, ACCESS@KRDC.INT.Alcan.CA, moeller@dgogwdg5
CC:	
Subj:	VMS 5.4 ZTDRIVER part 3 of 4

Received: by ADVAX.DECnet (utk-mail11 v1.5) ; Tue, 22 Jan 91 00:30:17 EST
Received:  from mcnc by ge-dab.GE.COM (5.61/GE-DAB 1.15) with UUCP
	id AA03777 for everhart; Tue, 22 Jan 91 00:28:59 -0500
Received: from pucc.PRINCETON.EDU by mcnc.mcnc.org (5.59/MCNC/6-11-90)
	id AA02565; Mon, 21 Jan 91 23:32:49 -0500
	for Arisia.dnet.ge.com!Everhart
Message-Id: <9101220432.AA02565@mcnc.mcnc.org>
Received: from DGOGWDG1.BITNET by pucc.PRINCETON.EDU (IBM VM SMTP R1.2.2MX) with BSMTP id 1298; Mon, 21 Jan 91 23:32:44 EST
Received: from dnet.gwdg.de by DGOGWDG1.BITNET (Mailer R2.07) with BSMTP id
 7545; Mon, 21 Jan 91 22:19:24 MEZ
Date:    Mon, 21 Jan 1991 22:18:47 +0100
From: "GWDGV1::MOELLER" <mcnc!pucc.PRINCETON.EDU!moeller%gwdgv1.dnet.gwdg.de>
To: Arisia::Everhart, jim@mango.rsmas.miami.edu, R602MS5U@vb.CC.CMU.EDU,
        PALTER@UBVMS.BITNET, johnsond@calstate.bitnet, FOX@MSUNSCL.BITNET,
        awpsys@ultb.isc.rit.edu, ACCESS@KRDC.INT.Alcan.CA, moeller@dgogwdg5
Subject: VMS 5.4 ZTDRIVER part 3 of 4
 
+-+-+-+ Beginning of part 3 +-+-+-+
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:
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;
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`009DESCR ncb_dsc = `1230-0,0,0,ncb`125;
X
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);
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 = "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)
-+-+-+-+-+ End of part 3 +-+-+-+-+-
