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

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

+-+-+-+ Beginning of part 2 +-+-+-+
X`009   if tape is mounted foreign & MT$M_ENAUTOPACK is set,
X`009   then set UCB$M_VALID on "medium online" interrupt */
X`009/*...................................................*/
X`009if(!hw_medonline) `123
X`009`009msgp->ucbsts &= `126UCB$M_VALID;
X`009`125
X#endif`009/*...................................................*/
X`125
X
X
Xstatic unsigned set_aftertm()`009/* ggf. find out if tape is positioned
X`009`009`009`009`009after a tape mark */
X`123
X`009if(aftertm != dunno) return SS$_NORMAL;`009/* nothing to be done */
X
X`009ns_req(IO$_SKIPRECORD,-1);
X`009msgp->record -= ns_iosb.count;
X`009if(ns_iosb.count != 1) `123
X`009`009if((ns_iosb.devdep & MT$M_BOT) == 0) `123
X`009`009`009pos_unsafe = 1;
X`009`009`009return SS$_TAPEPOSLOST;
X`009`009`125 else `123
X`009`009`009pos_unsafe = 0;`009/* we're at BOT! */
X`009`009`009aftertm = no;
X`009`009`009return SS$_NORMAL;
X`009`009`125
X`009`125
X`009aftertm = (ns_iosb.status == SS$_ENDOFFILE) ? yes : no;
X
X`009ns_req(IO$_SKIPRECORD,1);
X`009msgp->record += ns_iosb.count;
X`009if(ns_iosb.count != 1) `123
X`009`009pos_unsafe = 1;
X`009`009return SS$_TAPEPOSLOST;
X`009`125
X`009return SS$_NORMAL;
X`125
X
Xstatic void`009/* "end of volume" recognized */
Vset_eov(sca)`009/* backspace over 2nd eof mark, decrement spacing count etc.
X */
Xint sca;`009`009/* spacing count so far (>0) */
X`123
X`009ns_req(IO$_SKIPRECORD,-1);
X`009if(ns_iosb.count == 1 && ns_iosb.status == SS$_ENDOFFILE) `123 /* o.k. */
X`009`009msgp->record --;
X`009`009ns_iosb.status = SS$_ENDOFVOLUME;
X`009`009/* aftertm remains == yes */
X`009`125 else `123
X`009`009pos_unsafe = 1;
X`009`009ns_iosb.status = SS$_TAPEPOSLOST;
X`009`009aftertm = dunno;
X`009`125
X`009ns_iosb.count = sca - 1;`009/* final count */
X`125
X
X
Xstatic void do_skiprec()
X`123
X`009/* all modifiers ignored */
X`009int sc;
X
X
X`009sc = msgp->media.w[0];
X
X`009if(sc == 0) `123
X`009`009do_nop();
X`009`009return;
X
X`009`125 else if(sc > 0) `123`009`009`009`009`009/* FORWARD */
X`009`009int/*logical*/ no_acp;
X
X#if UNSAFE_AFTER_ERROR
X`009`009if(pos_unsafe) return;
X#endif
X
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`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`009`009`125
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(no_acp && (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`009`009int/*logical*/ no_acp;
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`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`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`009`009`125
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`009`009`009`009if(no_acp) `123
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`009`009`009`009`125
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`009`009`009`009sca ++;
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 4 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
X`009`009unsigned mask = MT$M_BOT `124 MT$M_EOF `124 MT$M_EOT `124 MT$M_HWL;
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 = "ZTNS.H"
$ CHECKSUM_IS = 67703244
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/* definitions for ZT<->ZTnetserver protocol */
X
Xtypedef struct IOSB `123
X`009unsigned short status;
X`009unsigned short count;
X`009unsigned long devdep;
X`125 IOSB;
X
X
X/***** ZTNS function codes *****/
X
X#define ZTNS_F_IOREQ`0091`009/* ZT -> NS: iofunc + count`009`009*/
X#define ZTNS_F_IOREPLY`0092`009/* NS -> ZT: iosb,`009`009`009*/
X`009`009`009`009/*   ZT -> NS: iosb.status only`009`009*/
X`009`009`009`009/*`009`009(after CMP & PUT)`009*/
X#define ZTNS_F_DATA`0093`009/* 'DMA' data (both directions): count`009*/
X#define ZTNS_F_R_DATA`0094`009/* NS -> ZT: accept <count> 'DMA' data`009*/
X#define ZTNS_F_W_DATA`0095`009/* NS -> ZT: send <count> 'DMA' data`009*/
X#define ZTNS_F_C_DATA`0096`009/* NS -> ZT: rcv.&check <count> 'DMA' data */
X
X
X/***** ZTNS network messages *****/
X
X#define ZTNS_DATALEN 1400`009/* max. #bytes transferred in 1 message */
X`009`009`009`009/* ? ought to be a single Ethernet packet ? */
X
Xtypedef struct ZTNS_MSG `123
X`009int seq;`009`009/* sequence number, starts at 1 */
X`009unsigned short func;`009/* ZTNS_F_xxxx */
X`009unsigned short iofunc;`009/* used by:`009IOREQ, IO$_xxx + modifiers */
X`009int count;`009`009/* used by:`009IOREQ (signed!),`032
X`009`009`009`009`009`009xxxDATA (total cnt),
X`009`009`009`009`009`009DATA (#bytes in 'data') */
X`009IOSB iosb;`009`009/* used by:`009IOREPLY */
X`009unsigned char data[ZTNS_DATALEN];`009/* used with DATA only */
X`125 ZTNS_MSG;
X
X#define ZTNS_LEN1 (sizeof(ZTNS_MSG) - ZTNS_DATALEN)`009/* short packet */
X
X/* note: length of a DATA packet must be ZTNS_LEN1 + (count) */
$ GOSUB UNPACK_FILE

$ FILE_IS = "ZTNS2.C"
$ CHECKSUM_IS = 1248242859
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/* serve real tape, for ZT2/ZTserver */
X/* w.j.m. jun 1989 */
X
X/* implicit inputs:
X`009logical name ZT_TAPE points to a tape unit mounted foreign
X`009logical name ZT_NETOBJECT has equivalence `096node::"0=name/'
X*/
X
X#define T_LOGNAME "ZT_TAPE"
X#define N_LOGNAME "ZT_NETOBJECT"
X
X
X#include "ztns.h"`009/* includes IOSB, VMS_ITEM */
X
X#include ssdef
X#include lnmdef
X#include "iodef.h"`009/* my own! */
X#include "mtdef.h"
X
X#include stdio
X#include stddef
X#include string
X#include descrip
Xtypedef struct dsc$descriptor DESCR;
X
X#define CHECK(x) do `123unsigned s=x; if(!(s&1)) lib$stop(s);`125 while(0)
X#define FEHLER(m) do `123$DESCRIPTOR(d,m); Fehler(&d);`125 while(0)
X#define CHECKX(x) do `123unsigned s=x; if(!(s&1)) sys$exit(s);`125 while(0)
X#define MIN(a,b) ((a) < (b)) ? (a) : (b)
X
Xextern unsigned lib$get_foreign(),lib$stop();
Xextern unsigned sys$exit(),sys$assign(),sys$wake(),sys$hiber(),sys$trnlnm();
Xextern unsigned sys$qiow(int,int,int,
X`009`009`009IOSB*,void*,int,
X`009`009`009void*,int,int,int,int,int);
Xextern unsigned sys$qio(int,int,int,
X`009`009`009IOSB*,void*,int,
X`009`009`009void*,int,int,int,int,int);
X
Xtypedef struct VMS_ITEM `123
X`009unsigned short size;
X`009unsigned short code;
X`009void *bufp;
X`009int *lenp;
X`125 VMS_ITEM;
X
X
X/***** tape data *****/
Xstatic IOSB t_iosb;
Xstatic short t_chan;
Xstatic unsigned char t_buffer[0xFFFF];
X
Vstatic unsigned short ti_iofunc = 0;`009/* request function, !=0 while busy *
X/
Xstatic int ti_count;`009`009`009/* request count */
X
Xstatic unsigned char *ti_datap = NULL;`009/* input 'DMA' pointer,
X`009`009`009`009`009`009==NULL unless data expected */
Xstatic int ti_datacnt = 0;`009`009/* input 'DMA' counter */
X
Xstatic int/*logical*/ ti_replyexp = 0;`009/* IOREPLY expected */
Xstatic unsigned short ti_replysts;`009/* status from same */
X
X/***** network data *****/
Xstatic short n_chan;
X
X`009/* ZT -> NS */
Xstatic IOSB ni_iosb;
Xstatic ZTNS_MSG ni_buf;
Xstatic int ni_seq = 1;
X
X`009/* NS -> ZT (our output) */
Xstatic IOSB no_iosb;
Xstatic ZTNS_MSG no_buf;
Xstatic int no_seq = 1;
X
X
X/*****/
X
Xstatic void net_ast();`009`009/*forward*/
X
Xstatic void net_read()
X`123
X`009CHECKX(sys$qio(1,n_chan,IO$_READVBLK,
X`009`009&ni_iosb,net_ast,0,
X`009`009&ni_buf,sizeof(ni_buf),0,0,0,0));
X`125
X
X
Xstatic void net_send(fct)
Xint fct;`009/* ZTNS_F_xxxx */
X`123
X`009no_buf.seq = no_seq++;
X`009no_buf.func = fct;
X
X`009CHECKX(sys$qiow(0,n_chan,IO$_WRITEVBLK,
X`009`009&no_iosb,0,0,
X`009`009&no_buf,
X`009`009((fct == ZTNS_F_DATA) ? (ZTNS_LEN1 + no_buf.count) : ZTNS_LEN1),
X`009`0090,0,0,0));
X`009CHECKX(no_iosb.status);
X`125
X
X
Xstatic void net_start()
X`123
X`009char ncb[512];
X`009DESCR ncb_dsc = `1230-0,0,0,ncb`125;
X
X
X/* translate n_logname */
X
X`009`123
X`009`009$DESCRIPTOR(lnmtabdsc,"LNM$FILE_DEV");
X`009`009$DESCRIPTOR(lognamedsc,N_LOGNAME);
X`009`009VMS_ITEM lnmlist[] =
X`009`009`009`123`123sizeof(ncb),LNM$_STRING,ncb,&ncb_dsc.dsc$w_length`125,
X`009`009`009 `1230,0,NULL,NULL`125`125;
X
X`009`009CHECK(sys$trnlnm(0,&lnmtabdsc,&lognamedsc,0,lnmlist));
X`009`125
X
X/* assign channel to NET */
X
X`009`123
X`009`009$DESCRIPTOR(netdsc,"_NET:");
X
X`009`009CHECK(sys$assign(&netdsc,&n_chan,0,0));
X`009`125
X
X/* open connection */
X
X`009if(ncb_dsc.dsc$w_length+2+1+16+1 > sizeof(ncb)) `123
X`009`009FEHLER("ncb too small");
X`009`125
X
X`009/* clear conn.id & ncb info */
X`009memset(ncb+ncb_dsc.dsc$w_length,0,2+1+16);
X`009ncb_dsc.dsc$w_length += 2+1+16;
X
X`009/* add trailing quotemark */
X`009ncb[ncb_dsc.dsc$w_length] = '\"';
X`009ncb_dsc.dsc$w_length += 1;
X
X`009CHECK(sys$qiow(0,n_chan,IO$_ACCESS,
X`009`009`009&no_iosb,0,0,
X`009`009`0090,&ncb_dsc,0,0,0,0));
X`009CHECK(no_iosb.status);
X
X
X/* start async. read from net */
X
X`009net_read();
X`125
X
X
Xstatic void net_ast()`009/* here when we receive net msg */
X`123
X/* check I/O */
X`009CHECKX(ni_iosb.status);
X
X/* check seq# */
X`009if(ni_buf.seq != ni_seq++) FEHLER("prot.error: iseq");
X
X/* check minimum length */
X`009if(ni_iosb.count < ZTNS_LEN1) FEHLER("prot.error: msg too short");
X
X/* process low level function */
X`009switch(ni_buf.func) `123
X`009  default:
X`009`009FEHLER("prot.error: bad func1");
X`009`009return;
X
X`009  case ZTNS_F_IOREPLY:
X`009`009if(ti_replyexp == 0) `123
X`009`009`009FEHLER("prot.error: unexpected IOREPLY");
X`009`009`125
X`009`009ti_replyexp = 0;
X`009`009ti_replysts = ni_buf.iosb.status;
X`009`009CHECK(sys$wake(0,0));
X`009`009break;
X
X`009  case ZTNS_F_IOREQ:
X`009`009if(ti_iofunc != 0) `123`009/* still busy ... */
X`009`009`009FEHLER("prot.error: unexpected IOREQ");
X`009`009`125
X`009`009ti_iofunc = ni_buf.iofunc;
X`009`009ti_count = ni_buf.count;
X`009`009CHECK(sys$wake(0,0));
X`009`009break;
X
X`009  case ZTNS_F_DATA:
X`009`009if(ti_datap == NULL) `123
X`009`009`009FEHLER("prot.error: unexpected DATA");
X`009`009`125
X`009`009if(ni_iosb.count != ZTNS_LEN1 + ni_buf.count) `123
X`009`009`009FEHLER("prot.error: bad DATA msg length");
X`009`009`125
X`009`009if(ni_buf.count > ti_datacnt) `123
X`009`009`009FEHLER("prot.error: too much data");
X`009`009`125
X
X`009`009memcpy(ti_datap,ni_buf.data,ni_buf.count);
X`009`009ti_datacnt -= ni_buf.count;
X`009`009ti_datap += ni_buf.count;
X
X`009`009if(ti_datacnt == 0) `123`009/* data transfer complete */
X`009`009`009ti_datap = NULL;
X`009`009`009CHECK(sys$wake(0,0));
X`009`009`125
X`009`009break;
X`009`125
X
X/* wait for next msg */
X`009net_read();
X`125
X
X
X/*****/
X
Xstatic void tap_invfun()`009/* unsupported function or modifier */
X`123
X`009t_iosb.status = SS$_ILLIOFUNC;
X`009t_iosb.count = 0;
X`009/* leave devdepend! */
X`125
X
X
Xstatic void tap_0par()`009`009/* REWIND, REWINDOFF, WRITEOF */
X`123
X`009CHECK(sys$qiow(0,t_chan,ti_iofunc,
X`009`009`009&t_iosb,0,0,
X`009`009`0090,0,0,0,0,0));
X`125
X
X
Xstatic void tap_skiprec()`009/* skip records, forward/backward */
X`123
X`009CHECK(sys$qiow(0,t_chan,IO$_SKIPRECORD,
X`009`009`009&t_iosb,0,0,
X`009`009`009ti_count,0,0,0,0,0));
X
X/* must undo "end-of-volume" recognition */
X`009if(t_iosb.status == SS$_ENDOFVOLUME) `123
X`009`009unsigned char dummybuf[80];
X
X`009`009if(t_iosb.count != 0) FEHLER("skipcount !=0 on e.o.v.");
X
X`009`009CHECK(sys$qiow(0,t_chan,IO$_READVBLK,
X`009`009`009`009&t_iosb,0,0,
X`009`009`009`009dummybuf,sizeof(dummybuf),0,0,0,0));
X`009`009if(t_iosb.status != SS$_ENDOFFILE) `123
X`009`009`009/* tape position lost since EOF must be next */
X`009`009`009t_iosb.status = SS$_TAPEPOSLOST;
X`009`009`125
X`009`009t_iosb.count = 1;
X`009`125
X`125
X
X
Xstatic void tap_read_wchk(wchk)`009/* wchk==0: read, possibly w/datacheck */
Xint wchk;`009`009`009/* wchk==1: simulated writecheck */
X`123
X`009CHECK(sys$qiow(0,t_chan,wchk ? IO$_READLBLK : ti_iofunc,
X`009`009`009&t_iosb,0,0,
X`009`009`009t_buffer,ti_count,0,0,0,0));
X`009if(t_iosb.count > 0) `123
X`009`009int bcnt,c;
X`009`009unsigned char *bpt;
X
X`009`009no_buf.count = bcnt = MIN(t_iosb.count,ti_count);
X`009`009net_send(wchk ? ZTNS_F_C_DATA : ZTNS_F_R_DATA);
X`009`009bpt = t_buffer;
X`009`009do `123
X`009`009`009no_buf.count = c = MIN(bcnt,ZTNS_DATALEN);
X`009`009`009bcnt -= c;
X`009`009`009memcpy(no_buf.data,bpt,c);
X`009`009`009bpt += c;
X`009`009`009if(bcnt == 0) `123`009/* last message */
X`009`009`009`009ti_replyexp = 1;
X`009`009`009`125
X`009`009`009net_send(ZTNS_F_DATA);
X`009`009`125 while(bcnt > 0);
X`009`009CHECK(sys$hiber());`009/* wait for reply */
X
X`009`009if(wchk) `123`009/* CMP may have error = SS$_DATACHECK */
X`009`009`009if((ti_replysts & 1) == 0) `123
X`009`009`009`009t_iosb.status = ti_replysts;
X`009`009`009`125
X`009`009`125 else `123`009/* GET must be o.k. */
X`009`009`009CHECKX(ti_replysts);
X`009`009`125
X`009`125
X`125
X
X
Xstatic void tap_write()`009`009/* write, possibly w/datacheck */
X`123
X`009if(ti_count > 0) `123
X`009`009no_buf.count = ti_datacnt = ti_count;
X`009`009ti_datap = t_buffer;
X`009`009net_send(ZTNS_F_W_DATA);
X
X`009`009CHECK(sys$hiber());`009/* wait for data */
X`009`125
X
X`009CHECK(sys$qiow(0,t_chan,ti_iofunc,
X`009`009`009&t_iosb,0,0,
X`009`009`009t_buffer,ti_count,0,0,0,0));
X`125
X
X
Xstatic unsigned ztns()`009`009/* the action routine */
X`123
X`009int/*logical*/ ok = 1;
X`009unsigned fcode,fmodif;
X
X
X`009while(ok) `123
X
X/* sleep waiting for function */
X`009`009CHECK(sys$hiber());
X
X/* check & dispatch function */
X`009`009fcode = ti_iofunc & IO$M_FCODE;
X`009`009fmodif = ti_iofunc & IO$M_FMODIFIERS;
X`009`009switch(fcode) `123
X
X`009`009  case IO$_WRITEOF:`009/* no modifiers */
X`009`009`009if(fmodif != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_0par();
X`009`009`009`125
X`009`009`009break;
X
X`009`009  case IO$_REWIND:`009/* mod: NOWAIT */
X`009`009  case IO$_REWINDOFF:`009/* mod: NOWAIT */
X`009`009`009if((fmodif & `126IO$M_NOWAIT) != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_0par();
X`009`009`009`125
X`009`009`009break;
X
X`009`009  case IO$_SKIPRECORD:`009/* no modifiers */
X`009`009`009if(fmodif != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_skiprec();
X`009`009`009`125
X`009`009`009break;
X
X`009`009  case IO$_READLBLK:`009/* mod: datacheck */
X`009`009`009`009`009/* note: datacheck is not end-to-end */
X`009`009`009if((fmodif & `126IO$M_DATACHECK) != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_read_wchk(0);
X`009`009`009`125
X`009`009`009break;
X
X`009`009  case IO$_WRITELBLK:`009/* mod: datacheck */
X`009`009`009`009`009/* note: datacheck is not end-to-end */
X`009`009`009if((fmodif & `126IO$M_DATACHECK) != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_write();
X`009`009`009`125
X`009`009`009break;
X
X`009`009  case IO$_WRITECHECK:`009/* no modifiers */
X`009`009`009`009`009/* note: this PHYSICAL I/O,`032
X`009`009`009`009`009simulated as end-to-end check */
X`009`009`009if(fmodif != 0) `123
X`009`009`009`009tap_invfun();
X`009`009`009`125 else `123
X`009`009`009`009tap_read_wchk(1);
X`009`009`009`125
X`009`009`009break;
X
X`009`009  default:
X`009`009`009tap_invfun();
X`009`009`125
X
X/* fudge */
X`009`009if(t_iosb.status == SS$_VOLINV) `123`009
X`009`009`009/* 'real' VALID bit apparently clear,
X`009`009`009/* since we can't change that,
X`009`009`009/* say MEDOFL (manual intervention required) */
X`009`009`009t_iosb.status = SS$_MEDOFL;
X`009`009`125
X
X/* say we're done */
X`009`009ti_iofunc = 0;
X
X/* return result from t_iosb */
X`009`009no_buf.iosb = t_iosb;
X`009`009net_send(ZTNS_F_IOREPLY);
X`009`125
X
X`009return 1;`009/* not reached */
X`125
X
X`009`009
X/*****/
X
Xstatic unsigned main()
X`123
X`009static $DESCRIPTOR(tape_dsc,T_LOGNAME);
X
X
X/* assign channel to tape */
X`009CHECK(sys$assign(&tape_dsc,&t_chan,0,0));
X
X/* rewind tape. this MUST succeed, otherwise something is wrong */
X/* in particular, this checks that the tape is mounted foreign */
X`009CHECK(sys$qiow(0,t_chan,IO$_REWIND,
X`009`009`009&t_iosb,0,0,
X`009`009`0090,0,0,0,0,0));
X`009CHECK(t_iosb.status);
X
X/* start the network connection & remote ZTserver */
X`009net_start();
X
X/* do our work ... */
X
X`009return ztns();
X`125
$ GOSUB UNPACK_FILE
$ EXIT
-+-+-+-+-+ End of part 2 +-+-+-+-+-

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