Trailing-Edge
-
PDP-10 Archives
-
TOPS-20_V6.1_DECnetSrc_7-23-85
-
mcb/sc/scxdsp.bli
There is 1 other file named scxdsp.bli in the archive. Click here to see a list.
module SCXDSP ( ! RSX User Interface Module
ident = 'X01340'
) =
begin
!
! COPYRIGHT (c) 1980, 1981, 1982
! DIGITAL EQUIPMENT CORPORATION
! Maynard, Massachusetts
!
! 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 its software on equipment which is not supplied by
! DIGITAL.
!
!++
!
! FACILITY: Session Control
!
! ABSTRACT: This module handles all I/O packets originating from
! the user, destined for Session Control. The I/O packets
! are handled like those in a device service routine.
! CCBs arriving from Session Control are also handled here.
!
! ENVIRONMENT: MCB
!
! AUTHOR: Buren Hoffman CREATION DATE: 1-Aug-80
!
! MODIFIED BY:
! X01010 Changed code to use $byt_ptr macro in place of the
! ch$ptr macro.
! X01020 Fixed faulty dispatch vector processing, and
! fixed xportability problems, concerning number of
! bytes per word.
! X01030 Corrected memory allocation problem in U$OPN.
! X01040 Updated signal_stop processing to show more info.
! X01050 Provide own queueing - can't use the CCB queueing
! facilities in MCB, because they are for CCBs only.
! X01060 Fixed byte-vector handling problem in user interface.
! X01070 Use new Comm/Exec to process linkage (.CRDAT for database)
! X01080 Upgraded GLN support to return node addresses, ...
! X01090 Updated to use library calls, instead of requires.
! X01100 Fixed return to RSX so that RSX$ call is done before
! returning.
! X01110 Repaired bug in LUN number calculation.
! X01120 Numerous minor bug fixes.
! X01130 Added call to AST queueing routine.
! X01140 Put in bullet proofing to keep user from using
! unopened link.
! X01150 Fixed resource wait dispatch vectors.
! X01160 Fixed disconnect/reject/timeout processing to
! keep proper count of active links.
! X01170 Fix for memory and link management in abort/disconnect
! processing.
! X01180 ?
! X01190 Changed code in user abort or disconnect to expect
! optional data as in a transfer function.
! X01200 Changed disconnect processing to use control format
! instead of the transfer function format.
! X01210 Fixed memory management bug in Reject processing.
! X01220 Took out fix of X01210, it was wrong.
! X01230 Did away with old LLLTM$ clock usage - went to new clock.
! X01240 Fixed LN2 cleanup on connect failures.
! X01250 Optimization work.
! X01260 Fixed error where database was being set up before $mcb call.
! X01270 Fix for disconnect-received before connect received completion,
! and fixed context error for $HEADR reference while in MCB mode.
! X01280 Cleaned up LNK deallocation bug.
! X01290 Fix of DSR management bug in connect-received processing.
! X01300 Fixed active-link count for connect failure.
! x01310 Use DSR space instead of LDB's for connect info
! X01320 Fixed connect-accept failure to properly clean up link.
! X01330 Repaired race condition when disconnect received.
! X01340 Work on bug uncovered by edit #34.
!--
!
! INCLUDE FILES:
!
library 'SCPRM'; ! Our parameter and macro definitions
library 'MCB:MCBLIB';
library 'MCB:RSXLIB';
library 'MCB:XPORTX';
library 'MCB:SCSYS';
require 'SCRSX';
!
! TABLE OF CONTENTS:
!
forward routine
U$DSP: rsx_ucb_scb_iop novalue, ! QIO dispatch
UFCRCP: mcb_db_ccb_mod novalue, ! Receive complete
UFCTMO: mcb_db_ccb_mod novalue, ! Timeout
UFCXCP: mcb_db_ccb_mod novalue; ! Transmit complete
!
! MACROS:
!
!
! EQUATED SYMBOLS:
!
!
! OWN STORAGE:
!
!
! EXTERNAL REFERENCES:
!
external
$DSPCR,
$HEADR: ref block field (HDR_FIELDS);
external routine
SRUDSW: novalue, ! Disconnect-received-wait
SRUINW: novalue, ! Interrupt-received-wait
U$ABW: novalue, ! Abort-wait
U$ACW: novalue, ! Accept-wait
U$ARQ: novalue, ! * Abort-request-wait *
U$CLW: novalue, ! Close-wait
U$CNW: novalue, ! Connect-wait-processing
U$DSW: novalue, ! Disconnect-wait
U$GLW: novalue, ! Get-local-node-information-wait
U$IRQ: novalue, ! * Interrupt-request-wait *
U$RCW: novalue, ! Receive-wait
U$RJW: novalue, ! Reject-wait
U$SNW: novalue, ! Send-wait
U$XMW: novalue, ! Send-interrupt-wait
BUFCHK, ! User buffer verification and mapping
FNDOBJ, ! Find specified object task
GETLCB, ! Obtain and init LCB
LCBKIL: novalue, ! Unlink and deallocate LCB
MBPROC, ! Process mailbox queue
NOOP: novalue, ! This routine just returns
QUEAST, ! Queue an AST to RSX
STXMAP, ! Map from SC codes to RSX User codes
ULAGET, ! Find available ULA
ULARD, ! Read specified ULA entry
ULASET: novalue; ! Set value in specified ULA entry
!++
!
! *** RSX DISPATCH VECTOR ***
!
! This vector is the route via which RSX dispatches
! IOPs to SCX.
!
!--
global bind
$NSTBL = uplit (
U$DSP, ! QIO dispatcher
NOOP, ! I/O cancellation
NOOP, ! Timeout
NOOP), ! Power failure
$ODSP = uplit (
uplit (U$SNW, U$XMW), ! IOP_XMT
uplit (U$RCW), ! IOP_RCV
uplit (U$CNW, U$ACW), ! IOP_CON
uplit (U$DSW, U$ABW, U$RJW), ! IOP_DSC
uplit (U$CLW, U$CLW, -1, -1, -1, -1, -1, U$GLW)), ! IOP_CTL
$IDSP = uplit (
none_such, !
none_such, !
SRUINW, ! Interrupt received
SRUDSW); ! Disconnect received
!++
!
! *** MCB DISPATCH VECTOR ***
!
! This vector is the route via which the MCB dispatches
! CCBs to SCX.
!
!--
global bind
$SCXLL = TABLE$ ($DSPCR, FC_CCP,
(FC_TIM, UFCTMO), ! UFCTMO - Timeout
(FC_XCP, UFCXCP), ! UFCXCP - Transmit complete
(FC_RCP, UFCRCP)); ! UFCRCP - Receive complete
%sbttl 'User Interface';
routine U$DSP (UCB, SCB, IOP): RSX_UCB_SCB_IOP novalue =
!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
! UCB The unit control block
! SCB The Status Control Block
! IOP The I/O packet
!
! IMPLICIT INPUTS:
! IOP, SCB, & UCB contents
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map IOP: ref block field (IOP_FIELDS);
local
LUN,
MODIFIER,
QFLAG,
STS,
COUNT: byte_vector [2],
SCXDB: ref block field (SCXDB_FIELDS),
LCB: ref block field (LCB_FIELDS),
MB_PREV: ref block field (MBP_FIELDS),
MB: ref block field (MBP_FIELDS),
STATUS: byte_vector [2],
TNB: ref block field (TNB_FIELDS);
bind
COUNT_WORD = COUNT [0],
STATUS_WORD = STATUS [0];
label
DATA_PROC,
CONNECT_PROC,
DISCONNECT_PROC,
CONTROL_PROC;
compiletime
LUN_OFFSET = %fieldexpand (H_LUN, 0) * %upval;
! ** Become an MCB process
MCB$ (.UCB, SCXDB);
STATUS_WORD = 0; ! Initialize the STATUS vector
STS = 0; ! and status flag
COUNT_WORD = 0; ! and COUNT variables
QFLAG = true; ! Assume to queue it to LC_OQUE
%if %bliss (bliss36)
%then
IOP [I_LN2] = (.IOP [I_LN2])^%upval + .$HEADR + LUN_OFFSET - %upval;
%fi
LUN = (.IOP [I_LN2] - .$HEADR - LUN_OFFSET + %upval) ^-%upval;
LCB = TNB = (.(.IOP [I_LN2]) and -2);
MODIFIER = .IOP [I_MOD] and %o'177';
STS =
begin
if (.IOP [I_FNC] eql IOP_CTL) and (.MODIFIER eql IOP$OPN) ! If OPEN
then (if .$HEADR [H_NML] neq 0 then IE_PRI else IS_SUC) ! Can't have two
else (if .$HEADR [H_NML] eql 0 then IE_PRI else IS_SUC) ! But must have one
end;
if .STS eql IS_SUC
then STS =
begin
case .IOP [I_FNC] from IOP_LO to IOP_HI of
set
! ***************************
! ** Send and Receive Data **
! ***************************
[IOP_XMT, IOP_RCV]: DATA_PROC:
! Expected inputs
! I_PRM1 = Buffer bias
! I_PRM2 = Buffer address
! I_PRM3 = Buffer length
! ***************************
! ** U$SND & U$INT & U$RCV **
! ***************************
begin
if (.LCB eql 0) or .LCB [LCF_DSC]
then leave DATA_PROC with IE_PRI;
TNB = .LCB [LC_TNB];
if .MODIFIER eql IOP$INT
then
begin
$SCX_ENQUEUE (LCB [LC_NQUE], .IOP);
QFLAG = false
end;
IS_SUC
end;
! ************************
! ** Connect Processing **
! ************************
[IOP_CON]: CONNECT_PROC:
begin
if .LCB neq 0 then leave CONNECT_PROC with IE_PRI;
selectone .MODIFIER of
set
! ***********
! ** U$ACC **
! ***********
[IOP$ACC]:
! Expected inputs
! I_PRM1 = Connect block bias
! I_PRM2 = " " address
! I_PRM3 = " " length
! I_PRM4 = Optional output buffer address
! I_PRM5 = " " " length
begin
local
TMP;
bind
CND = IOP [I_PRM2]: ref block field (CND_FIELDS);
if .IOP [I_PRM3] lss 2
then leave CONNECT_PROC with IE_BAD;
if (TMP = BUFCHK (IOP [I_PRM4], IOP [I_PRM3], 16) lss 0)
then leave CONNECT_PROC with .TMP;
TNB = .((.$HEADR [H_NML])^%upval + .$HEADR + LUN_OFFSET - %upval);
MAP$ (.IOP [I_PRM1]); ! Look at connect block
MB = TNB [TN_MBXQ]; ! Scan mailbox
while (MB_PREV = .MB; MB = .MB [MB_LINK]) neq 0 do
begin
if .MB eql .CND [CND_TLA] then exitloop
end;
if .MB eql 0 then leave CONNECT_PROC with IE_BAD;
if not GETLCB (TNB, LCB, .IOP [I_TCB])
then leave CONNECT_PROC with IE_RSU;
.IOP [I_LN2] = .LCB;
LCB [LC_LUN] = .LUN;
LCB [LC_LLA] = .MB [MB_LLA];
if (MB_PREV [MB_LINK] = .MB [MB_LINK]) eql 0
then TNB [TN_MBTL] = .MB_PREV;
$MCB_RETURN_DSR (MBP_SIZE*bytes_word + .MB [MB_CNT], .MB)
end;
! ***********
! ** U$CON **
! ***********
[IOP$CON]:
! Expected inputs
! I_PRM1 = Connect block bias
! I_PRM2 = " " address
! I_PRM3 = " " length
! I_PRM4 = Optional output buffer address
! I_PRM5 = " " " length
! I_PRM6 = Optional input buffer address
! I_PRM7 = " " " length
begin
local
TMP;
if .IOP [I_PRM3] neq N_RQL
then leave CONNECT_PROC with IE_BAD;
if ((TMP = BUFCHK (IOP [I_PRM4], IOP [I_PRM3], 16)) lss 0) or
((TMP = BUFCHK (IOP [I_PRM6], IOP [I_PRM6], 16)) lss 0)
then leave CONNECT_PROC with .TMP;
if not GETLCB (TNB, LCB, .IOP [I_TCB])
then leave CONNECT_PROC with IE_RSU;
TNB [TN_ACT] = .TNB [TN_ACT] + 1;
.IOP [I_LN2] = .LCB;
LCB [LC_LUN] = .LUN
end;
! **********
! ** OOPS **
! **********
[otherwise]: leave CONNECT_PROC with IE_PRI;
tes;
leave CONNECT_PROC with IS_SUC
end;
! ***************************
! ** Disconnect Processing **
! ***************************
[IOP_DSC]: DISCONNECT_PROC:
! Expected inputs
! I_PRM1 = " " address
! I_PRM2 = " " length
! I_PRM4 = Optional output buffer address (REJ only)
! I_PRM5 = " " " length ( " " )
begin
local
TMP;
IOP [I_PRM5] = .IOP [I_PRM4]; ! Copy PRM3 & PRM4
IOP [I_PRM4] = .IOP [I_PRM3]; ! to make room for
! expanded address
if (TMP = BUFCHK (IOP [I_PRM1], IOP [I_PRM1], 0)) lss 0
then leave DISCONNECT_PROC with TMP;
selectone .MODIFIER of
set
! *******************
! ** U$ABO & U$DSC **
! *******************
[IOP$ABO, IOP$DSC]:
! Expected inputs
! I_PRM1 = Optional Data bias
! I_PRM2 = " " address
! I_PRM3 = " " length
begin
local
TMP;
if (.LCB eql 0) or .LCB [LCF_DSC]
then leave DISCONNECT_PROC with IE_PRI;
TNB = .LCB [LC_TNB];
if .IOP [I_PRM3] gtr 16
then leave DISCONNECT_PROC with IE_BAD;
LCB [LCF_DSC] = true; ! Abort/Disc started
if .MODIFIER eql IOP$ABO
then
begin
$SCX_STACK (LCB [LC_NQUE], .IOP);
QFLAG = false
end
end;
! ***********
! ** U$REJ **
! ***********
[IOP$REJ]:
! Expected inputs
! I_PRM1 = Connect block bias
! I_PRM2 = " " address
! I_PRM3 = " " length
! I_PRM4 = Optional output buffer address
! I_PRM5 = " " " length
begin
local
TMP;
bind
CND = IOP [I_PRM2]: ref block field (CND_FIELDS);
LCB = 0;
if .LUN neq .$HEADR [H_NML]
then leave DISCONNECT_PROC with IE_PRI;
if .IOP [I_PRM3] lss 2
then leave DISCONNECT_PROC with IE_BAD;
if (TMP = BUFCHK (IOP [I_PRM4], IOP [I_PRM3], 16)) lss 0
then leave DISCONNECT_PROC with .TMP;
MAP$ (.IOP [I_PRM1]); ! Look at connect block
MB = TNB [TN_MBXQ]; ! Scan mailbox
while (MB_PREV = .MB; MB = .MB [MB_LINK]) neq 0 do
begin
if .MB eql .CND [CND_TLA] then exitloop
end;
if .MB eql 0 then leave DISCONNECT_PROC with IE_BAD;
IOP [I_PRM6] = .MB [MB_LLA]; ! Remember LLA
if (MB_PREV [MB_LINK] = .MB [MB_LINK]) eql 0
then TNB [TN_MBTL] = .MB_PREV;
$MCB_RETURN_DSR (MBP_SIZE*bytes_word + .MB [MB_CNT], .MB);
$SCX_ENQUEUE (TNB [TN_OQUE], .IOP);
QFLAG = false
end;
! **********
! ** OOPS **
! **********
[otherwise]: leave DISCONNECT_PROC with IE_PRI;
tes;
leave DISCONNECT_PROC with IS_SUC
end;
! *************
! ** Control **
! *************
[IOP_CTL]: CONTROL_PROC:
begin
LCB = 0;
if .MODIFIER neq IOP$OPN
then
begin
if (.LUN neq .$HEADR [H_NML]) or (.TNB eql 0)
then leave CONTROL_PROC with IE_PRI
end;
selectone .MODIFIER of
set
! ***********
! ** U$OPN **
! ***********
[IOP$OPN]:
! Expected inputs
! I_PRM1 = Maximum allowed logical links
begin
! Get TNB block of memory from DSR
if not $MCB_GET_DSR (TNB_SIZE*bytes_word, TNB)
then leave CONTROL_PROC with IE_RSU;
! ** Zero and initialize block
ch$fill(0, SCXDB_SIZE*bytes_word, .TNB);
$HEADR [H_NML] = TNB [TN_LUN] = .LUN; ! Record LUN #
TNB [TN_LINK] = .SCXDB [SCX_TNB];
SCXDB [SCX_TNB] = .TNB;
.(IOP [I_LN2]) = .TNB; ! Set TNB addr in LN2
TNB [TN_TASK] = .IOP [I_TCB]; ! TCB address
TNB [TN_MAX] = .IOP [I_PRM1]; ! Max # of links
TNB [TN_OQTL] = TNB [TN_OQHD]; ! Init queue
TNB [TN_MBTL] = TNB [TN_MBHD]; ! headers
TNB [TN_IQTL] = TNB [TN_IQHD]; ! ...
! ** Now move stuff from general delivery mailbox
! ** to the task's mailbox
MB = SCXDB [SCX_MBHD]; ! Point to head of list
while (MB_PREV = .MB; MB = .MB [MB_LINK]) neq 0 do ! Go thru whole list
begin
if .MB [MB_TASK] eql .TNB [TN_TASK] ! If for this task
then
begin
if (.MB [MB_FNC] eql MB$CON) and
((.TNB [TN_MAX] neq 0) and (.TNB [TN_ACT] geq .TNB [TN_MAX]))
then
MB [MB_TIME] = 1 ! Too many links, a short timeout
else
begin
if .MB [MB_FNC] eql MB$CON
then TNB [TN_ACT] = .TNB [TN_ACT] + 1;
if (MB_PREV [MB_LINK] = .MB [MB_LINK]) eql 0
then SCXDB [SCX_MBTL] = .MB_PREV;
$SCX_ENQUEUE (TNB [TN_MBXQ], .MB);
MB = .MB_PREV
end
end
end;
STATUS [0] = .STS;
RSX$ (.SCXDB);
IOFIN$ (.UCB, .IOP, .STATUS_WORD, .COUNT_WORD);
return
end;
! ***********
! ** U$CLS **
! ***********
[IOP$CLS]:
begin
$SCX_STACK (TNB [TN_OQUE], .IOP); ! Do it soon
TNB [TNF_CLS] = true; ! We started it
QFLAG = false;
leave CONTROL_PROC with IS_SUC
end;
! ***********
! ** U$SPA **
! ***********
[IOP$SPA]:
! Expected inputs
! I_PRM1 = AST address
begin
TNB [TN_SPA] = .IOP [I_PRM1];
! Count number of things in queue
MB = TNB [TN_MBXQ];
while (MB = .MB [MB_LINK]) neq 0 do
begin
if .MB [MB_FNC] neq MB$CNP
then COUNT [0] = .COUNT [0] + 1
end;
RSX$ (.SCXDB);
IOFIN$ (.UCB, .IOP, IS_SUC, .COUNT_WORD);
return
end;
! ***********
! ** U$GND **
! ***********
[IOP$GND1, IOP$GND2, IOP$GND3]:
! Expected inputs
! I_PRM1 = Buffer address
! I_PRM2 = Buffer length
! I_PRM3 = Mask parameter
! I_PRM4 = (PRM3 will be copied to here)
begin
local
FNC,
SELEKT;
IOP [I_PRM4] = .IOP [I_PRM3]; ! Copy mask parameter
if .MODIFIER neq IOP$GND2 ! Check buffer, if must
then
begin
local TMP;
if (TMP = BUFCHK (IOP [I_PRM1], IOP [I_PRM1], 0)) lss 0
then leave CONTROL_PROC with .TMP
end;
! Now scan the mailbox queue
MB = TNB [TN_MBXQ];
while (MB_PREV = .MB; MB = .MB [MB_LINK]) neq 0 do
begin
SELEKT = true; ! Assume success
if (FNC = .MB [MB_FNC]) eql MB$CNP ! Pending connects are invisible to caller
then SELEKT = false ! No good
else
begin
local
TYPE_MASK,
LUN_MASK;
if .MODIFIER eql IOP$GND1 ! If normal GND
then exitloop; ! Got it !
TYPE_MASK = .IOP [$sub_field (I_PRM4, LO_BYTE)];
LUN_MASK = .IOP [$sub_field (I_PRM4, HI_BYTE)];
if (
((.TYPE_MASK neq 0) and (.TYPE_MASK neq .FNC)) or
((.LUN_MASK neq 0) and (.LUN_MASK neq .MB [MB_LUN])))
then SELEKT = false; ! Didn't make it
end;
if .SELEKT then exitloop
end;
if not .SELEKT then leave CONTROL_PROC with IE_NDA;
if .MODIFIER eql IOP$GND2 ! Length and type only
then
begin
STS = IS_SUC;
STATUS [1] = .FNC;
COUNT [0] = .MB [MB_CNT]
end
else
begin
COUNT [0] = min (.MB [MB_CNT], .IOP [I_PRM3]); ! Determine size of xfer
COUNT [1] = .MB [MB_LUN]; ! Say which LUN (zero for connect)
STS = (if .COUNT [0] geq .MB [MB_CNT] then IS_SUC else IE_DAO);
STATUS [1] = .FNC; ! Tell user what it is
MAP$ (.IOP [I_PRM1]); ! Map user buffer
ch$move (.COUNT [0], byt$ptr (MB [MB_DATA]), byt$ptr (.IOP [I_PRM2]));
if .FNC eql MB$CON
then
MB [MB_FNC] = MB$CNP ! Logically dequeue connect
else
begin
if (MB_PREV [MB_LINK] = .MB [MB_LINK]) eql 0 ! Physically dequeue MB
then TNB [TN_MBTL] = .MB_PREV; ! entry, and
LCB = ULARD (.MB [MB_ULA]); ! Get ULA address
$MCB_RETURN_DSR (MBP_SIZE*bytes_word + .MB [MB_CNT], .MB); ! dealc memory
if .FNC eql MB$INT
then U$IRQ (.LCB)
else
begin
LCB [LCF_DSC] = true;
U$ARQ( .LCB)
end
end
end;
STATUS [0] = .STS;
RSX$ (.SCXDB);
IOFIN$ (.UCB, .IOP, .STATUS_WORD, .COUNT_WORD);
return
end;
! ***********
! ** U$GLN **
! ***********
[IOP$GLN]:
! Expected inputs
! I_PRM1 = Buffer address
! I_PRM2 = Buffer length
! I_PRM3 = Option selector
begin
local
TMP;
IOP [I_PRM4] = .IOP [I_PRM3];
if (.IOP [I_PRM2] eql 0) or
(TMP = BUFCHK (IOP [I_PRM1], IOP [I_PRM1], 0)) lss 0
then leave CONTROL_PROC with .TMP;
$SCX_ENQUEUE (TNB [TN_OQUE], .IOP);
QFLAG = false
end;
! **********
! ** OOPS **
! **********
[otherwise]: leave CONTROL_PROC with IE_PRI;
tes
end;
! **********
! ** Zonk **
! **********
[inrange, outrange]:
begin
selectoneu .IOP [I_FNC] of
set
! ***********
! ** CLOSE **
! ***********
[IOP$CLS]:
begin
if (.LUN neq .$HEADR [H_NML]) or (.TNB [TNF_CLS]) then return
IOP [I_FNC] = IOP_CTL; ! Change codes awhile
IOP [I_MOD] = IOP$CLO;
$SCX_STACK (TNB [TN_OQUE], .IOP);
QFLAG = false;
IS_SUC
end;
! ********************
! ** DISMOUNT, OR ? **
! ********************
[otherwise]: IE_PRI;
tes
end
tes
end;
STATUS [0] = .STS;
if .STS geq 0
then
begin
if .QFLAG then $SCX_ENQUEUE (LCB [LC_OQUE], .IOP);
if .TNB neq 0
then $SCX_DISPATCH_OUTPUT (TNB [TN_OQUE], .TNB);
if .LCB neq 0
then
begin
$SCX_DISPATCH_OUTPUT (LCB [LC_NQUE], .LCB);
$SCX_DISPATCH_OUTPUT (LCB [LC_OQUE], .LCB)
end;
RSX$ (.SCXDB)
end
else
begin
RSX$ (.SCXDB);
IOFIN$ (.UCB, .IOP, .STATUS_WORD, .COUNT_WORD)
end
end;
%sbttl 'Receive-Complete from Session Control';
routine UFCRCP (SCXDB, CCB, FCM): mcb_db_ccb_mod novalue =
!++
! FUNCTIONAL DESCRIPTION:
! This routine is activated by receipt of a receive
! complete from Session Control.
!
! FORMAL PARAMETERS:
! CCB CCB to pass to handler routine
! FCM Function code modifier
!
! IMPLICIT INPUTS:
! CCB contents
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
$scx_get_data_base (SCXDB);
map CCB: ref block field (C_FIELDS);
local
LCB: ref block field (LCB_FIELDS),
TNB: ref block field (TNB_FIELDS),
MB: ref block field (MBP_FIELDS);
case .FCM^-1 from 0 to 3 of
set
! ************
! ** SRUCNR **
! ************
[S$CNR^-1]:
begin
local
STS,
MBD: ref block field (CND_FIELDS),
TCB: ref block field (TCB_FIELDS);
bind
CB = CCB [C_ADDR]: ref block field (CB_FIELDS);
literal
CB_L1 = (%fieldexpand (CB_SFMT, 0) - %fieldexpand (CB_DFMT, 0)) * bytes_word,
CB_L2 = (%fieldexpand (CB_ENDD, 0) - %fieldexpand (CB_SFMT, 0)) * bytes_word;
MAP$ (.CCB [C_BIAS]); ! Look at connect block
if not FNDOBJ (CB [CB_DFMT], TCB)
then
begin
$SCX_DO_RCE (.CCB, S_EURO);
return
end;
if not $MCB_GET_DSR (MBP_SIZE*bytes_word + CND_SIZE*bytes_word, MB)
then
begin
$SCX_DO_RCE (.CCB, S_ERES);
return
end;
MBD = MB [MB_DATA]; ! Set cb base
MBD [CND_TLA] = .MB; ! Temporary LLA
MBD [CND_SEG] = 0;
ch$move (CB_L1, byt$ptr (CB [CB_DFMT]), byt$ptr (MBD [CND_DFMT]));
ch$move (6, byt$ptr (CB [CB_NODE]), byt$ptr (MBD [CND_NODE]));
ch$move (CB_L2, byt$ptr (CB [CB_SFMT]), byt$ptr (MBD [CND_SFMT]));
MB [MB_CNT] = CND_SIZE*bytes_word;
MB [MB_FNC] = MB$CON;
MB [MB_FLG] = 0;
MB [MB_LLA] = .CCB [C_LIX];
MB [MB_LUN] = 0;
MB [MB_TIME] = .CCB [C_PRM2] - 1;
MB [MB_TASK] = .TCB;
TNB = .SCXDB [SCX_TNB];
while .TNB neq 0 do
begin
if .TNB [TN_TASK] eql .TCB
then exitloop
else TNB = .TNB [TN_LINK]
end;
MB [MB_TNB] = .TNB; ! Remember where (if) the TNB
STS = S_SSUC;
if .TNB neq 0
then
begin
if (.TNB [TN_MAX] neq 0) and (.TNB [TN_ACT] geq .TNB [TN_MAX])
then
begin
$MCB_RETURN_DSR (MBP_SIZE*bytes_word + .MB [MB_CNT], .MB);
STS = S_EOTB
end
else
begin
TNB [TN_ACT] = .TNB [TN_ACT] + 1;
$SCX_ENQUEUE (TNB [TN_MBXQ], .MB);
QUEAST (.TNB);
end
end
else
begin
if not TSKRT$ (.TCB, 0) then MB [MBF_REQ] = true;
$SCX_ENQUEUE (SCXDB [SCX_MBX], .MB);
SCXDB [SCXF_KLOK] = true
end;
$SCX_DO_RCE (.CCB, .STS);
return
end;
! *********************
! ** SRUINT & SRUDSR **
! *********************
[S$INT^-1, S$DSR^-1]:
begin
if (LCB = ULARD (.CCB [$sub_field (C_PRM1, LO_BYTE)])) eql 0
then
begin
$SCX_DO_RCE (.CCB);
return
end;
TNB = .LCB [LC_TNB];
$SCX_ENQUEUE (TNB [TN_IQUE], .CCB);
$SCX_DISPATCH_INPUT (TNB [TN_IQUE])
end;
! ************
! ** SRUERR **
! ************
[inrange, outrange]: SIGNAL_STOP (SCX$_ISC, .CCB);
tes;
end;
%sbttl 'Timeout or Initialization From Comm/Exec';
routine UFCTMO (SCXDB, CCB, FCM): mcb_db_ccb_mod novalue =
!++
! FUNCTIONAL DESCRIPTION:
! This routine is activated by some event noted by
! the Comm/Exec.
!
! FORMAL PARAMETERS:
! CCB CCB to pass to handler routine
! FCM Function code modifier
!
! IMPLICIT INPUTS:
! CCB Contents
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
$scx_get_data_base (SCXDB);
map CCB: ref block field (C_FIELDS);
case .FCM^-1 from 0 to 3 of
set
! ************
! ** CXULTM **
! ************
[1]:
begin
local
LCB: ref block field (LCB_FIELDS),
TNB: ref block field (TNB_FIELDS);
SCXDB [SCX_TICK] = .SCXDB [SCX_TICK] + 1; ! Restart clock
SCXDB [SCXF_SUCC] = true;
MBPROC (SCXDB [SCX_MBX]); ! Process Gen-Deliv connects
TNB = .SCXDB [SCX_TNB]; ! Point to TNB list
while .TNB neq 0 do ! Look at all TNBs
begin
MBPROC (TNB [TN_MBXQ]); ! Process TNB connects
if .SCXDB [SCXF_SUCC] and .TNB [TNF_RWT] ! Anyone wanting resources ?
then
begin ! Yes
TNB [TNF_RWT] = false; ! Turn off request flag
$SCX_DISPATCH_OUTPUT (TNB [TN_OQUE], .TNB); ! Do task level stuff
LCB = TNB [TN_LCB]; ! Now, step thru LCBs
while (LCB = .LCB [LC_LINK]) neq 0 do
begin
if .LCB [LCF_NRES] ! Interrupt request ?
then
begin
LCB [LCF_NRES] = false;
U$IRQ (.LCB)
end;
if .LCB [LCF_ARES] ! Abort request ?
then
begin
LCB [LCF_ARES] = false;
LCB [LCF_DSC] = true;
U$ARQ (.LCB)
end;
! Pump the interrupt, input, and output queues
if .SCXDB [SCXF_SUCC]
then
begin
$SCX_DISPATCH_OUTPUT (LCB [LC_NQHD], .LCB);
$SCX_DISPATCH_OUTPUT (LCB [LC_OQHD], .LCB);
$SCX_DISPATCH_INPUT (TNB [TN_IQHD])
end
end
end;
if .TNB [TNF_CLS] ! Net being closed ?
then
begin ! Yes
local
NXT_TNB;
NXT_TNB = .TNB [TN_LINK];
U$CLW (.TNB); ! Do the close
TNB = .NXT_TNB
end
else
TNB = .TNB [TN_LINK]
end
end;
! ************
! ** CXUPWF **
! ************
[2]: return;
! ************
! ** CXUPIN **
! ************
[3]:
begin
bind SC =
%if %bliss (bliss36)
%then %rad50_10 'SC'
%else %rad50_11 'SC'
%fi;
if not PDVID$ (SC, SCXDB [SCX_SCPIX]) ! Set SC PIX
then SIGNAL_STOP (SCX$_NSC);
RSX$ (.SCXDB, SCXDB [SCX_UCB]); ! Record UCB address
MCB$ (.SCXDB [SCX_UCB]); ! Back to MCB
$MCB_ENABLE_LONG_TIMER (); ! Start clock
SCXDB [SCX_TICK] = 1 ! ...
end;
! ************
! ** CXUERR **
! ************
[inrange, outrange]: SIGNAL_STOP (SCX$_ISC);
tes
end;
%sbttl 'Transmit-Complete From Session Control';
routine UFCXCP (SCXDB, CCB, FCM): mcb_db_ccb_mod novalue =
!++
! FUNCTIONAL DESCRIPTION:
! This routine is activated by receipt of an xmit
! complete from Session Control.
!
! FORMAL PARAMETERS:
! CCB CCB to pass to handler routine
! FCM Function code modifier
!
! IMPLICIT INPUTS:
! CCB contents
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
$scx_get_data_base (SCXDB);
map CCB: ref block field (C_FIELDS);
local
COUNT,
IOP: ref block field (IOP_FIELDS);
compiletime
LUN_OFFSET = %fieldexpand (H_LUN, 0) * %upval;
label
ABO_DIS;
COUNT = 0;
IOP = .CCB [C_PRM5]; ! Set up address of IOP
case .FCM^-1 from 0 to 10 of
set
! ******************************
! ** SXUABO & SXUDIS & SXUACC **
! ******************************
[S$ABO^-1, S$DIS^-1, S$ACC^-1]: ABO_DIS:
begin
local
LCB: ref block field (LCB_FIELDS),
TNB: ref block field (TNB_FIELDS),
LIOP: ref block field (IOP_FIELDS),
MB: ref block field (MBP_FIELDS),
MB_PREV: ref block field (MBP_FIELDS);
LCB = ULARD (.CCB [$sub_field (C_PRM1, LO_BYTE)]);
TNB = .LCB [LC_TNB];
if .FCM eql S$ACC
then
begin
COUNT = .CCB [C_CNT];
leave ABO_DIS
end;
MB = TNB [TN_MBXQ]; ! Flush mailbox for this link
while (MB_PREV = .MB; MB = .MB [MB_LINK]) neq 0 do
begin
if .MB [MB_ULA] eql .CCB [$sub_field (C_PRM1, LO_BYTE)]
then
begin
if (MB_PREV [MB_LINK] = .MB [MB_LINK]) eql 0
then TNB [TN_MBTL] = .MB_PREV;
$MCB_RETURN_DSR (MBP_SIZE*bytes_word + .MB [MB_CNT], .MB)
end
end;
! Flush the output queues
while $SCX_DEQUEUE (LCB [LC_OQUE], LIOP) do IOFIN$ (.SCXDB [SCX_UCB], .LIOP, IE_ABO, 0);
while $SCX_DEQUEUE (LCB [LC_NQUE], LIOP) do IOFIN$ (.SCXDB [SCX_UCB], .LIOP, IE_ABO, 0);
! Clear user's LN2 word, clear the ULA, and get rid of link
((.LCB [LC_LUN] ^%upval) + .$HEADR + LUN_OFFSET - %upval) = 0;
ULASET (.LCB [LC_ULA], 0);
TNB [TN_ACT] = .TNB [TN_ACT] - 1;
LCBKIL (.LCB)
end;
! ************
! ** SXUCON **
! ************
[S$CON^-1]:
begin
local
LCB: ref block field (LCB_FIELDS);
LCB = (.(.IOP [I_LN2]) and -2);
if .CCB [C_STS] neq S_SSUC
then
begin
bind TNB = .LCB [LC_TNB]: block field (TNB_FIELDS);
TNB [TN_ACT] = .TNB [TN_ACT] - 1;
LCBKIL (.LCB); ! Deallocate LCB and ULA and LN2
ULASET (.CCB [$sub_field (C_PRM1, LO_BYTE)], 0);
(.IOP [I_LN2]) = 0;
end
else
LCB [LC_LLA] = .CCB [C_LIX];
IOFIN$ (.IOP [I_UCB], .IOP, STXMAP (.CCB [C_STS]), .CCB [C_PRM4]);
$MCB_RETURN_DSR( DSR_CONNECT_BLOCK_SIZE, .CCB[C_ADDR]);
CCBRT$( .CCB);
return
end;
! ************
! ** SXUREJ **
! ************
[S$REJ^-1]:
begin
bind
TNB = CCB [C_PRM4]: ref block field (TNB_FIELDS);
if .TNB neq 0 then TNB [TN_ACT] = .TNB [TN_ACT] - 1;
COUNT = .CCB [C_CNT]
end;
! ********************************************
! ** SXUGLN, SXUIRQ, SXUMRQ, SXUSND, SXUSNI **
! ********************************************
[inrange]: COUNT = .CCB [C_CNT];
! ************
! ** SXUERR **
! ************
[outrange]: SIGNAL_STOP (SCX$_ISC, .CCB);
tes;
if .IOP neq 0 then IOFIN$ (.IOP [I_UCB], .IOP, STXMAP (.CCB [C_STS]), .COUNT);
CCBRT$ (.CCB)
end;
end
eludom