Universal FALUNV - Universal Symbol Definitions for the FAL Modules Search MACTEN,UUOSYM ; Get the standard symbol definitions Search SWIL ; Get some SWIL symbols Search GLXMAC,QSRMAC,ORNMAC ; 'Coupla other nice universals Search ACTSYM ; Get the accounting system symbols SALL ; Make the listing look nice .Directive FLBLST ; very nice ; Version number information: FALVER==2 ; Major version number FALMIN==1 ; Minor version number FALEDT==56 ; Edit number FALWHO==0 ; Who last patched %FAL== Comment ~ FAL -- File Access Listener THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1985,1986,1987,1988,1990. ALL RIGHTS RESERVED. ~ ; End Comment SUBTTL Table of Contents ; Table of Contents for FAL ; ; Section Page ; ; ; 1. Definitions ; 1.1 Assembly Parameters, Channel, Other Random Sym 5 ; 1.2 Status Flags, Stream Blocking Bits . . . . . . 6 ; 1.3 Macros . . . . . . . . . . . . . . . . . . . . 7 ; 1.4 Error Handler Interface . . . . . . . . . . . 8 ; 1.5 GLXLIB Symbols . . . . . . . . . . . . . . . . 10 ; 1.6 Stream Parameter Area . . . . . . . . . . . . 11 ; 2. End of FALUNV . . . . . . . . . . . . . . . . . . . . 12 ; 3. Commentary . . . . . . . . . . . . . . . . . . . . . . 14 ; 4. Definitions ; 4.1 Local Accumulator Usage . . . . . . . . . . . 15 ; 4.2 Macros . . . . . . . . . . . . . . . . . . . . 16 ; 5. Storage ; 5.1 Static Impure . . . . . . . . . . . . . . . . 17 ; 5.2 Static Pure - IB and HELLO Message Blocks . . 18 ; 5.3 Static Pure ; 5.3.1 WTO Response Strings . . . . . . . . . . 19 ; 6. Program Startup . . . . . . . . . . . . . . . . . . . 20 ; 7. Scheduler ; 7.1 Idle Loop . . . . . . . . . . . . . . . . . . 21 ; 7.2 CHKHNG - Check for Hung Streams . . . . . . . 22 ; 7.3 CHKTIM - Routine to Check Wakeup Time . . . . 23 ; 7.4 DSCHD - Deschedule the Current Stream . . . . 24 ; 7.5 CHKQUE - Receive and Schedule an IPCF Message 26 ; 7.6 CHKOBJ - Validate the QUASAR/Orion/OPR Message 28 ; 7.7 GETBLK - Break an IPCF Message into its Data B 29 ; 8. QUASAR Service Routines ; 8.1 ACK - Process an ACK . . . . . . . . . . . . . 30 ; 8.2 CONTIN, PAUSE - Continue or Pause a Stream . . 31 ; 8.3 DEFINE - Set Object Data . . . . . . . . . . . 32 ; 8.4 DSTATUS - Send Status Info . . . . . . . . . . 33 ; 8.5 CHKPNT - Checkpoint A Stream . . . . . . . . . 34 ; 8.6 KILL - Abort a Connection . . . . . . . . . . 36 ; 8.7 SETUP - Handle Stream Setup . . . . . . . . . 37 ; 8.8 SHUTDN - Shutdown Processing on a Stream . . . 39 ; 8.9 FALEND - Process FAL Stream Termination . . . 40 ; 9. FALSWI Service ; 9.1 SETCHN - Inform the World about a New Channel 41 ; 10. IPCF Subroutines ; 10.1 FNDOBJ - Find an Object Block in our Data Base 42 ; 10.2 RSETUP - Respond to a Setup Message . . . . . 43 ; 10.3 SNDQSR - Send a Message to Quasar . . . . . . 44 ; 10.4 QSRGON - Flag that QUASAR has Gone Away . . . 45 ; 10.5 QSRBAK - Flag QUASAR is Back . . . . . . . . . 46 SUBTTL Table of Contents (page 2) ; Table of Contents for FAL ; ; Section Page ; ; ; 11. PSI Routines ; 11.1 INTINI - Initialize the PSI System . . . . . . 47 ; 11.2 INDCON - Connect a Disk Channel to the Interru 48 ; 11.3 INDDIS - Disconnect a Disk Channel from the In 49 ; 11.4 INTCON - Connect a Stream to the Interrupt Sys 50 ; 11.5 INTDIS - Disconnect a Stream from the Interrup 51 ; 11.6 INTCNA, INTDNA - Connect an ANF-10 Channel to 52 ; 11.7 INTCND - Connect a DECnet Channel to the Inter 53 ; 11.8 ANFINT - ANF-10 Interrupt Service . . . . . . 54 ; 11.9 DECINT - DECnet Interrupt Service . . . . . . 55 ; 11.10 DSKINT - Disk Interrupt Service . . . . . . . 57 ; 11.11 IPCINT - IPCF Message Available Interrupt Serv 58 ; 12. SWIL Memory Manager ; 12.1 .MMGWD - Get some Words of Memory . . . . . . 59 ; 12.2 .MMFWD - Deallocate a Chunk of Memory . . . . 60 ; 13. Operator Messages ; 13.1 BEGJOB - Begin a FAL Job . . . . . . . . . . . 61 ; 13.2 ENDJOB - End a FAL Job . . . . . . . . . . . . 62 ; 13.3 ERRMSG - STOPCD/ERROR/WARN/INFRM Processor . . 63 ; 13.4 FRCCHK - Force a Checkpoint . . . . . . . . . 65 ; 13.5 NETERR - Report a Network Lossage Error . . . 66 ; 13.6 .STOPCD - Abort a Stream . . . . . . . . . . . 67 ; 14. Dummy SWIL Routines ; 14.1 .ASKYN, .ASKNY . . . . . . . . . . . . . . . . 68 ; 15. End of FALQSR . . . . . . . . . . . . . . . . . . . . 69 ; 16. Definitions ; 16.1 Accumulator Usage . . . . . . . . . . . . . . 71 ; 17. FAL initialization ; 17.1 FALINI set FAL job parameters . . . . . . . . 73 ; 17.2 UTXINI initialize USERS.TXT buffer . . . . . . 75 ; 18. Main FAL processing loop . . . . . . . . . . . . . . . 79 ; 19. FAL "JOB" process . . . . . . . . . . . . . . . . . . 81 ; 20. File read access . . . . . . . . . . . . . . . . . . . 91 ; 20.1 Subroutines - RENAME option . . . . . . . . . 100 ; 21. File write access . . . . . . . . . . . . . . . . . . 101 ; 22. File rename access . . . . . . . . . . . . . . . . . . 113 ; 23. File delete access . . . . . . . . . . . . . . . . . . 115 ; 24. File directory-list access . . . . . . . . . . . . . . 116 ; 25. File (BATCH) submission access . . . . . . . . . . . . 117 ; 26. General-purpose file-level subroutines . . . . . . . . 118 ; 27. General-purpose non-specific subroutines . . . . . . . 137 ; 28. FALGLX Interface Routines . . . . . . . . . . . . . . 147 ; 29. CDB initialization vectors . . . . . . . . . . . . . . 151 ; 30. SWIL Argument Blocks . . . . . . . . . . . . . . . . . 152 ; 31. Impure data . . . . . . . . . . . . . . . . . . . . . 153 Subttl Revision History ;INITIAL VERSION CREATED FROM NIK 25-MAR-80 ;6 RDH 18-Mar-84 ; Fix typo that broke RSX/RSTS/VAX non-wildcarded directory; Do not ; generate a FOP field (at FFAD28), just "echo" back whatever the ; remote has sent (keeps RSTS happy, probably the right thing to do ; anyway). ;11 RDH 16-Jul-84 ; Send ACK between each file for DIRECTORY LIST if talking to ; a DAP protocol version 7 (or later) accessor. ;12 RDH 29-Nov-84 ; A zero-length USERS.TXT file causes UTXINI to do a "random" ; core allocation, typically resulting in ?PC out of bounds ; (by deallocating part of the hi seg). ;13 DRB 13-Dec-84 ; Add multistream operation to allow a single copy of FAL to provide ; multiple FAL server connections. This edit makes the following ; major changes: ; 1) Add multithreaded support. Make all network I/O non- ; blocking and add a scheduler. ; 2) Add a QUASAR/ORION interface to allow control of FAL ; via OPR. ; 3) Remove from the NFT/NIP/TSC utility and make FAL a ; standalone module. ; 4) Remove the command interface, which is replaced by (2) ; above. ; 5) Add a GLXLIB interface so that we don't have to reinvent ; the wheel when we're talking with QUASAR. ; The last point above implies that FAL will now be dealing with both ; GLXLIB and SWIL. In order to keep conflicts to a minimum, this edit ; will also split FAL into two code modules: one which contains the ; scheduler and GLXLIB interface, the other contains the mainline FAL ; code and SWIL interface. ;14 DRB 29-Jan-85 ; Release any I/O channels if a connection is aborted. ;15 DRB 31-Jan-85 ; Clean up the file write error code if we get an input error from the ; network. This is probably due to the other end going away, and is ; nothing to get riled up about. ;16 DRB 05-Feb-85 ; Make sure the "file open" status bit always gets cleared before we ; call ENDJOB so that we don't send bogus status updates to QUASAR. ;17 DRB 07-Feb-85 ; Clear all related blocking and wake bits when disabling interrupts for ; network or disk. ;20 DRB 14-Feb-85 ; FILIFF (called by the ERROR macro handler) is observing the register ; preservation conventions. Make it do so. ;21 DRB 14-Feb-85 ; Remove lots of error and/or warning messages that get sent to OPR due ; to user command error (from NFT). Change lots of spurious STOPCDs to ; non-fatal errors or warnings. Change other error/warning messages to ; DEBUG messages which only get typed if FTDEBUG is on. ;22 DRB 25-Mar-85 ; Re-implement the rejection list and add code to receive both the ; rejection list and network ppn via the new .QOODB QUASAR message. ;23 DRB 16-Apr-85 ; Don't crash when/if QUASAR goes away or restarts. If C%SEND returns an ; error, just mark all current streams as potentially killable when ; QUASAR restarts, and corrupt all their object blocks so that any new ; streams started by a new QUASAR won't look like any of the old ones. ; Keep trying to retransmit HELLO messages to QUASAR until it looks up ; again. If we successfully receive or transmit a message to QUASAR, ; mark all the old streams for shutdown, since the new QUASAR is probably ; going to tell us to start some new streams. Note that this leaves two ; holes: First, if QUASAR is stopped and restarted with the same PID, ; and we don't try to send anything while he's out, we'll never know that ; he was gone. The new guy won't know who we are, and this whole edit is ; for naught. Perhaps we should watch for NAKs, and assume that QUASAR ; is gone and back. Second, if we were running more than 1/2 NFAL ; streams at the time of failure, and the new QUASAR attempts to start ; more than 1/2 NFAL new streams, we're probably going to fail in some ; random fashion. We really ought to keep a queue of streams to be ; started if no slots are available. ;24 DRB 17-Apr-85 ; Prevent ILM crashes if we receive a shutdown for a stream we don't ; have. ;25 DRB 18-Apr-85 ; Pay attention to received NAKs from QUASAR. ;26 DRB 11-Jul-85 QAR 868149 ; Don't allow setups from remote operators. This can be detected by ; comparing the node number in the setup object block with that stored ; by SWIL in .MYNNM. ;27 DRB 23-Jul-85 ; Don't allow the job to go virtual until some monitor bugs get fixed. ;30 LEO 15-AUG-85 ; DO COPYRIGHTS. ;31 DRB 16-Oct-85 ; Always get the user's profile when starting a new DAP access. Use ; this profile to find the user's name. Convert the eight bit username ; to SIXBIT, and supply it for spooled file prints. Additionally, pay ; attention to the bit in the user's profile which enables network file ; access, and refuse any connection (with invalid user/password error) ; which attempts to reference a userid that doesn't have this set ; in the profile. ;32 DRB 30-Oct-85 ; Edit 31 correctly gets the user's name from the user profile and stores ; it in .IOQ6N. Unfortunately, SWIQUE stomps on .IOQ6N later when it ; tries to validate the username/password. Save .IOQ6N around the call ; to QUEOP1 until SWIQUE gets fixed such as to not put garbage into ; these two words. Also, output more descriptive error messages to ; the operator than "invalid PPN/Password" if the connection is rejected ; due to the operator's rejection list or if the user doesn't have ; network file access privileges. ;33 DRB 19-Nov-85 ; Update for new ACTSYM symbols. ;34 DRB 20-Nov-85 ; New ACTDAE uses 8 bit ASCII passwords in SIXBIT, so do the same here. ;35 DRB 22-Nov-85 ; Fix the I/O abort code such that channels really do get released when ; the network link is aborted. This requires edit 1025 to SWIL. ;36 DRB 02-Dec-85 ; If a stream gets going reading or writing a file at full speed, it may ; never deschedule, especially on heavily loaded systems. This somewhat ; defeats the multithreaded idea. Add fairness counts to the file read ; and write loops. Also, fix a typo in the write record loop. ;37 DRB 26-Dec-85 ; Another iteration on aborting I/O, due to edit 1026 of SWIL. With any ; luck, this is the last time around on this one. ;40 RDH 4-Jan-86 SPR 10-35424 ; Can't transfer LSN-formatted ASCII. ;41 DRB 16-Jan-86 ; Non-blocking disk I/O misses interrupts, because we're too smart about ; when we enable the PSI system. Quit being so "smart". ;42 DRB 22-Jan-86 ; Pre-zero the password block so we don't get confused over old fragments ; laying around from prior connections. ;43 BSC 25-Mar-86 ; Modify the BADDAP Macro to return a STATUS message to remote task when ; a DAP error occurs. ;44 BSC 8-Apr-86 ; Let SHR flags in an ACCESS message include the flag for ; "No access by other users". DECnet/E DAP version 5.6 sets this. ;45 TL 4-Dec-86 ; Use edit 1047 of SWILIO to correctly transfer implied-CRLF files ; with imbedded non-trailing carriage control (such as MACRO-32's ; listing files). See edit 1047 in SWIL for more details. ;46 RCB 5-Dec-86 ; Change to use the new STOPCD macro rather than the old $STOP. ; This only words because FALGLX searches GLXMAC before FALUNV, and ; the FAL module doesn't search GLXMAC at all. Keep it this way. ;47 KDO 13-Aug-87 ; Allow a Configuration message at the start of a new access. ;50 KDO 18-Aug-87 ; Fix the SCAN (SWIL) intercept routine. ;51 JJF/KDO 21-Nov-88 ; If we are talking to a VAX/VMS system, convert all commas in ; directory spec to dots, as VMS RMS fails to conform ; to the DAP spec. This new behavior is controlled by the FTDOT ; feature-test switch, which is on by default. ; SPR:10-36163 ;52 JJF 21-Dec-88 ; FAL is far too paranoid about the incoming data type bits that ; are lit. Once we've determined ASCII or BINARY data types, the ; rest of the bits don't matter (as far as accepting or rejecting ; the connection), so don't test them. Makes transfers with RSTS ; systems work (since they like to send files with both ASCII ; and EXECUTABLE attributes). ; SPR: 10-35591 ;53 JJF 9-Jan-89 ; Make remote directory specs work better. If we're doing remote ; directory parsing, after looking at the whole name, check the file ; name and extension. If either is null (the case from some remote ; nodes, such as RSTS), change them to * (full wildcard), and light ; appropriate wildcard bits and set appropriate masks. ; SPR: 10-35591 ;54 JJF 11-Apr-89 ; Add support for appending to local files. If a CONTROL(CONNECT) ; message comes in that has the 'position-to-EOF' bit lit in the ; Record Operations Menu, then light the IO.APP flag and do ; some setup work, then jump into the file-writing routines. ; SPR: 10-36155 ;55 RCB 30-Nov-89 ; Fix priv handling for administrative privs with the QUEUE. UUOs to ; talk to ACTDAE. ; Also requires an edit to SWIL. ; No SPR ;56 LWS 3-Dec-89 ; Edit 26 doesn't work when there's no ANF support in monitor. If ; .MYNNM is zero, there can't be a remote operator. ; No SPR Subttl Definitions -- Assembly Parameters, Channel, Other Random Symbols ; Feature tests ND FTUTXT,0 ; Default exclude support for USERS.TXT ND FTDEBUG,-1 ; Default to debugging features ND FTDOT,-1 ; Convert comma-separated directories to ; dot-separated, but ONLY if the remote ; system is VAX/VMS ; Other assembly parameters: ND $NTPPN,<377777,,377777> ; Default access PPn ND NFAL,^D30 ; Maximum number of concurrent streams ND NANF10,^D15 ; Maximum number of ANF-10 streams ND PDSIZE,200 ; Size of push down list ND CHKPTIM,^D30 ; Default time between checkpoints ND CHKMIN,^D10 ; Minimum number of seconds between checkpoints ND HNGTIM,^D60*3 ; Time (seconds) before I/O is considered hung ND QSRTRY,^D60*3 ;[23] Hello retry interval when QUASAR down ND DIRCNT,^D10 ; Number of files to list before blocking (directory) ND PSWDLN,^D39 ; Maximum number of characters in a password PSWDWD==/4 ;[34] Number of words in password string ND ARSPLN,.AEACC+1 ;[33] Length of the ACTDAE response buffer ND CHARFC,10000 ;[36] Maximum chars copied before deschedule ND RECFC,100 ;[36] Maximum records copied before deschedule ; I/O channels internally dedicated UTX==10 ; For reading USERS.TXT ; Constant parameters: XP MSBSIZ,>; The size of a message block XP .PSLEN,.PSVIS+1 ; Length of a PSI block ; Some stream abort reasons: $FSNNS==1 ; No network software $FSISP==2 ; Insufficient privileges $FSNRM==3 ;[26] Can't start remote FAL streams ; Some message type symbols: .ETINF==0 ; Informational message .ETBEG==1 ; Beginning of session message .ETEND==2 ; End of session message .ETREJ==3 ; Connection rejected .ETWRN==4 ; Warning message .ETERR==5 ; Error message .ETSTP==6 ; Stream STOPCD .ETPRO==7 ;[21] Protocol error message .ETMAX==.ETPRO ;[21] Maximum message type value IFN FTDEBUG,< .ETDBG==10 ;[21] Debug error message .ETMAX==.ETDBG ;[21] Redefine the maximum message type > Subttl Definitions -- Status Flags, Stream Blocking Bits ; Some status flags we'll find in S: S.RUN==1B0 ; The FAL stream has been started S.OPEN==1B1 ; A connection is active for this stream S.PSIN==1B2 ; Network interrupts have been enabled S.PSID==1B3 ; Disk interrupts have been enabled S.SHUT==1B4 ; Shut this stream down S.KILL==1B5 ; Abort the current connection S.NPPN==1B6 ; Connection is using NETPPN S.CONN==1B7 ; Connection accepted, waiting for link to start S.QSRD==1B8 ;[23] QUASAR has gone away S.PROF==1B9 ;[31] We have the user's profile S.CLR==S.OPEN!S.PSIN!S.PSID!S.KILL!S.NPPN!S.CONN!S.PROF ; Flags to clear between connections ; Stream blocking status bits: PSF%NI==1B0 ; Stream is blocked waiting for network input PSF%NO==1B1 ; Stream is blocked waiting for network output PSF%SL==1B2 ; Sleeping PSF%ST==1B3 ; Stopped by the operator PSF%CW==1B4 ; Waiting for network connection PSF%DI==1B5 ; Stream is blocked waiting for local input PSF%DO==1B6 ; Stream is blocked waiting for local output PSF%DF==1B7 ; Stream is blocked because disk is offline PSF%CR==1B8 ; Stream has crashed PSF%IO==PSF%NI!PSF%NO!PSF%DI!PSF%DO ; Stream is blocked for some kind of I/O Subttl Definitions -- Macros ; Define a macro to allocate storage on the per stream process pages. ; This macro was copied from LPTSPL.MAC DEFINE LP(SYM,VAL),< IF1,< XLIST IFNDEF J...X, IFDEF SYM, SYM==J...X J...X==J...X+VAL LIST SALL > ;; End IF1 IF2,< .XCREF J...X==SYM .CREF SYM==J...X > ;; End IF2 > ; End DEFINE LP ; A macro to pull a symbol from a universal file that we've searched DEFINE GS (SYM),< .XCREF ...FOO==SYM .CREF > Subttl Definitions -- Error Handler Interface ; The following definitions are to provide the SWIL context routines ; a mechanism for accessing the Orion WTO facility. ; A macro to kill of a stream, with optional $WTO text: DEFINE STOPCD (TXT,RTN,ADR,DIE<.STOPCD##>),< IFB ,JRST DIE ;; If no text, just kill off the stream IFNB ,< PUSHJ P,@[Z ERRMSG## ;; Got some text - type it XWD .ETSTP,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to go die > > ; A macro to complain about protocol errors DEFINE BADDAP (MAC<0>,MIC,TXT,DIE<.POPJ##>),< PUSHJ P,@[EXP DAPERR## ;; Address of DAP status sender IFB , ;; DAP status for MA.SYN IFNB ,> ;; DAP status otherwise EXP [ASCIZ ~TXT~];; Text to type out EXP DIE] ;; A place to go when we're done > ; A macro to type an error message: DEFINE ERROR (PFX,TXT,RTN<0>,ADR<0>,DIE<.POPJ##>),< E..'PFX:!PUSHJ P,@[Z ERRMSG## ;; Address of text typer XWD .ETERR,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to go when we're done > ; A macro to say we're rejecting a connection: DEFINE REJECT (PFX,TXT,RTN<0>,ADR<0>,DIE<.+1>),< R..'PFX:!PUSHJ P,@[Z ERRMSG## ;; Address of text typer XWD .ETREJ,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to go when we're done > ; A macro to type warning messages: DEFINE WARN (PFX,TXT,RTN<0>,ADR<0>,DIE<.+1>),< W..'PFX:!PUSHJ P,@[Z ERRMSG## ;; Address of text typer XWD .ETWRN,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to go on return > ; One more time, for information messages: DEFINE INFRM (PFX,TXT,RTN<0>,ADR<0>,DIE<.+1>),< I..'PFX:!PUSHJ P,@[Z ERRMSG## ;; Address of text typer XWD .ETINF,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to return to > ; Last one is for DEBUG only errors: IFE FTDEBUG,), > IFN FTDEBUG,< DEFINE DEBUG (TXT,RTN<0>,ADR<0>,DIE<.+1>),< PUSHJ P,@[Z ERRMSG## ;; Address of text typer XWD .ETDBG,[ASCIZ ~TXT~] Z RTN ;; Optional typeout routine Z ADR ;; Optional data for typeout routine Z DIE] ;; A place to return to > > ; Definitions of MACCODE field values to use when invoking BADDAP macro. MA.PND==0B23 ; Operation in progress MA.SUC==1B23 ; Successful result MA.UNS==2B23 ; Unsupported DAP request MA.RES==3B23 ; Reserved MA.FOP==4B23 ; Error occurred before file opened MA.TER==5B23 ; Transfer error i.e. I/O error on a file MA.TWN==6B23 ; Transfer warning i.e. operation completed abnormally MA.ACT==7B23 ; Access termination error on a file MA.FMT==10B23 ; Format error parsing message MA.INV==11B23 ; Invalid field in message MA.SYN==12B23 ; Synchronization error i.e. DAP message out of order Subttl Definitions -- GLXLIB Symbols ; Pull some symbols out of GLXLIB so that the SWIL half of FAL doesn't ; have to search any QUASAR/GLXLIB related universals to mess with these ; symbols. ; Symbols in a file descriptor block: GS .FDLEN ; Length and type word GS FD.LEN ; Mask to length field GS FD.TYP ; Mask to type field GS .FDLEN ; Length of the FD GS .FDFIL ; Pointer to first word in file descriptor GS .FDSTR ; Structure name GS .FDNAM ; File name GS .FDEXT ; Extension GS .FDPPN ; Project programmer number GS .FDPAT ; Remaining path (SFDs) GS FDXSIZ ; Maximum length of an FD ; Some symbols from SWIL for FALGLX GS IO.DCN ; DECnet network type GS IO.ANF ; ANF-10 network type GS JWW.FL ; Watch bits for "first" in error processing ; Some symbols for reading the rejection list: RJ.NOD==REJ.ND-ARG.DA ;[22] Rejected node name ;RJ.NDM==REJ.NM-ARG.DA ;[22] Rejected node name mask RJ.PPN==REJ.PP-ARG.DA ;[22] Rejected PPN RJ.PPM==REJ.MK-ARG.DA ;[22] Rejected PPN mask RJ.MAX==REJ.SZ-ARG.DA ;[22] Length of the rejection sub block Subttl Definitions -- Stream Parameter Area ; Define the storage on the per stream pages: LP J$$BEG,0 ; Beginning of the parameter area ; Storage required by the scheduler: LP J$RPDL,PDSIZE ; The context pushdown list LP J$RACS,20 ; The saved context ACs LP J$RTIM,1 ; Time that the current request started ; Parameter storage for the FAL process: LP J$FTYP,1 ; FAL stream type (ANF-10 or DECnet) LP J$FSLP,1 ; Sleep time after FAL disconnect LP J$DOFF,1 ; Old PC when disk offline ; Record management: LP J$RALC,2 ; Allocation pointer to record buffer LP J$RLEN,1 ; Record length (Input Service Routine call) LP J$RBUF,1 ; Record buffer (Input Service Routine call) ; Stream status storage: LP J$STFD,FDXSIZ ; File descriptor of current file being accessed LP J$SNOD,1 ; Node that this stream is connected to LP J$SACC,1 ; File access type LP J$SBYT,1 ; Number of bytes transfered LP J$SUSR,^D8 ; Username of accessor LP J$SPSW,PSWDWD ; Password string (8 bit ASCIZ) LP J$SACT,^D8 ; Account string of access ; Storage for SWIL interface: LP J$SMSG,^D100 ; Area to build error message strings LP J$SWLD,1 ; Pointer to WILD's storage LP J$SERP,1 ;[50] Saved PDL pointer LP J$SERT,1 ;[50] Error routine ; Storage for talking to the accounting daemon LP J$ABLK,20 ; ACTDAE QUEUE. UUO argument block LP J$AUSR,^D10 ; A copy of the 8 bit username LP J$ARSP,ARSPLN ; A buffer for ACTDAE's response ; Other misc variables: LP J$DCNT,1 ; Number of directory files before blocking LP J$LCHK,1 ; Time of last checkpoint/status update LP J$SFC,1 ;[36] Fairness count for reading/writing files LP J$$END,0 ; Size of the per stream area Subttl End of FALUNV PRGEND Title FALGLX -- GLXLIB Interface and Scheduler for FAL Search JOBDAT ; Get the job data symbols Search GLXMAC ; Get the GLXLIB parameters PROLOG (FAL) ; Do the standard GLXLIB setup Search QSRMAC ; Get QUASAR symbols Search ORNMAC ; and the OPR/ORION parmeters Search FALUNV ; Get our symbols Search SWIL ; And finally, SWIL SALL ; Make the listing look nice .Directive FLBLST ; etc... ; Stuff the version number in .JBVER: LOC .JBVER EXP %FAL RELOC 0 ; Normal relocation COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1990. ALL RIGHTS RESERVED. \;END COPYRIGHT MACRO Comment ~ FAL -- File Access Listener COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1985,1986,1988,1990. ALL RIGHTS RESERVED. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO OR OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. ~ Subttl Commentary Comment ~ Herein lies FAL's interface to GLXLIB and the stream scheduler. These functions have been taken out of the main FAL module so that the GLXLIB interface does not interfere with the SWIL interface in the main line code. Thus, this module will interface the SWIL environment routines to GLXLIB, performing any calling and AC convention translation. Since GLXLIB and SWIL use different AC definitions, AC usage will probably be the largest potential source of problems. The following is a map of AC usage of both the subroutine libraries: AC GLXLIB SWIL 0 TF M0 1 S1 T1 2 S2 T2 3 T1 T3 4 T2 T4 5 T3 P1 6 T4 P2 7 P1 P3 10 P2 P4 11 P3 IO 12 P4/M ID 13 CI 14 CO 15 J J 16 S S 17 P P The most notable fallout of this is that GLXLIB's T3 and T4 map to SWIL's P1 and P2. Thus, we must save SWIL's P1/2 so that they are not destroyed by calls to FALGLX which may assume that these are temporary registers. NOTE WELL: Calls to .SAVE1, .SAVE2, .SAVE3, .SAVE4 or $SAVE (P1), $SAVE(P1,P2), $SAVE (P1,P2,P3) and $SAVE (P1,P2,P3,P4) will result in SWIL's .SAVEn routine being called and NOT GLXLIB's. These routines will save FALGLX's T3, T4, P1 and P2. In general, don't try these routines from FALGLX. ~ ; End Comment Subttl Definitions -- Local Accumulator Usage ; Despite the fact the the GLXLIB universals should have already defined ; these for us, we're going to go redefine them ourselves, just to avoid ; any confusion: TF==0 ; Returned True/False status S1==1 ; Argument register S2==2 ; other argument register T1==3 ; Temporaries T2==4 T3==5 T4==6 P1==7 ; Preserved registers P2==10 P3==11 P4==12 M==12 ; Current message pointer (overlaps P4) J==15 ; Job context pointer S==16 ; Current stream status P==17 ; Stack pointer Subttl Definitions -- Macros ; Define a macro to build an interrupt service routine header for ANF-10 ; interrupts. DEFINE ANFINH(Z),< XLIST $BGINT 1, ;; Normal interrupt service routine entry MOVEI S1,Z ;; Get the stream number MOVEI S2,ANFVEC+<.PSLEN*Z> ;; Point to the PSI block JRST ANFINT ;; Continue in main line code ANHDSZ==4 ;; Length of this header LIST > ; End define ANFINH ; Another one, but this time for disk interrupts: DEFINE DSKINH(Z),< XLIST $BGINT 1, ;; Normal interrupt service routine entry MOVEI S1,Z ;; Get the stream number MOVEI S2,DSKVEC+<.PSLEN*Z> ;; Point to the PSI block JRST DSKINT ;; Continue in main line code DSHDSZ==4 ;; Length of this header LIST > Subttl Storage -- Static Impure ; Some impure storage PDL: BLOCK PDSIZE ; The stack BZER==. ; Start of memory to zero on startup QSRDIE: BLOCK 1 ;[23] Non-zero if QUASAR is dead MESSAG: BLOCK 1 ; Address of the message just received IMESS: BLOCK 1 ; IPCF message: -1 means something to be released BLKADR: BLOCK 1 ; IPCF message block address save area SAB: BLOCK SAB.SZ ; Send argument block MSGBLK: BLOCK MSBSIZ ; A block to build message into RUTINE: BLOCK 1 ; IPCF message dispatch TEXTCT: BLOCK 1 ;[21] Number of chars remaining in TEXTBP TEXTBP: BLOCK 1 ; A byte pointer for DEPBP SCHEDL: BLOCK 1 ; Stream scheduling counter SLEEPT: BLOCK 1 ; Sleep interval FALBTS: BLOCK 1 ; Non-zero if status wants to be stored to saved register block ; The resident stream database: STREAM: BLOCK 1 ; The current stream number FALACT: BLOCK NFAL ; -1 if stream is active, 0 otherwise FALPAG: BLOCK NFAL ; Address of the FAL stream data FALOBA: BLOCK NFAL ; Table of object block addresses FALOBJ: BLOCK OBJ.SZ*NFAL ; Table of object blocks FALWKT: BLOCK NFAL ; Stream's wakeup time FALSTW: BLOCK NFAL ; Stream status word FALWAK: BLOCK NFAL ; Reasons why a stream should wake up. ; Parallel to FALSTW (prevents races) IFN FTDEBUG,< FALBLK: BLOCK NFAL ; UDT when stream blocked for I/O > FALCHK: BLOCK NFAL ; Stream checkpoint indicator ; contains the time for the next checkpoint FALCHN: BLOCK NFAL ; FAL stream's channel number FC%ANF==1B0 ; Channel is ANF-10 (not DECnet) FALDSK: BLOCK NFAL ; FAL stream's disk channel number ; Interrupt system storage: PSIVEC: BLOCK 0 ; Start of the interrupt system storage IPCVEC: BLOCK .PSLEN ; IPCF interrupt block DECVEC: BLOCK .PSLEN ; DECnet interrupt block ANFVEC: BLOCK .PSLEN*NANF10 ; ANF-10 interrupt blocks DSKVEC: BLOCK .PSLEN*NFAL ; Disk interrupt blocks EZER==.-1 ; End of memory to zero on startup Subttl Storage -- Static Pure - IB and HELLO Message Blocks ; Setup the interrupt system block ala GLXLIB: IB: $BUILD IB.SZ $SET (IB.PRG,,%%.MOD) ; Setup the program name $SET (IB.INT,,PSIVEC) ; Setup the interrupt vector address $SET (IB.PIB,,PIB) ; Setup the PIB address $SET (IB.FLG,IP.STP,1) ; Stopcodes to Orion $SET (IB.FLG,IB.NPF,1) ;[27] Don't enable the page fault handler $EOB ; The PIB: PIB: $BUILD PB.MNS $SET (PB.HDR,PB.LEN,PB.MNS) ; PIB length,,0 $SET (PB.FLG,IP.PSI,1) ; PSI on $SET (PB.INT,IP.CHN,0) ; Interrupt channel $EOB ; The hello message we send to QUASAR on startup: HELLO: $BUILD HEL.SZ $SET (.MSTYP,MS.TYP,.QOHEL) ; Message type (Hello again) $SET (.MSTYP,MS.CNT,HEL.SZ) ; Message length $SET (HEL.NM,,<'FAL '>) ; Program name $SET (HEL.FL,HEFVER,%%.QSR) ; QUASAR version number $SET (HEL.NO,HENNOT,1) ; Number of object types (1) $SET (HEL.NO,HENMAX,NFAL) ; Maximum number of streams $SET (HEL.OB,,.OTFAL) ; FAL's object type $EOB ; A dummy object block for stray $WTOs DUMOBJ: $BUILD OBJ.SZ $SET (OBJ.TY,,.OTFAL) ;[23] Our object type $SET (OBJ.UN,OU.LRG,0) ;[23] The unit number (zero) $SET (OBJ.ND,,0) ;[23] The node name/number $EOB Subttl Storage -- Static Pure -- WTO Response Strings ; Table of abort messages: SETMSG: [ASCIZ ~Shutdown by operator~] [ASCIZ ~No network software~] [ASCIZ ~Insufficient privileges~] [ASCIZ ~Cannot start remote FAL streams~] [ASCIZ ~Shutdown~] ; Table of file access strings indexed by function code (from J$SACC) CHKFNC: [ASCIZ ~(unknown function)~] ; 0 - Not known [ASCIZ ~Reading~] ; 1 - Read file [ASCIZ ~Writing~] ; 2 - Write file [ASCIZ ~Rename~] ; 3 - Rename file [ASCIZ ~Delete~] ; 4 - Delete file [ASCIZ ~(illegal function)~] ; 5 - ??? [ASCIZ ~Directory of~] ; 6 - Directory of files [ASCIZ ~Submit~] ; 7 - Submit file [ASCIZ ~Execute~] ; 10 - Execute file CHKFLN==.-CHKFNC ; Highest function code we know about Subttl Program Startup FAL:: JFCL ; Avoid CCL entry RESET ; As usual MOVE P,[IOWD PDSIZE,PDL] ; Setup the stack pointer SETZM BZER ; Clear a word of storage MOVE S1,[BZER,,BZER+1] ; Make a pointer to get the rest BLT S1,EZER ; Clear all our impure storage MOVEI S1,IB.SZ ; Get the IB size MOVEI S2,IB ; Point to the IB PUSHJ P,I%INIT ; Initialize the world PUSHJ P,FALINI## ; Initialize the SWIL side of the world PUSHJ P,INTINI ; Initialize the interrupt system PUSHJ P,I%ION ; Turn the interrupt system on MOVEI T1,HELLO ; Point to the hello message PUSHJ P,SNDQSR ; Tell QUASAR we're here MOVSI P1,-NFAL ; Setup the stream counter ; Fall into the scheduler loop Subttl Scheduler -- Idle Loop ; Here is the stream scheduler. We loop over each stream, running it ; if possible, then check for any pending IPCF messages to process. ; This code borrowed from LPTSPL.MAC MAIN: SKIPN FALACT(P1) ; Is this stream active? JRST MAIN.2 ; No, skip it HRRZM P1,STREAM ; Yes, store as the current stream number MOVE J,FALPAG(P1) ; Get the context storage page PUSHJ P,CHKTIM ; Adjust the sleep time if needed PUSHJ P,DSTATUS ; Do any status stuff SKIPE FALSTW(P1) ; Is this stream blocked? JRST MAIN.2 ; Yes, go on to the next stream SETZM FALWAK(P1) ; If we're awake, no reason to wake us MOVEM P1,SCHEDL ; No, store the scheduling counter HRLZ T1,J$SWLD(J) ; * Hack * Point at the saved WILD data HRRI T1,.WILDZ## ; * Hack * Point to where it goes BLT T1,.WILDZ##+.WILDL##-1 ; Move WILD's data back MOVSI 0,J$RACS+1(J) ; Setup the source address for the BLT HRRI 0,1 ; Get the destination address BLT 0,17 ; Restore the stream ACs POPJ P, ; And return to the stream context ; Here when the stream blocks again MAIN.1: MOVE P1,SCHEDL ; Restore the scheduler counter PUSHJ P,DSTATUS ; Do the status thing again PUSHJ P,CHKTIM ; Reset the wakeup timer ; Here to schedule the next stream MAIN.2: AOBJN P1,MAIN ; Loop back for the next stream number PUSHJ P,CHKQUE ; Check for incoming IPCF messages SKIPN QSRDIE ;[23] Is QUASAR dead? JRST MAIN.3 ;[23] No, don't send any hellos then MOVEI T1,HELLO ;[23] Yes, try to send PUSHJ P,SNDQSR ;[23] a HELLO message SKIPN QSRDIE ;[23] We tried. Did we succeed? JRST MAIN.4 ;[23] Yes. Everything probably just woke up SKIPE S1,SLEEPT ;[23] No. Get the sleep interval JRST MAIN.3 ;[23] None, don't sleep then SKIPG S1 ;[23] Is there really one? MOVX S1,QSRTRY ;[23] No, set our default interval MOVEM S1,SLEEPT ;[23] Store the new sleep interval MAIN.3: SKIPE MESSAGE ; Did we process a message? JRST MAIN.4 ; Yes, don't sleep then IFN FTDEBUG,< PUSHJ P,CHKHNG ; See if anyone's hung JRST MAIN.4 ; Yup. Try to run him again > MOVE S1,SLEEPT ; No, get the sleep time JUMPE S1,MAIN.4 ; Don't sleep if no sleep time specified SKIPG S1 ; Positive value, or default? IFE FTDEBUG,SETZ S1, ; Default, set infinite sleep time IFN FTDEBUG,MOVEI S1,HNGTIM*3 ; (Unless debugging) PUSHJ P,I%SLP ; Go wait ; Here if message have been processed. Restart the scheduler MAIN.4: MOVE P,[IOWD PDSIZE,PDL] ; Reset the stack pointer SETOM SLEEPT ; Reset the sleep timer MOVSI P1,-NFAL ; Reset the loop counter JRST MAIN ; And restart the scan Subttl Scheduler -- CHKHNG - Check for Hung Streams ; Here if we just completed a scan of all streams and found nothing ; to run and no IPCF messages to play with. This routine is called under ; the debug conditional to see if there are any streams that have been ; blocked for I/O for an undue length of time. If we find such a stream, ; we'll send a warning to the operator, and clear the I/O wait bits, to ; see if the stream can continue (thus unblocking an unforseen race). ; Calling sequence: ; PUSHJ P,CHKHNG ; See if anything is hung ; returns non-skip if something was hung ; returns skip if nothing hung ; Destroys S1, S2, T1-T4 IFN FTDEBUG,< CHKHNG: MOVSI T4,-NFAL ; Setup an AOBJN pointer to the tables PUSHJ P,I%NOW ; Go get the current date/time MOVE T3,S1 ; Get a safer copy of it MOVEI T2,1 ; Assume skip return ; Loop here for each task. See if it's just blocked for I/O only. If it ; is, see if it's been out for a long time. CHKH.1: SKIPN FALACT(T4) ; Is this guy active? JRST CHKH.3 ; No, skip it SKIPN T1,FALSTW(T4) ; Yes, is it blocked? JRST CHKH.2 ; No, but there's something to run now, ; so pretend we just unnblocked it TXNE T1,^-PSF%IO ; Blocked for any non-I/O conditions? JRST CHKH.3 ; Yes, leave this guy alone MOVE S1,T3 ; Get the current time SUB S1,FALBLK(T4) ; Subtract the time we started waiting CAIGE S1,HNGTIM*3 ; Been too long? JRST CHKH.3 ; No, skip over it ; Here if we got a task that's been waiting too long. Just unblock any I/O ; wait and tell the operator about it. TXZ T1,PSF%IO ; Clear any I/O block EXCH T1,FALSTW(T4) ; Store the new hoked up status TXNE T1,PSF%NI!PSF%NO ; Network wait? SKIPA T1,[[ASCIZ ~Network~]] ; Yes, say so MOVEI T1,[ASCIZ ~Disk~] ; No, say disk $WTOJ (Error,,@FALOBA(T4)) CHKH.2: SETZ T2, ; Say we want the non-skip return CHKH.3: AOBJN T4,CHKH.1 ; Loop if more streams to check ADDM T2,(P) ; Adjust the return address POPJ P, ; Return > Subttl Scheduler -- CHKTIM - Routine to Check Wakeup Time ; The purpose of this routine is to check and set the sleep time based ; on the current conditions. The sleep time is checked based on the stream's ; wakeup time. Whoever wants to wake up the earliest sets the sleep time. ; Calling sequence: ; PUSHJ P,CHKTIM ; Set the wakeup time ; returns here, True if time to wake this stream ; Destroys S1, S2, T1 CHKTIM: PUSHJ P,I%NOW ; Get the current time into S1 MOVE T1,STREAM ; Get the stream number SKIPN S2,FALWKT(T1) ; Get the wakeup time for this stream $RETF ; No time set, nothing to do here SUB S2,S1 ; Calculate the number IDIVI S2,3 ; of seconds to sleep JUMPLE S2,CHKT.1 ; Wake stream if it's wakeup time CAILE S2,^D60 ; Is it a full minute? MOVEI S2,^D60 ; Yes, truncate to one minute SKIPL SLEEPT ; Always set new time if none set CAMGE S2,SLEEPT ; Is this less than the previous? MOVEM S2,SLEEPT ; Yes, set new sleep time $RETF ; And say we're still asleep ; Here if it's time to run us CHKT.1: SETZM SLEEPT ; Clear the sleep time MOVE T1,STREAM ; Get the stream number back MOVX S1,PSF%SL ; And clear the status ANDCAM S1,FALSTW(T1) ; flag for this stream SETZM FALWKT(T1) ; Clear the wakeup time $RETT ; Return true and wake the stream Subttl Scheduler -- DSCHD - Deschedule the Current Stream ; This routine will descedule the current process, and return to the top ; level scheduling loop. ; Calling sequence: ; J/ current per context storage pointer ; MOVX M0, ; PUSHJ P,DSCHD ; Block until condition satisfied ; returns here when unblocked and rescheduled ; This routine makes the following assumptions: ; 1) STREAM contains the current stream number and J points to the ; per stream storage. ; 2) We're currently in stream context. If this is not the case, bad ; things can happen. ; 3) If called with an IPCF message currently in use, it is assumed ; that the user has everything needed from the message, and the ; message will be released. This assumption is necessary to ; prevent another message being received before the old message ; is released. ; A stream context registers are preserved in the per stream memory ; Top level ACs S1, S2 and T1 are clobbered. DSCHD:: MOVEM 0,J$RACS(J) ; Save the registers MOVEI 0,J$RACS+1(J) ; with a BLT HRLI 0,1 ; ... BLT 0,J$RACS+17(J) ; Save them all MOVE T1,STREAM ; Get the current stream number ; Store the blocking flags in the stream status HLLZ S1,TF+J$RACS(J) ; Get the flags HRRZ S2,TF+J$RACS(J) ; Get the sleep time IORM S1,FALSTW(T1) ; Store the new blocking bits IFN FTDEBUG,< PUSHJ P,I%NOW ; Get the current time MOVEM S1,FALBLK(T1) ; Store it for the hung checker > SETZ S1, ; Get a zero EXCH S1,FALWAK(T1) ; Clear the reasons why we should wake ANDCAM S1,FALSTW(T1) ; Clear any sloppiness on our part ; Copy the WILD data back to the per stream area so it doesn't get ; wiped out. This is a temporary solution to this problem until WILD ; learns about multithreaded operation. HRLZI T2,.WILDZ## ; * Hack * Get the source of the data HRR T2,J$SWLD(J) ; * Hack * Get the destination HRRZ T3,T2 ; * Hack * Copy the destination base BLT T2,.WILDL##-1(T3) ; Copy the WILD data JUMPE S2,DSCH.D ; If no sleep time given, go away PUSHJ P,I%NOW ; Get the current time IMULI S2,3 ; Convert seconds to UDT ticks (sort of) ADD S1,S2 ; Build the wakeup time MOVEM S1,FALWKT(T1) ; Save the wakeup time ; Make sure we're really in stream context. DSCH.D: HRRZ S1,P ; Get the current stack address CAIL S1,J$RPDL(J) ; Is it less than stream stack base? CAILE S1,PDSIZE+J$RPDL(J) ; No, is it inside the stream stack? STOPCD (CDS,HALT,,Call to DSCHD while not in stream context) MOVE P,[IOWD PDSIZE,PDL] ; Reset the scheduler stack pointer JRST MAIN.1 ; And re-enter the scheduler cycle Subttl Scheduler -- CHKQUE - Receive and Schedule an IPCF Message ; Here to receive and schedule an incoming IPCF message. ; Calling sequence: ; PUSHJ P,CHKQUE ; Process incoming IPCF messages ; returns here always, no particular status ; Destroys S1, S2, T1-T4 CHKQUE: SETZM MESSAG ; Say no messages received yet PUSHJ P,C%RECV ; Go try to get one JUMPF .POPJ ; Nothing there, return SETOM IMESS ; Say we got something SETZM BLKADR ; Clear the IPCF message block address save area LOAD S2,MDB.SI(S1) ; Get the special index word TXNN S2,SI.FLG ; Is there an index there? JRST CHKQ.5 ; No, ignore it ANDX S2,SI.IDX ; AND out the index CAIE S2,SP.OPR ; Is it from OPR? CAIN S2,SP.QSR ; No, is it from QUASAR? SKIPA ; Yes, go on JRST CHKQ.5 ; No, punt the message CAIN S2,SP.QSR ;[23] So it's ok. Was it from QUASAR? PUSHJ P,QSRBAK ;[23] Yes, go make sure we know it's there ; Here with something valid to do. CHKQ.2: LOAD M,MDB.MS(S1),MD.ADR ; Get the message address MOVEM M,MESSAG ; Save it away LOAD S2,.MSTYP(M),MS.TYP ; Get the message type MOVSI S1,-NMSGT ; Get an AOBJN pointer to the type table CHKQ.3: HRRZ T1,MSGTAB(S1) ; Get a message type CAMN S2,T1 ; Is it our boy? JRST CHKQ.4 ; Yes, go handle it AOBJN S1,CHKQ.3 ; No, try the next one JRST CHKQ.5 ; No match anywhere, punt it CHKQ.4: HLRZ T2,MSGTAB(S1) ; Get the processing routine address MOVEM T2,RUTINE ; Save the routine address PUSHJ P,CHKOBJ ; Go find the object block JUMPF CHKQ.5 ; Not there, just delete it PUSHJ P,@RUTINE ; Call the processor SKIPN FALBTS ; Do we want to save the status bits? MOVEM S,J$RACS+S(J) ; Yes, save the status bits then SETZM FALBTS ; Reset the default for saving flags CHKQ.5: SKIPE IMESS ; Do we have a message allocated? PUSHJ P,C%REL ; Yes, release it SETZM IMESS ; Say we don't have a message anymore POPJ P, ; And return to the scheduler ; Table of message types and corresponding processor routine: MSGTAB: XWD DSTATUS,.QORCK ; Checkpoint request XWD SETUP,.QOSUP ; Setup/shutdown XWD DEFINE,.QOODB ; Define (object data) XWD CONTIN,.OMCON ; Operator continue request XWD PAUSE,.OMPAU ; Operator pause/stop request XWD KILL,.OMCAN ; Cancel transfer XWD ACK,MT.TXT ;[25] Acknowledgement we hope NMSGT==.-MSGTAB ; The number of message types we know about Subttl Scheduler -- CHKOBJ - Validate the QUASAR/Orion/OPR Message Object Blocks ; This routine is called on the receipt of an IPCF message to validate ; the message's object blocks. ; Calling sequence: ; S1/ offset into MSGTAB ; S2/ message type ; PUSHJ P,CHKOBJ ; Check the object blocks ; returns false if not valid ; returns true with: ; STREAM/ stream number ; J/ database address ; S/ status bits ; Destroys S1, S2, T1-T3 CHKOBJ: CAIL S2,MT.OFF ;[25] Is it a common message? $RETT ;[25] Yes, no object to look for CAIL S2,.OMOFF ; No, is this an OPR/Orion message? JRST CHKO.1 ; Yes, go setup the object search XCT MSGOBJ(S1) ; Get the object block address JRST CHKO.2 ; Continue below ; Here if an OPR/Orion message: CHKO.1: PUSHJ P,GETBLK ; Get a message block JUMPF .RETF ; No more, that's an error CAIE T1,.OROBJ ; Is this the object block? JRST CHKO.1 ; No, try the next one then MOVE S1,T3 ; Get the block data address CHKO.2: PUSHJ P,FNDOBJ ; Go find the object block POPJ P, ; Return and propogate T/F ; Here if .QOODB - find object type block CHKO.3: PUSHJ P,GETBLK ;[22] Get the next block JUMPF .RETF ;[22] No more. That's an error CAIE T1,.ORTYP ;[22] Is this an object type block? JRST CHKO.3 ;[22] No, skip it MOVEI T1,.OTFAL ;[22] Yes, get our object type CAME T1,(T3) ;[22] Is it for us? $RETF ;[22] No, punt it off $RETT ;[22] Yes, return happy MSGOBJ: MOVEI S1,RCK.TY(M) ; Get the checkpoint message object address $RETT ;[22] Return happy if setup message JRST CHKO.3 ;[22] Look for object type block for .QOODB Subttl Scheduler -- GETBLK - Break an IPCF Message into its Data Blocks ; here to extract data blocks from an IPCF message. ; Calling sequence: ; M/ message address ; PUSHJ P,GETBLK ; Get the next block from the message ; returns false if no more message blocks ; returns true with message block: ; T1/ block type ; T2/ block length ; T3/ block data pointer ; Destroys S1, T1-T3 GETBLK: SOSGE .OARGC(M) ; Subtract one from block count $RETF ; No more. Return in shame SKIPN S1,BLKADR ; Get the previous block address MOVEI S1,.OHDRS+ARG.HD(M) ; None there, get the first block address LOAD T1,ARG.HD(S1),AR.TYP ; Get the block type LOAD T2,ARG.HD(S1),AR.LEN ; Get the block length MOVEI T3,ARG.DA(S1) ; Point to the data block address ADD S1,T2 ; Point to the next block MOVEM S1,BLKADR ; Save it for next time $RETT ; And return success Subttl Program Restart -- RESTRT - Restart after a Fatal Error ;[50] Here after a fatal error to restart the FAL job. ; Calling sequence: ; S1/ address of ASCIZ text ; PJRST RESTRT RESTRT::MOVE P,[IOWD PDSIZE,PDL] ; Give GLXLIB a valid stack PJOB S2, ; Get our job number $WTO (,<^T/(S1)/>,,$WTFLG(WT.SJI)) JRST FAL ; Restart this job Subttl QUASAR Service Routines -- ACK - Process an ACK ; Here when we receive a text message. Normally, this should be an ; ACK, but it could be some sort of error. Ignore acks, and attempt the ; appropriate action on a NAK. ; Calling sequence: ; M/ message address ; PUSHJ P,ACK ; Process hopeful ACK ; returns true always (unless we halt) ; Destroys S1, S2, T1-T4 ACK: SETOM FALBTS ;[25] Don't try to update S MOVX S1,MF.FAT ;[25] Get the fatal error indicator TDNN S1,.MSFLG(M) ;[25] Fatal error? $RETT ;[25] No, just ignore the message LOAD S1,.MSFLG(M),MF.SUF ;[25] Yes, get the suffix MOVSI S2,-NAKLEN ;[25] Get the number of known errors ; Loop here throught a table of errors that needs to be processed specially ACK.01: HLRZ T1,NAKTBL(S2) ;[25] Get an error prefix CAME S1,T1 ;[25] Is it a match? AOBJN S2,ACK.01 ;[25] No, try the next one JUMPGE S2,ACK.02 ;[25] No match? Go handle normally HRRZ T1,NAKTBL(S2) ;[25] Got one, get the dispatch address PJRST (T1) ;[25] Call the special processor ; Here if some unknown or normal error: ACK.02: PUSHJ P,GETBLK ;[25] Go get the ASCII string if any $RETT ;[25] None, just return CAIE T1,.CMTXT ;[25] Text string? JRST ACK.02 ;[25] No, try the next block PJOB T1, ;[25] Get our job number $WTO (,<^T/(T3)/>,DUMOBJ) $RETT ;[25] Just return after this NAKTBL: XWD 'IPE',NOPRIV ;[25] Not enough privs XWD 'SNY',NEWQSR ;[25] QUASAR gone away and come back? XWD 'WVN',BADVER ;[25] Bad version number NAKLEN==.-NAKTBL ;[25] Length of this table ; Here if bad QSRMAC version number. Just complain and exit. BADVER: PJOB T1, ;[25] Get our job number $WTO (,,DUMOBJ) JRST STOPIT ;[25] All done, exit ; Here if QUASAR says we don't have enough privs to do this. If this is the ; case, there's little chance that we're running from FRCLIN, so I suppose ; it's ok to OUTSTR a message: NOPRIV: OUTSTR [ASCIZ ~?FALIPE Insufficient privileges ~] ;[25] Type our complaint STOPIT: MONRT. ;[25] And exit JRST STOPIT ;[25] (If we're continued) ; Here if we think QUASAR went away and came back again NEWQSR: PUSHJ P,QSRGON ;[25] Say he's gone MOVEI T1,HELLO ;[25] And try to send PJRST SNDQSR ;[25] a HELLO message Subttl QUASAR Service Routines -- CONTIN, PAUSE - Continue or Pause a Stream ; Here to continue a stream paused by OPR. ; Calling sequence: ; STREAM/ current stream number ; PUSHJ P,CONTIN ; Continue processing on this stream ; returns true always ; Destroys S1, S2 CONTIN: MOVX S2,PSF%ST ; Get the stopped but MOVE S1,STREAM ; Get the current stream number ANDCAM S2,FALSTW(S1) ; Clear the stop condition $ACK (Continued,,@FALOBA(S1),.MSCOD(M)) ; Tell the operator SETZM FALCHK(S1) ; Cause a status update $RETT ; Return happy ; Same thing, but this time, stop the stream instead of continuing it. ; Calling sequence: ; STREAM/ current stream number ; PUSHJ P,PAUSE ; Pause processing on this stream ; returns true always ; Destroys S1, S2 PAUSE: MOVE S1,STREAM ; Get the current stream number MOVX S2,PSF%ST ; Get the stopped bit IORM S2,FALSTW(S1) ; Stop the stream $ACK (Stopped,,@FALOBA(S1),.MSCOD(M)) ; Tell the operator SETZM FALCHK(S1) ; Make a checkpoint happen $RETT ; And return happy Subttl QUASAR Service Routines -- DEFINE - Set Object Data ; This routine is called in response to an OPR DEFINE FILE-ACCESS ; command, and will process the object data sent. The data to be set ; depends on the blocks we find in the message. We assume that the .ORTYP ; block has already been checked to verify our object type, and that the ; next block is a valid data block. ; Calling sequence: ; M/ message address ; BLKADR/ previous block address ; PUSHJ P,DEFINE ; Go set the object data ; returns true always ; Destroys S1, S2, T1-T4 DEFINE: SETOM FALBTS ; Make sure we don't update S PUSHJ P,GETBLK ; Get the next block in the message JUMPF .RETT ; No more. Just return MOVE S2,[-DEFLEN,,DEFTYP] ; Get an AOBJN pointer DEFI01: HLRZ S1,(S2) ; Get a block type CAME T1,S1 ; Is it our type? AOBJN S2,DEFI01 ; No, try the next type JUMPGE S2,DEFINE ; Didn't find it? Try next block HRRZ S1,(S2) ; Got it. Get the dispatch JRST (S1) ; Call the appropriate processor ; Table of DEFINE block types: DEFTYP: XWD .ORDPP,DEFPPN ; DEFINE FILE-ACCESS DEFAULT-PPN XWD .ORREJ,DEFREJ ; DEFINE FILE-ACCESS REJECTION-LIST DEFLEN==.-DEFTYP ; Here to set the default access PPN DEFPPN: MOVE S1,(T3) ; Get the default access PPN MOVEM S1,NETPPN## ; Store it JRST DEFINE ; And go try for more blocks ; Here to set the rejection list: DEFREJ: SKIPN S2,REJFIR## ; Is there any old rejection list? JRST DEFR01 ; No, skip this MOVE S1,REJLAS## ; Get the last one SUB S1,S2 ; Compute number of words to deallocate SETZM REJFIR## ; Then, zero the pointers SETZM REJLAS## ; to the old list PUSHJ P,.MMFWD ; Deallocate the old list JRST DEFINE ; Oh, punt! DEFR01: MOVEI S1,-ARG.DA(T2) ; Get the number of words to allocate PUSHJ P,.MMGWD ; Go allocate memory for the new list JRST DEFINE ; Oh well, try another block MOVE T1,S2 ; Copy the new block pointer HRL T1,T3 ; Point to the incoming data ADD S1,S2 ; Get BLT destination BLT T1,-1(S1) ; Copy the list IFN ARG.DA-1,SUBI S1,ARG.DA-1 ; Compute REJLAS pointer MOVEM S1,REJLAS## ; Store it MOVEM S2,REJFIR## ; Store the new first pointer JRST DEFINE ; And go try for another block Subttl QUASAR Service Routines -- DSTATUS - Send Status Info ; This routine provides a uniform means of handling checkpointing ; within a stream. it decides whether to send status messages. ; CHKPNT is called based on FALCHK or elapsed time since the last CHKPNT. ; The time till the next checkpoint is set if called. If FALCHK is 0, ; CHKPNT is always called. ; This is the only routine that should call CHKPNT. ; Calling sequence: ; STREAM/ current stream number ; J/ per stream storage pointer ; PUSHJ P,DSTATUS ; Send a statups update ; returns here always, no particular status ; Destroys S1, S2, T1-T4 DSTATU: $SAVE ; Save a couple of preserved registers MOVE P1,STREAM ; Get the stream number MOVE S,J$RACS+S(J) ; Get the stream's status SKIPN FALACT(P1) ; Are we active? $RET ; No. Nothing to checkpoint then PUSHJ P,I%NOW ; Get the current time MOVE P2,S1 ; Copy to a safer place SUB S1,FALCHK(P1) ; Compute time to checkpoint SKIPGE S1 ; Is it time to checkpoint yet? $RET ; No, just return now PUSHJ P,CHKPNT ; Yes, do a checkpoint then ADDI P2,CHKPTIM*3 ; Get UDT (sort of) for next time MOVEM P2,FALCHK(P1) ; Store the next checkpoint time $RET ; And return Subttl QUASAR Service Routines -- CHKPNT - Checkpoint A Stream ; We come here periodically to checkpoint the progress on a FAL stream. ; The checkpoint message we are about to send to QUASAR is not the normal ; QUASAR checkpoint, but rather one tailored for this application. This ; routine should be called by DSTATUS only. ; Calling sequence: ; J/ pointer to the stream's data pages ; S/ current stream status bits ; PUSHJ P,CHKPNT ; Do a checkpoint ; returns here always. Aborts if error in send ; Destroys S1, S2, T1-T4 CHKPNT: TXNE S,S.QSRD ;[23] Is our QUASAR gone? POPJ P, ;[23] Yes. Don't try to send anything MOVEI T1,MSGBLK ; Point at the message storage ; Pre-zero the message block storage in case we're not copying a file: SETZM MSGBLK ; Zero a word MOVE S1,[MSGBLK,,MSGBLK+1] ; Make a BLT pointer BLT S1,FAL.ST(T1) ; Clear up to the first string word ; Figure out what this stream's doing: MOVE S2,FALSTW(P1) ; Get the blocked bits for this stream MOVX S1,%IDLE ; Assume that we're idle TXNE S2,PSF%ST ; Are we stopped? MOVX S1,%STOPD ; Yes, say so TXNE S2,PSF%CR ; Did it crash? MOVX S1,%NAVAL ; Yes, say so CAIE S1,%IDLE ; Get any status yet? JRST CHKP.0 ; Yes, don't look any more MOVE S2,FALPAG(P1) ; Get the per stream storage pointer MOVE S2,J$RACS+S(S2) ; Get the stream's status word TXNE S2,S.OPEN ; Do we have a file open? MOVX S1,%ACTIV ; Yes, say so TXNE S2,S.CONN ; Did we just connect to someone? MOVX S1,%CNECT ; Yes, say so TXNE S2,S.KILL ; Are we killing this connection? MOVX S1,%CNCLG ; Yes, tell him that CHKP.0: MOVEM S1,STU.CD(T1) ; Store the status word HRLZ S1,FALOBA(P1) ; Get the object block pointer HRRI S1,STU.RB(T1) ; Point at the destination BLT S1,STU.RB+OBJ.SZ-1(T1) ; Copy the object block into the message ; Store the network type and see if we're active. If not, send a message ; minus the connect time, node names, bytes sent and status string MOVE S1,J$FTYP(J) ; Get the network type CAXE S1,IO.ANF ; ANF-10? SKIPA S1,[2] ; No, say it's DECnet MOVEI S1,1 ; Yes, say it's ANF MOVEM S1,FAL.PR+.OBNTY(T1) ; Store the network type MOVEI S1,FAL.ST+1 ; Assume this is a short message TXNN S,S.OPEN ; Do we have a connection open? JRST CHKP.1 ; No, send a short message ; Compute the connect time for this stream, and convert from UDT units ; to jiffies. PUSHJ P,I%NOW ; Get the current date/time SUB S1,J$RTIM(J) ; Compute the connect time MOVX S2,%CNSTS ; Get the system status GETTAB S2, ; So we can get cycles/second SKIPA ; Error? Assume 60Hz TXNN S2,ST%CYC ; Ok, is this 50 Hz? SKIPA S2,[^D60] ; No, it's good ol' 60 Hz MOVEI S2,^D50 ; Yes, remember this IMUL S1,S2 ; Multiply by jiffies/sec IMULI S1,^D60*^D60*^D24 ; Convert from UDT fraction to seconds HLRZM S1,FAL.PR+1(T1) ; * hack.OBCTM(T1) ; Store it MOVE S1,J$SBYT(J) ; Get the number of bytes moved MOVEM S1,FAL.PR+.OBBYT(T1) ; Store in the status message MOVE S1,J$SNOD(J) ; Get the node name MOVEM S1,FAL.PR+.OBNDN(T1) ; Store the node name ; Make a status string which says what's happening: MOVEI S1,FAL.ST(T1) ; Point at the string storage HRLI S1,(POINT 7,) ; Make it an ASCII byte pointer MOVEM S1,TEXTBP ; Store for the following $TEXT call MOVEI S1,<*5>-1 ;[21] Get the max string length MOVEM S1,TEXTCT ;[21] Store as max byte count MOVE T2,J$SACC(J) ; Get the file access type $TEXT (DEPBP,<^T/@CHKFNC(T2)/ ^F/J$STFD(J)/ for user ^T/J$SUSR(J)/^0>) HRRZ S1,TEXTBP ; Get the ending byte pointer SUBI S1,MSGBLK-1 ; Compute the number of words filled CHKP.1: STORE S1,.MSTYP(T1),MS.CNT ; Store the length of the message MOVX S1,.QOFAS ; Get the function code STORE S1,.MSTYP(T1),MS.TYP ; Store it PUSHJ P,SNDQSR ; Go send this to QUASAR PUSHJ P,I%NOW ; Get the current time and date MOVEM S1,J$LCHK(J) ; Store as last checkpoint time $RETT ; And return happy PJRST SNDQSR ; Send it and return ; Helper routine for storing $TEXT strings DEPBP: SOSL TEXTCT ;[21] Skip if no more room IDPB S1,TEXTBP ; Store the byte $RETT ; And return Subttl QUASAR Service Routines -- KILL - Abort a Connection ; Here to abort processing on a connection. This routine is called ; by an operator command to tell a FAL stream to stop whatever it's doing. ; If it isn't doing anything, there's nothing to stop ... ; Calling sequence: ; S/ current stream status word ; PUSHJ P,KILL ; Kill it off ; returns true always ; Destroys no registers KILL: TXNN S,S.OPEN ; Do we really have something going? $RETT ; No, just punt it off TXO S,S.KILL ; Yes, say we want to kill it MOVE S1,STREAM ; Get the current stream number $WTOJ (Abort,,@FALOBA(S1)) $RETT ; Return Subttl QUASAR Service Routines -- SETUP - Handle Stream Setup ; Here when we receive a setup stream message from QUASAR. Decide ; whether it's a setup or shutdown, and dispatch to the appropriate ; processor. If this is a setup, we will start and enter a stream context ; to perform the remainder of this call. This will cause the stream context ; to be started. ; Calling sequence: ; PUSHJ P,SETUP ; Go handle SETUP/SHUTDOWN message ; returns here, no particular status ; Destroys all registers SETUP: LOAD S1,SUP.FL(M) ; Get the flags TXNE S1,SUFSHT ; Is this really a shudown? JRST SHUTDN ; Yes, go to the other processor SETZ T2, ; Initialize a loop counter SETU.1: SKIPN FALPAG(T2) ; Do we have a free stream here? JRST SETU.2 ; Yes, go use it CAIGE T1,NFAL-1 ; No, have we tried them all? AOJA T2,SETU.1 ; No, go try another one then STOPCD (TMS,HALT,,Too many setups) ; Yes, die ; Here if we have an idle stream: SETU.2: MOVEM T2,STREAM ; Store as the current stream number MOVEI S1,_- ; Get the number of pages needed PUSHJ P,M%AQNP ; Go allocate some pages JUMPF [STOPCD (NEM,HALT,,Not enough memory to start stream)] LSH S1,WID(PAGSIZ-1) ; Convert page number to address MOVEM S1,FALPAG(T2) ; Save the stream storage pointer MOVE J,S1 ; Copy the pointer to the traditional place MOVEI S1,.WILDL## ; * Hack * Get the number of words required for WILD PUSHJ P,.MMGWD ; * Hack * Go allocate it STOPCD (CWD,HALT,,Cannot Allocate WILD data storage) MOVEM S2,J$SWLD(J) ; * Hack * Store the memory pointer SETZM FALSTW(T2) ; No reason why we can't run yet ... MOVEM J,J$RACS+J(J) ; Save the storage address pointer MOVE S2,T2 ; Copy the stream number IMULI T2,OBJ.SZ ; Get the offset of an object block ADDI T2,FALOBJ ; Add in the table base MOVEM T2,FALOBA(S2) ; Store the object block address MOVE S1,T2 ; Get a BLT destination pointer HRLI S1,SUP.TY(M) ; Get the BLT source pointer BLT S1,OBJ.SZ-1(T2) ; Copy the object block MOVE S1,OBJ.ND(T2) ;[26] Get the processing node SKIPE S2,.MYNNM## ;[56] ANF support? CAMN S1,S2 ;[56] If so, is it the local node? TRNA ;[56] No ANF support or local node JRST [MOVX S1,$FSNRM ;[26] Not local node - error PJRST RSETUP] ;[26] Inform QUASAR and quit SETOM FALCHN(S2) ; Say no channel number assigned yet MOVX S1,%RSUOK ; Get the startup code PUSHJ P,RSETUP ; Reply to the setup message MOVE S2,STREAM ; Get the stream number back $WTO (,,@FALOBA(S2)) ; Say we've started ok SETOM FALACT(S2) ; Make the stream active SETZM FALCHK(S2) ; Force a checkpoint/status update MOVE S1,SUP.CN(M) ; Get the fake conditioning data MOVE S1,[EXP IO.DCN,IO.ANF,IO.DCN](S1) ; Convert to our own flavor of expression MOVEM S1,J$FTYP(J) ; Store as the network type MOVEI S1,J$RPDL-1(J) ; Point at the beginning of the stack HRLI S1,-PDSIZE ; Setup the stack length PUSH S1,[EXP FALEND] ; Last thing to call is final shutdown PUSH S1,[EXP FALL##] ; Store the start address MOVEM S1,J$RACS+P(J) ; Save the initial stack pointer MOVX S,S.RUN ; Get the running bit SETZM FALBTS ; Say we want to update the status POPJ P, ; And return to the scheduler Subttl QUASAR Service Routines -- SHUTDN - Shutdown Processing on a Stream ; SHUTDN will shut down processing on a stream. This routine will just ; set a flag to the effect that we're supposed to drop everything, and assume ; that everyone else down the line will take care of things appropriately. ; Calling sequence: ; S/ current stream status word ; PUSHJ P,SHUTDN ; Shut the stream down ; returns true always ; Destroys S1, S2, T1-T4, modifies S SHUTDN: SETOM FALBTS ;[24] Assume we don't want to update bits MOVEI S1,SUP.TY(M) ; Get the object block address PUSHJ P,FNDOBJ ; Find the matching stream JUMPF .RETT ; Return if no such stream SHUTIN::TXO S,S.SHUT ; Mark this stream for shutdown SETZM FALBTS ; Say we want the status stored MOVE S2,STREAM ; Get the stream number MOVX S1,PSF%CW ; If we're in connect wait ANDCAM S1,FALSTW(S2) ; we're not anymore SETZM FALCHK(S2) ; Make sure we send a status update $RETT ; Return happily Subttl QUASAR Service Routines -- FALEND - Process FAL Stream Termination ; We come here when a FAL stream has shut down. This routine will ; output the appropriate error message if the stream aborted due to ; unnatural causes, and in any case, clse the stream down. This mostly ; consists of deallocating any per stream data that may be lying about. ; Calling sequence: ; (not formally called, other than being POPJed to by FALL) ; S1/ shutdown/abort reason code FALEND: MOVE P,[IOWD PDSIZE,PDL] ; Reset the stack pointer to scheduler context MOVE T2,S1 ; Copy the abort/shutdown reason MOVE P1,STREAM ; Get the stream number SETOM FALBTS ; Say no status update needed SKIPE T2 ; Abort reason given? $WTO (<^T/@SETMSG(T2)/>,,@FALOBA(P1)) ; Yes, complain SETZM FALACT(P1) ; Say the stream isn't active MOVE S2,FALOBA(P1) ; Get the object block address MOVE T1,S2 ; Make another copy of this SETZM (S2) ; Clear the first word HRL S2,S2 ; Make a BLT pointer ADDI S2,1 ; (Point at obj+1) BLT S2,OBJ.SZ-1(T1) ; Clear the object block SKIPN J,FALPAG(P1) ; Get any per stream storage pointer JRST MAIN.4 ; Nothing. Don't try to deallocate MOVX S1,.WILDL## ; * Hack * Get the size of the WILD data SKIPE S2,J$SWLD(J) ; * Hack * Get the pointer to it PUSHJ P,.MMFWD ; * Hack * Release the memory JFCL ; * Hack * Punt any error here SETZM J$SWLD(J) ; * Hack * No more WILD data SETZM FALPAG(P1) ; Say no more stream pages MOVEI S1,<_-> ; Get the number of pages to release MOVE S2,J ; Copy the base address LSH S2,- ; Convert to a page number PUSHJ P,M%RLNP ; Release a few pages PUSHJ P,M%CLNC ; Get rid of unwanted pages JRST MAIN.4 ; And return to the scheduler Subttl FALSWI Service -- SETCHN - Inform the World about a New Channel ; Here when a FAL stream (running in FALSWI) opens a new network channel, ; usually just after a stream is started. This routine is called to inform the ; scheduler about the existance of this new channel, and to setup the interrupt ; system. ; Calling sequence: ; S1/ new channel number ; J/ pointer to per stream storage area ; S/ current stream flags word ; PUSHJ P,SETCHN ; Setup channel stuff ; returns non-skip if error in the PSI setup ; returns skip on success. ; Destroys S1, S2, T1 (SWIL's T1-T3) SETCHN::MOVE T1,STREAM ; Get the current stream number MOVE S2,J$FTYP(J) ; Get the stream type CAXN S2,IO.ANF ; Is it an ANF-10 channel? TXO S1,FC%ANF ; Yes, remember this for later MOVEM S1,FALCHN(T1) ; Store the channel number in our tables PUSHJ P,INTCON ; Connect this guy to the interrupt system POPJ P, ; That's bad, pass it on JRST .POPJ1 ; Ok, return happily Subttl IPCF Subroutines -- FNDOBJ - Find an Object Block in our Data Base ; here when we've received an IPCF message refering to some object. This ; routine will compare the object block given with those that we have tucked ; away in our stream tables, so that we can figure out which one of the streams ; this message is refering to. ; Calling sequence: ; S1/ pointer the the object block in question. ; PUSHJ P,FNDOBJ ; Match this object block against ours ; returns false if we don't have this guy ; returns true on success. J contains the stream data pointer, status in S. ; Destroys S2, T1-T4, J, S FNDOBJ: MOVE T1,.ROBTY(S1) ; Get the object type MOVE T2,.ROBAT(S1) ; Get the unit number MOVE T3,.ROBND(S1) ; Get the node number SETZ T4, ; And init our loop counter FNDO.1: MOVE S2,T4 ; Copy the stream number IMULI S2,OBJ.SZ ; Multiply by words per object block CAMN T1,FALOBJ+.ROBTY(S2) ; Is it the right object type? CAME T2,FALOBJ+.ROBAT(S2) ; Yes, is it also the right unit number? JRST FNDO.2 ; No, try the next one CAMN T3,FALOBJ+.ROBND(S2) ; Yes, is it the right node number? JRST FNDO.3 ; Yes, go do this one ; Here if this one doesn't match. Try the next one. FNDO.2: ADDI T4,1 ; Bump to the next stream number CAIL T4,NFAL ; HAve we done them all? $RETF ; Yes, return error JRST FNDO.1 ; No, try this one ; We got a match. Setup the stream data pointer and status, then return. FNDO.3: MOVEM T4,STREAM ; Store the stream number SKIPN J,FALPAG(T4) ; Get the stream data pointer $RETF ; Nothing? That's an error MOVE S,J$RACS+S(J) ; Get the stream's status word $RETT ; And return happy Subttl IPCF Subroutines -- RSETUP - Respond to a Setup Message ; here when processing is complete on a SETUP message from QUASAR ; This routine is called to send the IPCF response. ; Calling sequence: ; S1/ SETUP condition code ; PUSHJ P,RSETUP ; Respond to the SETUP ; returns true always ; Destroys S1, S2, T1-T2 RSETUP: MOVE T2,S1 ; Copy the setup condition code MOVX S1,RSU.SZ ; Get the message length MOVEI S2,MSGBLK ; And point to the message block PUSHJ P,.ZCHNK ; Clear the message block MOVEI T1,MSGBLK ; Point back at it MOVX S1,RSU.SZ ; Get the message size again STORE S1,.MSTYP(T1),MS.CNT ; Store the message size MOVX S1,.QORSU ; Get "Response to SETUP" code STORE S1,.MSTYP(T1),MS.TYP ; Store it MOVE S1,STREAM ; Get the stream number MOVS S1,FALOBA(S1) ; Get object addr,,0 HRRI S1,RSU.TY(T1) ; Get the place to move it to BLT S1,RSU.TY+OBJ.SZ-1(T1) ; And move the object block SKIPE S1,T2 ;[26] Setup ok? MOVX S1,%RSUDE ;[26] No, say the device doesn't exist STORE S1,RSU.CO(T1) ; Store the response code PUSHJ P,SNDQSR ; Send it off to QUASAR SKIPN S1,T2 ;[26] Copy the response code back $RETT ;[26] No errors, just return PJRST FALEND ;[26] Error, shut the stream Subttl IPCF Subroutines -- SNDQSR - Send a Message to Quasar ; Routine to send an IPCF message to QUASAR. ; Calling sequence: ; T1/ pointer to message to be sent ; PUSHJ P,SNDQSR ; Send the message ; returns here if success, crashes on failure ; Preserves P1-P4 SNDQSR: MOVX S1,SP.QSR ; Get the QUASAR flag TXO S1,SI.FLG ; Set the special index flag STORE S1,SAB+SAB.SI ; and store it SETZM SAB+SAB.PD ; Clear the PID word LOAD S1,.MSTYP(T1),MS.CNT ; Get the message length STORE S1,SAB+SAB.LN ; Save the message address STORE T1,SAB+SAB.MS ; Save the message address MOVEI S1,SAB.SZ ; Load the message size MOVEI S2,SAB ; And point at the message text PUSHJ P,C%SEND ; Send the message JUMPT QSRBAK ;[23] Make sure we know QUASAR's here ; PJRST QSRGON ;[23] Say QUASAR's gone away Subttl IPCF Subroutines -- QSRGON - Flag that QUASAR has Gone Away ; Here if we think QUASAR has gone away. This can be because we couldn't ; send to QUASAR, or that QUASAR is insisting that our streams shouldn't be ; here. Flag all the streams for possible shutdown. ; Calling sequence: ; PUSHJ P,QSRGON ; QUASAR has gone away ; returns true always ; Destroys S1, S2, T1-T2 QSRGON: SKIPE QSRDIE ;[23] Already been here? $RETT ;[23] Yes, just return now MOVSI T1,-NFAL ;[23] No, setup an AOBJN pointer MOVX S2,S.QSRD ;[23] Get the "QUASAR is DEAD" flag ; Loop here, flagging each stream as going away soon: QSRG01: SKIPE FALACT(T1) ;[23] Is this stream active? SKIPN S1,FALPAG(T1) ;[23] Yes, any memory assigned? JRST QSRG02 ;[23] No, skip this stream IORM S2,J$RACS+S(S1) ;[23] Yes, lite the QUASAR gone bit SKIPE S1,FALOBA(T1) ;[23] Any object block address? SETZM OBJ.TY(S1) ;[23] Yes, corrupt the object block QSRG02: AOBJN T1,QSRG01 ;[23] Loop for all possible streams TXO S,S.QSRD ;[23] Make sure we set it for ourselves SETOM QSRDIE ;[23] Flag for the world $RETT ;[23] And return sort of happy Subttl IPCF Subroutines -- QSRBAK - Flag QUASAR is Back ; Here when we either received or transmitted an IPCF message to QUASAR ; successfully. We'll see if we thought it was gone, and if so, flag all the ; old stale streams for shutdown. ; Calling sequence: ; QSRDIE/ non-zero if we thought QUASAR was dead ; PUSHJ P,QSRBAK ; Kill stale streams ; returns true always ; Destroys S1, S2, T1 QSRBAK: SKIPN QSRDIE ;[23] Did we think QUASAR's dead? $RETT ;[23] No, just return fdh SETZM QSRDIE ;[23] Yes. It ain't anymore $WTO (Reset,,DUMOBJ) $SAVE ;[23] Save a bunch of registers MOVSI P1,-NFAL ;[23] Setup an AOBJN pointer ; Loop here for each possible stream. Flag each broken one we find for ; shutdown at end of job. QSRD01: SKIPE FALACT(P1) ;[23] Is this stream active? SKIPN J,FALPAG(P1) ;[23] Maybe. Is there memory assigned? JRST QSRD02 ;[23] No, skip this one. MOVE S,J$RACS+S(J) ;[23] Yes, get the status bits HRRZM P1,STREAM ;[23] Store the stream number in a nice place PUSHJ P,SHUTIN ;[23] Go shut the stream down MOVEM S,J$RACS+S(J) ;[23] Put the new status back QSRD02: AOBJN P1,QSRD01 ;[23] Loop for all streams $RETT ;[23] And return happy Subttl PSI Routines -- INTINI - Initialize the PSI System ; Here on program startup to initialize the interrupt system. This simply ; consists of putting the interrupt routine address in the vector block ; for each condition. GLXLIB handles the rest. ; Calling sequence: ; PUSHJ P,INTINI ; Initialize the interrupt system ; returns here always, no particular status ; Destroys S1, T1-T3 INTINI: MOVEI S1,IPCINT ; Get the address of the IPCF interrupt routine MOVEM S1,IPCVEC+.PSVNP ; Store in the vector block MOVEI S1,DECINT ; Get the DECnet interrupt vector MOVEM S1,DECVEC+.PSVNP ; Store it ; Setup the ANF-10 interrupt vector blocks: SETZ T1, ; Init the index/loop counter INTI.1: MOVEI S1,INTANF(T1) ; Get the service routine address MOVEM S1,ANFVEC+.PSVNP(T1) ; Store in the interrupt block ADDI T1,ANHDSZ ; Bump the pointer CAIGE T1,ANHDSZ*NANF10 ; Done all of them? JRST INTI.1 ; No, do another one ; Setup the disk interrupt vector blocks: SETZ T1, ; Init the index again INTI.2: MOVEI S1,INTDSK(T1) ; Get the service routine address MOVEM S1,DSKVEC+.PSVNP(T1) ; Store in the interrupt block ADDI T1,DSHDSZ ; Bump the pointer CAIGE T1,DSHDSZ*NFAL ; Done them all? JRST INTI.2 ; No, go do another one MOVX S1,PS.FAC!T1 ; Setup function and arg block pointer MOVX T1,.PCNSP ; Set interrupts for NSP. MOVSI T2,DECVEC-PSIVEC ; Get the PSI block offset SETZ T3, ; No priority PISYS. S1, ; Turn the condition on/off $RETF ; Error, punt $RETT ; Ok, return happy POPJ P, ; And return Subttl PSI Routines -- INDCON - Connect a Disk Channel to the Interrupt System ; Here from FALSWI when we've opened a new channel to disk. This ; routine is called to connect that stream to the interrupt system. ; Calling sequence: ; S1/ channel number ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INDCON ; Connect us to the interrupt system ; returns non-skip if errors ; returns skip if success ; Destroys S1, S2 (SWIL's T1 and T2) INDCON::$SAVE ; Save some temporaries MOVE S2,STREAM ; Get the stream number MOVEM S1,FALDSK(S2) ; Store the disk channel number IMULI S2,.PSLEN ; Make an offset into the interrupt blocks ADDI S2,DSKVEC-PSIVEC ; Add in the base PSI offset HRLZS S2 ; Put the offset in the left half TXO S2,PS.RID!PS.ROD!PS.RDO!PS.ROL ; Get the interrupt enables IFN , SETZ T1, ; No priority (as if it matters) MOVX T2,PS.FAC!S1 ; Say we want to add a condition PISYS. T2, ; Tell the system about it POPJ P, ; Error, just punt TXO S,S.PSID ; Ok. Say we were here JRST .POPJ1## ; And return happy Subttl PSI Routines -- INDDIS - Disconnect a Disk Channel from the Interrupt System ; Here from FALSWI when we're about to close a disk channel. This ; routine will remove the channel from the interrupt system. ; Calling sequence: ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INDDIS ; Disconnect us from the interrupt system ; returns here if error (not likely) ; returns skip if success ; Destroys S1 and S2 (SWIL's T1 and T2) INDDIS::$SAVE ; Save some registers MOVE S2,STREAM ; Get the stream number SETO S1, ; Get a null channel number EXCH S1,FALDSK(S2) ; Get rid of our knowledge of this TXZE S,S.PSID ; Were we enabled for PSI? SKIPGE S1 ; Yes, was there a channel number? JRST INDD.1 ;[17] No, skip this IMULI S2,.PSLEN ; Multiply stream number by PSI block size ADDI S2,DSKVEC-PSIVEC ; Add in the base PSI vector offset HRLZS S2 ; Put it in the left half TXO S2,PS.RID!PS.ROD!PS.RDO!PS.ROL ; Get what we were enabled for SETZ T1, ; No priority MOVX T2,PS.FRC!S1 ; Point at the arg block PISYS. T2, ; Remove us from interruptions JFCL ; Don't worry about errors here INDD.1: MOVX S1,PSF%DI!PSF%DO!PSF%DF ;[17] Get the valid blocking reasons MOVE S2,STREAM ;[17] Get the stream number back ANDCAM S1,FALSTW(S2) ;[17] Clear any block from disk ANDCAM S1,FALWAK(S2) ;[17] And clear any bogus pending wake JRST .POPJ1## ; Just return happy Subttl PSI Routines -- INTCON - Connect a Stream to the Interrupt System ; Here from FALSWI when we've opened a new stream. This routine is ; called to connect that stream to the interrupt system. ; Calling sequence: ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INTCON ; Connect us to the interrupt system ; returns non-skip if errors ; returns skip if success ; Destroys S1, S2 (SWIL's T1 and T2) INTCON: $SAVE ; Save some temporaries TXNE S,S.PSIN ; Are we already enabled? JRST .POPJ1 ; Yes, just return happy MOVE S1,STREAM ; No, get the stream number MOVX S2,PSF%NI!PSF%NO!PSF%CW ;[17] Get all the reasons we may be blocked ANDCAM S2,FALSTW(S1) ;[17] Make sure we aren't blocked from these ANDCAM S2,FALWAK(S1) ;[17] and that we're not going to unblock MOVE S2,FALCHN(S1) ; Get the channel number TXNN S2,FC%ANF ; Is this an ANF-10 channel? JRST INTC.1 ; No, try DECnet PUSHJ P,INTCNA ; Yes, call the appropriate processor JRST INTC.2 ; Continue below INTC.1: PUSHJ P,INTCND ; Connect to the DECnet interrupt system INTC.2: JUMPF .POPJ ; Give error return if we failed TXO S,S.PSIN ; Ok, say we're turned on JRST .POPJ1 ; And return happy Subttl PSI Routines -- INTDIS - Disconnect a Stream from the Interrupt System ; Here from FALSWI to disconnect a network channel from the interrupt ; system. ; Calling sequence: ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INTDIS ; Disconnect from the interrupt system ; never gives error return ; returns skip always ; Destroys S1 and S2 (SWIL's T1 and T2) INTDIS::$SAVE ; Save some termporaries TXNN S,S.PSIN ; Are we enabled? JRST INTD.2 ; No. Not much to do then. MOVE S1,STREAM ; Get the stream number MOVE S2,FALCHN(S1) ; Get the channel number TXNN S2,FC%ANF ; Is this an ANF-10 channel? JRST INTD.1 ; No, go do DECnet PUSHJ P,INTDNA ; Yes, call the appropriate handler JRST INTD.2 ; Continue below INTD.1: PUSHJ P,INTDND ; Disconnect from DECnet interrupts INTD.2: TXZ S,S.PSIN ; Say we aren't enabled anymore MOVE S2,STREAM ; Get the stream number back SETZM FALCHN(S2) ; Clear to avoid interrupt confusion MOVX S1,PSF%NI!PSF%NO!PSF%CW ;[17] Get all the reasons we may be blocked ANDCAM S1,FALSTW(S2) ;[17] Make sure we aren't blocked from these ANDCAM S1,FALWAK(S2) ;[17] and that we're not going to unblock JRST .POPJ1## ; And return Subttl PSI Routines -- INTCNA, INTDNA - Connect an ANF-10 Channel to the Interrupt System ; Here to add or remove a channel from the interrupt system. ; Calling sequence: ; J/ pointer to the stream context data ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INTCNA ; Connect the ANF channel to an interrupt ; or ; PUSHJ P,INTDNA ; Remove the ANF channel from the interrupt system ; returns false if errors ; returns true on success ; Destroys S1, S2, T1-T3 INTCNA: SKIPA S1,[PS.FAC+T1] ; Say we want to add a condition ; Special entry to remove the channel from the interrupt system INTDNA: MOVX S1,PS.FRC!T1 ; Say we want to remove the condition MOVE T2,STREAM ; Get the current stream number MOVE T1,FALCHN(T2) ; Get the channel number TXNN T1,FC%ANF ; Is this really an ANF-10 channel? STOPCD (CDA,HALT,,Tried to connect DECnet channel to ANF-10 interrupt system) TLZ T1,-1 ; Get rid of junk. IMULI T2,.PSLEN ; Multiply buy the PSI block length ADDI T2,ANFVEC-PSIVEC ; Add in the block offset HRLZS T2 ; Make it offset,,0 HRRI T2,PS.RID!PS.ROD!PS.REF!PS.RDO!PS.ROL ; Get enable bits SETZ T3, ; No particular priority PISYS. S1, ; Add/remove the condition $RETF ; Error, punt $RETT ; Ok, return happy Subttl PSI Routines -- INTCND - Connect a DECnet Channel to the Interrupt System ; Here when we open a new DECnet channel. This routine will connect ; that channel to the interrupt system. ; Calling sequence: ; J/ pointer to stream context data ; S/ current stream status ; STREAM/ current stream number ; PUSHJ P,INTCND ; Connect the channel to the DECnet interrupts ; returns false if error ; returns true on success ; Destroys S1, T1-T3 INTCND: TXNE S,S.PSIN ; Are interrupts already enabled? $RETT ; Yes, just punt this HRRZI T3,-1 ; Enable interrupts on all events JRST INCD.1 ; Continue in common code below ; Here if we want to disconnect: INTDND: TXNN S,S.PSIN ; Were we enabled? $RETT ; No, nothing to do here then SETZ T3, ; Yes, disable everything INCD.1: MOVE T1,[.NSFPI,,3] ; Get the function set set reason mask HRRZ T2,STREAM ; Get the stream number MOVE T2,FALCHN(T2) ; Get the DECnet channel number TXNE T2,FC%ANF ; Is this really an ANF-10 channel? STOPCD (CAD,HALT,,Tried to connect ANF channel to DECnet interrupt system) TLZ T2,-1 ; In any case, get rid of flags MOVEI S1,T1 ; Point at the argument block NSP. S1, ; Tell the system about it $RETF ; Error, punt $RETT ; And return happy Subttl PSI Routines -- ANFINT - ANF-10 Interrupt Service ; Here when ANF-10 I/O is complete or when the link status changes. ; This routine will determine the class of event and unblock the appropriate ; stream according to the event found. Note that most link failure interrupts ; will simply unblock the top level if it is waiting for I/O to complete, on ; the assumption that we'll get an error as soon as we try anything, and will ; therefore notice the event for ourselves. ; Calling sequence: ; (none - this is an interrupt service routine) ; All registers are preserved INTANF: ; Label for start of the headers ZZ==0 ; Init the kludge counter REPEAT NANF10, ANFINT: MOVE J,FALPAG(S1) ; Get the per stream storage pointer HRRZ T1,.PSVFL(S2) ; Get the interrupt reason flags ANDCAM T1,.PSVFL(S2) ; Clear them SETZ T2, ; Init our wake conditions TXNE T1,PS.ROL ; Did we just get a connect initiate? TXO T2,PSF%CW ; Yes, not in connect wait any longer TXNE T1,PS.RID ; Input done? TXO T2,PSF%NI ; Yes, unblock if that's what we're waiting for TXNE T1,PS.ROD ; Output done? TXO T2,PSF%NO ; Yes, clear the condition TXNE T1,PS.RDO!PS.REF ; Connection drop or eof? TXO T2,PSF%NO!PSF%NI!PSF%CW ; Yes, unblock whatever we're doing ANDCAM T2,FALSTW(S1) ; Clear any blocked bits IORM T2,FALWAK(S1) ; And set wake bits to prevent race in DSCHD $DEBRK ; And return from the interrupt Subttl PSI Routines -- DECINT - DECnet Interrupt Service ; Here when DECnet I/O is complete or when the link status changes. ; This routine will determine the class of event and unblock the appropriate ; stream according to the event found. Note that most link failure interrupts ; will simply unblock the top level if it is waiting for I/O to complete, on ; the assumption that we'll get an error as soon as we try anything, and will ; therefore notice the event for ourselves. ; Calling sequence: ; (none - this is an interrupt service routine) ; All registers are preserved DECINT: $BGINT 1 ; Normal isr entry stuff HRRZ S1,DECVEC+.PSVIS ; Get the interrupting channel number MOVSI S2,-NFAL ; Setup an AOBJN counter to find the stream ; Loop here to find the stream number corresponding to this channel number: DECI.1: SKIPN FALACT(S2) ; Is this stream active? JRST DECI.2 ; No, skip it then MOVE T1,FALCHN(S2) ; Yes, get the channel number TXNE T1,FC%ANF ; Is this an ANF channel number? JRST DECI.2 ; Yes, skip it CAIN S1,(T1) ; No, is it the one we're looking for? JRST DECI.3 ; Yes, go play with it then DECI.2: AOBJN S2,DECI.1 ; Loop if more streams to look at ; here if we got an interrupt from a channel that we don't have any matching ; stream for. This really shouldn't happen. I dunno, do sumthin' HRRZ T2,S1 ; Copy the channel number MOVEI S1,T1 ; Point at a temp argument block MOVX T1,.NSFPI ; Say we want to set an interrupt mask SETZ T3, ; Don't allow interrupts on this channel NSP. S1, ; Tell the system about it JFCL ; Oh well, punt it $DEBRK ; Return ; Here with the winning stream number in the right half of S2: DECI.3: HLLZ S1,DECVEC+.PSVIS ; Get the channel status SETZ T1, ; Init our reasons for waking TXNE S1,NS.IDA!NS.IDR!NS.NDA!NS.NDR ; Anything we recognize? JRST DECI.4 ; Yes, go unblock the right thing CAMN S1,[.NSSCW,,0] ; No, are we just in connect wait? JRST DECI.5 ; Yes, just exit the interrupt now TXO T1,PSF%NI!PSF%NO!PSF%CW ; No. Just unblock and hope the top ; level can figure out the link state ; change DECI.4: TXNE S1,NS.NDA ; Input data available? TXO T1,PSF%NI ; Yes, unblock if waiting for input TXNE S1,NS.NDR ; Can we do output now? TXO T1,PSF%NO ; Yes, unblock if waiting for output ANDCAM T1,FALSTW(S2) ; Clear the appropriate blocks IORM T1,FALWAK(S2) ; And set wake bits (prevent DSCHD racee) DECI.5: $DEBRK ; And return from this interrupt Subttl PSI Routines -- DSKINT - Disk Interrupt Service ; Here when disk I/O is complete or when the link status changes. ; This routine will determine the class of event and unblock the appropriate ; stream according to the event found. If we see the disk go offline, we'll ; block the stream until it comes back online. Sometime, we should queue ; a message to the operator saying that this is happening. ; Calling sequence: ; (none - this is an interrupt service routine) ; All registers are preserved INTDSK: ; Label for start of the headers ZZ==0 ; Init the kludge counter REPEAT NFAL, DSKINT: MOVE J,FALPAG(S1) ; Get the per stream storage pointer HRRZ T1,.PSVFL(S2) ; Get the interrupt reason flags ANDCAM T1,.PSVFL(S2) ; Clear them SETZ T2, ; Init our mask of wake reasons ; TXNE T1,PS.RDO ; Did the disk just go offline? ; TXO T2,PSF%DF ; Yes, block the process TXNE T1,PS.ROL ; Did the disk just come back on line? TXO T2,PSF%DF ; Yes, unblock the task TXNE T1,PS.RID ; Input done? TXO T2,PSF%DI ; Yes, unblock if that's what we're waiting for TXNE T1,PS.ROD ; Output done? TXO T2,PSF%DO ; Yes, clear the condition ANDCAM T2,FALSTW(S1) ; Reset any blocking bits IORM T2,FALWAK(S1) ; And prevent race in DSCHD $DEBRK ; And return from the interrupt Subttl PSI Routines -- IPCINT - IPCF Message Available Interrupt Service Routine ; Here on an IPCF message available PSI interrupt. This handler will ; simply make the top level aware of the condition, and return from the ; interrupt. ; Calling sequence: ; (none, this is an interrupt service routine) ; All registers preserved IPCINT: $BGINT 1 ; Preserve registers, etc PUSHJ P,C%INTR ; Tell the top level about this $DEBRK ; And return from the interrupt Subttl SWIL Memory Manager -- .MMGWD - Get some Words of Memory ; This routine replaces the routine of the same name in SWIL. Since ; GLXLIB insists on being in charge of memory allocation, and since it ; does a better job than the default SWIL mechanism, we just intercept all ; calls to the default SWIL memory manager here, and forward them to the ; corresponding routine in GLXLIB. ; Calling sequence: ; S1/ number of words to allocate (SWIL's T1) ; PUSHJ P,.MMGWD ; Get a chunk of memory ; returns non-skip if allocation failure ; returns skip if success, pointer to block in S2 (SWIL's T2) ; Destroys S2 (SWIL's T2) .MMGWD::PUSHJ P,M%GMEM ; Call GLXLIB's memory manager ; (which works just the way we want ; it to). JUMPT .POPJ1 ; Take the good return if success POPJ P, ; Else take the non-skip return Subttl SWIL Memory Manager -- .MMFWD - Deallocate a Chunk of Memory ; This preforms the inverse of .MMGWD; that is it deallocates memory. ; Calling sequence: ; S1/ size of chunk to be deallocated (SWIL's T1) ; S2/ address of chunk to deallocate (SWIL's T2) ; PUSHJ P,.MMFWD ; Free some memory ; never returns non-skip ; returns skip when done ; Destroys no registers .MMFWD::PUSHJ P,TSAV12## ; Save the registers we'll use PUSHJ P,M%RMEM ; Go release the memory JRST .POPJ1 ; And return happily Subttl Operator Messages -- BEGJOB - Begin a FAL Job ; Here when a FAL stream has accepted a connection. This routine is ; called to notify the operator that we're talking to someone. ; Calling sequence: ; J/ pointer to the per stream storage ; STREAM/ current stream number ; J$SUSR/ username of accessing person ; J$SNOD/ node we're talking to ; PUSHJ P,BEGJOB ; Tell the operator ; returns non-skip always ; Destroys S1, S2 (SWIL's T1 and T2), updates J$RTIM BEGJOB::TXNE S,S.QSRD ;[23] Is QUASAR dead? POPJ P, ;[23] Yes, don't bother PUSHJ P,I%NOW ; Get the current time MOVEM S1,J$RTIM(J) ; Store for the checkpoints MOVE S1,STREAM ; Get the stream number MOVE S2,J$FTYP(J) ; Get the stream type CAXE S2,IO.ANF ; ANF-10 node? SKIPA S2,[[ASCIZ \DECnet\]] ; No, say it's DECnet MOVEI S2,[ASCIZ \ANF-10\] ; Yes, say so $WTOJ (Begin,,@FALOBA(S1)) POPJ P, ; Return Subttl Operator Messages -- ENDJOB - End a FAL Job ; Here when a FAL stream has closed a FAL session. This routine is ; called to notify the operator that we're done talking to someone. ; Calling sequence: ; J/ pointer to the per stream storage ; STREAM/ current stream number ; J$SUSR/ username of accessing person ; J$SNOD/ node we're talking to ; PUSHJ P,ENDJOB ; Tell the operator ; returns non-skip always ; Destroys S1, S2 (SWIL's T1 and T2) ENDJOB::TXNE S,S.QSRD ;[23] Is QUASAR dead? POPJ P, ;[23] Yes, don't bother MOVE S1,STREAM ; Get the stream number SETZM FALCHK(S1) ; Say we want the status updated MOVE S2,J$FTYP(J) ; Get the stream type CAXE S2,IO.ANF ; ANF-10 node? SKIPA S2,[[ASCIZ \DECnet\]] ; No, say it's DECnet MOVEI S2,[ASCIZ \ANF-10\] ; Yes, say so $WTOJ (End,,@FALOBA(S1)) POPJ P, ; Return Subttl DAP Status messages -- DAPERR -- Processor ; This routine is called by the BADDAP macro to type an error message and ; send a DAP status message to the remote task to inform it of the error. ; Calling sequence: ; STREAM/ current stream number ; J/ per stream storage pointer ; PUSHJ P,@[EXP DAPERR ; Call the error processor ; EXP MAC!MIC ; DAP status ; EXP [ASCIZ ~TXT~] ; Error text ; EXP DIE] ; Address to resume from ; returns to DIE (defaults to call+1) ; Destroys no registers IO==11 ; I/O CDB Address DAPERR::$SAVE ; Save some registers MOVE P1,-11(P) ; Get the return address HRRZ P1,-1(P1) ; Get the argument block address MOVE S1,1(P1) ; Get the DAP status LDB S2,[POINT 6,1(P1),23] ; Get the MACCODE by itself CAIE S2,MA.SYN ; MACCODE indicate DAP msg out of sync? JRST DAPE.0 ; No, full is in S1 HRRZ S2,.IODIM(IO) ; Yes, get the MICCODE (i.e. msg type) DPB S2,[POINT 12,S1,35] ; Now is in S1 DAPE.0: CLEAR S2, ; No secondary status PUSHJ P,FXSTS0## ; Send the status to the remote JFCL ; Do not care here if link is gone TXNE S,S.QSRD ; Is QUASAR dead? JRST DAPE.1 ; Yes, don't bother MOVE S1,[POINT 7,J$SMSG(J)] ; Point at the message buffer MOVEM S1,TEXTBP ; Can use this as the pointer storage MOVEI S1,<100*5>-1 ; Get the max string length MOVEM S1,TEXTCT ; Store for DEPBP MOVEI S1,DEPBP ; Get the address of the byte stuffer PUSHJ P,.TYOCH## ; Swap SWIL's output routine PUSH P,S1 ; Save the old one HRRZ S1,2(P1) ; Get the text string PUSHJ P,.TSTRG## ; Copy to our storage SETZ S1, ; Then, null terminate IDPB S1,TEXTBP ; the error string MOVE T1,STREAM ; Get our stream number LDB T3,[POINT 6,1(P1),23] ; Get the MACCODE $WTOJ (<^T/@MACFLD(T3)/>,<^T/J$SMSG(J)/>,@FALOBA(T1)) ; Send the error off POP P,S1 ; Restore SWIL's old output routine PUSHJ P,.TYOCH## ; Put it back DAPE.1: MOVEI S1,@3(P1) ; Get the return address MOVEM S1,-11(P) ; Set it as our return POPJ P, ; Restore our ACs and return MACFLD: [ASCIZ ~Pending~] [ASCIZ ~Successful~] [ASCIZ ~Unsupported~] [ASCIZ ~Reserved~] [ASCIZ ~File Open~] [ASCIZ ~Transfer Error~] [ASCIZ ~Transfer Warning~] [ASCIZ ~Access Termination~] [ASCIZ ~Format~] [ASCIZ ~Invalid~] [ASCIZ ~Sync~] Subttl Operator Messages -- ERRMSG - STOPCD/ERROR/WARN/INFRM Processor ; Here from FALSWI on execution of a STOPCD, ERROR, WARN or INFRM ; macro. This routine is called by those macros to type an error message. ; In this case, typing an error message means sending a WTO to ORION so ; that everyone running OPR can see it. ; Calling sequence: ; STREAM/ current stream number ; J/ per stream storage pointer ; PUSHJ P,@[Z ERRMSG ; Call the error processor ; XWD type,[ASCIZ ~TXT~] ; Message type and error text ; Z RTN ; Additional output routine ; Z ADR ; Additional data for output routine ; Z DIE] ; Address to resume from ; returns to DIE (defaults to call+1) ; Destroys no registers ERRMSG::$SAVE ; Save some registers TXNE S,S.QSRD ;[23] Is QUASAR dead? JRST ERRM.3 ;[23] Yes, don't bother MOVE T4,-10(P) ; Get the return address HRRZ T4,-1(T4) ; Get the argument block address MOVE S1,[POINT 7,J$SMSG(J)] ; Point at the message buffer MOVEM S1,TEXTBP ; Can use this (I hope) as the pointer storage MOVEI S1,<100*5>-1 ;[21] Get the max string length MOVEM S1,TEXTCT ;[21] Store for DEPBP MOVEI S1,DEPBP ; Get the address of the byte stuffer PUSHJ P,.TYOCH## ; Swap SWIL's output routine PUSH P,S1 ; Save the old one HLRZ T3,1(T4) ; Get the message type SKIPL T3 ; Out of range? CAILE T3,.ETMAX ; ... JRST ERRM.2 ; Yes, just punt the WTO CAIE T3,.ETREJ ; Is this a rejection message? JRST ERRM.0 ; No, skip this mess MOVE S1,STREAM ; Get the stream number MOVE S2,J$FTYP(J) ; Get the stream type CAXE S2,IO.ANF ; ANF-10 node? SKIPA S2,[[ASCIZ \DECnet\]] ; No, say it's DECnet MOVEI S2,[ASCIZ \ANF-10\] ; Yes, say so $TEXT (DEPBP,) ERRM.0: HRRZ S1,1(T4) ; Get the text string PUSHJ P,.TSTRG## ; Copy to our storage SKIPN S2,2(T4) ; Did he request a routine? JRST ERRM.1 ; No, don't even bother SKIPE S1,3(T4) ; Did he give an address MOVE S1,@S1 ; Yes, load the data PUSHJ P,@S2 ; Call the processor ERRM.1: SETZ S1, ; Then, null terminate IDPB S1,TEXTBP ; the error string MOVE T1,STREAM ; Get our stream number $WTOJ (<^T/@MSGPFX(T3)/>,<^T/J$SMSG(J)/>,@FALOBA(T1)) ; Send the error off ERRM.2: POP P,S1 ; Restore SWIL's old output routine PUSHJ P,.TYOCH## ; Put it back ERRM.3: MOVEI S1,@4(T4) ; Get the return address MOVEM S1,-10(P) ; Set it as our return POPJ P, ; Restore our ACs and return ; A table of message types: MSGPFX: [ASCIZ ~Information~] [ASCIZ ~Begin~] [ASCIZ ~End~] [ASCIZ ~Connect rejected~] [ASCIZ ~Warning~] [ASCIZ ~Error~] [ASCIZ ~Stream abort~] [ASCIZ ~Received DAP protocol error~] ;[21] IFN FTDEBUG,[ASCIZ ~Diagnostic warning~] ;[21] Subttl Operator Messages -- FRCCHK - Force a Checkpoint ; Here when we've opened a new file to disk. This routine is called ; to force a checkpoint on this stream. ; Calling sequence: ; STREAM/ current stream number ; PUSHJ P,FRCCHK ; Force a checkpoint ; returns non-skip always ; Destroys no registers FRCCHK::$SAVE ; Save a couple of registers PUSHJ P,I%NOW ; Get the current date and time MOVE S2,J$LCHK(J) ; Get the last checkpoint time ADDI S2,CHKMIN*3 ; Compute minimum checkpoint interval CAMGE S1,S2 ; Have we passed that time yet? MOVE S1,S2 ; Now, force the minimum interval MOVE S2,STREAM ; Get the stream number MOVEM S1,FALCHK(S2) ; Store the new checkpoint time POPJ P, ; And return Subttl Operator Messages -- NETERR - Report a Network Lossage Error ; Here if FAL decides that the network has gone away, which is the ; usual reason for one of the SWIL routines to take the error return. ; This routine will redirect the SWIL output routines to our cannonical ; string in memory, call the SWIL error routine to decode the error ; string, then WTO the message to OPR. ; Calling sequence: ; TF(M0)/ SWIL funny error number ; P3(IO)/ SWIL funny CDB pointer for SWIERM ; PUSHJ P,NETERI ; Network input error ; or ; PUSHJ P,NETERO ; Network output error ; returns non-skip always (what's the point of an error return here?) ; Destroys TF, S1, S2, T1, T2 (SWIL's M0, T1-T4) NETERI::SKIPA T1,[.ERISR##] ; Save the input error routine addr NETERO::XMOVEI T1,.EROSR## ; Get the output error routine addr TXNE S,S.QSRD ;[23] Is QUASAR dead? POPJ P, ;[23] Yes, don't bother MOVE S1,[POINT 7,J$SMSG(J)] ; Get the string pointer MOVEM S1,TEXTBP ; Store in the proper place MOVEI S1,<<100*5>-1> ; Get the max string length MOVEM S1,TEXTCT ; Store for the char putter MOVEI S1,DEPBP ; Get the address of the char putter PUSHJ P,.TYOCH## ; Go reset the output routine address PUSH P,S1 ; Save the old routine address MOVE S1,P3 ; Copy the CDB pointer PUSHJ P,(T1) ; Go call the processor SETZ S1, ; Get a null IDPB S1,TEXTBP ; Terminate the string MOVE T1,STREAM ; Get the stream number $WTOJ (Error,<^T/J$SMSG(J)/>,@FALOBA(T1)) ; Send the error POP P,S1 ; Restore the old output routine addr PUSHJ P,.TYOCH## ; Go restore it POPJ P, ; And return Subttl Operator Messages -- .STOPCD - Abort a Stream ; Here when a stream decides that the best thing to do is to stop ; running. This will just type a message to the operator and mark the ; stream as having crashed. ; PUSHJ P,.STOPCD ; Go away ; never returns .STOPCD::MOVE T1,STREAM ; Get our stream number TXNN S,S.QSRD ;[23] Is QUASAR dead? $WTOJ (,,@FALOBA(T1)) SETZM FALCHK(T1) ; Say we want the status updated MOVX TF,PSF%CR ; Say we've crashed PUSHJ P,DSCHD ; Deschedule this task JRST .-2 ; In the unlikely event that it returns Subttl Dummy SWIL Routines -- .ASKYN, .ASKNY ; A couple of dummy entries to satisfy some SWIL externals. These ; will always give the non-skip (error return). .ASKNY:: ; Ask Yes or No .ASKYN:: ; Ask No or Yes .DFLND:: ; Ask for userid, password, etc. ONERCK:: ; /OKERR checker POPJ P, ; Error return ; Some randy error messages: ERRCDI::STOPCD (CDI,HALT,,Can't initialize input CDB) ERRCDO::STOPCD (CDO,HALT,,Can't initialize output CDB) Subttl End of FALQSR PRGEND TITLE FAL NFT File Access Listener module SUBTTL Robert Houk/RDH SEARCH JOBDAT,MACTEN,UUOSYM ;STANDARD DEFINITIONS SEARCH FALUNV ;FAL DEFINITIONS SEARCH SWIL ;SWIL PACKAGE DEFINITIONS SEARCH ACTSYM ;GET SOME ACTDAE INTERFACE SYMBOLS SALL ;PRETTY LISTINGS .DIREC FLBLST ;PRETTIER LISTINGS .TEXT \REL:SWIL/S/EXCLUDE:.POPJ/INCLUDE:.ERROR/SEGMENT:LOW,REL:GLXLIB/SUPPRESS:(.SAVE1,.SAVE2,.SAVE3,.SAVE4)/S/INCLUDE:GLXINI\ COMMENT \ FAL -- NFT "File Access Listener" module COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1985,1986,1988,1990. ALL RIGHTS RESERVED. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF TIS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. \ SUBTTL Definitions -- Accumulator Usage ; Define our accumulator usage here: M0==0 ;RETURNED STATUS T1==1 ;TEMPORARIES T2==2 T3==3 T4==4 P1==5 ;PRESERVED P2==6 P3==7 P4==10 NM==7 ;SWIL'S PLACE TO PUT A NUMBER CH==10 ;SWIL'S PLACE TO PUT A CHARACTER IO==11 ;CURRENT CDB ID==12 CI==13 ;INPUT CDB CO==14 ;OUTPUT CDB J==15 ;PER STREAM DATA STORAGE POINTER S==16 ;STATUS FLAGS WORD P==17 ;STACK POINTER ;NONPP - Routine to check for and disallow NETPPN access NONPP1: MOVE M0,.IOPPN(CI) ;GET ACCESSING PPN CAME M0,NETPPN ;IS IT NETPPN? JRST .POPJ1## ;NO, NO PROBLEM MOVEI M0,$EFPRT ;YES, DISALLOW WITH A "PRIVILEGE VIOLATION" POPJ P, ;AND TELL CALLER TO FLICK THIS REQUEST IN SUBTTL FAL initialization -- FALINI set FAL job parameters ;FALINI -- INITIALIZE FAL JOB RUNTIME PARAMETERS ;Call is: ; ; PUSHJ P,FALINI ; error return ; normal return ; ;FALINI sets up FAL's runtime job parameters so that FAL stands a chance ;of working: ; ; 1) Set program name to "FAL-10" 'cuz it looks purty ; ; 2) DSKFUL ERROR so that error codes returned to FAL rather ; than stopping the job and barfing on the "user" ; ; 3) LOCATE 0 so that batch/etc. submissions via QUEUE. UUO ; work right (else batch jobs end up on a DN87's "processor" ; queue! Amusing, but...) ; ; 4) SPOOL ALL so that randoms from remote places can't tie up ; real lineprinters or whatever. This is somewhat dubious, ; but since DAP doesn't give the user choice of real or ; spooled, this is the most "practical" choice . . . ; ;The error return is not exercised. ; ;Uses T1, T2. FALINI::SETZM BZFAL ;CLEAR OUT AND INITIALIZE IMPURE DATA MOVE T1,[BZFAL,,BZFAL+1] ;BLT POINTER TO BLT T1,EZFAL-1 ;CLEAN OUT DATA AREAS ;SET PROGRAM NAME TO "FAL-10" MOVE T2,['FAL-10'] ;TENTATIVE NAME SETNAM T2, ;DECLARE MORE MEANINGFUL PROGRAM NAME ;SET THE JOB'S MESSAGE WATCH BITS TO FIRST, NO PREFIX HRROI T1,.GTWCH ;[21] GET THIS JOB'S GETTAB T1, ;[21] WATCH BITS SETZ T1, ;[21] NONE? ANDX T1,JW.WAL ;[21] GET RID OF THE OLD MESSAGE BITS TXO T1,JW.WFL ;[21] SET FIRST ONLY HLRZS T1 ;[21] PUT IN A SETUUOABLE PLACE HRLI T1,.STWTC ;[21] GET THE SET WATCH SETUUO FUNCTION SETUUO T1, ;[21] RESET OUR WATCH BITS JFCL ;[21] OH WELL, IT'S NOT THAT IMPORTANT ;CONTINUED ON NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE ;SET DSKFUL ERROR SO GET ERRORS WE CAN RETURN TO REMOTE ACCESSOR MOVE T1,[.STDFL,,.DFERR] ;ARGUMENT TO SETUUO TO SETUUO T1, ;SET DSKFUL ERROR WARN DFL, ;LOCATE TO CENTRAL HOST SO BATCH JOB SUBMISSION A LA QUEUE. UUO WORKS SETZ T1, ;0 = CENTRAL HOST LOCATE T1, ;PUT US THERE TO NOT CONFUSE GALAXY WARN LCS, ;SET SPOOL ALL (IT'S A COP OUT, BUT DAP DOESN'T GIVE US PROPER CONTROL!) MOVE T1,[.STSPL,,JS.PAL] ;SETUUO ARGUMENT TO SETUUO T1, ;SET SPOOL ALL WARN SPL, ;[55] SET ADMINISTRATIVE PRIVILEGES, SO WE CAN DO ACCOUNTING FUNCTIONS MOVE T1,[.STPRV,,[EXP .STCPS,JP.ADM]] ;[55] SETUUO ARGUMENT TO SETUUO T1, ;[55] LIGHT JP.ADM IN JBTPRV WARN AMF, ;INITIALIZE USERS.TXT FOR "USERID" NAME TO PPN TRANSLATION IFN FTUTXT,< ;IF TRANSLATING NAMES TO PPNS, THEN PUSHJ P,UTXINI ;INITIALIZE USERS.TXT TRANSLATION BUFFER WARN UTX,ppn translation> > ;END IFN FTUTXT ;CALL .ISCAN SO'S TO INITIALIZE ALL THE GOOD STORAGE MOVE T1,[ISLEN,,ISBLK] ;GET THE .ISCAN ARG BLOCK POINTER PUSHJ P,.ISCAN## ;INITIALIZE SCAN/SWIL XMOVEI T1,.POPJ## ;GET A NICE NULL ROUTINE PUSHJ P,.TYOCH## ;MAKE SURE SPURIOUS SWIL OUPTUT GETS FLUSHED MOVX T1,$NTPPN ;GET THE DEFAULT NETPPN MOVEM T1,NETPPN ;STORE IT POPJ P, ;RETURN SUBTTL FAL initialization -- UTXINI initialize USERS.TXT buffer ;UTXINI -- INITIALIZE USERS.TXT BUFFER ;Call is: ; ; PUSHJ P,UTXINI ; return ; ;On return, UTXCTR and UTXPTR are the byte counter and pointer to the ;USERS.TXT name to ppn translation buffer, or 0 if no translation is to ;be performed. ; ;*** This routine needs much smartening . . . ; ;Uses T1 - T4, P1 - P4. IFN FTUTXT,< UTXINI: OPEN UTX,[.IODMP ;DUMP MODE I/O HERE FOR CONVENIENCE 'SYS ' ;FROM DEVICE SYS: 0,,0] ;WITH NO RING HEADERS JRST UTXIE0 ;NO, BOMB IT OUT MOVE P1,.JBFF ;ADDRESS OF START OF BUFFER AREA MOVEI T1,.RBSIZ+1(P1) ;END ADDRESS OF LOOKUP BLOCK CORE T1, ;ALLOCATE MEMORY FOR LOOKUP BLOCK JRST UTXIE5 ;CAN'T EVEN GET A LOOKUP BLOCK??? MOVEI T1,.RBSIZ+1 ;EXTENDED LOOKUP BLOCK LENGTH MOVEM T1,.RBCNT(P1) ;SET IN THE LOOKUP BLOCK SETZM .RBPPN(P1) ;NO EXPLICIT PATH DMOVE T1,[EXP 'USERS ','TXT '] ;USERS.TXT DMOVEM T1,.RBNAM(P1) ;SET IN THE LOOKUP BLOCK LOOKUP UTX,(P1) ;SEE IF THE FILE IS AVAILABLE JRST UTXIEL ;NO, BOMB IT OUT SKIPG P2,.RBSIZ(P1) ;[12] SIZE OF FILE (DATA WORDS WRITTEN) JRST UTXIEZ ;[12] EMPTY FILE, IGNORE IT. MOVE T1,P1 ;ADDRESS OF START OF BUFFER ADDI T1,-1(P2) ;ADDRESS OF END OF BUFFER CORE T1, ;MAKE SURE THE BUFFER WILL FIT JRST UTXIE5 ;NO, BOMB IT OUT MOVN T1,P2 ;IOWDS WANT NEGATIVE LENGTH HRLZ T1,T1 ; IN THE LEFT HALF HRRI T1,-1(P1) ;AND ADDRESS-1 IN THE RIGHT HALF SETZ T2, ;TERMINATE THE I/O LIST IN UTX,T1 ;READ IN USERS.TXT CAIA ;BINGO! JRST UTXIE6 ;NO, BOMB IT OUT RELEAS UTX, ;WE ARE DONE WITH THE FILE NOW HRLI P1,(POINT 7,) ;BYTE POINTER TO USERS.TXT BUFFER MOVEM P1,UTXPTR ;REMEMBER USERS.TXT BUFFER POINTER IMULI P2,5 ;BYTE COUNTER FOR USERS.TXT BUFFER MOVE P3,P1 ;BYTE POINTER TO WRITE USERS.TXT ;CONTINUED ON NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE ;STILL IFN FTUTXT ;USERS.TXT contains ASCII ppn<=>name correspondences of the form ;"dev:[p,pn],name" (this format is defined by the MS mail proggie). ;Internally, they will be compressed to just "[p,pn]name" form. UTXIN2: PUSHJ P,UTXGT1 ;GET ONE USERS.TXT CHARACTER JRST UTXIN9 ;DONE, REMEMBER IT CAIE T1,"[" ;START OF PPN YET? JRST UTXIN2 ;NO, SKIP REST OF DEVICE PORTION UTXIN3: PUSHJ P,UTXPT1 ;YES, SAVE START OF PPN FIELD JRST UTXIE7 ;NO, BOMB OUT PUSHJ P,UTXGT1 ;GET NEXT USERS.TXT CHARACTER JRST UTXIN9 ;DONE CAIE T1,"]" ;END OF PPN PART YET? JRST UTXIN3 ;NO, STILL PPN, SAVE IT PUSHJ P,UTXPT1 ;YES, CAP OFF PPN JRST UTXIE7 ;BOMB IT OUT PUSHJ P,UTXGT1 ;NEXT INPUT CHARACTER JRST UTXIN9 ;DONE CAIE T1,"," ;SHOULD BE A COMMA JRST UTXIN2 ;NO, JUST RESTART, JUNKING THIS ENTRY . . . UTXIN5: PUSHJ P,UTXGT1 ;GET NAME CHARACTER JRST UTXIN9 ;DONE PUSHJ P,UTXPT1 ;AND SAVE IT TOO JRST UTXIE7 ;DOMB IT OUT CAIE T1,.CHLFD ;END OF PPN<=>NAME ENTRY? JRST UTXIN5 ;NO, FINISH OFF NAME JRST UTXIN2 ;YES, DO NEXT ENTRY ;Here when completed successfully UTXIN9: MOVEI T1,.CHLFD ;A CHARACTER PUSHJ P,UTXPT1 ;ENSURE USERS.TXT BUFFER ENDS WITH A JRST UTXIE7 ;HOW INCONVENIENT A PLACE TO BOMB TDZA T1,T1 ;A NULL CHARACTER IDPB T1,P3 ;STASH ANOTHER NULL TXNE P3,74B5 ;BYTE POINTER FILLED UP A WORD YET? JRST .-2 ;NO, ZERO-FILL THE WORD MOVEI P1,1(P3) ;END ADDRESS+1 OF USERS.TXT BUFFER MOVE T2,.JBFF ;START ADDRESS OF USERS.TXT BUFFER SUBM P1,T2 ;T2:=COUNT OF WORDS IN BUFFER IMULI T2,5 ;T2:=COUNT OF BYTES IN BUFFER MOVEM T2,UTXCTR ;SAVE BYTE COUNTER FOR UTXPTR MOVEM P1,.JBFF ;MARK THAT WE NOW OWN USERS.TXT BUFFER MOVEM P1,CMDFF## ;TELL REST OF WORLD TOO MOVEM P1,SAVFF## ;TELL REST OF THE UNIVERSE ALSO HRLM P1,.JBSA ;*** FINALLY, TELL EVEN THE GODS . . . JRST .POPJ1## ;HAPPY ;STILL IFN FTUTXT ;Here when error setting up USERS.TXT UTXIEL: HRRZ T1,.RBEXT(P1) ;RETRIEVE LOOKUP ERROR CODE CAIN T1,ERPRT% ;PROTECTION FAILURE? JRST UTXIE1 ;YES CAIN T1,ERTRN% ;RIB/DIRECTORY ERROR? JRST UTXIE2 ;YES CAIE T1,ERFNF% ;FILE NOT FOUND? JRST UTXIE3 ;RANDOM ERROR INFRM UTM, ppn translation will be performed> UTXIEZ: AOS (P) ;[12] TAKE HAPPY (ALBEIT FAILED IN THIS CASE) RETURN PJRST UTXINE ;BLAST AWAY THE I/O CHANNEL UTXIE0: ERROR UT0,,,,UTXINE UTXIE1: ERROR UT1,,,,UTXINE UTXIE2: ERROR UT2,,,,UTXINE UTXIE3: ERROR UT3,,,,UTXINE UTXIE5: ERROR UT5,,,,UTXINE UTXIE6: ERROR UT6,,,,UTXINE UTXIE7: ERROR UT7,,,,UTXINE UTXINE: RELEAS UTX, ;STOMP ON I/O CHANNEL SETZM UTXPTR ;MARK NO USERS.TXT BUFFER MOVE T1,.JBFF ;START OF BUFFER CORE T1, ;DEALLOCATE NOW-USELESS BUFFER JFCL ;HO HUM POPJ P, ;AND THAT IS THAT ;STILL IFN FTUTXT ;UTXGT1 - GET ONE USERS.TXT CHARACTER UTXGT1: SOJL P2,.POPJ## ;ERROR IF NO MORE ILDB T1,P1 ;NEXT INPUT CHARACTER JUMPE T1,UTXGT1 ;SUPPRESS NULLS CAIN T1,.CHCRT ;? JRST UTXGT1 ;YES, JUST RETURN THE CAIE T1," " ;SPACE? CAIN T1,.CHTAB ; OR TAB? JRST UTXGT1 ;YES, SUPPRESS CAIE T1,";" ;COMMENT? CAIN T1,"!" ; ALTERNATE COMMENT? JRST UTXGT3 ;YES, EAT IT UP CAIL T1,"a" ;LOWERCASE ALPHA? CAILE T1,"z" ; . . . JRST .POPJ1## ;NO, RETURN VALID CHARACTER SUBI T1,"a"-"A" ;SHIFT TO UPPERCASE ALPHA JRST .POPJ1## ;AND RETURN IT UTXGT3: SOJL P2,.POPJ## ;ERROR IF NO MORE ILDB T1,P1 ;NEXT CHARACTER CAIN T1,.CHLFD ;END OF LINE (COMMENT) YET? JRST UTXGT3 ;NO, KEEP EATING JRST .POPJ1## ;YES, RETURN END OF LINE ;UTXPT1 -- WRITE ONE USERS.TXT CHARACTER UTXPT1: IDPB T1,P3 ;STASH VALID CHARACTER JRST .POPJ1## ;ALL DONE! > ;END IFN FTUTXT SUBTTL Main FAL processing loop FALL:: TXZ S,S.CLR ;CLEAR THE PER CONNECTION BITS PUSHJ P,FALLI ;INITIALIZE A FAL JOB PROCESS JRST FALL70 ;CHECK OUR ERROR TXZE S,S.KILL ;DID WE JUST ABORT A TRANSFER? JRST FALL ;YES, START A NEW ONE THEN TXNN S,S.SHUT ;ARE WE SUPPOSED TO SHUT DOWN? JRST FALL ;NO, TRY FOR ANOTHER SESSION SETZ T1, ;YES, SAY WE'RE SHUTTING DOWN NORMALLY POPJ P, ;AND FINISH THIS STREAM OFF ;HERE ON ERROR FROM FALLI FALL70: TXZE S,S.KILL ;DID WE JUST ABORT A TRANSFER? JRST FALL ;YES, START A NEW ONE THEN CAIE M0,$EFUID ;DID WE REJECT THE USER ID? CAIN M0,$EFUAC ;DID WE REJECT THE USER ACCOUNT DATA? JRST FALL77 ;YES, RETRY IMMEDIATELY CAIN M0,$EINLA ;DID LINK "TERMINATE" NORMALLY? JRST FALL77 ;YES, RETRY IMMEDIATELY CAIN M0,$EFNNS ;GOT ANY NETWORK SOFTWARE? JRST [MOVEI T1,$FSNNS ;SAY NO NETWORK SOFTWARE POPJ P,] ;RETURN TO TOP LEVEL CAIN M0,$EFPRV ;PRIVILEGE VIOLATION? JRST [MOVEI T1,$FSISP ;SAY NO PRIVS POPJ P,] ;RETURN TO SETUP PROCESSOR ;LINK TERMINATED ABNORMALLY - USE SLIDING WAIT INTERVAL TO ALLOW ;THE WORLD TO CALM DOWN MOVE M0,J$FSLP(J) ;GET THE SLEEPER VALUE SKIPN M0 ;ANY VALUE SET? MOVEI M0,1 ;NONE, START WITH 1 LSH M0,1 ;DOUBLE THE INTERVAL CAILE M0,^D64 ;TIME GOTTEN TOO BIG? MOVEI M0,^D64 ;YES, PEG AT ABOUT ONE MINUTE WAITS MOVEM M0,J$FSLP(J) ;SAVE FOR NEXT TIME TXO M0,PSF%SL ;SAY WE'RE SLEEPING PUSHJ P,DSCHD## ;DESCHEDULE FOR A WHILE TXNN S,S.SHUT ;SHOULD WE SHUT DOWN? JRST FALL ;NO, NOW TRY AGAIN SETZ T1, ;YES, GET THE REASON POPJ P, ;AND RETURN FALL77: JRST FALL ;JUST TRY AGAIN IMMEDIATELY ;INITIALIZE ONE FAL JOB PROCESS FALLI: MOVE P1,J$FTYP(J) ;SELECT EITHER ANF (IO.ANF) OR DECNET (IO.DCN) SETZM J$RTIM(J) ;FLAG THAT WE HAVEN'T DONE ANYTHING YET PUSHJ P,FALJB ;FIRE UP A SINGLE FAL JOB STREAM SKIPA P1,M0 ;SAVE ERROR CODE FROM FALJB SETZ P1, ;FLAG NO ERROR TXZ S,S.OPEN!S.CONN ;[16] NO FILES OPEN ANYMORE SKIPE IO,CI ;[14] GET THE NETWORK CDB POINTER SKIPN .IONCH(IO) ;[14] ANY CHANNEL OPEN HERE? JRST FALLI1 ;[14] NO, DON'T TRY TO CLOSE IT THEN MOVE IO,CI ;[14] YES, GET THE CDB ADDRESS SETZ T3, ;[14] NO OPTIONAL DATA ON ABORT PUSHJ P,NTNAB1## ;[14] GO ABORT THIS CONNECTION JFCL ;[14] NOT REAL FATAL IF ERROR HERE FALLI1: PUSHJ P,INTDIS## ;DISCONNECT AND/OR CLEAR INTERRUPT ENABLES JFCL ;ERROR IS MEANINGLESS HERE SKIPN IO,CO ;[14] GET THE SLAVE CDB ADDRESS JRST FALLI3 ;[14] NO, DON'T TRY TO CLOSE IT THEN PUSHJ P,IOZAP1## ;[37] KILL OFF ANYTHING THAT'S STILL AROUND JFCL ;[37] DON'T WORRY ABOUT ERRORS FALLI3: PUSHJ P,INDDIS## ;DISCONNECT FROM DISK INTERRUPTS JFCL ;DON'T WORRY ABOUT ERRORS HERE SKIPE J$RTIM(J) ;DID WE DO ANYTHING? PUSHJ P,ENDJOB## ;YES, SAY WE'RE DONE WITH THIS SESSION FALLI2: SKIPN T2,CI ;PRIMARY CDB ADDRESS JRST FALLI4 ;NONE? SKIPN T1,.IOXSZ(T2) ;SIZE OF CDB ALLOCATED MOVE T1,.IOSIZ(T2) ;SIZE OF CDB ALLOCATED PUSHJ P,.MMFWD## ;DEALLOCATE THE CDB DEBUG FALLI4: SKIPN T2,CO ;SLAVE CDB ADDRESS JRST FALLI6 ;NONE SKIPN T1,.IOXSZ(T2) ;SIZE OF CDB ALLOCATED MOVE T1,.IOSIZ(T2) ;SZIE OF CDB ALLOCATED PUSHJ P,.MMFWD## ;DEALLOCATE THE CDB DEBUG FALLI6: JUMPE P1,.POPJ1## ;RETURN HAPPILY IF SUCCESSFUL MOVE M0,P1 ;RESTORE ERROR CODE TO STATUS REGISTER POPJ P, ;AND PROPAGATE FALJB'S ERROR SUBTTL FAL "JOB" process ;STARTUP A FAL PROCESS FALJB: SETZB CI,CO ;NO CDB'S ALLOCATED YET ;ALLOCATE AND INITIALIZE PRIMARY CDB FOR THE NETWORK-BASED LINK MOVEI T2,FALIV ;FAL'S INIT STUFF PUSHJ P,.IOINA## ;ALLOCATE AND INITIALIZE PRIMARY CDB JRST ERRCDI## ;DUH? MOVE CI,T1 ;REMEMBER PRIMARY CDB ADDRESS ;FROM HERE ON FAL OPERATES IN A "NATIVE" MODE RE THE I/O PACKAGE, FREELY ;USING T1 - P4, AND IO AS THE I/O CDB INDEX. ; ;THIS SAVES OODLES OF AC PUSHING/SHOVING/POPPING! MOVE IO,CI ;SELECT THE PRIMARY CDB IORM P1,.IOCCF(IO) ;SELECT REQUESTED NETWORK PROTOCOL MOVEI T1,SCHEDL ;GET THE SCHEDULER ADDRESS MOVEM T1,.IOSCH(IO) ;STORE FOR SWIL ;SETUP THE DESTINATION (THAT'S US) PROCESS DESCRIPTOR BLOCK FALOBJ:!MOVX T3,<0,,21> ;GENERIC FAL FORMAT/OBJECT TYPE MOVEM T3,.IONDF(IO) ;SET IN THE CDB SETZM .IONDP(IO) ;NO PPN SPECIFIED SETZM .IONDN(IO) ;NOR ANY SPECIFIC PROCESS NAME ;SETUP THE SOURCE (REMOTE NFT/ETC.) PROCESS DESCRIPTOR BLOCK MOVX T3,<0,,-1> ;GENERIC ANYTHING FORMAT/OBJECT TYPE MOVEM T3,.IONSF(IO) ;SOURCE FORMAT/OBJECT (DON'T CARE) SETZM .IONSP(IO) ;SOURCE PPN (DON'T CARE) SETZM .IONSN(IO) ;SOURCE NAME (DON'T CARE) ;NO OTHER RESTRICTIONS EITHER SETZM .IONUS(IO) ;USER ID (DON'T CARE) SETZM .IONPW(IO) ;USER PASSWORD (DON'T CARE) SETZM .IONAC(IO) ;USER ACCOUNT STRING (DON'T CARE) SETZM .IONUD(IO) ;USER DATA (DON'T CARE) ;TELL MONITOR WHAT WE'RE UP TO FALJ20: SETZ T2, ;ANY NODE OK PUSHJ P,NTNIP1## ;INITIALIZE A PASSIVE NETWORK CHANNEL POPJ P, ;OOPS - NETWORK NOT BEING COOPERATIVE MOVE T1,.IONCH(IO) ;GET THE NETWORK CHANNEL NUMBER PUSHJ P,SETCHN## ;SETUP INTERRUPTS ON THIS CHANNEL JRST [PUSHJ P,NTFIN1## ;ERROR, BLOW OFF THIS CHANNEL JFCL ;PUNT ANY ERRORS HERE MOVEI M0,$EEXXX ;GET A GENERIC ERROR CODE POPJ P,] ;AND BLOW US OFF ;NOW WAIT FOR SOMEONE, SOMEWHERE, SOMETIME, . . . FALJ30: MOVX M0,PSF%CW ;SAY WE'RE WAITING FOR A CONNECTION PUSHJ P,DSCHD## ;GO AWAY FOR A WHILE TXNE S,S.SHUT!S.KILL ;ARE WE SHUTTING DOWN? JRST [PUSHJ P,NTNRL1## ;YES, BLOW OFF THIS CHANNEL JFCL ;PUNT ERROR RETURNS HERE SETZ M0, ;FLAG NORMAL SHUTDOWN POPJ P,] ;RETURN PUSHJ P,NTNCW1## ;GO RECEIVE THE CONNECT INITIATE DATA POPJ P, ;HMMM - A RECALCITRANT NOTWORK TXO S,S.CONN ;SAY WE'RE CONNECTING MOVE T1,.ION6M(IO) ;GET THE SIXBIT NODE NAME MOVEM T1,J$SNOD(J) ;LET FALGLX KNOW ABOUT IT TOO SETZM J$SBYT(J) ;SAY NO BYTES MOVED YET ;WE HAVE A CONNECT, SEE IF WE ARE WILLING TO CONSIDER IT FALJ32: MOVX T1,%CNSTS ;GETTAB POINTER TO GETTAB T1, ;READ THE SYSTEM "STATES" FLAGS SETZ T1, ;DUH? TXNE T1,ST%NRT!ST%NLG;DEBUGGING/ETC? JRST FALJR0 ;YES, REJECT "ABORT BY DIALOG PROCESS" MOVX T1,%NSKTM ;GETTAB POINTER TO GETTAB T1, ;READ THE KSYS TIMER VALUE SETZ T1, ;DUH? JUMPL T1,FALJR1 ;REJECT "NODE SHUTTING DOWN" XMOVEI P1,.IONUS(IO) ;POINT AT THE ORIGINAL USERNAME STRING XMOVEI T1,J$SUSR(J) ;POINT AT THE DESTINATION PUSHJ P,F8BAZ ;CONVERT TO ASCIZ NAME STRING JFCL ;DON'T WORRY ABOUT AN ERROR HERE XMOVEI P1,.IONUS(IO) ;ADDRESS OF USER ID STRING HLRZ T1,@P1 ;GET USER ID STRING LENGTH (IF ANY) LDB T2,[POINT 8,.IONUS+1(IO),7] ;*** PEEK AT FIRST BYTE CAIN T2,0 ;*** ANYTHING THERE? SETZ T1, ;*** NO - VAX SENDS 4 NULLS!!!!! JUMPE T1,[SKIPN T1,NETPPN ;FETCH DEFAULT USER NETPPN JRST FALJR2 ;NONE, REJECT USERID MOVEM T1,.IOPPN(IO) ;SET DEFAULT "ON-BEHALF-OF" PPN DMOVE T1,[EXP 'NETWOR', 'K USER'] ;FAKE UP A USER NAME DMOVEM T1,.IOQ6N(IO) ;SET DEFAULT USER NAME TOO DMOVE T1,[ASCII ~Network us~] ;THEN, COPY THE DMOVEM T1,J$SUSR(J) ;ASCII VERSION OF THAT MOVE T1,[ASCIZ ~er~] ;TO THE PER STREAM MOVEM T1,J$SUSR+2(J) ;STORAGE SETZM .IOACT(IO) ;WITH NO ACCOUNT STRING JRST FALJ34] ;AND ALLOW THE NETWORK CONNECTION PUSHJ P,F8BUP ;CONVERT 8-BIT USERID STRING INTO PPN JRST FALJR2 ;CAN'T MAKE A PPN, JUNK USER ID MOVEM T1,.IOPPN(IO) ;STORE "ON-BEHALF-OF" PPN TXNE S,S.PROF ;[31] DO WE HAVE THE USER'S PROFILE? JRST FALJ33 ;[31] YES, DON'T GET IT THEN XMOVEI T4,J$ABLK-1(J) ;[31] POINT AT THE ARGUMENT BLOCK STORAGE PUSH T4,[QF.RSP!.QUMAE] ;[31] SAY WE WANT TO TALK TO ACTDAE PUSH T4,[0] ;[31,55] SET THE NODE TO CENTRAL XMOVEI T2,J$ARSP(J) ;[31] POINT AT THE RESPONSE STORAGE HRLI T2,ARSPLN ;[31] GET THE NUMBER OF WORDS WE CAN PLAY WITH HERE PUSH T4,T2 ;[31] PUT IN THE ARG BLOCK PUSH T4,[QA.IMM!<1,,.QBAFN>] ;[31] GET THE SUBFUNCTION ARGUMENT TYPE PUSH T4,[EXP AF.PRV!UGOUP$] ;[31,55] SAY WE WANT THE USER PROFILE PUSH T4,[QA.IMM!<1,,.UGPPN>] ;[31] SAY WE'RE SUPPLYING THE PPN PUSH T4,T1 ;[31] STORE THE USER'S PPN ANDI T4,-1 ;[31] GET RID OF JUNK IN THE LEFT HALF SUBI T4,J$ABLK-1(J) ;[31] COMPUTE THE NUMBER OF WORDS WE FILLED IN XMOVEI T2,J$ABLK(J) ;[31] POINT AT THE ARGUMENT BLOCK HRL T2,T4 ;[31] COPY THE BLOCK LENGTH QUEUE. T2, ;[31] ASK FOR THE PPN FOR THIS GUY SETZM .AEACC+J$ARSP(J) ;[31,33] NO PROFILE? ASSUME NO FAL PRIVS FALJ33: SKIPE T2,.AEACC+J$ARSP(J) ;[31,33] GET THE JOB'S PROFILE BITS TXO S,S.PROF ;[31] YES, REMEMBER THAT WE DID TXNE S,S.PROF ;[31] DID WE GET A PROFILE? PUSHJ P,NAM826 ;[31] YES, STORE IT IN .IOQ6N TXNN S,S.NPPN ;[31] IS THIS THE NETWORK ACCESS PPN? TXNE T2,AE.FAL ;[31] NO, DO WE HAVE FILE ACCESS PRIVS? SKIPA ;[32] YES, GO ON JRST FALJR6 ;[32] NO, REJECT THE USERID FALJ34: PUSHJ P,FALCR1 ;SEE IF NODE/PPN REJECTED BY COMMAND JRST FALJR5 ;[32] YES, REJECT USERID XMOVEI P1,.IONAC(IO) ;ADDRESS OF USER ACCOUNT STRING XMOVEI T1,.IOACT(IO) ;WHERE TO STORE ASCIZ STRING PUSHJ P,F8BAZ ;COPY AND ASCIZIZE STRING JRST FALJR4 ;JUNK ACCOUNT STRING MOVSI T1,J$SPSW(J) ;[42] CLEAR THE OLD HRRI T1,J$SPSW+1(J) ;[42] PASSWORD STRING SETZM J$SPSW(J) ;[42] ... BLT T1,J$SPSW+PSWDWD-1(J) ;[42] XMOVEI P1,.IONPW(IO) ;ADDRESS OF USER ID PASSWORD XMOVEI T1,J$SPSW(J) ;POINT TO THE PASSWORD STRING STORAGE PUSHJ P,F8BAZ8 ;[34] CONVERT 8-BIT STRING INTO 6-BIT WORD JRST FALJR4 ;JUNK PASSWORD STRING ;VERIFY THE USERID/PASSWORD/ACCOUNT FALJ37: DMOVE P1,.IOQ6N(IO) ;[32] SAVE THE USERNAME 'CAUSE SWIL STOMPS IT MOVE T2,.IOPPN(IO) ;RETRIEVE COPY OF ACCESSING PPN CAMN T2,NETPPN ;IS THIS THE DEFAULT USER PPN? JRST FALJ40 ;YES, THEN IT WORKS. XMOVEI T3,J$SPSW(J) ;POINT TO THE PASSWORD IN T3 MOVEI T2,.QUMAE ;ACCESS VALIDATION PUSHJ P,QUEOP0## ;[32] ASK ACTDAE IF USER IS A GOOD GUY SKIPA T2,M0 ;CAN'T VALIDATE USERID/ETC. JRST FALJ40 ;USERID/ETC OK, USER NAME/ETC SETUP JSP T4,.CDISP## ;DISPATCH BASED ON ERROR FALJR2,,$EQILP ;ILLEGAL PPN/USERID FALJR2,,$EQIPW ;INVALID PASSWORD FALJR3,,$EQIVA ;INVALID ACCOUNT STRING 0 ;NO OTHERS RETURN AN ERROR ;HERE WHEN CAN'T VALIDATE USERID/ETC., REJECT UNLESS DEBUGGING FALJ3A: CAIN M0,$EQCNR ;"COMPONET NOT RUNNING"? (I.E., NO ACTDAE) ERROR ANR,,,,FALJR4 CAIE M0,$EQPRA ;LACKING PRIVILEGES TO DO ACCOUNTING? DEBUG ,,,FALJR4 MOVE T1,.MYPPN## ;GET MY JOB'S PPN CAME T1,.PPFFA## ;AM I [OPR]? SKIPN .JBDDT ;NO, ALLOW IF DEBUGGING JRST FALJR4 ;CALL FUNNY USERID/ETC ERROR INFRM UAR,,,,FALJ40 ;VALID USER ID, ACCEPT NETWORK CONNECTION FALJ40: DMOVEM P1,.IOQ6N(IO) ;[32] RESTORE THE USERNAME WORDS MOVE T1,.IOPPN(IO) ;GET OUR PPN CAME T1,NETPPN ;IS IT THE NETWORK PPN? TXZA S,S.NPPN ;NO, CLEAR ANY INDICATION OF THAT TXO S,S.NPPN ;YES, REMEMBER THAT FOR LATER SETZB T2,T3 ;NO OPTIONAL CONNECT CONFIRM DATA PUSHJ P,NTNCA1## ;SEND A CONNECT ACCEPT MESSAGE POPJ P, ;BUTTS PUSHJ P,BEGJOB## ;GO NOTIFY THE OPERATOR THAT WE'RE STARTING ;BUILD BUFFERS FOR FURTHER "REAL" COMMUNICATIONS FALJ45: PUSHJ P,NTINI1## ;BUILD BUFFERS ETC. POPJ P, ;BUTTS ;EXCHANGE CONFIGURATION MESSAGES WITH THE REMOTE DAP PROCESS FALJ50: PUSHJ P,DPICM1## ;EXCHANGE CONFIGURATION MESSAGES ERROR FCM,,.TSIXN,J$SNOD(J) SETZM J$FSLP(J) ;GOOD CONNECT, RESET WAIT INTERVAL TXZ S,S.CONN ;SAY WE'RE NO LONGER WAITING TO CONNECT TXO S,S.OPEN ;SAY WE HAVE A CONNECTION OPEN PJRST FJOB00 ;ENTER FAL JOB MAIN LOOP ;SEE IF INCOMING CONNECT REQUEST IS REJECTED BY OPERATOR COMMAND FALCR1: SKIPN P1,REJFIR ;GOT A REJECTION LIST? JRST .POPJ1## ;NO, INCOMING CONNECT OK BY US ;LOOP CHECKING AGAINST THE REJECTION LIST, SPEC BY SPEC FALCR2: SKIPN T1,RJ.NOD(P1) ;[22] GET REJECTED NODE SPEC JRST FALCR5 ;NO NODE, JUST CHECK THE PPN ; XOR T1,.ION6M(IO) ;COMPARE AGAINST CONNECTING NODE ; TDNE T1,RJ.NDM(P1) ;[22] DOES THIS NODE MATCH THE REJECTION? CAME T1,.ION6M ;[22] DOES THIS NODE MATCH THE REJECTION? JRST FALCR9 ;NO, SKIP TO NEXT SPEC THEN FALCR5: MOVE T2,RJ.PPN(P1) ;[22] GET REJECTED PPN SPEC XOR T2,.IOPPN(IO) ;COMPARE AGAINST CONNECTING USERID TDNN T2,RJ.PPM(P1) ;[22] DOES THIS PPN MATCH THE REJECTION? POPJ P, ;YES, USERID REJECTED FALCR9: ADDI P1,RJ.MAX ;[22] DOESN'T MATCH THIS REJECTION SPEC, ADVANCE CAMGE P1,REJLAS ;ANY MORE SPECS TO CHECK? JRST FALCR2 ;YES JRST .POPJ1## ;NO, INCOMING CONNECT NOT REJECTED HERE ;CONNECT REJECTS COME HERE FALJR0: REJECT BDP, MOVEI T3,^D09 ;REJECT "BY DIALOGE PROCESS" JRST FALRJ1 ;COMMON CODE FALJR1: REJECT NSD, MOVEI T3,^D03 ;REJECT "NODE SHUTTING DOWN" JRST FALRJ1 ;COMMON CODE FALJR2: REJECT IPP, MOVEI T3,^D34 ;REJECT "INVALID PPN/PASSWORD" JRST FALRJ1 ;COMMON CODE FALJR3: REJECT IAC, MOVEI T3,^D36 ;REJECT "INVALID ACCOUNT STRING" JRST FALRJ1 ;COMMON CODE FALJR4: REJECT FFE, MOVEI T3,^D43 ;REJECT GENERAL IMAGE FIELD FORMAT ERROR JRST FALRJ1 ;COMMON CODE FALJR5: REJECT UNJ, MOVEI T3,^D34 ;[32] REJECT "INVALID PPN/PASSWORD" JRST FALRJ1 ;[32] COMMON CODE FALJR6: REJECT NUP, MOVEI T3,^D34 ;[32] REJECT "INVALID PPN/PASSWORD" ; JRST FALRJ1 ;[32] COMMON CODE ;ALL CONNECT REJECTS COME THROUGH HERE FALRJ1: TXZ S,S.CONN!S.OPEN ;NOT CONNECTING ANYMORE PUSHJ P,INTDIS## ;DISCONNECT THIS CHANNEL FROM THE INTERRUPT SYSTEM JFCL ;PUNT ERRORS HERE SETZ T2, ;NO OPTIONAL DISCONNECT DATA PUSHJ P,NTNCR1## ;REJECT THE CONNECT JFCL ;DUH??? MOVEI M0,$EFUID ;DECLARE THIS TERMINATION "USERID" POPJ P, ;END OF THIS ACCESS ;TOP-LEVEL OR MAIN FAL "JOB" PROCESS IDLE LOOP - WAIT FOR SOMETHING TO DO FJOB00: MOVE IO,CI ;SELECT PRIMARY CDB PUSHJ P,RDMSG1## ;START UP FIRST DAP MESSAGE JRST .POPJ1## ;ASSUME ALL DONE ;WE HAVE SOMETHING TO DO, INITIALIZE THE SLAVE CDB AND GO DO IT JUMPN CO,FJOB03 ;JUST RESET SLAVE IF ALREADY ALLOCATED MOVEI T2,FALIV ;FAL'S INIT STUFF PUSHJ P,.IOINA## ;ALLOCATE AND INITIALIZE SLAVE CDB JRST ERRCDO## ;DUH? MOVE CO,T1 ;REMEMBER SLAVE CDB ADDRESS JRST FJOB07 ;CLEAR OUT COMMUNICATIONS AREAS ;HERE WHEN ALREADY HAVE A SLAVE CDB, AS AFTER AN ACCESS COMPLETE, WITH ;MORE ACCESS MESSAGES COMING UP FJOB03: MOVE IO,CO ;SELECT SLAVE CDB SKIPN .IOCHN(IO) ;GOT AN I/O CHANNEL? SKIPE .IONCH(IO) ;OR A NETWORK CHANNEL? CAIA ;YES??? JRST FJOB05 ;NO IFN FTDEBUG,INFRM ASS, PUSHJ P,IOABO1## ;ABORT WHATEVER IS THERE JFCL ;HOHUM FJOB05: MOVE T1,CO ;ADDRESS OF SLAVE CDB MOVEI T2,FALIV ;FAL'S INIT STUFF PUSHJ P,.IOINI## ;[RE-]INITIALIZE SLAVE CDB ; IN PARTICULAR, CLEAR OUT OLD .IOFSB ; AND RESET .IOXFF JRST ERRCDO## ;DUH? ;SETUP THE CDB FOR SLAVE USAGE BY REST OF FAL FJOB07: MOVX T2,IO.SLV ;THE "SLAVE" BIT IORM T2,.IOCCF(CO) ;MARK THE SLAVE CDB (E.G., FOR QUEOP) ;SET "ON-BEHALF-OF" STUFF IN THE SLAVE CDB (WHERE IT REALLY COUNTS) MOVE T1,.IOPPN(CI) ;"ON-BEHALF-OF" PPN MOVEM T1,.IOPPN(CO) ;COPY IT INTO THE SLAVE CDB MOVSI T1,.IOACT(CI) ;"ON-BEHALF-OF" ACCOUNT STRING HRRI T1,.IOACT(CO) ;WHERE WE WANT IT BLT T1,.IOACT+7(CO) ;LEAVE IT FOR FILOP ETC. TO FIND DMOVE T1,.IOQ6N(CI) ;"ON-BEHALF-OF" USER NAME DMOVEM T1,.IOQ6N(CO) ;LEAVE IT FOR QUEOP ETC. ;CLEAR OUT INTERNAL "JOB" DATA BASE ;CLEAR OUT DAP COMMUNICATIONS REGION FOR A FRESH START MOVE IO,CI ;REFRESH CDB ADDRESS (JUST IN CASE) MOVEI T2,$DHACS ;ACCESS MESSAGE PUSHJ P,RDCLR1## ;CLEAR OUT DAP MESSAGE AREA STOPCD ;CAN'T HAPPEN MOVEI T2,$DHATR ;MAIN ATTRIBUTES MESSAGE PUSHJ P,RDCLR1## ;CLEAR OUT DAP MESSAGE AREA STOPCD ;CAN'T HAPPEN MOVEI T2,$DHALC ;ALLOCATION ATTRIBUTES MESSAGE PUSHJ P,RDCLR1## ;CLEAR OUT DAP MESSAGE AREA STOPCD ;CAN'T HAPPEN MOVEI T2,$DHTIM ;DATE/TIME ATTRIBUTES MESSAGE PUSHJ P,RDCLR1## ;CLEAR OUT DAP MESSAGE AREA STOPCD ;CAN'T HAPPEN MOVEI T2,$DHPRT ;PROTECTION ATTRIBUTES MESSAGE PUSHJ P,RDCLR1## ;CLEAR OUT DAP MESSAGE AREA STOPCD ;CAN'T HAPPEN SKIPG T2,.IODIM(IO) ;GET PENDING DAP MESSAGE CODE STOPCD JRST FJOB12 ;DISPATCH ON DAP MESSAGE TYPE ;START UP NEW DAP INPUT MESSAGE FJOB10: PUSHJ P,RDMSG1## ;GET A DAP MESSAGE HEADER PJRST NETERI## ;[21] ERROR (MAYBE DISCONNECT) ;HERE WITH DAP MESSAGE CODE IN T2 FJOB12: JSP T4,.CDISP## ;DISPATCH ON RECEIVED MESSAGE TYPE FJOB40,,$DHCFG ;[47] CONFIGURATION FJOB17,,$DHSTS ;STATUS (HUH?) FJOB20,,$DHATR ;MAIN ATTRIBUTES FJOB20,,$DHALC ;ALLOCATION ATTRIBUTES FJOB20,,$DHTIM ;DATE/TIME ATTRIBUTES FJOB20,,$DHPRT ;PROTECTION ATTRIBUTES FJOB30,,$DHUSR ;USER ID FJOB50,,$DHACS ;FILE ACCESS FJOB90,,$DHACM ;ACCESS COMPLETE 0 ;END OF TABLE JSP T4,FEROS ;DAP MESSAGE RECEIVED OUT OF SEQUENCE ;RECEIVED STATUS - SHOULDN'T USUALLY HAPPEN! FJOB17: PUSHJ P,RDSTS1## ;READ IN REST OF STATUS PJRST NETERI## ;[21] NET DIED CAIE M0,$EGOIP ;"OPERATION IN PROGRESS"? CAIN M0,$EGAOK ;"A-OK"? JRST FJOB10 ;YES, JUST EAT IT ;*** PUSHJ P,ERMSX1## ;TYPE OUT STATUS MESSAGE JRST FJOB10 ;KEEP ON CRUSIN' JRST FJOB10 ;KEEP ON CRUSIN' ;RECEIVED SOME FLAVOR OF FILE ATTRIBUTES FJOB20: PUSHJ P,RDDAP1## ;READ IN THE REST OF THE DAP MESSAGE JSP T4,FERDP ;DAP ERROR JRST FJOB10 ;LOOP BACK FOR MORE ;RECEIVED USERID MESSAGE FJOB30: PUSHJ P,RDDAP1## ;READ IN USERID