.TITLE MONLAV .IDENT /V3.1/ ; This program will dump information about Ethernet based clusters. It ; uses the cluster multicast message to gather information about clusters. ; Author = David Gagne .LIBRARY "SYS$LIBRARY:LIB.MLB" .DISABLE GLOBAL $IODEF ;Define I/O functions and modifiers $NMADEF ;Define Network Management parameters $LNMDEF ;Define logical name parameters $RMSDEF ;Define RMS data structs,status codes $SSDEF ; define System error codes $LIBDEF ; Define Library macros .SHOW MEB .EXTERNAL LIB$GET_INPUT .EXTERNAL LIB$PUT_OUTPUT .EXTERNAL SYS$FAO ; Modification history ; ; 3.1 Lee Leahy 30 Jan 91 ; 01 Updated LAVc protocol version. ; 02 Defined the MOP code for the DEMFA. ; ; 3.0 Lee Leahy 26 Oct 90 ; 01 Modified to support multi-adapter Local Area Clusters. ; 02 Updated the device table. ; 03 Added support for the DEMFA. ; ; 2.0 David Gagne ; 01 Add the hardware address to the displays. .PSECT DATA PAGE, RD, WRT, NOEXE ; RMS data structures for reading MONLAV.DAT IO_FAB: $FAB FNM=,ORG=SEQ,FAC= IO_RAB: $RAB FAB=IO_FAB, UBF=RECORD, USZ=256 ; QIO data structures for the LAVC channel. ; Setmode parameter buffer SETPARM: .WORD NMA$C_PCLI_PTY ; Protocol type .LONG ^X0760 .WORD NMA$C_PCLI_BFN ; Number of buffers to save .LONG 4 .WORD NMA$C_PCLI_BUS ; Max. receivable buffer size .LONG 1500 .WORD NMA$C_PCLI_MLT ; All multicast addresses .LONG NMA$C_STATE_ON .WORD NMA$C_PCLI_CON ; Set controller mode .LONG NMA$C_LINCN_NOR .WORD NMA$C_PCLI_RES ; Protocol restart. .LONG NMA$C_LINRES_ENA SETPARMLEN = .-SETPARM SETPARMDSC: .LONG SETPARMLEN .ADDRESS SETPARM ; Read buffer for LAVC multicast hello messages RCVBUF: .BLKB 1504 RCVBUFLEN = .-RCVBUF ; Place to store incoming P5 buffer RCVP5: RCVDA: .BLKB 6 RCVSA: .BLKB 6 RCVPTY: .BLKB 2 ; QIO data structures for the MOP (SYSTEM ID) channel. ; P2 parameter buffer for finding devices of other nodes. SIDPARM: .WORD NMA$C_PCLI_PTY ; Protocol Type .LONG ^X0260 .WORD NMA$C_PCLI_CON ; Set controller mode .LONG NMA$C_LINCN_NOR .WORD NMA$C_PCLI_RES ; Protocol restart. .LONG NMA$C_LINRES_ENA SIDPARMLEN = .-SIDPARM SIDPARMDSC: .LONG SIDPARMLEN .ADDRESS SIDPARM ; P2 transmit data buffer for sending request SYSID messages. XMTP2BUF: .BYTE 05 ; SYSTEM ID request code .BYTE 00 ; Reserved XMTRCPT: .WORD 4242 ; Receipt number (to be returned) XMTP2LEN = .-XMTP2BUF ; Address of the node whose Device ID we would like to find. SIDADDR: .BLKB 6 ; Read buffer for receiving System IDs RCVBUF2: .BLKB 1504 RCVBUFLEN2 = .-RCVBUF2 ; Place to store incoming P5 buffer RCVP52: RCVDA2: .BLKB 6 RCVSA2: .BLKB 6 RCVPT2: .BLKB 2 ; Node name descriptor NAMDSC: .LONG 6 ; Node name is always 6 characters .LONG RCVBUF+25 ; Node name is always at byte 25 ; in the receive buffer IDDESC: .LONG 40 ; maximum Identifier string length IDSTR: .BLKL 1 ; address of ID string ; Save the previous node name. PREVIOUS_NODE: .BLKQ 1 ; Message structures ; General message buffer LINE_LENGTH = 80 FAODESC: FAOLEN: .LONG LINE_LENGTH .ADDRESS FAOBUF FAOBUF: .BLKB LINE_LENGTH .MACRO MSG message_text, ?label .SAVE_PSECT .PSECT TEXT RD, NOWRT, NOEXE label: .ASCID "message_text" .RESTORE_PSECT .ADDRESS label .ENDM MSG .ALIGN LONG NONAME: .ASCID "!5UW = !AS" HDR_MSGS: MSG .LONG 0 INP_MSGS: MSG MSG < 1) Monitor a single cluster node> MSG < 2) Monitor all nodes in a specific cluster> MSG < 3) Monitor all nodes in all clusters> MSG < 4) Monitor all nodes is all clusters, LTM display> MSG < any other input will stop the program> .LONG 0 IOMSG: .ASCID "!/The contents of the 2nd longword in the IOSB is !XL" NDMSG: .ASCID "No device found. Please define ETH appropriately." DNEMSG: .ASCID "MONLAV complete. Thank you for your continued support." BLNKMSG: .ASCID "" ; Output strings for monitoring a single cluster node .ALIGN LONG M1_HDR: MSG < Monitor output from a single cluster node> MSG < -----------------------------------------> .LONG 0 M1NAME: .ASCID " Node name: !AS" M1NODE: .ASCID " Node number: !2UB.!UW" M1ADDR: .ASCID " Node address: !XB-!XB-!XB-!XB-!XB-!XB" M1GRUP: .ASCID " Cluster Group Number: !UW" M1CMCA: .ASCID " Cluster Multicast Address: AB-00-04-01-!XB-!XB" M1IDEN: .ASCID " Identifier: !AS" M1DTYP: .ASCID " Ethernet controller: !UB = !AS" M1HWA: .ASCID " Hardware address: !XB-!XB-!XB-!XB-!XB-!XB" M1NHWA: .ASCID " Hardware address: None found" M1NOTC: .ASCID " This node is not in a cluster or cannot be monitored." ; Output strings for monitoring all nodes in a specific cluster .ALIGN LONG M2_HDR: MSG < Monitor output from all nodes in a specific cluster> MSG < ---------------------------------------------------> .LONG 0 M2GHDR: .ASCID " ==================================================== " M2GRUP: .ASCID " !UW) Cluster Group Number: !UW (AB-00-04-01-!XB-!XB)" M2IDEN: .ASCID " Identifier: !AS" .ALIGN LONG M2_HDR2: MSG < System LAN Device Device Node LAN> MSG < Name ID Hardware Address Name Type Number DECnet Address> MSG < ------ ------ ----------------- ---- -------- ------- -----------------> .LONG 0 M2INFO: .LONG LINE_LENGTH .ADDRESS M2INFO_BUF M2INFO_BUF: .BLKB LINE_LENGTH M2INF1: .ASCID '!3UB) !6AD !5UW ' M2INF2: .ASCID '!XB-!XB-!XB-!XB-!XB-!XB' M2INF3: .ASCID ' !4AC !2UB=!5AS' M2INF4: .ASCID ' !7 !XB-!XB-!XB-!XB-!XB-!XB' M2NIN3: .ASCID "None found " M2NOTC: .ASCID " This cluster does not exist or cannot be monitored." LTM_MCA: .ASCID 'AB-00-04-01-!XB-!XB CLUSTER_!UW' LTM_DECNET: .ASCID '!XB-!XB-!XB-!XB-!XB-!XB !AD' LTM_HWA: .ASCID '!XB-!XB-!XB-!XB-!XB-!XB !AD_!AS' ; Output strings for monitoring all nodes in all clusters .ALIGN LONG M3_HDR: MSG < Monitor output from all nodes in all clusters> MSG < ---------------------------------------------> .LONG 0 M3TRLR: .ASCID " Total of !UW cluster!%S and !UL cluster node!%S found." M3NOTC: .ASCID " No clusters found." ; Strings for various device names .MACRO LAN_DEVICE value, dev_name, ?label .ENABLE LOCAL_BLOCK .SAVE_PSECT .PSECT TEXT label: .ASCII "dev_name" DEV_NAME_LEN = . - label .PSECT DEV_NAME_TABLE QUAD, RD, NOWRT, NOEXE .IF NOT_DEFINED DEV_NAME_TABLE DEV_NAME_TABLE: .ENDC .LONG DEV_NAME_LEN ; Build the string descriptor. .ADDRESS label .PSECT DEV_TYPE_TABLE RD, NOWRT, NOEXE .IF NOT_DEFINED DEV_TYPE_TABLE DEV_TYPE_TABLE: .ENDC .BYTE value .RESTORE_PSECT .DISABLE LOCAL_BLOCK .ENDM LAN_DEVICE LAN_DEVICE 1, DEUNA LAN_DEVICE 5, DEQNA LAN_DEVICE 11, DELUA LAN_DEVICE 17, LANCE LAN_DEVICE 23, DEBNA LAN_DEVICE 37, DELQA LAN_DEVICE 39, DESVA LAN_DEVICE 65, DEBNI LAN_DEVICE 66, DEMNA LAN_DEVICE 75, DEQTA LAN_DEVICE 93, DEMFA .LONG 0 ; End of list. DEVNR: .ASCID "Noans" DEVUK: .ASCID "Unkwn" DEVMS: .ASCID "Misng" DEVDSC: .BLKQ 1 ; General device name descriptor DEVID: .BLKB 1 ; Device ID from SYSID response HWA: .BLKB 6 ; Device HWA from SYSID response ; Buffers, variables, and strings for the time control of the program HOURS: .BLKB 1 ; Storage of requested input MINUTES:.BLKB 1 SECONDS:.BLKB 1 ; The following variable are for reading input from the user after prompting. INPSTRDSC: ; Input buffer descriptor .LONG 0 .ADDRESS INPSTR INPSTR: .BLKB 18 ; Input buffer INPSIZ: .BLKL 1 ; The prompts are defined next. RPRMT: .ASCID "Which monitor request would you like to make: " HPRMT: .ASCID "How many hours would you like to monitor: " MPRMT: .ASCID "How many minutes would you like to monitor: " SPRMT: .ASCID "How many seconds would you like to monitor: " APRMT: .ASCID "Enter the address of the node (ex: AA-00-04-00-75-4C): " CPRMT: .ASCID "Which Cluster Group Code: " ; Input variables from prompts TESTNO: .BLKB 1 ; Test number DSTADR: .BLKB 6 ; Address to look for CGC: .BLKW 1 ; Cluster Group Code to look for ENDTIM: .BLKQ 1 ; Time to end test TIME: .BLKQ 1 ; Temporary time buffer DTIME: .ASCID /0 !2ZB:!2ZB:!2ZB.00/ ; String for calculating delta time ; Miscellaneous variables CMCA: .BLKW 1 ; Cluster Multicast Address (last ; two bytes) CLUSNO: .BLKW 1 ; Cluster number - used to count ; the number of clusters RCVTRY: .BLKL 1 ; Counter for receive attempts IOSB: .BLKQ 1 ; I/O status block IOSB_HWA: .BLKQ 1 ; I/O status block for MOP requests. ; Device names .ALIGN LONG DEVADR: MSG ETH ; Units to use for test. MSG ESA0 MSG ETA0 MSG EXA0 MSG EZA0 MSG FXA0 MSG XEA0 MSG XQA0 .LONG 0 ; Channels - one for LAVC and one for Remote Console CHNLAV: .BLKL 1 CHNRMC: .BLKL 1 .PSECT CODE PAGE, RD, NOWRT, EXE .ENTRY START,^M<> ; See if ther is a MONLAV.DAT file and read in the IDs if ther are any BSBW DO_FILE ; Assign both channels to the first device found which is available CLRL R5 ; Check each channel name to see if one 10$: TSTL DEVADR(R5) ; is available until one is found: the BEQL 30$ ; first name checked is "ETH", a dummy MOVL DEVADR(R5),R4 ; name which can be defined to the $ASSIGN_S- ; device desired if either: DEVNAM=(R4),- ; 1) An unregistered device is used CHAN=CHNLAV ; or 2) One device is prefered BLBS R0,20$ ; If success, assign the 2nd channel ADDL #4,R5 ; Skip to next device name CMPW R0,#SS$_NOSUCHDEV ; Was the error "no such device"? BEQL 10$ ; If yes, try next device name BSBW ERROR ; Else, exit with error 20$: $ASSIGN_S- ; Assign the 2nd channel to the same DEVNAM=(R4),- ; device name CHAN=CHNRMC BLBS R0,ASSIGN_OK ; If success, continue BSBW ERROR ; Else, exit with an error ; No device was found. 30$: BSBW BLANK ; No device was found, so say so and PUSHAB NDMSG ; then exit. CALLS #1, OUTPUT_LINE BRW EXIT ASSIGN_OK: ; Start up the first channel for examining LAV packets. $QIOW_S FUNC=#,- CHAN=CHNLAV,- IOSB=IOSB,- P2=#SETPARMDSC BLBS R0,START_REQ_OK1 BSBW ERROR START_REQ_OK1: MOVZWL IOSB,R0 BLBS R0,START_IO_OK1 BSBW ERROR START_IO_OK1: ; Start up the second channel for getting the device ID and name. $QIOW_S FUNC=#,- CHAN=CHNRMC,- IOSB=IOSB,- P2=#SIDPARMDSC BLBS R0,START_REQ_OK2 BSBW ERROR START_REQ_OK2: MOVL IOSB,R0 BLBS R0,START_IO_OK2 BSBW ERROR START_IO_OK2: ; Print program header BSBW BLANK PUSHAB HDR_MSGS CALLS #1, OUTPUT_TEXT GET_TEST: ; Print the prompt that requests which monitor request the user wants. This ; is also the top of the loop that allows the user to make multiple monitor ; requests. BSBW BLANK PUSHAB INP_MSGS CALLS #1, OUTPUT_TEXT BSBW BLANK ; Read the user's input to our prompt for the number of the test to run. MOVL #2,INPSTRDSC ; Set number of bytes to read PUSHAB INPSIZ ; Push input size parameter PUSHAB RPRMT ; Push prompt string parameter PUSHAB INPSTRDSC ; Push String descriptor parameter CALLS #3,G^LIB$GET_INPUT ; Read the user's input ; Convert the input to a test number. CLRL R1 ; Start with zero in test number CLRL R2 ; Clear # of input characters done 10$: CMPW R2,INPSIZ ; Have we processed all the input? BGEQU 20$ ; If EQL, yes MOVZBL INPSTR(R2),R0 ; Get an input character SUBL2 #^A/0/,R0 ; Convert to a digit MULL2 #^D10,R1 ; Shift current decimal digits ADDL2 R0,R1 ; Add new digit INCL R2 ; Bump # of input characters done BRB 10$ ; Check next character ; Clear the per-test global variables. 20$: CLRL NODCNT CLRB HOURS CLRB MINUTES CLRB SECONDS ; Now perform the appropriate test based on the test number. MOVB R1,TESTNO ; Store test number for later CMPL R1,#1 ; Check if test #1 BNEQ 30$ ; If NEQ, no BSBW TEST_1 ; Do test BRW GET_TEST ; Check for another test to run 30$: CMPL R1,#2 ; Check if test #2, #3, or #4 BLSS 50$ ; No - branch CMPL R1,#4 ; Check if test #2, #3, or #4 BGTRU 50$ ; No - branch BSBW TEST_2 ; Do test BRW GET_TEST ; Check for another test to run ; Not a supported test, so exit. 50$: BRW EXIT ; Not any of above, so exit ; Test #1 ; ; This test will monitor a single node. It will request that the user enter ; the node's address. We then wait for a message from that address. If we ; don't get a message in 500 reads, then we exit and state that the node ; is not in a cluster or not able to be monitored. If a message from that ; address is received, a report on that node is displayed. TEST_1: BSBW GET_TIME BSBW BLANK BSBW GET_ADDR ; Get the target node's address BSBW SET_TIME ;========================================================================== ; Print the header BSBW BLANK PUSHAB M1_HDR CALLS #1, OUTPUT_TEXT ; Read messages until we find one from the target node or until we've ; looked for the requested amount of time. RCV_T1: ; Check if we've been looping for the requested amount of time. $GETTIM_S- ; Get current time TIMADR=TIME CMPL TIME+4,ENDTIM+4 ; Did we look long enough? BEQL 10$ ; If equal, need to check low longword BLSSU 20$ ; If LSSU, continue BRW NOTC_T1 ; Else end search for the node 10$: CMPL TIME,ENDTIM ; Check low longword BLSSU 20$ ; If LSSU, continue BRW NOTC_T1 ; Else, end search for the node 20$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNLAV,- IOSB=IOSB,- P1=RCVBUF,- P2=#RCVBUFLEN,- P5=#RCVP5 BLBS R0,RCV_REQ_OK_T1 BSBW ERROR RCV_REQ_OK_T1: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK_T1 CMPW R0,#SS$_ENDOFFILE BEQL RCV_T1 BSBW ERROR RCV_IO_OK_T1: ; Check if this is a multicast message. If not, throw it away and look for ; another message. BLBC RCVDA, 10$ ; Ignore packet if sent to physical ; Now check to see if the source address is the desired one. CMPL DSTADR,RCVSA ; First part of address okay? BNEQ 10$ ; If not, read another one CMPW DSTADR+4,RCVSA+4 ; Second part of address okay? BEQL PRINT_T1 ; If so, print it 10$: BRW RCV_T1 ; Else, read another one PRINT_T1: ; The address was the desired one, so print the results ;========================================================================== ; Print the node name PUSHAB NAMDSC PUSHAB M1NAME CALLS #2, FAO_LINE ;========================================================================== ; Print the node number CMPL #^X000400AA,DSTADR ; Is this a DECnet address? BNEQ 10$ ; If NEQ, no, so don't print it MOVZWL DSTADR+4,R0 BICW #^XFC00,R0 MOVZBL DSTADR+5,R1 ASHL #-2,R1,R1 PUSHL R0 PUSHL R1 PUSHAB M1NODE CALLS #3, FAO_LINE ;========================================================================== ; Print the node address 10$: MOVZBL DSTADR+5, -(SP) MOVZBL DSTADR+4, -(SP) MOVZBL DSTADR+3, -(SP) MOVZBL DSTADR+2, -(SP) MOVZBL DSTADR+1, -(SP) MOVZBL DSTADR, -(SP) PUSHL M1ADDR CALLS #7, FAO_LINE ;========================================================================== ; Print the cluster group code number MOVZWL RCVBUF+6, -(SP) PUSHAB M1GRUP CALLS #2, FAO_LINE ;========================================================================== ; Print the cluster multicast address MOVW RCVBUF+6,CMCA ADDW #^D256,CMCA MOVZBL CMCA+1, -(SP) MOVZBL CMCA, -(SP) PUSHAB M1CMCA CALLS #3, FAO_LINE ;========================================================================== ; Print the Ethernet controller ID and name MOVL DSTADR,SIDADDR MOVW DSTADR+4,SIDADDR+4 MOVB #^XFF, HWA ; Set no hardware address found flag. BSBW GET_IDHWA PUSHAB DEVDSC PUSHL DEVID PUSHAB M1DTYP CALLS #3, FAO_LINE ;======================================================================== ; Check the IDTBL for an entry for this cluster group code and ; print the Identifier if one is found MOVZWL RCVBUF+6,R0 ; get the cluster group code of interest BSBW FIND_ID ; try find an ID string for this ; cluster group code CMPW R0,#0 ; did we find an ID? BEQL DO_HWA ; no, => DO_HWA and continue ; Do the FAO for M1IDEN and print this ID MOVL R0,IDSTR ; set up the template descriptor PUSHAB IDDESC PUSHAB M1IDEN CALLS #2, FAO_LINE ;========================================================================== ; Print the Hardware address (if none, print "none found") DO_HWA: CMPB HWA,#^XFF BNEQ 20$ PUSHAB M1NHWA CALLS #1, OUTPUT_LINE BRB 30$ 20$: MOVZBL HWA+5, -(SP) MOVZBL HWA+4, -(SP) MOVZBL HWA+3, -(SP) MOVZBL HWA+2, -(SP) MOVZBL HWA+1, -(SP) MOVZBL HWA, -(SP) PUSHAB M1HWA CALLS #7, FAO_LINE 30$: ;========================================================================== RSB NOTC_T1: ; We could not find a multicast message from the node, so print the ; appropriate output. ;========================================================================== ; Print the node number CMPL #^X000400AA,DSTADR ; Is this a DECnet address? BNEQ 10$ ; If NEQ, no, so don't print it MOVZWL DSTADR+4,R0 BICW #^XFC00,R0 MOVZBL DSTADR+5,R1 ASHL #-2,R1,R1 PUSHL R0 PUSHL R1 PUSHAB M1NODE CALLS #3, FAO_LINE ;========================================================================== ; Print the node address 10$: MOVZBL DSTADR+5, -(SP) MOVZBL DSTADR+4, -(SP) MOVZBL DSTADR+3, -(SP) MOVZBL DSTADR+2, -(SP) MOVZBL DSTADR+1, -(SP) MOVZBL DSTADR, -(SP) PUSHAB M1ADDR CALLS #7, FAO_LINE ;========================================================================== ; Print the "node not in a cluster" message PUSHAB M1NOTC CALLS #1, OUTPUT_LINE ;========================================================================== RSB ; Return to caller ; Test #2 & Test #3 ; ; 2) This test will monitor all nodes in a specific cluster. ; 3) This test will monitor all nodes in all clusters. ; 4) This test will monitor all nodes in all clusters and generate an LTM display. TEST_2: BSBW GET_TIME CMPB TESTNO, #2 ; Skip over GET_CGC if not test 2. BNEQ 10$ ; Tests 3 or 4 - branch. BSBW BLANK BSBW GET_CGC 10$: BSBW SET_TIME ;========================================================================== ; Print the header CLRW CLUSNO ; Start with no clusters MOVAB M2_HDR, R1 ; Get the header address. CMPB TESTNO, #2 ; Check for test 2. BEQL 20$ ; Test 2 - branch. MOVAB M3_HDR, R1 ; Get the header address. CMPB TESTNO, #4 ; Skip if test 4. BEQL RCV_T2 ; Test 4 - branch. 20$: PUSHL R1 ; Set the header address. BSBW BLANK CALLS #1, OUTPUT_TEXT ; Display the header. ; Read and store messages for time requested. Then print the results. RCV_T2: ; Check if we've been looping for the requested amount of time. $GETTIM_S- ; Get current time TIMADR=TIME CMPL TIME+4,ENDTIM+4 ; Did we look long enough? BEQL 10$ ; If equal, need to check low longword BLSSU 20$ ; If LSSU, continue BRW PRINT_T2 ; Else stop monitoring 10$: CMPL TIME,ENDTIM ; Check low longword BLSSU 20$ ; If LSSU, continue BRW PRINT_T2 ; Else, stop monitoring 20$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNLAV,- IOSB=IOSB,- P1=RCVBUF,- P2=#RCVBUFLEN,- P5=#RCVP5 BLBS R0,RCV_REQ_OK_T2 BSBW ERROR RCV_REQ_OK_T2: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK_T2 CMPW R0,#SS$_ENDOFFILE BEQL RCV_T2 BSBW ERROR RCV_IO_OK_T2: ; If this is not a multicast packet or if this packet is not for the cluster ; we are monitoring (test 2 only), then ignore the packet. BLBC RCVDA, 22$ ; Ignore packet if sent to physical CMPB TESTNO, #2 ; Only check CGC for test 2. BNEQ 10$ ; Test 3 or 4 - branch. CMPW CGC,RCVBUF+6 ; Ignore packet if not in the ; specified cluster BNEQ 22$ ; If NEQ, then wrong cluster ; Check to see if this node is already in the node table. To match, the ; address and the cluster group code have to match an entry in the table. ; This allows us to log nodes that were in more than one cluster during the ; time of the monitoring. 10$: CLRL R1 ; Clear the number of entries checked MOVAL NODTBL,R2 ; Start at beginning of table 20$: CMPL R1,NODCNT ; Have we checked the entire table? BGEQU 40$ ; If GEQU, yes, so insert the node CMPL #^X000400AA,RCVSA ; Is this a DECnet address? BNEQ 25$ ; No - branch. CMPL RCVSA,(R2) ; Does the address match? BNEQ 30$ ; If NEQ, no, try next table entry CMPW RCVSA+4,4(R2) ; Does address match BNEQ 30$ ; If NEQ, no, try next table entry BRB 27$ 22$: BRW RCV_T2 25$: CMPL RCVSA, 24(R2) ; Does the address match? BNEQ 30$ ; No - branch. CMPW RCVSA+4,28(R2) ; Does the address match? BNEQ 30$ ; No - branch. 27$: CMPW RCVBUF+6,6(R2) ; Does cluster group code match? BEQL 22$ ; If EQL, yes, node already in table 30$: INCL R1 ; Bump our counter ADDL #NODSIZ,R2 ; Bump table entry pointer BRB 20$ ; Check next entry ; The node was not in the table, so add it if there are entries left. If ; there is space, the R2 is already pointing to an empty slot. 35$: BRW PRINT_T2 40$: CMPL NODCNT,#MAXNOD ; Is the table full? BGEQU 35$ ; If GEQU, yes, so print results ; Store this node's information. MOVL RCVSA, HWA ; Store 1st part of LAN hardware address MOVW RCVSA+4, HWA ; Store 2nd part of LAN hardware address MOVL RCVSA,(R2)+ ; Store 1st part of LAN DECnet address MOVW RCVSA+4,(R2)+ ; Store 2nd part of LAN DECnet address MOVW RCVBUF+6,(R2)+ ; Store cluster group code MOVL RCVBUF+14+10+1,(R2)+ ; Store 1st part of name MOVW RCVBUF+14+10+1+4,(R2)+ ; Store 2nd part of name MOVB RCVBUF+14+10, (R2)+ ; Save the node name length. MOVL RCVSA,SIDADDR ; Set up to call GET_IDHWA MOVW RCVSA+4,SIDADDR+4 ; Set up to call GET_IDHWA PUSHL R2 ADDL # 1 + 8 + 6, R2 ; Skip some of the fields. MOVW RCVBUF+8+4,(R2)+ ; Store SCSSYSTEMID MOVQ #^A' ', (R2) ; Assume no device specified. MOVQ #^A' ', 8(R2) ; Assume no device specified. CLRB (R2) ; No device name specified. CMPW IOSB+2, # 14 + 97 ; Check the LAVC protocol version. BLSSU 50$ ; Prior to V1.3 - branch. MOVQ RCVBUF+14+74, (R2) ; Save the device name. MOVQ RCVBUF+14+74+8, 8(R2) MOVL RCVBUF+14+90, HWA ; Save the LAN hardware address. MOVW RCVBUF+14+90+4, HWA+2 50$: BSBW GET_IDHWA ; Get device information POPL R2 MOVB DEVID,(R2)+ ; Store Device ID MOVQ DEVDSC,(R2)+ ; Store Device name descriptor MOVL HWA,(R2)+ ; Store HWA MOVW HWA+4,(R2)+ ; Store HWA INCL NODCNT ; One more node stored BRW RCV_T2 ; Read next message PRINT_T2: ; If this is test 2, we should just start printing. But if we do all the ; same checking for test 2 as we do for test 3, the output will still be ; the same. So we will not special case test 2. ; If no nodes were found, print the appropriate message. TSTL NODCNT ; Any nodes found? BNEQ PRINT_T2_START ; Print the cluster information BSBW BLANK CMPB TESTNO, #2 ; Check for test 2. BNEQ 10$ ; Test 3 or 4 - branch. INCW CLUSNO ; Count this cluster MOVW CGC,CMCA ADDW #^D256,CMCA PUSHAB M2GHDR CALLS #1, OUTPUT_LINE MOVZBL CMCA+1, -(SP) MOVZBL CMCA, -(SP) MOVZWL CGC, -(SP) PUSHL CLUSNO PUSHL M2GRUP CALLS #5, FAO_LINE BSBW BLANK PUSHAB M2NOTC BRB 20$ 10$: PUSHAB M3NOTC 20$: CALLS #1, OUTPUT_LINE RSB PRINT_T2_START: CMPB TESTNO, #4 ; Check for test 4. BNEQ PRINT_T2NEXT ; No - branch. BSBW BLANK PRINT_T2NEXT: ; Locate the lowest cluster group code in the table (other than zero). If ; none are found, then exit. CLRQ PREVIOUS_NODE ; No previous node name. BSBW GET_SMCGC ; Get the smallest CGC in the table TSTW CGC ; Did we get one? BNEQ PRINT_CLUSTER ; If NEQ, yes, so print a report CMPB TESTNO, #3 ; Check for test 3. BNEQ 10$ ; Test 2 or 4 - branch. BSBW BLANK BSBW BLANK PUSHAB M2GHDR CALLS #1, OUTPUT_LINE PUSHL NODCNT PUSHL CLUSNO PUSHAB M3TRLR CALLS #3, FAO_LINE 10$: RSB PRINT_CLUSTER: ; Print the information about each entry in the table. ;========================================================================== ; Print the cluster group number/multicast address and header MOVW CGC,CMCA ADDW #^D256,CMCA CMPB TESTNO, #4 ; Skip header for test 4. BNEQ 10$ ; Not test 4 - branch. MOVZWL CGC, -(SP) ; Cluster group code. MOVZBL CMCA+1, -(SP) ; Cluster multicast address. MOVZBL CMCA, -(SP) PUSHAB LTM_MCA CALLS # 4, FAO_LINE ; Format the multicast address. BRW DO_LTM 10$: BSBW BLANK TSTW CLUSNO ; Is this the first cluster? BEQL 20$ ; If EQL, yes, only one blank line BSBW BLANK 20$: INCW CLUSNO ; Count this cluster PUSHAB M2GHDR CALLS #1, OUTPUT_LINE MOVZBL CMCA+1, -(SP) MOVZBL CMCA, -(SP) MOVZWL CGC, -(SP) PUSHL CLUSNO PUSHAB M2GRUP CALLS #5, FAO_LINE ;======================================================================== ; Check the IDTBL for an entry for this cluster group code and ; print the Identifier if one is found MOVZWL CGC,R0 ; get the cluster group code of interest BSBW FIND_ID ; try find an ID string for this ; cluster group code CMPW R0,#0 ; did we find an ID? BEQL DO_HDR ; no, => DO_HWA and continue ; Do the FAO for M2IDEN and print this ID MOVL R0,IDSTR ; set up the template descriptor PUSHAB IDDESC PUSHAB M2IDEN CALLS #2, FAO_LINE ;========================================================================== ; Print the table header DO_HDR: BSBW BLANK PUSHAB M2_HDR2 CALLS #1, OUTPUT_TEXT ;========================================================================== ; Print the information about each node - in a loop DO_LTM: CLRL R1 ; Start our node counter at zero NEXT_NODE: BSBW GET_NODE ; Get next node to print TSTL R2 ; Did we get one? BNEQ 30$ ; If NEQ, yes, so print it BRW PRINT_T2NEXT ; Else we're done with this cluster 25$: BRW PRINT_LTM ; Display the LTM data. 30$: CLRW 6(R2) ; Clear the CGC so we don't look at ; this entry any more in GET_NODE CMPB TESTNO, #4 ; Check for test 4. BEQL 25$ ; LTM display - branch. MOVL #3+1+1+6+2+5+2+17,M2INFO ; Set the blank fill length. MOVAB M2INFO_BUF, M2INFO+4 PUSHR # ^M < R0, R1, R2, R3, R4, R5 > MOVC5 #0, (SP), #^A' ', #LINE_LENGTH, M2INFO_BUF ; Blank fill the string. POPR # ^M < R0, R1, R2, R3, R4, R5 > MOVAB 8(R2), R0 ; Get node name address. CMPL (R0), PREVIOUS_NODE ; Check for same node name. BNEQ 31$ ; No, another node - branch. CMPW 4(R0), 4+PREVIOUS_NODE ; Check for same node name. BEQL 32$ ; Yes - branch. 31$: INCL R1 ; Bump our counter - for printing MOVQ R1,-(SP) MOVQ (R0), PREVIOUS_NODE ; Set the next node name. MOVL #LINE_LENGTH,M2INFO ; Set the line length. $FAO_S CTRSTR=M2INF1,- OUTLEN=M2INFO,- OUTBUF=M2INFO,- P1=R1,- P2=#6, - P3=R0, - P4=30(R2) ; SCS system ID. MOVQ (SP)+, R1 ; Restore buffer address. 32$: MOVQ R1,-(SP) CMPL 24(R2), #^X000400AA ; Check for DECnet address. BEQL 33$ ; Yes - branch. MOVZWL M2INFO, R0 ; Get the line length. SUBL #17, R0 ; Remove the blank LAN address. ADDL R0, M2INFO+4 ; Set the next buffer piece. SUBW3 R0, #LINE_LENGTH, M2INFO ; Set remainder of message. MOVAB 6+24(R2), R1 ; Set end of LAN hardware address. MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) PUSHAW M2INFO PUSHAB M2INFO PUSHAB M2INF2 CALLS #9, G^ SYS$FAO MOVQ (SP), R1 ; Restore buffer address. 33$: MOVZWL M2INFO, R0 ; Get the line length. ADDL R0, M2INFO+4 ; Set the next buffer piece. SUBW3 R0, #LINE_LENGTH, M2INFO ; Set remainder of message. PUSHAB 16(R2) ; Device type descriptor address. MOVZBL 15(R2), -(SP) ; Device type ID value. PUSHAB 32(R2) ; Device name address. PUSHAW M2INFO PUSHAB M2INFO PUSHAB M2INF3 CALLS #6, G^ SYS$FAO ; Format the string. MOVQ (SP), R1 ; Restore buffer address. MOVZWL M2INFO, R0 ; Get the line length. ADDL R0, M2INFO+4 ; Set the next buffer piece. SUBW3 R0, #LINE_LENGTH, M2INFO ; Set remainder of message. CMPL (R2), #^X000400AA ; Check for DECnet address. BNEQ 35$ ; No DECnet info - branch. MOVAB 6(R2), R1 ; Set end of LAN DECnet address. MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) EXTZV #0, #10, 4(R2), -(SP) ; DECnet node number. EXTZV #10, #6, 4(R2), -(SP) ; DECnet area number. PUSHAW M2INFO PUSHAB M2INFO PUSHAB M2INF4 CALLS #11, G^ SYS$FAO MOVZWL M2INFO, R0 ; Get the line length. ADDL R0, M2INFO+4 ; Set the next buffer piece. 35$: MOVAB M2INFO_BUF, R0 SUBL3 R0, M2INFO+4, M2INFO ; Set the buffer length. MOVL R0, M2INFO+4 ; Set the buffer address. PUSHAB M2INFO CALLS #1, OUTPUT_LINE ; Display the node line. MOVQ (SP)+,R1 BRW NEXT_NODE ; Go to top of loop PRINT_LTM: ; ; Compute the node name length. ; MOVZBL 14(R2), R1 ; Get the node name length. 10$: CMPB -1+8(R2)[R1], # ^A' ' ; Check for a space. BNEQ 20$ ; No, node name length found - branch. SOBGTR R1, 10$ ; Set the next node name length. 20$: MOVB R1, 14(R2) ; Set the node name length. ; ; Display the DECnet address and the node name. ; CMPL # ^X 000400AA, (R2) ; Check for DECnet address. BNEQ 30$ ; No, hardware address only - branch. MOVAB 6(R2), R1 ; Set the end of the DECnet address PUSHAB 8(R2) ; Node name address. MOVZBL 14(R2), -(SP) ; Length of the node name. MOVZBL -(R1), -(SP) ; DECnet LAN address. MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) PUSHAB LTM_DECNET CALLS # 9, FAO_LINE ; Display DECnet LAN address and SCSNODE. 30$: ; ; Display the LAN hardware address if available. ; CMPL # ^X 000400AA, 24(R2) ; Check for LAN hardware address. BEQL 50$ ; No hardware address - branch. MOVAB 24+6(R2), R1 ; Set the end of the LAN address. MOVAB 32+1(R2), M2INFO+4 ; Set the device name address. MOVZBL 32(R2), M2INFO ; Set the device name length. BNEQ 40$ ; Device name is available - branch. MOVQ 16(R2), M2INFO ; Set the device type name. 40$: PUSHAB M2INFO ; Device name address. PUSHAB 8(R2) ; SCSNODE name address. MOVZBL 14(R2), -(SP) ; Node name length. MOVZBL -(R1), -(SP) ; LAN hardware address. MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) MOVZBL -(R1), -(SP) PUSHAB LTM_HWA CALLS # 10, FAO_LINE ; Display the LAN hardware address. 50$: BRW NEXT_NODE GET_IDHWA: ; Get the node's device ID, device name, and HWA. This is done by requesting ; a SYSID message from the node. The response (if any) contains the device ; ID. From the device ID, we will select the correct device name. Upon ; completion of this routine, DEVID (a byte) will have the device ID and ; DEVDSC will point to the device name. The response also contains the ; hardware address. CLRB DEVID ; Clear the Device ID number MOVQ DEVNR,DEVDSC ; Set the device name to no response ; Transmit the request ID message to the node we want to find out about. $QIOW_S FUNC=#IO$_WRITEVBLK,- CHAN=CHNRMC,- IOSB=IOSB_HWA,- P1=XMTP2BUF,- P2=#XMTP2LEN,- P5=#SIDADDR BLBS R0,DXMT_REQ_OK BSBW ERROR DXMT_REQ_OK: MOVL IOSB_HWA,R0 BLBS R0,DXMT_IO_OK BSBW ERROR DXMT_IO_OK: ; Receive the SYSID response. If there is no data ready to receive, then the ; Ethernet driver will return immediately with SS$_ENDOFFILE. CLRL RCVTRY ; Clear the number of read attempts DRCV: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNRMC,- IOSB=IOSB_HWA,- P1=RCVBUF2,- P2=#RCVBUFLEN2,- P5=#RCVP52 BLBS R0,DRCV_REQ_OK BSBW ERROR DRCV_REQ_OK: MOVL IOSB_HWA,R0 BLBS R0,DRCV_IO_OK CMPW IOSB_HWA,#SS$_ENDOFFILE BEQL DRCV_TRY BSBW ERROR DRCV_TRY: CMPL RCVTRY,#4000 ; Have we tried enough times? BGTR 20$ ; If GTR, yes, so message is lost INCL RCVTRY ; Count this attempt BRB DRCV ; Try again 20$: RSB ; Return to caller DRCV_IO_OK: ; Check that this is a SYSTEM ID message from the correct node. CMPB RCVBUF2,#7 ; Is this a SYSTEM ID message? BNEQ DRCV_TRY ; If NEQ, no, try again CMPL RCVSA2,SIDADDR ; Correct node? BNEQ DRCV_TRY ; If NEQ, no CMPW RCVSA2+4,SIDADDR+4 ; Correct node? BNEQ DRCV_TRY ; If NEQ, no ; We received a message from the remote node. Look for the Device ID entry ; in this SYSID message. MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the Device ID entry. 10$: CMPW R3,IOSB_HWA+2 ; Any buffer left to look at? BLSSU 20$ ; If LSSU, yes, so look for more BRW 50$ ; Else report Device ID missing 20$: CMPW RCVBUF2(R3),#^D100 ; Is this the device ID entry? BEQL 30$ ; If EQL, yes MOVZBL RCVBUF2+2(R3),R1 ; Get size of this entry ADDL #3,R3 ; Skip over entry type and size ADDL R1,R3 ; Skip over entry value BRW 10$ ; Check next entry ; The Device ID was found. Store the Device ID and select a device name. 30$: ADDL #3,R3 ; Skip over Device ID header MOVB RCVBUF2(R3),DEVID ; Store the Device ID MOVZBL DEVID, R2 ; Get the Device ID value. CLRL R3 ; Set the table index. 40$: TSTL DEV_NAME_TABLE[R3] ; Check for an entry. BEQL 60$ ; None - branch. MOVQ DEV_NAME_TABLE[R3], - ; Copy the string descriptor. DEVDSC CMPB R2, DEV_TYPE_TABLE[R3] ; Is this the ID value. BEQL 70$ ; Yes - branch. INCL R3 BRB 40$ 50$: CLRB DEVID ; No Device ID was found MOVQ DEVMS,DEVDSC ; Device ID is missing BRB 70$ 60$: MOVQ DEVUK,DEVDSC ; This is an unknown device 70$: ; Now look for the Hardware address in the SYSID response. MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the HWA entry. 310$: CMPW R3,IOSB_HWA+2 ; Any buffer left to look at? BLSSU 320$ ; If LSSU, yes, so look for more BRW 340$ ; Else report HWA missing 320$: CMPW RCVBUF2(R3),#^D7 ; Is this the HWA entry? BEQL 330$ ; If EQL, yes MOVZBL RCVBUF2+2(R3),R1 ; Get size of this entry ADDL #3,R3 ; Skip over entry type and size ADDL R1,R3 ; Skip over entry value BRW 310$ ; Check next entry ; The HWA was found. Store the HWA. 330$: ADDL #3,R3 ; Skip over HWA header MOVL RCVBUF2(R3),HWA ; Store first longword MOVW RCVBUF2+4(R3),HWA+4 ; Store last word RSB 340$: RSB GET_ADDR: ; Get the address to look for from the user. MOVL #18,INPSTRDSC ; Maximum input size is 18 bytes PUSHAB INPSIZ ; Place to store # of bytes entered PUSHAB APRMT ; Prompt to display PUSHAB INPSTRDSC ; Place to store input string CALLS #3,G^LIB$GET_INPUT CLRL R1 ; Index to next input character CLRL R3 ; Index to next address byte ; Get the first digit of the next address byte. 10$: MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 20$ ; If GEQU, yes, so branch SUBL3 #^A/0/,R0,R2 ; Convert digit character to digit BRB 30$ ; Get the next input character 20$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL3 #^D10,R0,R2 ; Add ten to have correct digit ; Get the second digit of the next address byte. 30$: MULL2 #^D16,R2 ; Put the first digit into its place MOVZBL INPSTR(R1),R0 ; Get next input character INCL R1 ; Bump input character index CMPB R0,#^A/A/ ; Is this a letter or greater? BGEQU 40$ ; If GEQU, yes, so branch SUBL2 #^A/0/,R0 ; Convert digit character to digit BRB 50$ ; Go to add the second digit 40$: SUBL2 #^A/A/,R0 ; Convert letter character to digit ADDL2 #^D10,R0 ; Add ten to have correct digit 50$: ADDL R0,R2 ; Add lower digit to address ; Store this address byte and see if we need to do more. MOVB R2,DSTADR(R3) ; Store this address byte INCL R3 ; Bump to next address byte CMPL R3,#^D06 ; Have we processed 6 bytes? BLSS 60$ ; Branch if not, more to do RSB ; Else return to caller 60$: INCL R1 ; Skip over "-" in input string BRW 10$ ; Do next address byte GET_CGC: ; Get cluster group code to watch for. 10$: MOVL #5,INPSTRDSC PUSHAB INPSIZ PUSHAB CPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT TSTW INPSIZ ; Do we have any input? BEQL 10$ ; If not, ask again ; Convert character string to cluster group code. CLRL R1 ; Start with zero CLRW R2 ; Start at offset 0 in string 20$: MOVZBL INPSTR(R2),R0 ; Get next input character SUBL2 #^A/0/,R0 ; Convert character to a digit MULL2 #^D10,R1 ; Shift current results ADDL2 R0,R1 ; Add new digit INCW R2 ; Increment counter/index CMPW R2,INPSIZ ; Have we processed all characters? BLSSU 20$ ; If LSSU, no, so loop again MOVW R1,CGC ; Store cluster group code RSB GET_TIME: ; Get number of hours to run test for GET_HOUR: BSBW BLANK MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB HPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of hours CLRL R1 CLRW R2 NUM_LOOP2: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP2 CMPL R1,#^D23 BGTR GET_HOUR MOVL R1,HOURS ; Get number of minutes to run test for GET_MINUTE: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB MPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of minutes CLRL R1 CLRW R2 NUM_LOOP3: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP3 CMPL R1,#^D59 BGTR GET_MINUTE MOVL R1,MINUTES ; Get number of seconds to run test for GET_SECOND: MOVL #6,INPSTRDSC PUSHAB INPSIZ PUSHAB SPRMT PUSHAB INPSTRDSC CALLS #3,G^LIB$GET_INPUT ; Convert number of seconds CLRL R1 CLRW R2 NUM_LOOP4: MOVZBL INPSTR(R2),R0 SUBL2 #^A/0/,R0 MULL2 #^D10,R1 ADDL2 R0,R1 INCW R2 CMPW R2,INPSIZ BLSS NUM_LOOP4 CMPL R1,#^D59 BGTR GET_SECOND MOVL R1,SECONDS RSB SET_TIME: ; Determine the time to stop the test ; Now put the total time into one string MOVL #LINE_LENGTH,FAOLEN $FAO_S CTRSTR=DTIME,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=HOURS,- P2=MINUTES,- P3=SECONDS ; Change the ASCII string for the time to a quadword value. $BINTIM_S- TIMBUF=FAODESC,- TIMADR=TIME MNEGL TIME+4,TIME+4 MNEGL TIME,TIME SBWC #0,TIME+4 ; Now get the present time and add the test time to get the end time. $GETTIM_S- TIMADR=ENDTIM ADDL TIME,ENDTIM ADWC TIME+4,ENDTIM+4 RSB GET_SMCGC: ; Locate the smallest CGC in the table (other than zero) and store its value ; in CGC. If none are found, store a zero in CGC. MOVQ R0,-(SP) ; Save R0 and R1 CLRL R1 ; Start our counter at zero CLRL R0 ; Start with no CGC found MOVAL NODTBL,R2 ; Start at beginning of table 10$: TSTW 6(R2) ; Is this a node in the table? BEQL 30$ ; If EQL, no, so check next entry ; Is this node the first node found? If so, save it, else compare its CGC ; with the smallest CGC found so far. TSTL R0 ; Did we find a CGC yet? BEQL 20$ ; If EQL, no, so save this one CMPW 6(R2),R0 ; Is the new one smaller? BGEQU 30$ ; If GEQU, no, so skip this node 20$: MOVW 6(R2),R0 ; Save this as the smallest CGC ; Skip to next node and continue if there are more nodes to look at. 30$: ADDL #NODSIZ,R2 ; Skip to next entry in table INCL R1 ; Bump node counter CMPL R1,NODCNT ; Are we done? BLSSU 10$ ; If LSSU, no, so loop MOVW R0,CGC ; Return smallest CGC or zero MOVQ (SP)+,R0 ; Restore R0 and R1 RSB GET_NODE: ; Locate the next node in the table to be printed. The Cluster Group Code ; must match the value in CGC. We will locate the next node in the matching ; cluster alphabetically. We will return the address of the table entry ; found in R2. If there is no entry for this cluster, then we will return ; a zero in R2. PUSHR # ^M < R0, R1 > CLRL R1 ; Start our counter at zero CLRL R0 ; Start with no node found MOVAL NODTBL,R2 ; Start at beginning of table 10$: CMPW 6(R2),CGC ; Is this a node in our cluster? BNEQ 30$ ; If NEQ, no, so check next node ; Is this node the first node found? If so, save it, else compare it with ; the previous node. TSTL R0 ; Did we find a node yet? BEQL 20$ ; If EQL, no, so save this one PUSHR # ^M < R0, R1, R2, R3, R4 > CMPC3 #6, 8(R2), 8(R0) ; Correct alphabetical choice? POPR # ^M < R0, R1, R2, R3, R4 > BGTR 30$ ; Yes - branch. BLSS 20$ ; No, replace with new node. PUSHR # ^M < R0, R1, R2, R3, R4 > MOVZBL 32(R0), R3 ; Get device name length. MOVZBL 32(R2), R4 ; Get device name length. CMPC5 R4, 1+32(R2), #^A' ', - ; Check for better choice. R3, 1+32(R0) POPR # ^M < R0, R1, R2, R3, R4 > BGEQU 30$ ; Not a better choice - branch. 20$: MOVL R2,R0 ; Save this as the smallest node ; Skip to next node and continue if there are more nodes to look at. 30$: ADDL #NODSIZ,R2 ; Skip to next entry in table INCL R1 ; Bump node counter CMPL R1,NODCNT ; Are we done? BLSSU 10$ ; If LSSU, no, so loop MOVL R0,R2 ; Return pointer to smallest node POPR # ^M < R0, R1 > RSB EXIT: BSBW BLANK PUSHAB DNEMSG CALLS #1, OUTPUT_LINE BSBW BLANK $DASSGN_S- CHAN=CHNLAV $DASSGN_S- CHAN=CHNRMC $EXIT_S BLANK: ; Print blank line PUSHAB BLNKMSG CALLS #1, OUTPUT_LINE RSB .ENTRY OUTPUT_TEXT ^M < R2 > ; Display the specified messages. MOVL 4(AP), R2 ; Get the message table. 10$: PUSHL (R2)+ ; Check for a message to display. BEQL 20$ ; No more lines to display - branch. CALLS #1, OUTPUT_LINE ; Display the text line. BLBS R0, 10$ ; Success, display next line - branch. 20$: RET ; Return the display status. .ENTRY FAO_LINE ^M < R2, R3 > ; Initialize the string descriptor. MOVL #LINE_LENGTH, FAOLEN ; Format the line. SUBL3 # 1, (AP), R2 ; Account for the format string. MOVAL 8(AP)[R2], R3 ; Get the last parameter. 10$: PUSHL -(R3) ; Build the parameter list. SOBGTR R2, 10$ ; Add all the parameters. PUSHAL FAOLEN ; Set the return length address. PUSHAB FAODESC ; Set the buffer descriptor address. PUSHL -(R3) ; Set the format string. ADDL3 # 2, -(R3), R1 ; Set the argument count. CALLS R1, G^ SYS$FAO ; Format the string. BLBC R0, 20$ ; Format error - branch. ; Display the text string. PUSHAB FAODESC CALLS # 1, OUTPUT_LINE 20$: RET .ENTRY OUTPUT_LINE ^M<> CALLG (AP), G^ LIB$PUT_OUTPUT ; Display the text line. RET ; An error has occured, so print R0 value and 2nd longword of IOSB. ERROR: PUSHL R0 ; Pass R0 error code CALLS #1,RBL$ERCODE ; Print error code ; Print IOSB 2nd longword value in hex PUSHL IOSB+4 PUSHAB IOMSG CALLS #2, FAO_LINE BRW EXIT ; Now exit normally .PAGE ; RBL$ERCODE ; ; This subroutine accepts a VMS error code in binary ; and print the message on the terminal. ; ; INPUT: 4(AP) = Error Code ; ; OUTPUT: all registers saved except R0 and R1 ; ; CALLING SEQ: PUSHx error code ; CALL_S #1,RBL$ERCODE ; .ENTRY RBL$ERCODE,^M MOVL 4(AP),R3 ; Get error code $GETMSG_S- ; Convert error code to message MSGID=R3,- MSGLEN=ERRMSG_LEN,- BUFADR=ERRMSG_BUF_DESC PUSHAB ERRMSG_BUF_DESC CALLS #1, OUTPUT_LINE RET ; Return to caller ; DO_FILE ; This is a macro program to open a text file MONLAV.DAT and read records ; which are basically a cluster group number followed by an ASCII styring ; of characters which are the identifier for a given cluster. ; ; Inputs: None ; ; Outputs: ; The records in the text file are converted and placed in the table ; IDTBL as pairs of cluster group numbers, and up to 40 characters ; of text. DO_FILE: ; fill the IDTBL with spaces MOVAB IDTBL,R0 ; address of the ID table MULL3 #IDSIZ,#MAXID,R1 ; size of IDTBL => R1 MOVC5 #0,(R0),#^X20,- ; fill with spaces ( 020 hex ) R1,(R0) ; OPEN the MONLAV.DAT file $OPEN FAB=IO_FAB ; open the file BLBS R0,2$ ; branch if no error BRW DO_FILE.ERR ; error 2$: $CONNECT RAB=IO_RAB ; connect the RAB BLBS R0,10$ ; branch if no errror BRW DO_FILE.ERR ; error 10$: ; clear out the data area used to read in records MOVAB RECORD,R0 ; get the address of the record storage area MOVC5 #0,(R0),#0,- ; fill it with zeros #256,(R0) ; Read a record CMPL IDCNT,#MAXID ; have we reached max allowable entries? BLSSU 15$ ; no keep going @ 15$ with read of next record $CLOSE FAB=IO_FAB ; yes, close the file and ... BRW 100$ ; => 100$ 15$: $GET RAB=IO_RAB ; get the next record in the file CMPL #RMS$_EOF, R0 ; end of file? BNEQ 20$ ; no => 20$ $CLOSE FAB=IO_FAB ; yes, close the file BRW 100$ ; go to 100$ 20$: BLBS R0,22$ ; branch if no error BRW DO_FILE.ERR ; error 22$: MOVL #0,SKIPLEN ; we have processed zero characters ; form this record so far MOVAB RECORD,R2 ; get the addresss of the beginnning ; of the string BSBW SKIPWS ; skip white space & control characters ; updating SKILEN, and R2 as it goes BSBW FLDLEN ; get the length of the first field CMPB R0,#MAXCGLEN ; is string too long? BLEQ 25$ ; branch if not too too long MOVW SS$_SSFAIL,R0 BRW DO_FILE.ERR ; Convert the leading numeric characters to an integer 25$: CLRL R1 ; Start with zero as CGN CLRL R4 ; Clear # of input characters done 30$: CMPW R4,R0 ; Have we processed the field BGEQU 40$ ; If EQL, yes MOVZBL (R2),R3 ; Get an input character SUBL2 #^A/0/,R3 ; Convert to a digit MULL2 #^D10,R1 ; Shift current decimal digits ADDL2 R3,R1 ; Add new digit INCL R4 ; Bump # of input characters done INCL R2 INCL SKIPLEN ; count up the characters already ; processsed BRB 30$ ; Check next character 40$: ; the conversion should be done, check the result CMPL R1,#65536 ; is it too large? MOVL #SS$_SSFAIL,R0 ; assume failure BLEQU 41$ BRW DO_FILE.ERR ; yes, => error ; check the identifier string for illegal characters in the first 40 41$: MOVAB RECORD,R2 ; get the beginning of the record ADDL SKIPLEN,R2 ; add the characters already processed BSBW SKIPWS ; skip any more white space BSBW STRLEN ; get the number of characters in the ID ; string CMPL R0,#40 ; is it too long? BLEQ 50$ ; no, its OK,.. => 40$ and continue MOVL #40,R0 ; its too long,... only take the first 40 50$: ; add the new cgn/identifier to the MOVAB IDTBL,R3 MULL3 #IDSIZ,IDCNT,R4 ; size of laready inserted entry ADDL R4,R3 ; make R3 point to the next available entry MOVW R1,(R3)+ ; store the cluster group number PUSHR #^M ; preserve registers MOVC3 R0,(R2),(R3) ; copy the identifier POPR #^M ; preserve registers INCL IDCNT ; count the new identifier BRW 10$ ; do next entry 100$: MOVL IDCNT,R4 ; get the number of IDs logged into the table MOVAL IDTBL,R5 ;110$: MOVAL 2(R5),IDDSC+4 ; PUSHAB IDDSC ; PUSHL (R5) ; PUSHAB NONAME ; CALLS #3, FAO_LINE ; ; ADDL #IDSIZ,R5 ; SOBGTR R4,110$ ; DO_FILE.ERR: RSB ; all done SKIPWS: ; ; INPUTS: ; R2 - the address of a character string which may or may not contain ; white space at the beginning... ; ; OUTPUTS: ; R2 will poont to the first "non-white space" character in the string ; or a carriage return ; SKIPLEN is incremented for each white space character found SKIPWS.NEXT: CMPB (R2),#^X15 ; is it a carriage return? BEQL SKIPWS.DONE ; if yes => DONE CMPB (R2),#^X021 ; is it a white space character BLSSU SKIPWS.CONT ; yes, => NEXT SKIPWS.DONE: RSB ; no,... we're done! SKIPWS.CONT: INCL SKIPLEN ; show that we skipped another character in this ; string INCL R2 ; point to the next character BRB SKIPWS ; go and check next character FLDLEN: ; ; This routine returns the length of the next field in a string,... ; fields are seperated by spaces, tabs, or CR's ; ; INPUTS: ; R2 - points to the beginning of the field ; ; OUTPUTS: ; R0 contains the length in characters of the field ; PUSHL R2 MOVL #0,R0 ; set up R0 as an index FLDLEN.NEXT: CMPB (R2),#^A' ' ; is next character white space? BLEQ FLDLEN.DONE ; yes => DONE INCL R0 ; add one more to the length INCL R2 ; point to the next char BRB FLDLEN.NEXT ; do the next FLDLEN.DONE: POPL R2 ; restore R2 RSB ; all done STRLEN: ; ; This routine returns the length of a string up to but not including ; a tab or a carriage return ; ; INPUTS: ; R2 points to the beginning of the string ; ; OUTPUTS: ; R0 will contain the length of the string ; CLRL R0 ; zero the length output STRLEN.NEXT: CMPB (R2)[R0],#^X15 ; is the next character a carriage control? BEQL STRLEN.DONE ; yes,... => DONE CMPB (R2)[R0],#^X10 ; is the next character a tab? BEQL STRLEN.DONE ; yes,... => DONE CMPB (R2)[R0],#^X020 ; is it a space or better? BLSSU STRLEN.DONE ; no,.. its a control character,.. its illegal ; so return now with the length of legal ; characters in R0 INCL R0 ; bump the length BRB STRLEN.NEXT ; do next character STRLEN.DONE: RSB ; FIND_ID ; ; This routine searches the IDTBL for an entry with the cluster group ; code that matches what is spoecified in GGC ; ; Inputs: ; R0 contains the cluster group code of interest ; ; Outputs: ; R0 will point to the first character in the ID string ; if one is found,.. ; OR ; R0 = 0 if no match ; FIND_ID: PUSHR #^M ; preserve registers CLRL R2 ; count of loops made MOVAB IDTBL,R1 ; base address of ID table FIND_ID.NEXT: CMPL R2,IDCNT ; have we already searched the whole table? BGEQU FIND_ID.NOMATCH ; yes => NOMATCH CMPW R0,(R1) ; does this entry match? BEQL FIND_ID.MATCH ; yes, => match INCL R2 ; count the number of entries searched ADDL #IDSIZ,R1 ; make R1 point to the next entry BRB FIND_ID.NEXT ; check the next entry FIND_ID.MATCH: ADDL3 #2,R1,R0 ; store the address of the ID string in R0 BRB FIND_ID.EXIT ; exit FIND_ID.NOMATCH: MOVL #0,R0 ; Indicate no match found ; BRB FIND_ID.EXIT ; exit FIND_ID.EXIT: POPR #^M ; restore registers RSB .PSECT DATA .ALIGN QUAD ; Structures used to build error message from error code ERRMSG_BUF_DESC: ERRMSG_LEN: .LONG 256 .ADDRESS- ERRMSG_BUF ERRMSG_BUF: .BLKB 256 ; Table for information on nodes already found. ; Each entry consists of: ; ; 0: 6 bytes of LAN DECnet address ; 6: 2 bytes of cluster group code ; 8: 6 bytes of node name ; 14: 1 byte of node name length ; 15: 1 byte of DEVICE ID ; 16: 8 bytes of DEVICE NAME descriptor ; 24: 6 bytes of LAN hardware address ; 30: 2 bytes of SCSSYSTEMID ; 32: 16 bytes of DEVICE name ; 48: NODSIZ = 6+2+6+1+1+8+6+2+16 MAXNOD = 2000 NODCNT: .LONG 0 NODTBL: .BLKB MAXNOD*NODSIZ ; Symbolic constants and data structures for storing the Identifier Strings ; from MONLAV.DAT IDDSC: .LONG 40 .LONG 0 RECORD: ; to hold a single RNS record read from .BLKL 256 ; MONLAV.DAT MAXCGLEN = 5 ; maximum length of the ascii string ; that can represent a CGN IDSIZ = 42 ; size of a valid ID entry,... ; 2 bytes for Cluster group number ; 40 bytes for the ID string MAXID = 100 ; we will deal with up to 100 IDs SKIPLEN: .BLKL 1 ; count of characters already ; processed for a given record from the ; MONLAV.DAT file IDCNT: .LONG 0 ; number of IDs IDTBL: .BLKB MAXID*IDSIZ ; Table of IDs .END START