.TITLE DB_SERVER - Database server process .IDENT /V1.0/ .SBTTL DEFINITIONS ; ;**************************************************************************** ;* * ;* COPYRIGHT (c) 1978, 1980, 1982, 1984 BY * ;* DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. * ;* 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 ITS * ;* SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. * ;* * ;* * ;**************************************************************************** ; ;++ ; FACILITY: DB_SERVER ; ; ABSTRACT: This program demonstrates how to declare a known network ; object and service and manage multiple logical links. The database ; USER_DB is accessed based on the name key supplied in the request buffer. ; ; ENVIRONMENT: User mode ; ; AUTHOR: Scott A. Shurts CREATION DATE: 10-Nov-1986 ; ; MODIFIED BY: ; ;-- .DSABL GLOBAL .LIBRARY /SYS$LIBRARY:LIB.MLB/ ;+ ; Define macros, Determine FATAL from normal DECnet error messages ;- .MACRO BR_FATIO DEST ; Fatal I/O errors CMPL R0,#SS$_BUFFEROVF BEQL DEST CMPL R0,#SS$_FILNOTACC BEQL DEST CMPL R0,#SS$_INSFMEM BEQL DEST .ENDM BR_FATIO .MACRO BR_FATACC DEST ; Fatal connect initiate accept errors CMPL R0,#SS$_DEVALLOC BEQL DEST CMPL R0,#SS$_INSFMEM BEQL DEST CMPL R0,#SS$_IVDEVNAM BEQL DEST .ENDM BR_FATACC ;+ ; Include system macros for definitions ;- $DSCDEF ; Descriptor definitions $DVIDEF ; Getdvi definitions $IODEF ; I/O function definitions $MSGDEF ; Message definitions (mailbox) $NFBDEF ; Network function definitions $RMSDEF ; RMS status values $SSDEF ; System status values ;+ ; Local definitions ;- TEMP_MBX = 0 ; Temporary mailbox MAX_BUFFS = 100 ; Maximum number of buffers MAX_LINKS = 32 ; Maximum number of logical links ( <= 32 ) MAX_MSG = 128 ; Maximum mailbox message (NETCMD) BUF_QUO = 128 ; Only one message MAX_NCB = 110 ; Maximum NCB message size NET_RD = 1 ; Input completion on logical link NET_WRT = 2 ; Output completion on logical link NET_CMD = 3 ; Input completion on net command mailbox FREE_QUE = 0 ; Free queue ( idle buffers ) LIVE_QUE = 1 ; Live queue ( messages to process ) $DEFINI DATA_DEF ; Data buffer/file record layout $DEF DATA_T_NAME .BLKB 20 $EQU DATA_S_NAME < . - DATA_T_NAME > $DEF DATA_T_ACCOUNT .BLKB 11 $EQU DATA_S_ACCOUNT < . - DATA_T_ACCOUNT > $DEF DATA_T_PHONE .BLKB 14 $EQU DATA_S_PHONE < . - DATA_T_PHONE > $DEF DATA_T_ADDRESS .BLKB 30 $EQU DATA_S_ADDRESS < . - DATA_T_ADDRESS > $DEF DATA_T_LOCATION .BLKB 30 $EQU DATA_S_LOCATION < . - DATA_T_LOCATION > $DEF DATA_L_STATUS .BLKL 1 $DEF DATA_T_SPARE .BLKB 7 $EQU DATA_S_SPARE < . - DATA_T_SPARE > $DEF DATA_K_LEN $DEFEND DATA_DEF $DEFINI MBX_DEF ; DECnet command mailbox messages $DEF MBX_MSG .BLKW 1 $DEF MBX_UNIT .BLKW 1 $DEF MBX_NAME_INFO .BLKB MAX_NCB $DEF MBX_K_LEN $DEFEND MBX_DEF $DEFINI BUFF_DEF ; Complete buffer layout $DEF BUFF_L_FLINK .BLKL 1 $DEF BUFF_L_BLINK .BLKL 1 $DEF BUFF_L_ASTID .BLKL 1 $DEF BUFF_Q_IOSB .BLKQ 1 $DEF BUFF_T_DATA_MBX .BLKB DATA_K_LEN $DEF BUFF_K_LEN $DEFEND ASSUME DATA_K_LEN,GE,MBX_K_LEN $DEFINI ASTID_DEF ; I/O completion parameter (ASTPRM) $DEF ASTID_B_TYPE .BLKB 1 $DEF ASTID_B_NDX .BLKB 1 $DEF ASTID_W_UNUSED .BLKW 1 $DEFEND ASTID_DEF $DEFINI LCT_DEF ; Link control table entry $DEF LCT_W_UNIT .BLKW 1 $DEF LCT_W_CHANNEL .BLKW 1 $DEF LCT_L_CUR_BUFF .BLKL 1 $DEF LCT_K_LEN $DEFEND LCT_DEF ;+ ; Declare external routines and variables ;- .EXTRN LIB$_NOTFOU,- LIB$_QUEWASEMP .SBTTL RO_DATA - Read Only DATA .PSECT RO_DATA RD,NOWRT,EXE NET_DEVICE: .ASCID /_NET:/ NETCMD_MBX: .ASCID /NETCMD_MBX/ .SBTTL RW_DATA - Read Write DATA .PSECT RW_DATA RD,WRT,EXE,QUAD QUE_HDR: .BLKQ 2 ; Queue headers BUFFERS: .BLKB ; Buffers DB_FAB: $FAB - ; Database FAB FNM=,- ; File name FAC=,- ; Get operations MRS=DATA_K_LEN,- ; Max record ORG=,- ; Indexed SHR=,- ; Complete sharing RAT= ; Carriage return DB_RAB: $RAB - ; Database RAB FAB=DB_FAB,- ; Associated FAB RAC=,- ; Key access KRF=0,- ; Key offset KSZ=DATA_S_NAME,- ; Key size USZ=DATA_K_LEN ; Size of user buffer OBJECT_NAME: .ASCID /DB_SERVER/ ; Network object name LINK_CONTROL: .BLKB ; Link Control Table (LCT) LCT_ALLOC_MASK: .BLKL << / 32> + 1> ; Allocation bit mask NCB_DESC: .WORD MAX_NCB ; Descriptor for NCB .WORD 0 ; .ADDRESS NCB NCB: .BLKB MAX_NCB ; Maximum size of NCB NFB_DESC: .WORD NFB_LEN ; Descriptor for network function block .WORD 0 .ADDRESS NFB NFB: .BYTE NFB$C_DECLNAME ; Declare name function .LONG 0 ; Terminator NFB_LEN = < . - NFB > GETDVI_ITM: .WORD 4 ; GETDVI item list, length .WORD DVI$_UNIT ; Return unit .ADDRESS UNIT ; Unit location .LONG 0 ; Return length .LONG 0 ; Terminator IOSB: .BLKQ 1 ; I/O status block CUR_BUFF: .BLKL 1 ; Current logical link buffer NETCMD_BUFF: .BLKL 1 ; Current NETCMD buffer UNIT: .BLKL 1 ; Temporary unit location MBX_CHAN: .BLKW 1 ; Channel for netcmd mailbox NETDCL_CHAN: .BLKW 1 ; _NET: channel INDEX: .BLKB 1 ; LCT index NET_SHUT: .BLKB 1 ; Shutdown flag .SBTTL CODE - Start of program .PSECT CODE RD,NOWRT,EXE .ENTRY DB_SERVER ^M<> ;+ ; After initialization, requests are processed until a NETSHUT message ; is received in the network command mailbox. ASTs are used to allow ; asynchronous processing, thus accommodating service of several logical ; links concurrently. ;- BSBW INITIALIZATION ; Initialization BLBC R0,99$ ; If LBC, error, return status ; While success and !NET_SHUT 10$: MOVAL CUR_BUFF,R2 ; Return current buffer MOVL #LIVE_QUE,R1 ; Remove from LIVE_QUE BSBW REMQUE_BUFFER ; Remove an entry from the queue BLBC R0,70$ ; If LBC, error, check below MOVL CUR_BUFF,R2 ; Get buffer address MOVAB BUFF_L_ASTID(R2),R3 ; Get base of ASTID CASEB ASTID_B_TYPE(R3),- ; Dispatch the message type #NET_RD,# 20$: .WORD 30$-20$ ; Network command message .WORD 40$-20$ ; Logical link read .WORD 50$-20$ ; Logical link write MOVL #SS$_BADPARAM,R0 ; Invalid type, set error BRB 99$ ; And return status 30$: BSBW PROCESS_REQUEST ; Process logical link read completion BRB 60$ ; Check error and shutdown 40$: BSBW PROCESS_RESPONSE ; Process logical link write completion BRB 60$ ; Check error and shutdown 50$: BSBW PROCESS_NETCMD ; Process DECnet command message 60$: BLBC R0,99$ ; If LBC, error, return status BLBC NET_SHUT,10$ ; If LBC, No shutdown, continue BRB 99$ ; Shutdown, exit 70$: CMPL R0,#LIB$_QUEWASEMP ; Queue empty ? BNEQ 99$ ; If NEQ, No, return status MOVL #SS$_NORMAL,R0 ; Queue empty, reset status $HIBER_S ; Snooze until next request BLBC R0,99$ ; If LBC, error, return status BRB 10$ ; Next 99$: RET INITIALIZATION: BSBW INITIALIZE_VARIABLES ; Initialize variables and queues BLBC R0,99$ ; If LBC, error, return status BSBW DECLARE_NETWORK_OBJECT ; Declare ourself as network object BLBC R0,99$ ; If LBC, error, return status BSBW OPEN_DATABASE ; Open the database BLBC R0,99$ ; If LBC, error, return status BSBW ISSUE_NETCMD_READ ; Issue a read on the NETCMD mailbox 99$: RSB INITIALIZE_VARIABLES: MOVL #SS$_NORMAL,R0 ; Start fresh, no errors CLRB NET_SHUT ; No NETSHUT yet MOVAB BUFFERS,R2 ; Get base of buffers MOVL #FREE_QUE,R1 ; Queue to receive buffers MOVAQ QUE_HDR[R1],R4 ; Get header address CLRL R3 ; For R3 = 0 to MAX_BUFFS-1 10$: INSQTI (R2),(R4) ; Insert buffer into queue at tail ADDL2 #BUFF_K_LEN,R2 ; Bump to next buffer AOBLSS #MAX_BUFFS,R3,10$ ; Next R3 MOVAL NETCMD_BUFF,R2 ; Removed queue buffer MOVL #FREE_QUE,R1 ; Remove from FREE_QUE BSBW REMQUE_BUFFER ; Remove a buffer from queue BLBC R0,99$ ; If LBC, error, return status MOVL NETCMD_BUFF,R2 ; Get buffer for receive 99$: RSB DECLARE_NETWORK_OBJECT: $CREMBX_S - ; Create mailbox to receive netcmd messages PRMFLG=#TEMP_MBX,- ; Temporary mailbox CHAN=MBX_CHAN,- ; Channel MAXMSG=#MAX_MSG,- ; Maximum message size BUFQUO=#BUF_QUO,- ; Message buffering quota LOGNAM=NETCMD_MBX ; Mailbox name BLBC R0,99$ ; If LBC, error, return status $ASSIGN_S - ; Assign a channel to _NET: DEVNAM=NET_DEVICE,- ; _NET: device CHAN=NETDCL_CHAN,- ; Channel MBXNAM=NETCMD_MBX ; Associate mailbox for NETCMD messages BLBC R0,99$ ; If LBC, error, return status $QIOW_S - ; Issue network declare function CHAN=NETDCL_CHAN,- ; Channel to _NET: device FUNC=#IO$_ACPCONTROL,- ; ACP function IOSB=IOSB,- ; I/O status block P1=NFB_DESC,- ; Network function block P2=#OBJECT_NAME ; Object to declare BLBC R0,99$ ; If LBC, error, return status MOVZWL IOSB,R0 ; Get completion status 99$: RSB OPEN_DATABASE: MOVAB DB_FAB,R6 ; Set base of FAB MOVAB DB_RAB,R7 ; Set base of RAB $OPEN (R6) ; Open the file BLBC R0,99$ ; If LBC, error, return status $CONNECT (R7) ; Connect a stream to file 99$: RSB PROCESS_REQUEST: BLBS BUFF_Q_IOSB(R2),10$ ; If LBS, I/O success, process MOVZWL BUFF_Q_IOSB(R2),R0 ; Get completion status ;+ ; The I/O completed with a failure. If the status is not a fatal ; error, treat it as a network failure and recover. Cleanup will be ; performed when the formal DECnet command message is delivered. ;- BR_FATIO 99$ ; Branch if Fatal status ? MOVL #SS$_NORMAL,R0 ; Recover status MOVL #FREE_QUE,R1 ; Queue to insert buffer BSBW INSQUE_BUFFER ; Insert the buffer BRB 99$ ; Return ;+ ; Successful I/O completion ;- 10$: MOVAB BUFF_T_DATA_MBX(R2),R3 ; Get address of data BSBW READ_DATABASE ; Read the database BLBC R0,99$ ; If LBC, error, return status MOVZBL BUFF_L_ASTID+ASTID_B_NDX(R2),R4 ; Get the LCT index BSBW ISSUE_LINK_WRITE ; Return the information 99$: RSB PROCESS_RESPONSE: BLBS BUFF_Q_IOSB(R2),10$ ; If LBS, I/O success, process MOVZWL BUFF_Q_IOSB(R2),R0 ; Get completion status ;+ ; The I/O completed with a failure. If the status is not a fatal ; error, treat it as a network failure and recover. Cleanup will be ; performed when the formal DECnet command message is delivered. ;- BR_FATIO 99$ ; Branch if Fatal I/O status MOVL #SS$_NORMAL,R0 ; Recover status MOVL #FREE_QUE,R1 ; Queue to insert buffer BSBW INSQUE_BUFFER ; Insert the buffer BRB 99$ ; Return ;+ ; Successful I/O completion ;- 10$: MOVAB BUFF_T_DATA_MBX(R2),R3 ; Get address of data MOVZBL BUFF_L_ASTID+ASTID_B_NDX(R2),R4 ; Get the LCT index BSBW ISSUE_LINK_READ ; Issue a read for next request 99$: RSB .ENABL LSB ; Enable LSB for dispatching PROCESS_NETCMD: MOVZWL BUFF_Q_IOSB(R2),R0 ; Get the I/O completion status BLBC R0,99$ ; If LBC, error, return status MOVAB BUFF_T_DATA_MBX(R2),R3 ; Get base of data portion CASEW MBX_MSG(R3),#MSG$_ABORT,- ; Dispatch to appropriate # ; subordinate 10$: .WORD ABORT-10$ ; ( msg$_abort ) .WORD CONFIRM-10$ ; ( msg$_confirm ) .WORD CONNECT-10$ ; ( msg$_connect ) .WORD DISCON-10$ ; ( msg$_discon ) .WORD EXIT-10$ ; ( msg$_exit ) .WORD INTMSG-10$ ; ( msg$_intmsg ) .WORD PATHLOST-10$ ; ( msg$_pathlost ) .WORD PROTOCOL-10$ ; ( msg$_protocol ) .WORD REJECT-10$ ; ( MSG$_REJECT ) .WORD THIRDPARTY-10$ ; ( msg$_thirdparty ) .WORD TIMEOUT-10$ ; ( msg$_timeout ) .WORD NETSHUT-10$ ; ( msg$_netshut ) MOVL #SS$_BADPARAM,R0 ; Unknown message BRB 99$ ; Return status ABORT: DISCON: EXIT: PATHLOST: PROTOCOL: THIRDPARTY: TIMEOUT: MOVZWL MBX_UNIT(R3),UNIT ; Link unit number to cleanup BSBW CLEANUP_LINK ; Cleanup after failure BRB 99$ ; Return with status CONFIRM: INTMSG: REJECT: BSBW NOT_USED ; Messages not used for example BRB 99$ ; Return with status CONNECT: BSBW ESTABLISH_LINK ; Establish link BRB 99$ ; Return with status NETSHUT: BSBW SHUTDOWN ; Shutdown processing 99$: RSB ; Return with status .DSABL LSB ; Enable LSB CLEANUP_LINK: BSBW FIND_LCT ; Locate the LCT entry BLBS R0,10$ ; If LBS, the entry was found MOVL #SS$_NORMAL,R0 ; Not found, reset status and BRB 20$ ; release buffer (timing problem) 10$: MULL3 #LCT_K_LEN,R4,-(SP) ; Calculate the offset MOVAB LINK_CONTROL,R3 ; Get base of table ADDL2 (SP)+,R3 ; Add offset to base $DASSGN_S - ; Deassign the logical link CHAN=LCT_W_CHANNEL(R3) ; Channel BLBC R0,99$ ; If LBC, error, return status BSBW RELEASE_LCT ; Release the LCT entry BLBC R0,99$ ; If LBC, error, return status 20$: MOVL #FREE_QUE,R1 ; Insert into FREE_QUE BSBW INSQUE_BUFFER ; Insert buffer at tail 99$: RSB NOT_USED: ;+ ; Some network command messages are not used in this program. Insert ; them into the FREE_QUE and dismiss the event. ;- MOVL #FREE_QUE,R1 ; Insert into FREE_QUE BSBW INSQUE_BUFFER ; Insert buffer at tail RSB ESTABLISH_LINK: ADDL2 #4,R3 ; Increment past (message/unit) MOVZBL (R3)+,R4 ; Get byte count of device name ADDL2 R4,R3 ; Skip over device string MOVZBL (R3)+,R4 ; Get byte count of information MOVW R4,NCB_DESC ; Update NCB descriptor (length) MOVC3 R4,(R3),NCB ; Copy NCB information into NCB MOVL #SS$_NORMAL,R0 ; Reset status MOVL CUR_BUFF,R2 ; Reset buffer address BSBW ALLOCATE_LCT ; Allocate a link control entry BLBS R0,10$ ; If LSB, entry available ;+ ; Reject the connection, no LCT entries are available. ;- $QIOW_S - ; Reject the request CHAN=NETDCL_CHAN,- ; _NET: channel FUNC=#IO$_ACCESS!IO$M_ABORT,- ; Abort the request IOSB=IOSB,- ; I/O status block P2=#NCB_DESC ; NCB of request BLBC R0,05$ ; If LBC, error, return status MOVL #FREE_QUE,R1 ; Insert into free_que BSBW INSQUE_BUFFER ; Insert buffer at tail 05$: BRW 99$ ; Return with status 10$: MOVAB LINK_CONTROL,R3 ; Get base of LCT MULL3 #LCT_K_LEN,R4,-(SP) ; Calculate offset for index ADDL2 (SP)+,R3 ; Calculate address of LCT entry $ASSIGN_S - ; Assign a channel for logical link DEVNAM=NET_DEVICE,- ; _NET: device CHAN=LCT_W_CHANNEL(R3),- ; Channel MBXNAM=NETCMD_MBX ; DECnet command mailbox BLBC R0,05$ ; If LBC, error, return status $GETDVIW_S - ; Request unit of logical link channel CHAN=LCT_W_CHANNEL(R3),- ; Logical link channel ITMLST=GETDVI_ITM,- ; Item list (unit) IOSB=IOSB ; I/O status block BLBC R0,99$ ; If LBC, error, return status MOVZWL IOSB,R0 ; Get completion status BLBC R0,99$ ; If LBC, error, return status MOVW UNIT,LCT_W_UNIT(R3) ; Insert unit into table $QIOW_S - ; Accept the connect initiate request CHAN=LCT_W_CHANNEL(R3),- ; Logical link channel FUNC=#IO$_ACCESS,- ; Accept IOSB=IOSB,- ; I/O status block P2=#NCB_DESC ; Network Connect Block (NCB) BLBC R0,99$ ; If LBC, error, return status MOVZWL IOSB,R0 ; Get completion status BLBS R0,20$ ; If LBS, Success, continue ;+ ; Check completion status and recover from network errors. ;- BR_FATACC 99$ ; Branch if Fatal accept error ? MOVL #SS$_NORMAL,R0 ; Recover network error BSBW CLEANUP_LINK ; Cleanup the link BRB 99$ ; And return status 20$: MOVL R2,LCT_L_CUR_BUFF(R3) ; Insert current buffer BSBW ISSUE_LINK_READ ; Issue a read on link 99$: RSB SHUTDOWN: ;+ ; A NETSHUT message was received. Set a flag to drop through the main ; processing loop and terminate. ;- MOVB #1,NET_SHUT ; Indicate shutdown MOVL #FREE_QUE,R1 ; Insert into FREE_QUE BSBW INSQUE_BUFFER ; Insert buffer at tail RSB ISSUE_NETCMD_READ: MOVL #NET_CMD,BUFF_L_ASTID(R2) ; Set AST type $QIO_S - ; Issue asynchronous read CHAN=MBX_CHAN,- ; Network command mailbox FUNC=#IO$_READVBLK,- ; Read request IOSB=BUFF_Q_IOSB(R2),- ; I/O status block ASTADR=AST_ROUTINE,- ; AST routine ASTPRM=BUFF_L_ASTID(R2),- ; AST parameter P1=BUFF_T_DATA_MBX(R2),- ; Buffer area P2=#MBX_K_LEN ; Maximum size for receive RSB ; Return with status ISSUE_LINK_READ: MOVAB BUFF_L_ASTID(R2),R3 ; Get base of ASTID MOVB R4,ASTID_B_NDX(R3) ; Set index of LCT MOVB #NET_RD,ASTID_B_TYPE(R3) ; Get I/O type MULL3 #LCT_K_LEN,R4,-(SP) ; Calculate offset for index MOVAB LINK_CONTROL,R3 ; Get base of table ADDL2 (SP)+,R3 ; Calculate address of entry $QIO_S - ; Issue asynchronous read on logical link CHAN=LCT_W_CHANNEL(R3),- ; Logical link channel FUNC=#IO$_READVBLK,- ; Read operation IOSB=BUFF_Q_IOSB(R2),- ; I/O status block ASTADR=AST_ROUTINE,- ; AST routine ASTPRM=BUFF_L_ASTID(R2),- ; AST parameter P1=BUFF_T_DATA_MBX(R2),- ; Data area P2=#DATA_K_LEN ; Maximum size of read RSB ISSUE_LINK_WRITE: MOVAB BUFF_L_ASTID(R2),R3 ; Get base of ASTID MOVB R4,ASTID_B_NDX(R3) ; Set index of LCT MOVB #NET_WRT,ASTID_B_TYPE(R3) ; Get I/O type MULL3 #LCT_K_LEN,R4,-(SP) ; Calculate offset for index MOVAB LINK_CONTROL,R3 ; Get base of table ADDL2 (SP)+,R3 ; Calculate address of entry $QIO_S - ; Issue asynchronous read on logical link CHAN=LCT_W_CHANNEL(R3),- ; Logical link channel FUNC=#IO$_WRITEVBLK,- ; Write operation IOSB=BUFF_Q_IOSB(R2),- ; I/O status block ASTADR=AST_ROUTINE,- ; AST routine ASTPRM=BUFF_L_ASTID(R2),- ; AST parameter P1=BUFF_T_DATA_MBX(R2),- ; Data area P2=#DATA_K_LEN ; Size of write RSB READ_DATABASE: MOVAB DB_RAB,R4 ; Get base of RAB MOVAB DATA_T_NAME(R3),RAB$L_KBF(R4) ; Key address MOVL R3,RAB$L_UBF(R4) ; User buffer $GET (R4) ; Read the record MOVL R0,DATA_L_STATUS(R3) ; Return status to user BLBS R0,99$ ; If LBS, the record was found CMPL #RMS$_RNF,R0 ; Recoverable error ? BNEQ 99$ ; if NEQ, nonrecoverable MOVL #SS$_NORMAL,R0 ; Recoverable reset status 99$: RSB FIND_LCT: MOVAB LINK_CONTROL,R3 ; Get base of table CLRL R4 ; While not found and < MAX_LINKS 10$: BBC R4,LCT_ALLOC_MASK,20$ ; If BC, Entry NOT inuse CMPW LCT_W_UNIT(R3),UNIT ; In use, entry match ? BEQL 99$ ; If EQL, found it 20$: ADDL2 #LCT_K_LEN,R3 ; No match, continue AOBLSS #MAX_LINKS,R4,10$ ; Next MOVL #LIB$_NOTFOU,R0 ; Not found, return status 99$: RSB ALLOCATE_LCT: FFC #0,#MAX_LINKS,LCT_ALLOC_MASK,R4 ; Available entry ? BNEQ 10$ ; If NEQ, available entry MOVL #LIB$_NOTFOU,R0 ; Table full, set and BRB 99$ ; return status 10$: BBSS R4,LCT_ALLOC_MASK,99$ ; Mark entry in use 99$: RSB RELEASE_LCT: BBCC R4,LCT_ALLOC_MASK,10$ ; Clear allocated flag 10$: MULL3 R4,#LCT_K_LEN,-(SP) ; Calculate offset for index MOVAB LINK_CONTROL,R1 ; Get base of LCT ADDL2 (SP)+,R1 ; Calculate address of entry CLRW LCT_W_UNIT(R1) ; Clear unit CLRW LCT_W_CHANNEL(R1) ; Clear channel CLRL LCT_L_CUR_BUFF(R1) ; Clear current buffer RSB REMQUE_BUFFER: MOVAQ QUE_HDR[R1],R3 ; Get address of header REMQHI (R3),(R2) ; Remove a buffer BVC 99$ ; If VC, an entry was removed MOVL #LIB$_QUEWASEMP,R0 ; Queue was empty, return status 99$: RSB INSQUE_BUFFER: MOVAQ QUE_HDR[R1],R3 ; Get address of header INSQTI (R2),(R3) ; Insert the buffer RSB .ENABL LSB .ENTRY AST_ROUTINE ^M MOVL #SS$_NORMAL,R0 ; Cleanup trash from AST delivery MOVZBL 4+ASTID_B_TYPE(AP),R1 ; Get the ASTID MOVZBL 4+ASTID_B_NDX(AP),R3 ; Get the LCT index CASEB R1,#NET_RD,# ; Dispatch to 10$: .WORD QUE_BUFF-10$ ; net_rd, insert in queue in live .WORD QUE_BUFF-10$ ; net_wrt, insert in queue in live .WORD QUE_AND_REISSUE-10$ ; net_cmd, reissue MOVL #SS$_BADPARAM,R0 ; Invalid value BRB 99$ QUE_BUFF: MOVAB LINK_CONTROL,R2 ; Get base of table MULL3 #LCT_K_LEN,R3,-(SP) ; Calculate offset for index ADDL2 (SP)+,R2 ; Add offset to base MOVL LCT_L_CUR_BUFF(R2),R2 ; Buffer to insert MOVL #LIVE_QUE,R1 ; Insert into live BSBW INSQUE_BUFFER ; Insert buffer at tail BRB 90$ ; Return QUE_AND_REISSUE: MOVL NETCMD_BUFF,R2 ; Buffer to insert MOVL #LIVE_QUE,R1 ; Insert into live BSBW INSQUE_BUFFER ; Insert buffer at tail MOVAL NETCMD_BUFF,R2 ; Address for buffer MOVL #FREE_QUE,R1 ; Remove from free BSBW REMQUE_BUFFER ; Remove buffer from head BLBC R0,99$ ; If LBC, error, terminate MOVL NETCMD_BUFF,R2 ; Set buffer to read into BSBW ISSUE_NETCMD_READ ; Issue another read BLBC R0,99$ ; If LBC, error, terminate 90$: $WAKE_S ; Wake the main process BLBC R0,99$ ; If LBC, error, terminate RET 99$: $EXIT_S R0 ; Exit with status .DSABL LSB .END DB_SERVER