.TITLE VDH - VIRTUAL DEVICE HOST SERVER .IDENT /V01.07/ ; ; COPYRIGHT (C) 1979,1980 BY ; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY ON A ; SINGLE COMPUTER SYSTEM AND MAY BE COPIED ONLY 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 EXCEPT FOR USE ON SUCH ; SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE TERMS. TITLE ; TO AND OWNERSHIP OF THE SOFTWARE SHALL AT ALL TIMES REMAIN ; IN DEC. ; ; THE INFORMATION IN THIS DOCUMENT IS SUBJECT TO CHANGE WITHOUT ; NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL ; EQUIPMENT CORPORATION. ; ; DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ; ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC. ; ; ; MODULE DESCRIPTION ; ; VIRTUAL DEVICE HOST SERVER ; ; DISTRIBUTED SYSTEMS SOFTWARE ENGINEERING ; ; IDENT HISTORY: ; ; 1.00 1-FEB-79 ; J. A. SCHRIESHEIM ; ; 1.01 5-JUN-80 J. A. SCHRIESHEIM ; SEPARATED INTO READ-ONLY AND READ-WRITE PSECTS ; ; 1.02 14-JUL-80 J. A. SCHRIESHEIM ; MADE DEVICE TYPE RETURNED BASED ON CHARACTERISTICS, NOT NAME ; ; 1.03 29-AUG-80 J. A. SCHRIESHEIM ; ADDED IO.KIL INTERRUPT MESSAGE SUPPORT ; ; 1.04 2-SEP-80 J. A. SCHRIESHEIM ; ADDED MAG-TAPE SPECIFIC FUNCTIONS ; ; 1.05 3-SEP-80 J. A. SCHRIESHEIM ; ADDED BIG BUFFER SUPPORT ; ; 1.06 8-SEP-80 J. A. SCHRIESHEIM ; MOVED BIG BUFFER INTO SEPARATE MODULE ; ; 1.07 19-MAR-81 J. A. SCHRIESHEIM ; FIXED BUG IN READ LOGIC (ONLY USE LOW BYTE OF "HIGH BLOCK NUMBER") ; .SBTTL MACRO CALLS AND LOCAL DEFINITIONS ; ; MACRO LIBRARY CALLS ; .MCALL EXIT$S,DIR$,ASTX$S,ALUN$S,CLEF$S,CSI$,DSAR$S,FINIT$ .MCALL SETF$S,QIOW$,CALLR,WTSE$S,MRKT$,CMKT$,OFNB$,FCSBT$ .MCALL FSRSZ$,FDBDF$,FDRC$A,FDOP$A,CSI$1,CSI$2,ENAR$S .MCALL OPNW$,DSCW$,CLSW$,REC$,SND$,ACCW$,GLUN$,FDAT$A .MCALL SNDW$,RECW$,GNDW$,SPAW$,NETDF$,QIO$,WSIG$S,GTSK$ .MCALL CSI$SW,CSI$SV,CSI$ND,EXTK$ NETDF$ ; DEFINE NETWORK SYMBOLS FCSBT$ ; DEFINE FCS BIT DEFINITIONS CSI$ ; DEFINE CSI SYMBOLS ; ; LOCAL MACRO DEFINITIONS ; .MACRO XDIR$ DPB ; EXECUTE A DIRECTIVE MOV DPB,-(SP) CALL .XDIR .ENDM XDIR$ .MACRO CODE$ ; GENERATE CODE PSECT .PSECT CODE$ I,RO .ENDM CODE$ .MACRO DATA$ P1 ; GENERATE DATA PSECTS .IF IDN .PSECT DATA$P D,RO .IFF .PSECT DATA$I D,RW .ENDC .ENDM DATA$ .MACRO FUNC$ FUNCTN,ROUTIN ; DEFINE I/O FUNCTION DISPATCH ENTRY .WORD FUNCTN/256. .WORD ROUTIN .ENDM FUNC$ ; ; LUN AND EVENT FLAG DEFINITIONS ; .IOLUN=1 ; FILE/DEVICE I/O LUN .MBXLU=2 ; MAILBOX LUN .LLLUN=3 ; LOGICAL LINK LUN .IOEFN=1 ; I/O EVENT FLAG .NTEFN=2 ; NETWORK I/O EVENT FLAG .SDEFN=3 ; XMIT EVENT FLAG .RCEFN=4 ; RECEIVE EVENT FLAG ; ; DEFINE BUFFER SIZES AND NUMBERS ; RCVSIZ=40. ; SIZE OF STARTUP RECEIVE BUFFER GNDSIZ=N.CBL ; SIZE OF GND BUFFER NRBUFS=3 ; NUMBER OF RECEIVE BUFFERS NTBUFS=2 ; NUMBER OF TRANSMIT BUFFERS NBLOKS=2. ; 2. BLOCKS/BUFFER BUFSIZ=NBLOKS*512. ; SIZE OF BUFFERS IN BYTES .SBTTL MESSAGE FORMAT DEFINITIONS ; ; CONFIGURATION MESSAGE ; .ASECT .=0 TY.CON=0 ; CONFIGURATION MESSAGE TYPE C.TYPE: .BLKB 1 ; TYPE FIELD ( = TY.CON ) C.OST: .BLKB 1 ; OPERATING SYSTEM TYPE C.BUFL: .BLKB 2 ; MAXIMUM BUFFER LENGTH C.VER: .BLKB 2 ; VERSION NUMBER C.LGTH: ; LENGTH ; ; REQUEST MESSAGE ; .=0 TY.REQ=2 ; REQUEST MESSAGE TYPE R.TYPE: .BLKB 1 ; TYPE FIELD ( = TY.REQ) R.FLAG: .BLKB 1 ; REQUEST FLAGS R.FUNC: .BLKW 1 ; REQUESTED FUNCTION R.PARM: .BLKW 6 ; PARAMETERS R.SEQN: .BLKW 1 ; REQUEST SEQUENCE NUMBER RF.NST=1 ; NO STATUS REQUESTED FLAG RF.LAB=2 ; REQUEST IS ON LABELED MAG-TAPE R.LGTH: ; LENGTH ; ; STATUS MESSAGE ; .=0 TY.STA=4 ; STATUS MESSAGE TYPE S.TYPE: .BLKB 1 ; TYPE FIELD ( = TY.STA) .BLKB 1 ; UNUSED S.STAT: .BLKB 2 ; STATUS S.LEN: .BLKB 2 ; LENGTH OF I/O TRANSFERRED S.LGTH: ; LENGTH ; ; I/O KILL INTERRUPT MESSAGE ; .=0 TY.KIL=5 ; I/O KILL MESSAGE TYPE K.TYPE: .BLKB 1 ; TYPE FIELD ( = TY.KIL) .BLKB 1 ; UNUSED K.SEQN: .BLKW 1 ; SEQUENCE NUMBER OF REQUEST KILLED K.LGTH: ; LENGTH .PSECT .SBTTL BUFFER OFFSETS ; ; OFFSETS INTO THE BUFFERS USED FOR RECEIVES AND TRANSMITS ; .ASECT .=0 B.IOSB: .BLKW 2 ; I/O STATUS BLOCK B.STAT: .BLKW 1 ; BUFFER STATUS WORD B.NEXT: .BLKW 1 ; POINTER TO NEXT BUFFER B.DATA: .BLKB BUFSIZ ; DATA PORTION OF BUFFER B.LGTH: ; LENGTH OF BUFFER .PSECT ; ; DEFINE BUFFER STATUS BITS (R.STAT) ; BF.SYS=1 ; SYSTEM HAS ACCESS TO BUFFER .SBTTL BUFFERS AND IMPURE STORAGE ; ; BUFFERS ; DATA$ IMPURE RCVBUF: .BLKB RCVSIZ ; RECEIVE BUFFER GNDBUF: .BLKB GNDSIZ ; GND BUFFER BUFF1=RBUFFS+B.DATA ; ADDRESS OF FIRST BUFFER ; ; RECEIVE BUFFERS ; RNEXT: .WORD 0 ; POINTER TO NEXT RECEIVE BUFFER .WORD 0 ; USER NOTIFICATION FLAG RBUFFS: .REPT NRBUFS .BLKW 2 ; I/O STATUS BLOCKS .WORD 0 ; BUFFER STATUS WORD .WORD 0 ; BUFFER LINK WORD .BLKB BUFSIZ ; DATA PORTION OF BUFFER .ENDR ; ; TRANSMIT BUFFERS ; TNEXT: .WORD TBUFFS ; POINTER TO NEXT TRANSMIT BUFFER .WORD 0 ; USER NOTIFICATION FLAG $$$=0 TBUFFS: .REPT NTBUFS $$$=$$$+1 .BLKW 2 ; I/O STATUS BLOCKS .WORD 0 ; BUFFER STATUS WORD .IF GT NTBUFS-$$$ .WORD .+BUFSIZ+2 ; POINTER TO NEXT BUFFER .IFF .WORD 0 ; LAST BUFFER HAS ZERO POINTER .ENDC .BLKB BUFSIZ ; DATA BUFFER .ENDR ; ; STATUS BLOCKS ; IOSTAT: .BLKW 2 ; DEVICE I/O STATUS NSSTAT: .BLKW 2 ; NETWORK I/O STATUS SNDSTT: .BLKW 2 ; SEND STATUS RCVSTT: .BLKW 2 ; RECEIVE STATUS ; ; FILE DESCRIPTOR BLOCK ; FSRSZ$ 0 ; ALLOCATE BASIC FSR STORAGE DATA$ IMPURE FDB: FDBDF$ ; FDB FOR FILE OPERATIONS FDRC$A FD.RWM ; DECLARE BLOCK I/O ON FILE FDOP$A .IOLUN,,,FO.MFY ; SET FILE OPEN PARAMETERS FDAT$A R.FIX,,512.,4800. ; DEFINE RECORD ATTRIBUTES (FOR CREATE) ; ; CSI SWITCHES AND SWITCH TABLE ; DATA$ PURE SW$CR=1 ; CREATE FILE SW$CO=2 ; MAKE FILE CONTIGUOUS SW$BL=4 ; DECLARE NUMBER OF BLOCKS SW$TM=10 ; CREATE TEMPORARY FILE SW$RO=20 ; OPEN FILE READ ONLY CSITBL: CSI$SW CR,SW$CR,SWITCH ; /CR CSI$SW CO,SW$CO,SWITCH,,NEG ; /CO CSI$SW BL,SW$BL,SWITCH,,,BLTAB ; /BL:n CSI$SW TM,SW$TM,SWITCH,,NEG ; /TM CSI$SW RO,SW$RO,SWITCH,,NEG ; /RO CSI$ND BLTAB: CSI$SV DECIMAL,FDB+F.CNTG,2 ; VALUE FOR /BL:n SWITCH CSI$ND ; ; MISC. STORAGE ; DATA$ IMPURE BIAS: .WORD 0 ; BIAS FOR MAPPING LOGICAL/VIRT. BLOCKS CURBLK: .BLKW 2 ; NEXT BLOCK TO WRITE/READ CURLEN: .BLKW 1 ; LENGTH OF REMAINING DATA TO BE XFERRED CSIBLK: .BLKB C.SIZE ; CSI CONTROL BLOCK FUNC: .BLKW 1 ; REQUESTED FUNCTION FLAGS: .BLKW 1 ; REQUEST FLAGS PARAM: .BLKW 6 ; REQUEST PARAMETERS CURSEQ: .WORD 0 ; CURRENT REQUEST SEQUENCE NUMBER KILSEQ: .WORD 0 ; SEQUENCE NUMBER OF REQUEST TO KILL SWITCH: .WORD 0 ; FILE OPEN SWITCHES VDVVER: .BLKW 1 ; VERSION NUMBER OF PARTNER VDV KILFLG: .BYTE 0 ; FLAG TO INDICATE KILL REQUEST RECEIVED DAOFLG: .BYTE 0 ; FLAG TO INDICATE DATA OVERRUN REQUEST DEVTYP: .BLKB 1 ; DEVICE TYPE BIGFLG: .BLKB 1 ; FLAG TO INDICATE USING BIG BUFFER BIGPTR: .BLKW 1 ; POINTER TO FREE SPACE IN BIG BUFFER BIGSIZ: .BLKW 1 ; SIZE OF BIG BUFFER .BSIZE::.WORD 0 ; MINIMUM SIZE TO EXTEND BIG-BUFFER TO ; FOR MAG-TAPE OPERATIONS .SBTTL NETWORK DIRECTIVE DPB'S ; ; NETWORK DPB'S ; OPN: OPNW$ .MBXLU,.NTEFN,NSSTAT,,<1> DSC: DSCW$ .LLLUN,.NTEFN CLS: CLSW$ .MBXLU,.NTEFN GND: GNDW$ .MBXLU,.NTEFN,NSSTAT,, ACC: ACCW$ .LLLUN,.NTEFN,,, SPA: SPAW$ .MBXLU,.NTEFN,,, SND: SND$ .LLLUN,,,SNDAST REC: REC$ .LLLUN,,,RCVAST,<,BUFSIZ> SNDW: SNDW$ .LLLUN,.SDEFN,SNDSTT RECW: RECW$ .LLLUN,.RCEFN,RCVSTT,, SNDSTA: SND$ .LLLUN,,,, ; ; CONFIGURATION MESSAGE ; CONMSG: .BYTE TY.CON ; CONFIGURATION MESSAGE OSTYPE: .BYTE 1 ; OS TYPE (DEFAULT = RSX-11M) .WORD BUFSIZ ; MAXIMUM BUFFER SIZE .BYTE 1,1 ; VERSION 1.1 CONSIZ=.-CONMSG ; ; STATUS MESSAGE ; STAMSG: .BYTE TY.STA ; STATUS MESSAGE .BYTE 0 ; UNUSED STATUS: .BLKW 1 ; STATUS .BLKW 1 ; AND BYTES TRANSFERRED STASIZ=.-STAMSG .SBTTL RSX DIRECTIVE DPB'S ; ; RSX DPB'S ; QIOW: QIOW$ ,.IOLUN,.IOEFN ; READ/WRITE QIOW QIO: QIO$ IO.WLB,.IOLUN,,,,QIOAST ; WRITE-NO-STATUS QIO KILQIO: QIOW$ IO.KIL,.IOLUN,.IOEFN ; KILL I/O (FOR ATTACH TIMEOUT) MRKT: MRKT$ ,5,2,MRKAST ; MARK TIME FOR ATTACH TIMEOUT CMKT: CMKT$ ; CANCEL MARKTIME GLUN: GLUN$ .IOLUN,BUFF1 ; GET LUN INFO GTSK: GTSK$ GNDBUF ; GET TASK INFO EXTK: EXTK$ ; EXTEND TASK .SBTTL VDH MAIN LINE CODE ;+ ; **-VDH-VIRTUAL DEVICE HOST MAIN LINE CODE ; ; VDH IS INITIATED BY A CONNECT FROM A REMOTE VDV. IT PERFORMS DEVICE/FILE ; OPERATIONS ON BEHALF OF IT'S REMOTE PARTNER, AND RETURNS STATUS. ; ;- CODE$ VDH:: ; ; INITIALIZE AND CONNECT ; CALL OPNNET ; OPEN THE NETWORK, AND PERFORM PREAMBLE BCS 100$ ; IF CS, FATAL ERROR - EXIT CALL OPNFIL ; OPEN THE DEVICE/FILE ; ; HANG RECEIVES IN ALL AVAILABLE BUFFERS ; MOV #NRBUFS,R5 ; GET THE NUMBER OF RECEIVE BUFFERS MOV #RBUFFS,R4 ; POINT TO FIRST RECEIVE BUFFER 10$: CALL HNGRCV ; ISSUE A RECEIVE REQUEST BCS 100$ ; IF CS, FATAL ERROR - EXIT ADD #B.LGTH,R4 ; POINT TO NEXT BUFFER DEC R5 ; DO FOR ALL BUFFERS BNE 10$ ; ... ; ; GET A REQUEST AND PROCESS IT ; 20$: CALL WTRCV ; WAIT FOR A REQUEST BCS 100$ ; IF CS, EXIT CALL PROREQ ; ELSE, PROCESS THE REQUEST BCC 20$ ; AND LOOP ; ; CLEAN UP AND EXIT ; 100$: XDIR$ #DSC ; DISCONNECT THE LINK (IF THERE IS ONE) XDIR$ #CLS ; CLOSE OUR MAILBOX (IF OPEN) CALL CLSFIL ; CLEAN UP THE DEVICE/FILE EXIT$S ; BYE-BYE ! .SBTTL .XDIR - EXECUTE A DIRECTIVE ;+ ; **-.XDIR-EXECUTE A DIRECTIVE ; ; THIS ROUTINE EXECUTES A DIRECTIVE. IF THE DIRECTIVE FAILS ; DUE TO LACK IF RESOURCES, THE DIRECTIVE WILL BE RE-EXECUTED ; AFTER A SIGNIFICANT EVENT. ; ; INPUTS: ; 2(SP) = ADDRESS OF DPB ; ; OUTPUTS: ; DPB ADDRESS REMOVED FROM STACK ;- .XDIR: 10$: MOV 2(SP),-(SP) ; PUSH DPB ADDRESS ONTO STACK EMT 377 ; EXECUTE THE DIRECTIVE BCC 20$ ; IF CC, OKAY CMPB $DSW,#IE.UPN ; WAS ERROR "NO RESOURCES" ? SEC ; ASSUME NO, INDICATE ERROR BNE 20$ ; IF NE, NO - RETURN WITH ERROR WSIG$S ; ELSE, WAIT A WHILE BR 10$ ; AND TRY AGAIN 20$: MOV (SP)+,(SP) ; CLEAN DPB OFF STACK RETURN .SBTTL OPNNET - ACCESS NETWORK AND PERFORM PREAMBLE ;+ ; **-OPNNET-ACCESS NETWORK AND PERFORM PREAMBLE ;- OPNNET: ; ; ASSIGN LUNS, OPEN MAILBOX AND GET THE CONNECT ; ALUN$S #.MBXLU,#"NS ; ASSIGN MAILBOX LUN BCS 10$ ; IF CS, COULDN'T - EXIT ALUN$S #.LLLUN,#"NS ; ASSIGN LOGICAL LINK LUN BCS 90$ ; IF CS, COULDN'T - EXIT XDIR$ #OPN ; OPEN THE NET BCS 90$ ; IF CS, EXIT TSTB NSSTAT ; SUCCESS ? BMI 90$ ; IF MI, NO XDIR$ #SPA ; SET UP OUR NETWORK DATA AST 10$: BCS 90$ ; IF CS, EXIT CALL SPAAST ; GET THE ORIGINATING CONNECT ; ; EXCHANGE CONFIGURATION MESSAGES ; XDIR$ #RECW ; TRY TO GET CONFIGURATION MESSAGE TSTB RCVSTT ; ERROR ? BMI 90$ ; IF MI, YES CMPB RCVSTT+2,#6 ; DID WE GET ENOUGH DATA ? BLO 90$ ; IF LO, NO - BAD MESSAGE CMPB RCVBUF,#TY.CON ; WAS IT A CONFIGURATION MESSAGE ? BNE 90$ ; IF NE, NO - ERROR MOV RCVBUF+C.VER,VDVVER ; SAVE PARTNER'S VERSION NUMBER MOV #CONMSG,SNDW+Q.IOPL ; SET UP TO SEND CONFIGURATION MESSAGE MOV #CONSIZ,SNDW+Q.IOPL+2 ; ... XDIR$ #SNDW ; SEND A CONFIGURATION MESSAGE ; ; GET THE ATTACH REQUEST ; XDIR$ #RECW ; RECEIVE THE REQUEST TSTB RCVSTT ; ERROR ? BMI 90$ ; IF MI, YES CMPB RCVSTT+2,#R.LGTH-2 ; DID WE GET ENOUGH DATA ? BLO 90$ ; IF LO, NO - BAD MESSAGE CMPB RCVBUF,#TY.REQ ; WAS IT REQUEST MESSAGE ? BNE 90$ ; IF NE, NO - ERROR XDIR$ #RECW ; GET THE DEVICE/FILE NAME TSTB RCVSTT ; ERROR ? BPL 100$ ; IF PL, NO - GOT IT 90$: SEC ; INDICATE ERROR 100$: RETURN .SBTTL OPNFIL - ACCESS DEVICE/FILE ;+ ; **-OPNFIL-ACCESS DEVICE/FILE ;- OPNFIL: ; ; PARSE THE DEVICE/FILE NAME, ATTACH THE DEVICE, OR OPEN THE FILE ; CALL GETDEV ; OPEN THE FILE OR ATTACH THE DEVICE MOV #STAMSG,SNDW+Q.IOPL ; SET UP FOR SENDING STATUS MOV #STASIZ,SNDW+Q.IOPL+2 ; ... XDIR$ #SNDW ; AND SEND IT TSTB STATUS ; DO WE HAVE ACCESS TO THE DEVICE/FILE ? BMI 100$ ; IF MI, NO - RETURN ; ; RETURN DEVICE CHARACTERISTITICS (TYPE AND NUMBER OF BLOCKS) ; MOV #BUFF1,SNDW+Q.IOPL ; SET UP FOR SENDING REQUEST MOV #10.,SNDW+Q.IOPL+2 ; ... XDIR$ #SNDW ; SEND THE REQUEST 100$: RETURN ; AND OUT .SBTTL GETDEV - PARSE THE NAME, AND ACCESS DEVICE OR FILE ;+ ; **-GETDEV-PARSE THE NAME, AND ACCESS DEVICE OR FILE ; ; THIS ROUTINE PARSES THE SUPPLIED NAME. IF IT WAS A FILE, THE FILE IS ; OPENED, ELSE THE DEVICE IS ATTACHED. ; ;- GETDEV: ; ; PARSE THE NAME USING CSI$ ; MOVB #IE.BNM,STATUS ; ASSUME BAD NAME CSI$1 #CSIBLK,#RCVBUF,RCVSTT+2; SYNTAX CHECK COMMAND LINE BCS 100$ ; IF CS, BAD LINE CSI$2 ,OUTPUT,#CSITBL ; CREATE DATASET DESCRIPTOR BCS 100$ ; IF CS, BAD NAME - RETURN ; ; CHECK IF ANY FILE NAME FIELDS WERE SPECIFIED, IF NONE WERE, TRY TO ATTACH ; THE DEVICE AND GET ITS CHARACTERISTICS. ; CLR BIAS ; ASSUME I/O TO A DEVICE BITB #^C,C.STAT(R0) ; ANY FILE NAME FIELDS INCLUDED ? BNE 10$ ; IF NE, YES - OPEN FILE TST C.MKW1(R0) ; ANY SWITCHES SET ? BNE 100$ ; IF NE, YES - RETURN WITH ERROR CALL ATTDEV ; ELSE, ATTEMPT ATTACH TO DEVICE BR 100$ ; AND RETURN ; ; A FILE NAME WAS SPECIFIED - ATTEMPT TO OPEN IT ; 10$: INC BIAS ; SET LOGICAL TO VIRTUAL BLOCK BIAS CALL SETFDB ; SET UP THE FDB BASED ON SWITCHES BCS 100$ ; IF CS, BAD SWITCHES - ERROR CALL OPEN ; TRY TO OPEN THE FILE BCS 100$ ; IF CS, COULDN'T OPEN FILE MOV #1,BUFF1 ; ELSE, SAY THAT TYPE = DISK MOV BUFF1+4,BUFF1+2 ; RETURN SIZE (HIGH) MOV BUFF1+6,BUFF1+4 ; ... AND LOW MOV #512.,BUFF1+6 ; AND RETURN "DEVICE" BLOCK SIZE 100$: RETURN .SBTTL ATTDEV - ATTACH A DEVICE WITH TIMEOUT ;+ ; **-ATTDEV -ATTACH A DEVICE WITH TIMEOUT ; ; THIS ROUTINE ASSIGNS THE IOLUN TO THE DEVICE, GETS THE LUN INFO, ; ATTEMPTS TO ATTACH THE DEVICE WITHIN 5 SECONDS. ; ;- ATTDEV: MOV CSIBLK+C.DSDS+2,R0 ; POINT TO DEVICE NAME STRING MOV (R0)+,R5 ; GET DEVICE NAME CALL $COTB ; CONVERT UNIT NUMBER TO BINARY MOV #IE.BDV,IOSTAT ; ASSUME BAD DEVICE NAME ALUN$S #.IOLUN,R5,R1 ; ASSIGN LUN BCS 100$ ; IF CS, COULDN'T - RETURN DIR$ #GLUN ; GET LUN INFORMATION MOV #DEVTBL,R0 ; POINT TO START OF DEVICE TABLE BIC #^C,BUFF1+G.LUCW ; ISOLATE RELEVANT CHARACTERISTICS 10$: CMP BUFF1+G.LUCW,(R0) ; IS THIS THE CORRECT TYPE ? BEQ 20$ ; IF EQ, YES - SET THE ENTRY ADD #4,R0 ; POINT TO NEXT ENTRY TST (R0) ; LAST ENTRY ? BNE 10$ ; IF NE, NO - KEEP LOOKING 20$: MOV 2(R0),BUFF1 ; SAVE DEVICE TYPE MOVB 2(R0),DEVTYP ; ... MOV BUFF1+G.LUCW+2,BUFF1+2 ; SAVE U.CW2 MOV BUFF1+G.LUCW+4,BUFF1+4 ; ... AND U.CW3 MOV BUFF1+G.LUCW+6,BUFF1+6 ; ... AND U.CW4 XDIR$ #MRKT ; SPECIFY TIMEOUT AST MOV #IO.ATT,QIOW+Q.IOFN ; SET THE ATTACH FUNCTION MOV #IOSTAT,QIOW+Q.IOSB ; SET STATUS BLOCK ADDRESS XDIR$ #QIOW ; ATTEMPT THE ATTACH DIR$ #CMKT ; IF HERE, CANCEL THE MARKTIME 100$: MOVB IOSTAT,STATUS ; SETUP STATUS RETURN BMI 110$ ; IF MI, JUST RETURN WITH ERROR CALL INIBUF ; ELSE, SET UP BIG BUFFER IF NEEDED 110$: RETURN ; AND RETURN MRKAST: TST (SP)+ ; CLEAN OFF STACK XDIR$ #KILQIO ; KILL THE ATTACH MOV #IE.DAA&377,IOSTAT ; SET ERROR STATUS ASTX$S ; AND EXIT THE AST ; ; TABLE OF DEVICE CHARACTERISTICS AND TYPES ; DEVTBL: .WORD ; MULTI-DIRECTORY = .WORD 1 ; DISK .WORD ; RECORD, SEQUENTIAL = .WORD 2 ; TAPE .WORD ; RECORD, CARRAIGE CONTROL = .WORD 3 ; PRINTER .WORD 0 ; END OF TABLE = .WORD 0 ; UNKNOWN TYPE .SBTTL SETFDB - SET UP THE FDB FOR OPEN ;+ ; **-SETFDB -SET UP THE FDB FOR OPEN ; ; THIS ROUTINE IS CALLED TO INITIALIZE THE FDB BASED ON ; SWITCHES SUPPLIED WITH THE FILE NAME. ; ; INPUTS: ; R0 = ADDRESS OF CSI BLOCK ; ;- SETFDB: BIT #SW$CR,SWITCH ; IS THIS A FILE CREATE ? BEQ 20$ ; IF EQ, NO - OPEN EXISTING FILE ; ; FILE CREATION SWITCH PROCESSING ; BIT #SW$RO,SWITCH ; ANY CONFLICTING SWITCHES ? SEC ; ASSUME YES BNE 100$ ; IF NE, YES - ERROR MOVB #FO.WRT,FDB+F.FACC ; ELSE, SET "CREATE" ACCESS BIT #SW$CO,SWITCH ; IS FILE TO BE CONTIGUOUS ? BNE 10$ ; IF NE, YES - LEAVE POS NUMBER OF BLOCKS NEG FDB+F.CNTG ; ELSE, SET ALLOCATION NON-CONTIG 10$: BIT #SW$TM,SWITCH ; TEMPORARY FILE ? BEQ 90$ ; IF EQ, NO BISB #FA.TMP,FDB+F.FACC ; ELSE, SET TEMPORARY ACCESS BIT BR 90$ ; AND RETURN ; ; EXISTING FILE OPEN SWITCH PROCESSING ; 20$: BIT #SW$TM!SW$BL!SW$CO,SWITCH ; ANY CONFLICTING SWITCHES ? SEC ; ASSUME YES BNE 100$ ; IF NE, YES - ERROR BIT #SW$RO,SWITCH ; OPEN READ-ONLY ? BEQ 90$ ; IF EQ, NO - RETURN MOVB #FO.RD,FDB+F.FACC ; ELSE, SET OPEN FOR READ ACCESS 90$: CLC ; INDICATE SUCCESS 100$: RETURN .SBTTL OPEN - OPEN THE SPECIFIED FILE ;+ ; **-OPEN-OPEN THE SPECIFIED FILE ; ; THIS ROUTINE IS CALLED TO OPEN THE SPECIFIED FILE. ; ; OUTPUTS: ; R0 = ADDRESS OF FDB ; CC, IF FILE OPENED ; CS, IF FILE NOT OPENED ;- OPEN: FINIT$ ; INTIALIZE THE FILE SYSTEM ALUN$S #.IOLUN,GNDBUF+N.CDEV,GNDBUF+N.CUNI ; ASSIGN LUN TO DEFAULT SY: MOV #FDB,R0 ; POINT TO THE FDB MOV #FDB+F.FNB,R1 ; ... THE FILE NAME BLOCK MOV #CSIBLK+C.DSDS,R2 ; ... THE DATASET DESCRIPTOR CLR R3 ; ... NO DEFAULT FILENAME BLOCK CALL .PARSE ; PARSE THE FILE NAME BCS 10$ ; IF CS, RETURN MOV #BUFF1,F.STBK(R0) ; SET UP STATISTICS BLOCK ADDRESS OFNB$ ; TRY TO OPEN THE FILE 10$: MOVB F.ERR(R0),STATUS ; SET STATUS FOR RETURN RETURN .SBTTL INIBUF - INITIALIZE THE BIG BUFFER ;+ ; **-INIBUF-INITIALIZE THE BIG BUFFER ; ; THIS ROUTINE IS CALLED TO CALCULATE/EXTEND THE BIG BUFFER USED FOR ; LARGE MAG-TAPE TRANSFERS. ; ;- INIBUF: CMPB DEVTYP,#2 ; IS THE DEVICE A MAG-TAPE ? BNE 100$ ; IF NE, NO - NO NEED FOR BIG BUFFER DIR$ #GTSK ; ELSE, GET TASK PARAMETERS MOV GNDBUF+G.TSTS,BIGSIZ ; COPY TASK SIZE SUB #BIGBUF,BIGSIZ ; CALCULATE BIG BUFFER SIZE MOV .BSIZE,R0 ; GET THE SPECIFIED BIG BUFF SIZE SUB BIGSIZ,R0 ; SEE IF WE HAVE ENOUGH SPACE YET BLOS 100$ ; IF LOS, YES - NO NEED TO EXTEND MOV .BSIZE,BIGSIZ ; ELSE, ASSUME WE HAVE THE SPACE CALL EXTEND ; AND TRY TO EXTEND THE TASK BCC 100$ ; IF CC, GOT THE SPACE MOVB #IE.UPN&377,STATUS ; ELSE, SET UNSUFFICIENT RESOURCE ERROR 100$: RETURN .SBTTL EXTEND - EXTEND THE TASK ;+ ; **-EXTEND-EXTEND THE TASK ; ; THIS ROUTINE IS CALLED TO EXTEND THE TASK A SPECIFIED NUMBER OF BYTES. ; ; INPUTS: ; R0 = NUMBER OF BYTES TO EXTEND THE TASK ; ; OUTPUTS: ; CC = TASK SUCCESSFULLY EXTENDED ; CS = EXTEND FAILED ;- EXTEND: ADD #<32.*2>-1,R0 ; ROUND UP TO NEXT 32. WORD BLOCK ASR R0 ; DIVIDE BY 64. ASR R0 ; ... ASR R0 ; ... ASR R0 ; ... ASR R0 ; ... ASR R0 ; ... MOV R0,EXTK+E.XTIN ; SET EXTEND INCREMENT DIR$ #EXTK ; TRY TO EXTEND THE TASK RETURN .SBTTL CLSFIL - DEACCESS DEVICE/FILE ;+ ; **-CLSFIL-DEACCESS DEVICE/FILE ;- CLSFIL: TST BIAS ; DEVICE OR FILE I/O ? BNE 10$ ; IF NE, FILE - CLOSE IT XDIR$ #KILQIO ; ELSE, KILL ALL I/O TO THE DEVICE MOV #IO.DET,QIOW+Q.IOFN ; SET DETACH FUNCTION XDIR$ #QIOW ; DETACH DEVICE BR 100$ ; AND RETURN 10$: MOV #FDB,R0 ; POINT TO FDB MOV F.HIBK(R0),F.EFBK(R0) ; SET EOF BLOCK TO LAST BLOCK MOV F.HIBK+2(R0),F.EFBK+2(R0); ... MOV #-1,F.FFBY(R0) ; SET NO FREE BYTES IN LAST BLOCK CALL .CLOSE ; AND CLOSE THE FILE 100$: RETURN .SBTTL SPAAST - NETWORK DATA AST ROUTINE ;+ ; **-SPAAST-NETWORK DATA AST SERVICE ROUTINE ; ; THIS ROUTINE IS CALLED TO PROCESS NETWORK DATA. ; ;- SPAAST: 10$: XDIR$ #GND ; GET NETWORK DATA CMPB #IE.NDA,NSSTAT ; WAS THERE ANY DATA? BEQ 100$ ; IF EQ, NO - ALL DONE MOVB NSSTAT+1,R5 ; ELSE, GET DATA TYPE ASL R5 ; CONVERT TO WORD OFFSET CALL @GNDTAB-2(R5) ; DISPATCH TO CORRECT ROUTINE BR 10$ ; LOOK FOR MORE DATA 100$: ASTX$S ; EXIT THE AST RETURN ; OR RETURN IF CALLED ; ; NETWORK DATA DISPATCH TABLE ; GNDTAB: .WORD GNDCON ; CONNECT REQUEST .WORD GNDINT ; INTERRUPT MESSAGE .WORD GNDDSC ; DISCONNECTS .WORD GNDDSC ; 3 FLAVORS .WORD GNDDSC ; .. .WORD GNDPEM ; NETWORK EVENT .SBTTL GNDCON - PROCESS CONNECT REQUEST .SBTTL GNDINT - PROCESS INTERRUPT MESSAGE .SBTTL GNDDSC - PROCESS DISCONNECT .SBTTL GNDPEM - PROCESS NETWORK EVENT ;+ ; **-GNDCON-PROCESS CONNECT REQUEST ; ; ALL INCOMING CONNECTS ARE ACCEPTED ; ;- GNDCON: XDIR$ #ACC ; ACCEPT THE CONNECT RETURN ;+ ; **-GNDINT-PROCESS INTERRUPT MESSAGE ; ; KILL REQUEST INTERRUPTS ARE PROCESSED HERE, ALL OTHER INTERRUPT ; MESSAGES ARE IGNORED. ; ;- GNDINT: CMPB GNDBUF+K.TYPE,#TY.KIL ; IS THIS A KILL REQUEST ? BNE 100$ ; IF NE, NO - IGNORE IT MOV GNDBUF+K.SEQN,KILSEQ ; ELSE, SAVE THE SEQUENCE NUMBER INCB KILFLG ; INDICATE I/O BEING KILLED CMP CURSEQ,KILSEQ ; IS THE KILL FOR THE CURRENT REQUEST ? BNE 100$ ; IF NE, NO - WAIT TILL LATER XDIR$ #KILQIO ; ELSE, KILL ANY CURRENT I/O 100$: RETURN ;+ ; **-GNDDSC-PROCESS DISCONNECT ; ; DISCONNECTS ARE IGONORED, SINCE AT LEAST 1 RECEIVE IS OUTSTANDING ; AT A TIME, AND WILL GET IE.ABO COMPLETION STATUS. ; ;- GNDDSC: RETURN ; TOSS IT ;+ ; **-GNDPEM-PROCESS NETWORK EVENT ; ; ALL NETWORK EVENTS RECEIVED ARE IGNORED ; ;- GNDPEM: RETURN ; TOSS IT .SBTTL HNGRCV - ISSUE A RECEIVE ON A BUFFER ;+ ; **-HNGRCV-ISSUE A RECEIVE ON A BUFFER ; ; ISSUE A RECEIVE REQUEST ON A BUFFER AND LINK IT INTO THE LIST OF ; PENDING RECEIVES. ; ; INPUTS: ; R4 = ADDRESS OF BUFFER ; ;- HNGRCV: DSAR$S ; DISABLE AST'S MOV R0,-(SP) ; SAVE R0 MOV #RNEXT-B.NEXT,R0 ; POINT TO RECEIVE LISTHEAD CALL LINKBF ; LINK BUFFER INTO LIST MOV (SP)+,R0 ; RESTORE R0 BIS #BF.SYS,B.STAT(R4) ; SAY SYSTEM HAS THE BUFFER MOV R4,REC+Q.IOSB ; SET I/O STATUS BLOCK ADDRESS MOV R4,REC+Q.IOPL ; SET THE BUFFER ADDRESS ADD #B.DATA,REC+Q.IOPL ; POINT TO THE DATA AREA XDIR$ #REC ; ISSUE THE REQUEST ROR (SP) ; SAVE THE C-BIT STATUS ENAR$S ; ENABLE AST'S ROL (SP) ; RESTORE THE C-BIT RETURN .SBTTL XMIT - ISSUE A TRANSMIT ON A BUFFER ;+ ; **-XMIT-ISSUE A TRANSMIT ON A BUFFER ; ; ISSUE A TRANSMIT REQUEST ON A BUFFER AND LINK IT INTO THE TRANSMIT ; PENDING QUEUE. ; ; INPUTS: ; R3 = LENGTH OF DATA TO TRANSMIT ; R4 = ADDRESS OF BUFFER ; ;- XMIT: MOV R0,-(SP) ; SAVE R0 MOV #TNEXT-B.NEXT,R0 ; POINT TO TRANSMIT LISTHEAD CALL LINKBF ; LINK BUFFER INTO LIST MOV (SP)+,R0 ; RESTORE R0 BIS #BF.SYS,B.STAT(R4) ; SAY SYSTEM HAS THE BUFFER MOV R4,SND+Q.IOSB ; SET I/O STATUS BLOCK ADDRESS MOV R4,SND+Q.IOPL ; SET THE BUFFER ADDRESS ADD #B.DATA,SND+Q.IOPL ; POINT TO THE DATA AREA MOV R3,SND+Q.IOPL+2 ; SET THE TRANSMIT LENGTH XDIR$ #SND ; ISSUE THE REQUEST RETURN .SBTTL LINKBF - LINK BUFFER INTO END OF A LIST ;+ ;**-LINKBF-LINK A BUFFER INTO THE END OF A LIST ; ; THIS ROUTINE IS CALLED TO INSERT A BUFFER INTO THE RECEIVE OR ; TRANSMIT PENDING QUEUES. ; ; INPUTS: ; R0 = ADDRESS OF LISTHEAD-B.NEXT ; R4 = ADDRESS OF BUFFER ; ;- LINKBF: MOV R1,-(SP) ; SAVE R1 10$: MOV B.NEXT(R0),R1 ; POINT TO NEXT BUFFER BEQ 20$ ; IF EQ, AT END OF LIST MOV R1,R0 ; ELSE, CHANGE POINTERS BR 10$ ; AND KEEP LOOKING 20$: MOV R4,B.NEXT(R0) ; LINK THE BUFFER INTO END OF LIST CLR B.NEXT(R4) ; MAKE THIS BUFFER THE LAST MOV (SP)+,R1 ; RESTORE R1 RETURN .SBTTL WTRCV - WAIT FOR COMPLETION ON THE NEXT RECEIVE ;+ ; **-WTRCV-WAIT FOR COMPLETION ON THE NEXT RECEIVE ; ; THIS ROUTINE RETURNS WITH COMPLETION ON THE NEXT RECEIVE BUFFER. ; THE BUFFER IS UNLINKED FROM THE LIST. ; ; INPUTS: ; RNEXT = ADDRESS OF NEXT RECEIVE BUFFER ; ; OUTPUTS: ; R4 = BUFFER ADDRESS ; RNEXT = UPDATED TO POINT TO NEXT BUFFER ; ;- WTRCV: MOV #RNEXT,R4 ; POINT TO RECEIVE BUFFER LISTHEAD MOV #.RCEFN,R3 ; SET RECEIVE EVENT FLAG CALL WTBUF ; WAIT FOR RECEIVE CMPB (R4),#IE.ABO ; LINK ABORTED ? CLC ; ASSUME NO BNE 10$ ; IF NE, NO SEC ; ELSE, INDICATE ERROR 10$: RETURN .SBTTL WTSND - WAIT FOR ACCESS TO A SEND BUFFER ;+ ; **-WTSND-WAIT FOR ACCESS TO TRANSMIT BUFFER ; ; THIS ROUTINE RETURNS WITH ACCESS TO A TRANSMIT BUFFER. THE BUFFER IS ; UNLINKED FROM THE LIST. ; ; INPUTS: ; TNEXT = ADDRESS OF NEXT TRANSMIT BUFFER ; ; OUTPUTS: ; R4 = BUFFER ADDRESS ; TNEXT = UPDATED TO POINT TO NEXT BUFFER ; ;- WTSND: MOV #TNEXT,R4 ; POINT TO TRANSMIT BUFFER LISTHEAD MOV #.SDEFN,R3 ; SET RECEIVE EVENT FLAG CALL WTBUF ; WAIT FOR BUFFER CMPB (R4),#IE.ABO ; LINK ABORTED ? CLC ; ASSUME NO BNE 10$ ; IF NE, NO SEC ; ELSE, INDICATE ERROR 10$: RETURN .SBTTL WTBUF - WAIT FOR COMPLETION ON A BUFFER ;+ ; **-WTBUF-WAIT FOR COMPLETION ON THE NEXT BUFFER IN A LIST ; ; THIS ROUTINE RETURNS WITH COMPLETION ON THE NEXT BUFFER IN A LIST AND ; UNLINKS IT. ; ; INPUTS: ; R3 = EVENT FLAG FOR WAIT ; R4 = ADDRESS OF BUFFER LISTHEAD ; ; OUTPUTS: ; R4 = ADDRESS OF BUFFER ;- WTBUF: MOV R0,-(SP) ; SAVE R0 INC 2(R4) ; INDICATE USER WAITING FOR BUFFER 10$: MOV (R4),R0 ; GET ADDRESS OF FIRST BUFFER IN LIST BEQ 20$ ; IF EQ, LIST EMPTY - WAIT AROUND BIT #BF.SYS,B.STAT(R0) ; DOES THE SYSTEM HAVE THE BUFFER ? BEQ 30$ ; IF EQ, NO - BUFFER IS AVAILABLE 20$: WTSE$S R3 ; ELSE, WAIT FOR NOTIFICATION CLEF$S R3 ; CLEAR THE FLAG BR 10$ ; AND CHECK AGAIN 30$: CLR 2(R4) ; USER NO LONGER WAITING FOR BUFFER MOV B.NEXT(R0),(R4) ; UNLINK BUFFER FROM LIST MOV R0,R4 ; RETURN POINTER TO BUFFER MOV (SP)+,R0 ; RESTORE R0 RETURN .SBTTL PROREQ - PROCESS A REQUEST RECEIVED ;+ ; **-PROREQ-REQUEST MESSAGE RECEIVED PROCESSING ; ; THIS ROUTINE IS CALLED WHEN A REQUEST MESSAGE IS RECEIVED. IT DISPATCHES ; THE REQUEST TO THE APPROPRIATE ROUTINE BASE ON I/O FUNCTION CODE. ; ; INPUTS: ; R4 = BUFFER ADDRESS ; ;- PROREQ: ; ; CHECK THE MESSAGE FORMAT ; CMP 2(R4),#R.LGTH ; DID WE RECEIVE ENOUGH DATA ? BGE 2$ ; IF GE, YES CMP VDVVER,(PC)+ ; ELSE, IS THIS AN OLD VERSION ? .BYTE 1,0 ; ... (VERSION 1.0) BNE 90$ ; IF NE, NO - ERROR CMP 2(R4),#R.LGTH-2 ; FOR 1.0 WE'LL ALLOW 2 LESS BYTES BLT 90$ ; IF LT, IT'S STILL AN ERROR 2$: CMPB B.DATA+R.TYPE(R4),#TY.REQ ; IS IT A REQUEST MESSAGE ? BNE 90$ ; IF NE, NO - ERROR ; ; DISPATCH THE REQUEST BASED ON FUNCTION CODE ; MOV B.DATA+R.FUNC(R4),FUNC ; SAVE THE FUNCTION MOVB B.DATA+R.FLAG(R4),FLAGS ; SAVE THE REQUEST FLAGS MOV B.DATA+R.SEQN(R4),CURSEQ; SAVE THE CURRENT SEQUENCE NUMBER MOV R4,R1 ; COPY BUFFER POINTER ADD #B.DATA+R.PARM,R1 ; POINT TO PARAMETERS SUPPLIED MOV #PARAM,R5 ; POINT TO PARAMETERS SAVE AREA MOV #6,R3 ; 6 PARAMETERS TO SAVE 5$: MOV (R1)+,(R5)+ ; SAVE THEM DEC R3 ; ... BNE 5$ ; ... CALL HNGRCV ; HANG ANOTHER RECEIVE ON BUFFER BCS 90$ ; IF CS, RETURN WITH ERROR MOVB FUNC+1,R0 ; GET THE FUNCTION CODE MOV #FCNTBL,R1 ; POINT TO THE DISPATCH TABLE 10$: CMP R0,(R1)+ ; IS THIS THE CORRECT ROUTINE ? BEQ 20$ ; IF EQ, YES - CALL IT TST -2(R1) ; AT END OF TABLE ? BEQ 20$ ; IF EQ, YES - CALL IT ILLEGAL FUNCTION TST (R1)+ ; ELSE, SKIP OVER ROUTINE ADDRESS BR 10$ ; AND KEEP LOOKING 20$: CALL @(R1) ; DISPATCH TO CORRECT ROUTINE CMP CURSEQ,KILSEQ ; DID WE KILL THIS I/O ? BNE 100$ ; IF NE, NO, JUST EXIT THE AST CLRB KILFLG ; ELSE, INDICATE NO KILL PENDING BR 100$ ; AND EXIT AST 90$: SEC ; INDICATE ERROR 100$: RETURN ; ; I/O FUNCTION DISPATCH TABLE ; FCNTBL: FUNC$ IO.WLB,WRITE ; WRITE LOGICAL BLOCK FUNC$ IO.RLB,READ ; READ LOGICAL BLOCK FUNC$ IO.RLV,READ ; READ LOGICAL BLOCK REVERSE FUNC$ IO.EOF,NOTRAN ; WRITE END-OF-FILE MARK FUNC$ IO.ERS,NOTRAN ; ERASE TAPE FUNC$ IO.RWD,NOTRAN ; REWIND FUNC$ IO.RWU,NOTRAN ; REWIND AND TURN UNIT OFF-LINE FUNC$ IO.SEC,NOTRAN ; SENSE TAPE CHARACTERISTICS FUNC$ IO.SMO,NOTRAN ; MOUNT AND SENSE TAPE CHARACTERISTICS FUNC$ IO.SPB,NOTRAN ; SPACE BLOCKS FUNC$ IO.SPF,NOTRAN ; SPACE FILES FUNC$ IO.STC,NOTRAN ; SET TAPE CHARACTERISTICS FUNC$ 0,ILEGAL ; END OF TABLE .SBTTL ILEGAL - PROCESS AN ILLEGAL FUNCTION CODE ;+ ; **-ILEGAL-PROCESS AN ILLEGAL FUNCTION CODE ; ; THIS ROUTINE RETURNS I/O STATUS OF IE.IFC ; ;- ILEGAL: MOV #IE.IFC&377,STATUS ; SET STATUS RETURN CLR STATUS+2 ; ... XDIR$ #SNDSTA ; AND RETURN IT RETURN .SBTTL WRITE - PROCESS WRITE REQUESTS ;+ ; **-WRITE-PROCESS WRITE REQUEST ; ; THIS ROUTINE WAITS FOR RECEIVE COMPLETION, AND WRITES TO THE DEVICE/FILE. ; A STATUS MESSAGE IS OPTIONALLY SENT. ; ;- WRITE: CALL TSTBIG ; SET UP BIG BUFFER IF NEEDED CLR STATUS+2 ; NO BYTES WRITTEN MOV PARAM,CURLEN ; SAVE LENGTH OF WRITE REQUEST MOV #QIOW,R0 ; ASSUME WRITE WITH WAIT BITB #RF.NST,FLAGS ; IS THIS A WRITE WITHOUT STATUS ? BEQ 10$ ; IF EQ, NO MOV #QIO,R0 ; ELSE, YES - DON'T WAIT ON QIO 10$: MOV PARAM+2,Q.IOPL+4(R0) ; SET VFC FOR WRITE MOVB PARAM+4,CURBLK ; SAVE BLOCK NUMBER (HIGH) MOV PARAM+6,CURBLK+2 ; ... AND LOW MOV #IO.WLB,Q.IOFN(R0) ; ASSUME LOGICAL BLOCK WRITES (DEVICE) TST BIAS ; LOGICAL I/O ? BEQ 20$ ; IF EQ, YES ADD BIAS,CURBLK+2 ; ELSE, ADD IN VIRTUAL BLOCK BIAS ADC CURBLK ; ... MOV #IO.WVB,Q.IOFN(R0) ; AND SET CORRECT FUNCTION CODE ; ; PROCESS ALL BUFFERS REQUIRED FOR THIS WRITE ; 20$: CALL WTRCV ; WAIT FOR A RECEIVE BUFFER BCS 100$ ; IF CS, JUST RETURN SUB B.IOSB+2(R4),CURLEN ; UPDATE REMAINING WRITE LENGTH MOV R4,Q.IOSB(R0) ; SET STATUS BLOCK ADDRESS MOV B.IOSB+2(R4),Q.IOPL+2(R0) ; SET COUNT TO WRITE MOV R4,Q.IOPL(R0) ; AND BUFFER ADDRESS ADD #B.DATA,Q.IOPL(R0) ; ... MOVB CURBLK,Q.IOPL+6(R0) ; SET HIGH BLOCK NUMBER MOV CURBLK+2,Q.IOPL+10(R0) ; AND LO BLOCK NUMBER CALL XQTWLB ; ISSUE THE WRITE BIT #RF.NST,FLAGS ; IS THIS A WRITE WITHOUT STATUS ? BNE 30$ ; IF NE, YES - DON'T HANG A RECEIVE CALL HNGRCV ; START ANOTHER RECEIVE ON BUFFER BCS 100$ ; IF CS, RETURN WITH ERROR 30$: TST CURLEN ; ANOTHER BUFFER COMING ? BNE 20$ ; IF NE, YES CALL BIGIO ; ISSUE THE BIG BUFFER I/O IF NEEDED BIT #RF.NST,FLAGS ; IS THIS A WRITE WITHOUT STATUS ? BNE 100$ ; IF NE, YES - DON'T SEND IT! XDIR$ #SNDSTA ; ELSE, SEND THE STATUS 100$: RETURN .SBTTL READ - PROCESS READ REQUESTS ;+ ; **-READ-PROCESS READ REQUEST ; ; THIS ROUTINE ISSUES INITIAL READS AND TRANSMITTS ON ALL BUFFERS. ; ;- READ: CALL TSTBIG ; SET UP BIG BUFFER IF NEEDED CLR STATUS+2 ; NO BYTES READ MOV PARAM,CURLEN ; SAVE LENGTH OF READ REQUEST MOV #QIOW,R0 ; POINT TO THE QIO DPB MOV PARAM+2,Q.IOPL+4(R0) ; SET VFC MOVB PARAM+4,CURBLK ; SAVE BLOCK NUMBER (HIGH) MOV PARAM+6,CURBLK+2 ; ... AND LOW MOV #IO.RLB,Q.IOFN(R0) ; ASSUME LOGICAL BLOCK READS (DEVICE) TST BIAS ; I/O TO A FILE ? BEQ 10$ ; IF EQ, NO ADD BIAS,CURBLK+2 ; ELSE, ADD IN VIRTUAL BLOCK BIAS ADC CURBLK ; ... MOV #IO.RVB,Q.IOFN(R0) ; AND SET CORRECT FUNCTION CODE 10$: CMPB FUNC,#IO.RLV ; READ REVERSE REQUEST ? BNE 11$ ; IF NE, NO - IO.RLB MOV #IO.RLV,Q.IOFN(R0) ; ELSE, SET IO.RLV FUNCTION CODE 11$: CALL BIGIO ; ISSUE BIG BUFFER READ IF NEEDED 12$: CALL WTSND ; WAIT FOR ACCESS TO BUFFER BCS 100$ ; IF CS, FATAL ERROR MOV CURLEN,R1 ; GET THE REMAINING TRANSMIT COUNT CMP R1,#BUFSIZ ; WILL IT FIT INTO A BUFFER ? BLOS 20$ ; IF LOS, YES MOV #BUFSIZ,R1 ; ELSE, ONLY READ A BUFFER FULL 20$: SUB R1,CURLEN ; UPDATE REMAINING READ COUNT MOV R4,Q.IOSB(R0) ; SET I/O STATUS BLOCK ADDRESS MOV R4,Q.IOPL(R0) ; SET READ BUFFER ADDRESS ADD #B.DATA,Q.IOPL(R0) ; ... MOV R1,Q.IOPL+2(R0) ; SET READ LENGTH MOVB CURBLK,Q.IOPL+6(R0) ; SET HIGH BLOCK NUMBER MOV CURBLK+2,Q.IOPL+10(R0) ; AND LOW BLOCK CALL XQTRLB ; ISSUE THE READ MOV 2(R4),R3 ; SET LENGTH OF TRANSMIT BNE 30$ ; IF NE, SOMETHING TO TRANSMIT INC R3 ; ELSE, XMIT 1 BYTE ANYWAY 30$: CMP R3,Q.IOPL+2(R0) ; DOES 2ND IOSB WORD SEEM TOO BIG ? ; (MORE BYTES READ THAN REQUESTED) BLOS 40$ ; IF LOS, NO - USE RETURNED COUNT MOV Q.IOPL+2(R0),R3 ; ELSE, SET NEW COUNT 40$: CALL XMIT ; AND TRANSMIT THE BUFFER BCS 100$ ; IF CS, RETURN WITH ERROR TST CURLEN ; ALL DONE ? BNE 12$ ; IF NE, NO - CONTINUE XDIR$ #SNDSTA ; ELSE, SEND THE STATUS 100$: RETURN .SBTTL NOTRAN - PROCESS NON-TRANSFER REQUESTS ;+ ; **-NOTRAN-PROCESS NON-TRANSFER REQUESTS ; ; THIS ROUTINE ISSUES NON-TRANSFER I/O REQUESTS TO THE DEVICE. ; A STATUS MESSAGE IS RETURNED. ; ;- NOTRAN: MOV #QIOW,R0 ; USE WRITE WITH WAIT MOV FUNC,Q.IOFN(R0) ; SET FUNCTION FOR I/O MOV PARAM,Q.IOPL(R0) ; SET MAX OF 1 PARAMETER CLR Q.IOPL+2(R0) ; ... MOV #STATUS,R4 ; POINT TO THE STATUS BLOCK MOV R4,Q.IOSB(R0) ; SET STATUS BLOCK ADDRESS CALL XQTQIO ; ISSUE THE I/O CALL CHKEOV ; CHECK END-OF-VOLUME STATUS XDIR$ #SNDSTA ; SEND THE STATUS MESSAGE RETURN .SBTTL CHKEOV - CHECK END-OF-VOLUME STATUS ;+ ; **-CHKEOV-CHECK END-OF-VOLUME STATUS ; ; THIS ROUTINE IS NEEDED TO BE COMPATIBLE WITH THE RSX MAG-TAPE DRIVER. ; THE DRIVER HANDLES SPACE FUNCTIONS DIFFERENTLY FOR LABELED AND UN-LABELED ; MAG-TAPES. IF AN IE.EOV ERROR IS RETURNED ON A SPACE FUNCTION FOR A ; LABELED TAPE, AN IO.RLB IS PERFORMED TO MOVE THE TAPE OVER THE EOV ; MARK. ; ; INPUTS: ; R0 = ADDRESS OF QIO DPB ; R4 = ADDRESS OF I/O STATUS BLOCK ; ;- CHKEOV: CMPB #IE.EOV,(R4) ; END-OF-VOLUME STATUS ? BNE 10$ ; IF NE, NO - RETURN BITB #RF.LAB,FLAGS ; IS THIS A LABELED MAG-TAPE ? BEQ 10$ ; IF EQ, NO MOV #IO.RLB,Q.IOFN(R0) ; ELSE, SET UP FOR READ LOGICAL MOV #RCVBUF,Q.IOPL(R0) ; READ INTO SCRATCH BUFFER MOV #RCVSIZ,Q.IOPL+2(R0) ; ... MOV 2(R4),-(SP) ; SAVE SECOND I/O STATUS WORD CALL XQTQIO ; EXECUTE THE I/O MOV #IS.SUC,(R4) ; RETURN SUCCESS STATUS MOV (SP)+,2(R4) ; RESTORE SECOND I/O STATUS WORD 10$: RETURN .SBTTL XQTQIO - EXECUTE A QIO REQUEST ;+ ; **-XQTQIO-EXECUTE A QIO REQUEST ; ; THIS ROUTINE EXECUTES A QIO, UNLESS THE CURRENT I/O IS BEING ; FINISHED IN ERROR.. THEN THE I/O IS NOT ISSUED, AND A ERROR ; IS RETURNED. ; ; INPUTS: ; R0 = ADDRESS OF QIO DPB ; R4 = ADDRESS OF I/O STATUS BLOCK ; ; OUTPUTS: ; R4 = ADDRESS OF I/O STATUS BLOCK, FILLED IN ; ;- XQTQIO: TSTB KILFLG ; VALID KILL REQUEST RECEIVED ? BNE 5$ ; IF NE, YES TSTB DAOFLG ; DATA OVERRUN ERROR ? BEQ 10$ ; IF EQ, NO - ISSUE I/O MOV #IE.DAO&377,(R4) ; ELSE, SET DATA OVERRUN ERROR BR 7$ ; ... 5$: CMP CURSEQ,KILSEQ ; ELSE, IS THIS THE REQUEST KILLED ? BNE 10$ ; IF NE, NO - ISSUE I/O MOV #IE.ABO&377,(R4) ; SET THE ABORT STATUS 7$: CLR 2(R4) ; INDICATE 0 BYTES TRANSFERRED BR 20$ ; AND RETURN 10$: XDIR$ R0 ; ISSUE THE QIO 20$: RETURN .SBTTL TSTBIG - TEST FOR AND SET UP BIG BUFFER I/O ;+ ; **-TSTBIG-TEST FOR AND SET UP BIG BUFFER I/O ; ; THIS ROUTINE CHECKS TO SEE IF THE I/O REQUEST NEEDS TO USE THE ; BIG BUFFER. THIS OCCURS IF THE BYTE COUNT IS GREATER THAN A ; STANDARD BUFFER, AND THE DEVICE IS A MAG-TAPE. THIS AVOIDS ; FRAMENTING DATA RECORDS. ; ;- TSTBIG: CLRB BIGFLG ; ASSUME NOT A BIG BUFFER I/O CLRB DAOFLG ; ASSUME NOT A DATA OVERRUN MOV PARAM,R0 ; GET REQUEST SIZE CMP R0,#BUFSIZ ; WILL REQUEST FIT IN NORMAL BUFFERS ? BLOS 100$ ; IF LOS, YES - USE THEM CMPB DEVTYP,#2 ; ELSE, IS THIS A MAG-TAPE REQUEST ? BNE 100$ ; IF NE, NO - NO PROBLEM WITH SEQMENTING SUB BIGSIZ,R0 ; WILL REQUEST FIT IN THE BIG BUFFER ? BLOS 10$ ; IF LOS, YES - USE IT CALL EXTEND ; ELSE, TRY TO EXTEND THE TASK BCS 5$ ; IF CS, COULDN'T - SET ERROR FLAG MOV PARAM,BIGSIZ ; ELSE, SET NEW BUFFER SIZE BR 10$ ; AND CONTINURE 5$: INCB DAOFLG ; ELSE, FLAG DATA OVERRUN ERROR BR 100$ ; ... 10$: INCB BIGFLG ; INDICATE BIG BUFFER I/O MOV #BIGBUF,BIGPTR ; SET UP INITIAL BUFFER POINTER 100$: RETURN .SBTTL XQTWLB - EXECUTE THE IO.WLB REQUEST .SBTTL XQTRLB - EXECUTE THE IO.RLB REQUEST ;+ ; **-XQTWLB-EXECUTE THE IO.WLB REQUEST ; **-XQTRLB-EXECUTE THE IO.RLB REQUEST ; ; THESE ROUTINES WILL EITHER ISSUE THE I/O REQUESTS, OR IF ; THE CURRENT REQUEST IS A BIG BUFFER REQUEST, THE DATA IS ; MOVED TO/FROM THE BIG BUFFER. ; ; INPUTS: ; R0 = ADDRESS OF QIO DPB ; R4 = ADDRESS OF I/O STATUS BLOCK ; ;- .ENABL LSB XQTWLB: MOV Q.IOPL(R0),R1 ; POINT TO DATA TO WRITE MOV BIGPTR,R3 ; POINT TO PLACE IN BIG BUFFER BR 10$ ; JOIN COMMON CODE XQTRLB: MOV BIGPTR,R1 ; POINT TO DATA TO XMIT MOV Q.IOPL(R0),R3 ; POINT TO XMIT BUFFER 10$: TSTB BIGFLG ; IS THIS A BIG BUFFER I/O ? BNE 20$ ; IF NE, YES CALL XQTQIO ; ELSE, EXECUTE THE QIO MOVB (R4),STATUS ; ELSE, SAVE THE I/O STATUS ADD 2(R4),STATUS+2 ; AND TOTAL UP THE BYTE COUNT ADD #BUFSIZ/512.,CURBLK+2 ; UPDATE THE BLOCK POINTER ADC CURBLK ; ... BR 30$ ; ... RETURN 20$: MOV Q.IOPL+2(R0),R2 ; GET THE BYTE COUNT ADD R2,BIGPTR ; UPDATE THE BIG BUFFER POINTER MOVB #IS.SUC,(R4) ; DUMMY UP SUCCESS STATUS MOV R2,2(R4) ; ... AND THE "I/O" BYTE COUNT BLXIO: INC R2 ; ROUND UP BYTE COUNT ASR R2 ; COVERT TO WORDS 25$: MOV (R1)+,(R3)+ ; COPY THE DATA DEC R2 ; ... BNE 25$ ; ... 30$: RETURN .DSABL LSB .SBTTL BIGIO - ISSUE I/O REQUEST FROM BIG BUFFER ;+ ; **-BIGIO-ISSUE I/O REQUEST FROM THE BIG BUFFER ; ; THIS ROUTINE IS CALLED TO ISSUE THE I/O REQUEST TO/FROM THE ; BIG BUFFER, IF IT IS BEING USED. ; ; INPUTS: ; R0 = ADDRESS OF QIO DPB ; ;- BIGIO: TSTB BIGFLG ; IS THIS A BIG BUFFER I/O ? BEQ 10$ ; IF EQ, NO MOV #BIGBUF,Q.IOPL(R0) ; ELSE, SET BIG BUFFER ADDRESS MOV PARAM,Q.IOPL+2(R0) ; ... SET LENGTH MOV PARAM+4,Q.IOPL+6(R0) ; ... SET BLOCK NUMBER MOV PARAM+6,Q.IOPL+10(R0) ; ... MOV #STATUS,R4 ; USE THE STATUS MESSAGE I/O SB MOV R4,Q.IOSB(R0) ; ... CALL XQTQIO ; ISSUE THE I/O 10$: RETURN .SBTTL QIOAST - WRITE-WITHOUT-STATUS COMPLETION ;+ ; **-QIOAST-WRITE-WITHOUT STATUS COMPETION AST ; ; THIS ROUTINE IS CALLED WHEN A QIO WRITE WITHOUT WAIT IS COMPLETED. ; IT ISSUES ANOTHER RECEIVE REQUEST INTO THE BUFFER. ; ;- QIOAST: MOV R4,-(SP) ; FREE UP R4 MOV 2(SP),R4 ; GET THE BUFFER ADDRESS CALL HNGRCV ; ISSUE ANOTHER RECEIVE REQUEST INTO IT MOV (SP)+,R4 ; RESTORE R4 TST (SP)+ ; CLEAN UP STACK ASTX$S ; EXIT THE AST .SBTTL RCVAST - MESSAGE RECEIVED PROCESSING ;+ ; **-RCVAST-MESSAGE RECEIVED PROCESSING ; ; THIS ROUTINE IS CALL WHEN A RECEIVE AST IS SPRUNG ; ;- RCVAST: MOV R4,-(SP) ; FREE UP R4 MOV 2(SP),R4 ; GET THE BUFFER ADDRESS BIC #BF.SYS,B.STAT(R4) ; SYSTEM NO LONGER HAS THE BUFFER TST RNEXT+2 ; USER WAITING FOR BUFFER ? BEQ 10$ ; IF EQ, NO SETF$S #.RCEFN ; ELSE, SET THE EVENT FLAG 10$: MOV (SP)+,R4 ; RESTORE R4 TST (SP)+ ; CLEAN UP STACK ASTX$S .SBTTL SNDAST - DATA TRANSMIT COMPLETE PROCESSING ;+ ; **-SNDAST-DATA RECEIVE COMPLETE PROCESSING ; ; THIS ROUTINE IS ENTERED AT AST LEVEL WHEN A DATA MESSAGE HAS BEEN ; TRANSMITTED. ; ;- SNDAST: MOV R4,-(SP) ; FREE UP R4 MOV 2(SP),R4 ; GET THE BUFFER ADDRESS BIC #BF.SYS,B.STAT(R4) ; SYSTEM NO LONGER HAS THE BUFFER TST TNEXT+2 ; IS THE USER WAITING FOR THE BUFFER ? BEQ 10$ ; IF EQ, NO SETF$S #.SDEFN ; ELSE, SET THE FLAG 10$: MOV (SP)+,R4 ; RESTORE R4 TST (SP)+ ; CLEAN UP THE STACK ASTX$S ; EXIT THE AST .END VDH