.TITLE VTDRV .IDENT /V3.00/ .NLIST BEX .ENABL LC ;******************************************************************** ; ; Virtual Terminal Driver for use with Batch System Version 3. ; ; This version supports multiple batch streams. The maximum ; number that can be handled depends on the data base. This ; code is not affected by that number. ; ; Version: V1 1979 ; Version: V2 1980 ; Version: V3 April 1983 ; ;--------------------------------------------------------------------- ; ; This driver, and the rest of the batch system, assumes a certain ; minimum amount of support in the operating system. In order for ; the system as a whole to work, the following support must be ; SYSGENed into the exec: ; ; 1. RSX-11M V4.0 (will not run on V3.2 and earlier) ; ; 2. M$$MGE Memory management hardware. ; ; 3. A$$BIO Asynchronous buffered I/O (always included if ; the full duplex terminal driver is present). ; ; 4. D$$YNM Dynamic memory allocation. ; ; 5. P$$OFF Parent/Offspring tasking. ; ; 6. S$$TOP Stop-bit support. ; ; 7. M$$MUP Multi-user support. ; ; 8. L$$DRV Loadable driver support (this driver can be ; built as resident if you desire by commenting ; out the definition of the symbol LD$VT in the ; file VTTAB.MAC). ; ; 9. C$$SMT Cancel selective marktimes. ; ; 10. QMG... Queue Manager. ; ;-------------------------------------------------------------------- ; ; N O T E ; ; If this driver is assembled during a SYSGEN (ie without the ; BV3PRE.MAC pre-assembly file), the following assumptions will ; be made: ; ; 1. Batch-external I/O from privileged tasks is allowed (the ; symbol B3$XIO will be defined). ; ; 2. Batch-external I/O from privileged tasks is forced to give ; a SYS category history file message (the symbol B3$FSY will ; be defined). ; ;--------------------------------------------------------------------- ; ; Steve Thompson ; School of Chemical Engineering ; Olin Hall ; Cornell University ; Ithaca NY 14853 ; (607) 256 3895 ; ;******************************************************************** .IIF NDF A$$BIO, .ERROR ; BUFFERRED I/O NOT SUPPORTED .IIF NDF M$$MGE, .ERROR ; MEMORY MANAGEMENT NOT SUPPORTED .IIF NDF D$$YNM, .ERROR ; DYNAMIC MEMORY ALLOCATION NOT SUPPORTED .IF NDF,B3$BAT B3$XIO = 0 ; Allow external privileged I/O B3$FSY = 0 ; Force it to SYS-class message MD$SHF = 240 ; SYS message goes to history file .ENDC ; NDF,B3$BAT ; ; Driver dispatch table ; .WORD VTDEA ; Buffer deallocation entry point $VTTBL::.WORD VTINI ; Initiator entry point .WORD VTCAN ; Cancel I/O entry point .WORD VTOUT ; Timeout entry point .WORD VTPWF ; Power fail entry point ;+ ; *** VTINI Batch stream driver entry point. ; ; This routine is entered from the queue I/O directive when an I/O request ; is queued and at the end of a previous I/O operation to propagate the execu- ; tion of the driver. The $GSPKT routine is called to perform selective ; acceptance of packets in the I/O queue. If no packets are present, a ; return to the Executive is made. For details of what is accepted, see ; the ACCEPT routine. If a packet is accepted, it is dequeued and the ; data transfer is performed. The UCB that we will finally get is not ; known on entry to $GSPKT, since all UCBs are on the same controller. ; ; Inputs: ; ; R5 Address of any UCB. ; ;- VTDONE: RETURN ; Return to exec if no work VTINI: MOV #ACCEPT,R2 ; Set acceptance routine address CALL $GSPKT ; Try to find an I/O packet ; for this unit BCS VTDONE ; If CS, no work to do ; ; The following arguments are returned by $GSPKT: ; ; R1 address of the I/O request packet. ; R2 physical unit number of the request UCB. ; R3 controller index [ always zero ] ; R4 address of the status control block. ; R5 address of the UCB to which I/O is directed ; ; Batch stream I/O request packet format: ; ; Word 00 I.LNK I/O queue thread word. ; Word 01 I.PRI,I.EFN Request priority, event flag number. ; Word 02 I.TCB Address of the TCB of the requester task. ; Word 03 I.LN2 Pointer to the second LUN word in the ; requestor task header. ; Word 04 I.UCB Contents of the first LUN word in the ; requester task header (UCB address). ; Word 05 I.FCN I/O function code. ; Word 06 I.IOSB Virtual address of I/O status block. ; Word 07 I.IOSB+2 Relocation bias of I/O status block. ; Word 10 I.IOSB+4 I/O status block address (real or displacement ; + 140000). ; Word 11 I.AST Virtual address of AST service routine. ; Word 12 I.PRM Relocation bias of I/O buffer. ; Word 13 I.PRM+2 Buffer address of I/O transfer. ; Word 14 I.PRM+4 Number of bytes to be transfered. ; Word 15 I.PRM+6 Carriage control (write functions only) ; Word 16 I.PRM+10 Not used. ; Word 17 I.PRM+12 Not used. ; Word 20 I.PRM+14 Not used. ; Word 21 I.PRM+16 Not used (UMD parameter word) ; ; MOV I.TCB(R1),R0 ; Get TCB address of requesting task CMPB #IO.WLB/256.,I.FCN+1(R1) ; Is it a write function? BEQ WLBFCN ; Yes ; If it's not a write, it must be a read ; or it wouldn't have got this far, so ; fall through to read code .PAGE ;-------------------------------------------------------------------- ; ; R E A D F U N C T I O N ; ========================= ; ; An IO.RLB function is handled as follows: ; ; 1. If there is no job active on the specified batch stream, ; the error code IE.EOF is returned. Else: ; ; 2. If the request was issued by a task running in the batch ; stream, the request is transferred to the batch processor ; (see below). Else: ; ; 3. If the request was not issued by the batch processor, ; the error code IE.EOF is returned. Else: ; ; 4. If the request was from the batch processor and the data ; base indicated that a read was already outstanding, the ; error code IE.EOF is returned (we should really crash the ; system here since this is a no-no). Else: ; ; 5. A read from the batch processor with no previous read out- ; standing is an indication to stash away the I/O packet ; until a job tries to do some output. ; RLBFCN: TST U.BTCB(R5) ; Batch processor active? BEQ IEEOF ; If EQ no, send IE.EOF CMP T.UCB(R0),R5 ; Read by batch job? BEQ JOBRLB ; If EQ yes, send to processor CMP U.BTCB(R5),R0 ; Read by batch processor? BNE IEEOF ; If NE no, send IE.EOF error TST U.BPKT(R5) ; Yes, read already outstanding? BNE IEEOF ; If NE yes, this is a no-no CMP I.PRM+4(R1),#3 ; Buffer at least three bytes long? BGE 10$ ; If GE yes MOV #IE.BAD&377,R0 ; Set bad buffer status BR VTALT ; and finish the I/O 10$: ; Ref. label ; ; Batch processor is trying to read. Since it may be a long time until ; the batch job next does any output, this function is buffered. ; MOV R1,U.BPKT(R5) ; Stash away the read CLR I.PRM+16(R1) ; Show that it's not buffered (yet) MOV R1,R3 ; Copy I/O packet address CALL $TSTBF ; Can we buffer this read? BCS VTINI ; If CS no, try for a batch write MOV I.UCB(R3),R5 ; Make sure we have the UCB address CALL $INIBF ; Initiate buffering BR VTINI ; Try for more work ; ; Status returns. Note that control may be transferred to the entry points ; IEEOF, VTALT and VTFIN only if the function being terminated has been ; dealt with in a single pass through the driver. This is because there is ; only one SCB for all UCBs, and so the S.PKT field is only valid if ; this condition is satisfied. ; IEEOF: MOV #IE.EOF&377,R0 ; Set end of file code VTALT: CLR R1 ; Zero bytes transferred VTFIN: MOV S.PKT(R4),R3 ; Get I/O packet address VTFN1: CALL $IOFIN ; Finish this I/O BR VTINI ; Try for more work .PAGE ;+ ; ; R E A D D A T A F R O M J O B ; =================================== ; ; When a task in the batch stream does a read request, the I/O ; packet is transferred to the batch processor so that it can ; satisfy the request. Since we only come here when the batch ; processor has a read outstanding, a read is handled by sending ; the error code IE.DAO to the batch processor, with the readers' ; I/O packet address in the second word of the I/O status block. ; It is then the responsibility of the batch processor to do ; something with this request. ; ; Inputs: ; R1 Reader's I/O packet address ; ;- JOBRLB: MOV U.BPKT(R5),R3 ; Get batch processor's read I/O ; packet address CLR U.BPKT(R5) ; Show it done with TST I.PRM+16(R3) ; Buffered read by processor? BEQ 10$ ; If EQ no MOV U.BTCB(R5),R4 ; Yes, get TCB address INCB T.IOC(R4) ; Adjust I/O request count DECB T.TIO(R4) ; and buffered I/O count 10$: MOV #IE.DAO&377,R0 ; Signal that job wants to read ; (R1 remains as is) BR VTFN1 ; Do it .PAGE ;-------------------------------------------------------------------- ; ; W R I T E F U N C T I O N ; =========================== ; ; An IO.WLB function is handled as follows: ; ; 1. If there is no batch job active on the specified unit, ; an IS.SUC status is returned, and all bytes are marked ; as transferred, but no transfer is actually performed. ; Else: ; ; 2. If the batch processor does not have a read outstanding, ; the same status as (1) is returned. The acceptance ; routine processing ensures that we don't throw away ; anything that might be important. Else: ; ; 3. If the write is by a task running in the batch stream, the ; buffer is transferred to the batch processor's input ; buffer, and both requests are terminated. Else: ; ; 4. If the write is by a privileged task (not running in the ; batch stream), the buffer is transferred to the batch ; processor's input buffer, and both requests are terminated. ; This allows external privileged tasks to write to log- ; files, and also the batch processor can put stuff there ; by doing a write (although it could more efficiently ; do it with a PUT$). NB Batch Processor is privileged. ; Else: ; ; 5. An IS.SUC indication is returned, but no data transfer ; actually occurs. ; WLBFCN: TST U.BTCB(R5) ; Batch job active? BEQ NODATA ; If EQ no TST U.BPKT(R5) ; Batch processor have outstanding ; read? BEQ NODATA ; If EQ no CMP T.UCB(R0),R5 ; Write by batch job? BEQ XFER ; If EQ yes, do the transfer .IF DF,B3$XIO ; External privileged I/O? BIT #T3.PRV,T.ST3(R0) ; Write by privileged task? .IF DF,B3$FSY ; Force SYS-class messages? BEQ NODATA ; If EQ no, no transfer MOVB #MD$SHF,I.PRM+7(R1) ; Yes, force SYS message->history file BR XFER ; Do the transfer .IFF BNE XFER ; If NE yes, do the transfer .ENDC ; DF,B3$FSY .ENDC ; DF,B3$XIO ; ; Success status is to be returned, but no data transfer performed. ; NODATA: MOV I.PRM+4(R1),R1 ; Get original byte count MOV #IS.SUC&377,R0 ; Show success status BR VTFIN ; Finish I/O ; ; Transfer writer's buffer to batch processor's input buffer. ; First transfer the carriage control information. This is two ; bytes: ; ; 1. The high order byte of the carriage control word, used by ; the batch processor to determine the message destination. ; 2. The carriage control byte proper. ; XFER: MOV R1,-(SP) ; Save writer's I/O packet address MOV U.BPKT(R5),R3 ; Get address of batch processor's ; read I/O packet which we stashed ; away. TST I.PRM+16(R3) ; Buffered read? ; NOTE: This only works on a mapped ; system (on unmapped systems this ; field is always zero, buffered I/O ; or not; on mapped system it is ; the user buffer PCB address for ; buffered I/O or zero for non-buffered ; I/O). BNE 100$ ; If NE yes ; ; Deal with transfer when batch processor's read is not buffered. ; MOV I.PRM(R3),U.BUF(R5) ; Set up UCB for $PTBYT MOV I.PRM+2(R3),U.BUF+2(R5) ; MOV I.PRM+6(R1),-(SP) ; Get message destination byte SWAB (SP) ; CALL $PTBYT ; Transfer to batch processor's buffer MOV I.PRM+6(R1),-(SP) ; Put carriage control byte on stack CALL $PTBYT ; Transfer to batch processor's buffer ; (I.PRM and I.PRM+2 are now out of ; date) ; ; Now transfer the writer's buffer proper. ; MOV I.PRM+4(R3),R0 ; Get batch processor's read count SUB #2,R0 ; Allow for carriage control info. CMP R0,I.PRM+4(R1) ; Does writer want to send too much? BLOS 10$ ; If LOS yes, use batch processor's ; read count MOV I.PRM+4(R1),R0 ; No, use writer's byte count 10$: MOV U.BUF+2(R5),R4 ; Get processor's buffer displacement MOV U.BUF(R5),R3 ; Get processor's APR6 bias ; (These two words have been left in ; the UCB as a result of the $PTBYT ; operations above). MOV I.PRM+2(R1),R2 ; Get writer's buffer displacement MOV I.PRM(R1),R1 ; Get writer's APR6 bias SUB #20000,R2 ; Convert to APR5 bias MOV R0,-(SP) ; Save the byte count CALL $BLXIO ; Move the data quickly ; ; Terminate the hidden read function from the batch processor. ; MOV U.BPKT(R5),R3 ; Get the I/O packet address MOV #IS.CR,R0 ; Set as terminator MOV (SP)+,R1 ; Get the byte count ADD #2,R1 ; Don't forget the carriage control MOV U.SCB(R5),R4 ; Get status control block address CALL $IOFIN ; Finish it off CLR U.BPKT(R5) ; Show no outstanding read ; ; Terminate the write request from the batch job or privileged task. ; Even if we didn't transfer all the buffer, we say that we did. The ; batch job will usually not mind this too much (when did you last ; check your I/O status on an output QIO?). ; 20$: MOV (SP)+,R3 ; Restore writer's I/O packet address MOV #IS.SUC&377,R0 ; Set success status MOV I.PRM+4(R3),R1 ; Say that we wrote everything JMP VTFN1 ; Finish request and get more ; work ;------------------------------------------------------------------- ; ; B U F F E R E D R E A D H A N D L E R ; ========================================= ; ; Perform the transfer when the batch processor's read is buffered. ; First, figure out what the byte count is and allocate a buffer of ; the appropriate size from the dynamic storage region (this buffer ; will be in use only for the time that it takes to load the batch ; processor if checkpointed and perform the transfer). ; At this point, the writer's I/O packet address is on the stack. ; ; To be really sure that no batch job output gets lost because of a ; low pool situation, we should allocate the pool buffer when the ; batch processor posts a read, rather than postponing it until now. ; However, this would tie up large amounts of pool for long periods, ; especially if several batch jobs are running simultaneously. An ; alternative to this would be to allocate buffers within the driver's ; address space, but this would consume physical memory, and in ; addition, the following disadvantages arise: (i) The driver source ; code would depend on the maximum number of batch streams (as ; opposed to just the data base in the present scheme), (ii) a fixed ; allocation would impose a maximum limit on the size of a batch ; jobs' output QIO. ; 100$: MOV I.PRM+4(R3),R0 ; Get batch processor's read count SUB #2,R0 ; Allow for carriage control info. CMP R0,I.PRM+4(R1) ; Does writer want to send too much? BLOS 110$ ; If LOS yes, use batch processor's ; read count MOV I.PRM+4(R1),R0 ; No, use writer's byte count 110$: MOV R0,-(SP) ; Save byte count MOV R0,R1 ; Copy byte count to R1 ADD #6,R1 ; Allow carr. contr. + header info CALL $ALOCB ; Allocate a pool buffer (R3 doesn't ; change) BCS 150$ ; If CS we couldn't get it MOV R0,I.PRM+12(R3) ; Put its address in I/O packet CLR U.BPKT(R5) ; Show read done with ; ; Transfer the writer's buffer to the block now sitting in pool. ; CLR (R0)+ ; Zero block link word MOV R1,(R0)+ ; Set up packet size word MOV 2(SP),R4 ; Get writer's I/O packet address MOVB I.PRM+7(R4),(R0)+ ; Insert high byte of carr. contr. wd. MOVB I.PRM+6(R4),(R0)+ ; Insert low byte of carr. contr. wd. ; (NB byte order is reversed). MOV I.PRM(R4),U.BUF(R5) ; Set up UCB for $GTBYT MOV I.PRM+2(R4),U.BUF+2(R5) ; MOV (SP),R4 ; Get byte count 120$: CALL $GTBYT ; Get next byte from writer's buffer MOVB (SP)+,(R0)+ ; Stuff it in pool (SP increments by 2) DEC R4 ; Done yet? BGT 120$ ; If GT no, so loop ; ; Terminate the batch processor's buffered read. ; (processor's I/O packet address is in R3). ; MOV #IS.CR,R0 ; Set as terminator MOV (SP)+,R1 ; Get byte count ADD #2,R1 ; Don't forget carr. contr. info. CALL $QUEBF ; Let the exec do the rest BR 20$ ; Finish writer's I/O ; ; Buffer allocation failed. Send a success indication to the writer but ; nothing to the batch processor (the read stays outstanding and is used ; the next time the job does output). One possibility would be to return ; the IE.DNS status to the batch processor, and to hold up the batch ; jobs' output until pool is available. This would require considerable ; modification to the driver and data base, since I/O requests from both ; the batch processor and user task could be outstanding at the same ; time. ; 150$: TST (SP)+ ; Clean byte count from stack BR 20$ ; Say OK to writer ;--------------------------------------------------------------------- ; ; P O W E R F A I L E N T R Y P O I N T ; ========================================= ; ; This is a no-op. ; VTPWF: ; Fall through to VTOUT ;---------------------------------------------------------------------- ; ; D E V I C E T I M E O U T E N T R Y ; ======================================= ; ; This is a no-op. ; VTOUT: RETURN ; Return to exec. ;---------------------------------------------------------------------- ; ; C A N C E L I / O E N T R Y ; =============================== ; ; This routine is called unconditionally from $IOKIL whenever ; an IO.KIL function is issued. If the batch processor has a ; read outstanding, the operation is aborted. A read request ; from a task running in the batch stream is allowed to ; complete. All other functions will have been purged from the queue ; by $IOKIL. ; ; Inputs: ; R1 Task's TCB address ; R5 UCB address ; VTCAN: CMP R1,U.BTCB(R5) ; Batch processor? BNE 20$ ; If NE no MOV U.BPKT(R5),R3 ; Get I/O packet address BEQ 20$ ; If EQ, no hidden read TST I.PRM+16(R3) ; Was it a buffered read? BEQ 10$ ; If EQ no INCB T.IOC(R1) ; If yes, adjust I/O request count DECB T.TIO(R1) ; and buffered I/O count 10$: CLR U.BPKT(R5) ; Clear hidden read CLR I.AST(R3) ; Make sure no AST occurs MOV #IE.ABO&377,R0 ; Set first status word CLR R1 ; Set no bytes transferred CALL $IOFIN ; Finish I/O 20$: RETURN ; ;---------------------------------------------------------------------- ; ; B U F F E R D E A L L O C A T I O N E N T R Y ; ================================================= ; ; This routine is called from $FINBF to deallocate the pool ; buffer that has been used to save the buffer written out ; by a task running in a batch job. ; This routine already handles the possibility of buffered ; I/O through multiple linked pool buffers. ; ; Inputs: ; R0 Buffer address ; VTDEA: MOV (R0),-(SP) ; Save link to next buffer MOV 2(R0),R1 ; Get length of buffer CALL $DEACB ; Deallocate to pool MOV (SP)+,R0 ; Restore next buffer address BNE VTDEA ; If NE, there are more RETURN ; else go back to exec. ;---------------------------------------------------------------------- ; ; $ G S P K T A C C E P T A N C E R O U T I N E ; ================================================= ; ; This routine is called by $GSPKT to determine whether or not ; a I/O request should be dequeued. Specifically: ; ; 1. If no job is active on the specified unit, the request is ; accepted, since it can always be dealt with immediately ; within the driver. Else: ; ; 2. If the batch processor has an outstanding read, the request ; is always accepted, since it can always be dealt with ; immediately within the driver. Else: ; ; 3. The request is rejected, since either a read or a write by the ; batch job requires service from the batch processor. ; ; Inputs: ; R1 I/O packet address ; R5 UCB address of unit ; ; Outputs: ; CC Accept request ; CS Reject request ; ;- ACCEPT: TST U.BTCB(R5) ; Job active on this unit? BEQ YES ; If EQ no, always accept TST U.BPKT(R5) ; Batch processor have read outstanding? BNE YES ; If NE yes, accept this request CMP I.TCB(R1),U.BTCB(R5) ; Function from batch processor? BNE NO ; If NE no, reject YES: CLC ; Accept request RETURN ; NO: SEC ; Reject request (will try later) RETURN ; .END