.TITLE MONLAV .IDENT /V2.0/ ; 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" $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 ; Modification history ; ; 2.0 David Gagne ; 01 Add the hardware address to the displays. ; 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 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 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 ; Message structures ; General message buffer FAODESC: FAOLEN: .LONG 80 .ADDRESS FAOBUF FAOBUF: .BLKB 80 HDRMSG1: .ASCID "MONLAV - Ethernet LAVC monitoring program. Version 2.0" INPMSG1: .ASCID "Monitor requests available:" INPMSG2: .ASCID " 1) Monitor a single cluster node" INPMSG3: .ASCID " 2) Monitor all nodes in a specific cluster" INPMSG4: .ASCID " 3) Monitor all nodes in all clusters" INPMSG5: .ASCID " any other input will stop the program" 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 M1HDR0: .ASCID " Monitor output from a single cluster node" M1HDR1: .ASCID " -----------------------------------------" 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 M2HDR0: .ASCID " Monitor output from all nodes in a specific cluster" M2HDR1: .ASCID " ---------------------------------------------------" M2GHDR: .ASCID " ==================================================== " M2GRUP: .ASCID " !UW) Cluster Group Number: !UW (AB-00-04-01-!XB-!XB)" M2IDEN: .ASCID " Identifier: !AS" M2HDR2: .ASCID " Name Node Address Device Hardware Address" M2HDR3: .ASCID " ------ ------- ----------------- -------- -----------------" M2INFO: .ASCID " " M2INF1: .ASCID " !3UB) !6AS !2UB.!UW " M2INF2: .ASCID "AA-00-04-00-!XB-!XB !2UB=!5AS " M2INF3: .ASCID "!XB-!XB-!XB-!XB-!XB-!XB" M2NIN3: .ASCID "None found " M2NOTC: .ASCID " This cluster does not exist or cannot be monitored." ; Output strings for monitoring all nodes in all clusters M3HDR0: .ASCID " Monitor output from all nodes in all clusters" M3HDR1: .ASCID " ---------------------------------------------" M3TRLR: .ASCID " Total of !UW clusters and !UL cluster nodes found" M3NOTC: .ASCID " No clusters found." ; Strings for various device names DEV01: .ASCID "DEUNA" DEV05: .ASCID "DEQNA" DEV11: .ASCID "DELUA" DEV17: .ASCID "LANCE" DEV23: .ASCID "DEBNA" DEV37: .ASCID "DELQA" DEV39: .ASCID "DESVA" DEV65: .ASCID "DEBNI" 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 ; Device names DEVDSC1:.ASCID 'ETH' ; Units to use for test DEVDSC2:.ASCID 'ESA0' DEVDSC3:.ASCID 'XQA0' DEVDSC4:.ASCID 'ETA0' DEVDSC5:.ASCID 'XEA0' DEVDSC6:.ASCID 'EXA0' DEVDSC7:.ASCID 'EZA0' ; Table of pointers to device names DEVADR: .ADDRESS DEVDSC1 .ADDRESS DEVDSC2 .ADDRESS DEVDSC3 .ADDRESS DEVDSC4 .ADDRESS DEVDSC5 .ADDRESS DEVDSC6 .ADDRESS DEVDSC7 .LONG 0 ; Channels - one for LAVC and one for Remote Console CHNLAV: .BLKL 1 CHNRMC: .BLKL 1 .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 BRW 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 BRW 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,G^LIB$PUT_OUTPUT 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 BRW ERROR START_REQ_OK1: MOVZWL IOSB,R0 BLBS R0,START_IO_OK1 BRW 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 BRW ERROR START_REQ_OK2: MOVL IOSB,R0 BLBS R0,START_IO_OK2 BRW ERROR START_IO_OK2: ; Print program header BSBW BLANK PUSHAB HDRMSG1 CALLS #1,G^LIB$PUT_OUTPUT 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 INPMSG1 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG3 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG4 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG5 CALLS #1,G^LIB$PUT_OUTPUT 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 BNEQ 40$ ; If NEQ, no BSBW TEST_2 ; Do test BRW GET_TEST ; Check for another test to run 40$: CMPL R1,#3 ; Check if test #3 BNEQ 50$ ; If NEQ, no 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 M1HDR0 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR1 CALLS #1,G^LIB$PUT_OUTPUT ; 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 BRW ERROR RCV_REQ_OK_T1: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK_T1 CMPW R0,#SS$_ENDOFFILE BEQL RCV_T1 BRW ERROR RCV_IO_OK_T1: ; Check if this is a multicast message. If not, throw it away and look for ; another message. BLBC RCVDA,RCV_T1 ; 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 RCV_T1 ; If not, read another one CMPW DSTADR+4,RCVSA+4 ; Second part of address okay? BEQL PRINT_T1 ; If so, print it BRW RCV_T1 ; Else, read another one PRINT_T1: ; The address was the desired one, so print the results ;========================================================================== ; Print the node name MOVL #80,FAOLEN $FAO_S CTRSTR=M1NAME,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#NAMDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_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 MOVL #80,FAOLEN $FAO_S CTRSTR=M1NODE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1,- P2=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the node address 10$: MOVL #80,FAOLEN $FAO_S CTRSTR=M1ADDR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DSTADR,- P2=DSTADR+1,- P3=DSTADR+2,- P4=DSTADR+3,- P5=DSTADR+4,- P6=DSTADR+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the cluster group code number MOVL #80,FAOLEN $FAO_S CTRSTR=M1GRUP,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=RCVBUF+6 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the cluster multicast address MOVW RCVBUF+6,CMCA ADDW #^D256,CMCA MOVL #80,FAOLEN $FAO_S CTRSTR=M1CMCA,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=CMCA,- P2=CMCA+1 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the Ethernet controller ID and name MOVL DSTADR,SIDADDR MOVW DSTADR+4,SIDADDR+4 BSBW GET_IDHWA MOVL #80,FAOLEN $FAO_S CTRSTR=M1DTYP,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DEVID,- P2=#DEVDSC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;======================================================================== ; 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 MOVL #80,FAOLEN $FAO_S CTRSTR=M1IDEN,- ; format the string OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#IDDESC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; print it ;========================================================================== ; Print the Hardware address (if none, print "none found") DO_HWA: CMPB HWA,#^XFF BNEQ 20$ PUSHAB M1NHWA BRB 30$ 20$: MOVL #80,FAOLEN $FAO_S CTRSTR=M1HWA,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=HWA,- P2=HWA+1,- P3=HWA+2,- P4=HWA+3,- P5=HWA+4,- P6=HWA+5 PUSHAB FAODESC 30$: CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== 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 MOVL #80,FAOLEN $FAO_S CTRSTR=M1NODE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1,- P2=R0 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the node address 10$: MOVL #80,FAOLEN $FAO_S CTRSTR=M1ADDR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=DSTADR,- P2=DSTADR+1,- P3=DSTADR+2,- P4=DSTADR+3,- P5=DSTADR+4,- P6=DSTADR+5 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the "node not in a cluster" message PUSHAB M1NOTC CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== 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. TEST_2: BSBW GET_TIME BLBS TESTNO,10$ ; Skip over GET_CGC if test 3 BSBW BLANK BSBW GET_CGC 10$: BSBW SET_TIME ;========================================================================== ; Print the header CLRW CLUSNO ; Start with no clusters BSBW BLANK BLBS TESTNO,20$ ; Skip over test 2 header if test 3 PUSHAB M2HDR0 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M2HDR1 CALLS #1,G^LIB$PUT_OUTPUT BRB RCV_T2 ; Skip over test 3 header 20$: PUSHAB M3HDR0 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M3HDR1 CALLS #1,G^LIB$PUT_OUTPUT ; 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 BRW ERROR RCV_REQ_OK_T2: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK_T2 CMPW R0,#SS$_ENDOFFILE BEQL RCV_T2 BRW 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,RCV_T2 ; Ignore packet if sent to physical BLBS TESTNO,10$ ; Skip over CGC check if test 3 CMPW CGC,RCVBUF+6 ; Ignore packet if not in the ; specified cluster BNEQ RCV_T2 ; 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 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 CMPW RCVBUF+6,6(R2) ; Does cluster group code match? BEQL 50$ ; 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. 40$: CMPL NODCNT,#MAXNOD ; Is the table full? BGEQU PRINT_T2 ; If GEQU, yes, so print results ; Store this node's information. MOVL RCVSA,(R2)+ ; Store 1st part of address MOVW RCVSA+4,(R2)+ ; Store 2nd part of address MOVW RCVBUF+6,(R2)+ ; Store cluster group code MOVL RCVBUF+25,(R2)+ ; Store 1st part of name MOVW RCVBUF+29,(R2)+ ; Store 2nd part of name MOVL RCVSA,SIDADDR ; Set up to call GET_IDHWA MOVW RCVSA+4,SIDADDR+4 ; Set up to call GET_IDHWA PUSHL R2 BSBW GET_IDHWA ; Get device information POPL R2 MOVB DEVID,(R2)+ ; Store Device ID TSTB (R2)+ ; Skip spare byte MOVQ DEVDSC,(R2)+ ; Store Device name descriptor MOVL HWA,(R2)+ ; Store HWA MOVW HWA+4,(R2)+ ; Store HWA INCL NODCNT ; One more node stored 50$: 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_T2NEXT ; Print the cluster information BSBW BLANK BLBS TESTNO,10$ ; If test3, goto 10$ INCW CLUSNO ; Count this cluster MOVW CGC,CMCA ADDW #^D256,CMCA PUSHAB M2GHDR CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M2GRUP,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=CLUSNO,- P2=CGC,- P3=CMCA,- P4=CMCA+1 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK PUSHAB M2NOTC BRB 20$ 10$: PUSHAB M3NOTC 20$: CALLS #1,G^LIB$PUT_OUTPUT RSB PRINT_T2NEXT: ; Locate the lowest cluster group code in the table (other than zero). If ; none are found, then exit. 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 BLBC TESTNO,10$ ; If test2, goto 10$ BSBW BLANK BSBW BLANK PUSHAB M2GHDR CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M3TRLR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=CLUSNO,- P2=NODCNT PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT 10$: RSB PRINT_CLUSTER: ; Print the information about each entry in the table. ;========================================================================== ; Print the cluster group number/multicast address and header BSBW BLANK TSTW CLUSNO ; Is this the first cluster? BEQL 10$ ; If EQL, yes, only one blank line BSBW BLANK 10$: INCW CLUSNO ; Count this cluster MOVW CGC,CMCA ADDW #^D256,CMCA PUSHAB M2GHDR CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M2GRUP,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=CLUSNO,- P2=CGC,- P3=CMCA,- P4=CMCA+1 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ;======================================================================== ; 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 MOVL #80,FAOLEN $FAO_S CTRSTR=M2IDEN,- ; format the string OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#IDDESC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; print it ;========================================================================== ; Print the table header DO_HDR: BSBW BLANK PUSHAB M2HDR2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M2HDR3 CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the information about each node - in a loop CLRL R1 ; Start our node counter at zero 20$: 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 30$: CLRW 6(R2) ; Clear the CGC so we don't look at ; this entry any more in GET_NODE INCL R1 ; Bump our counter - for printing MOVL 08(R2),RCVBUF+25 ; Move the node name into place MOVW 12(R2),RCVBUF+29 ; Move the node name into place CLRQ R3 ; Assume no node number CMPL #^X000400AA,(R2) ; Is this a DECnet address? BNEQ 40$ ; If NEQ, no, so don't print it MOVZWL 4(R2),R4 ; Calculate node number BICW #^XFC00,R4 MOVZBL 5(R2),R3 ASHL #-2,R3,R3 40$: MOVQ R1,-(SP) MOVL #80,FAOLEN ; Get the first part of the $FAO_S CTRSTR=M2INF1,- ; output ready OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1,- P2=#NAMDSC,- P3=R3,- P4=R4 MOVC3 FAOLEN,FAOBUF,M2INFO+8 ; Copy the 1st part into M2INFO MOVQ (SP)+,R1 MOVQ 16(R2),DEVDSC ; Retrieve Device name descriptor MOVQ R1,-(SP) MOVL #80,FAOLEN $FAO_S CTRSTR=M2INF2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=4(R2),- P2=5(R2),- P3=14(R2),- P4=#DEVDSC MOVC3 FAOLEN,FAOBUF,M2INFO+8+26 ; Copy the 2nd part into M2INFO MOVQ (SP)+,R1 ; Retrieve R2 MOVQ R1,-(SP) CMPB 24(R2),#^XFF ; Is there a HWA? BNEQ 50$ ; Br if yes MOVC3 #17,M2NIN3+8,M2INFO+8+58; Copy "none found" into M2INFO BRB 60$ ; Continue in common code path 50$: MOVL #80,FAOLEN $FAO_S CTRSTR=M2INF3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=24(R2),- P2=25(R2),- P3=26(R2),- P4=27(R2),- P5=28(R2),- P6=29(R2) MOVC3 FAOLEN,FAOBUF,M2INFO+8+58 ; Copy the 3rd part into M2INFO 60$: PUSHAB M2INFO CALLS #1,G^LIB$PUT_OUTPUT MOVQ (SP)+,R1 BRW 20$ ; Go to top of loop 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. Upon completion of this routine, HWA will contain the ; hardware address or FF in the first byte if none was found. ; Transmit the request ID message to the node we want to find out about. $QIOW_S FUNC=#IO$_WRITEVBLK,- CHAN=CHNRMC,- IOSB=IOSB,- P1=XMTP2BUF,- P2=#XMTP2LEN,- P5=#SIDADDR BLBS R0,DXMT_REQ_OK BRW ERROR DXMT_REQ_OK: MOVL IOSB,R0 BLBS R0,DXMT_IO_OK BRW 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,- P1=RCVBUF2,- P2=#RCVBUFLEN2,- P5=#RCVP52 BLBS R0,DRCV_REQ_OK BRW ERROR DRCV_REQ_OK: MOVL IOSB,R0 BLBS R0,DRCV_IO_OK CMPW IOSB,#SS$_ENDOFFILE BEQL DRCV_TRY BRW 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$: CLRB DEVID ; Clear the Device ID number MOVQ DEVNR,DEVDSC ; Set the device name to no response MOVB #^XFF,HWA ; Set "no HWA found" 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+2 ; Any buffer left to look at? BLSSU 20$ ; If LSSU, yes, so look for more BRW 210$ ; 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 CMPB DEVID,#^D01 ; Is this Device 1? BNEQ 40$ ; Branch if not MOVQ DEV01,DEVDSC ; Store Device Name for ID 1 BRW 300$ ; Exit 40$: CMPB DEVID,#^D05 BNEQ 50$ MOVQ DEV05,DEVDSC BRW 300$ 50$: CMPB DEVID,#^D11 BNEQ 60$ MOVQ DEV11,DEVDSC BRB 300$ 60$: CMPB DEVID,#^D17 BNEQ 70$ MOVQ DEV17,DEVDSC BRB 300$ 70$: CMPB DEVID,#^D23 BNEQ 80$ MOVQ DEV23,DEVDSC BRB 300$ 80$: CMPB DEVID,#^D39 BNEQ 90$ MOVQ DEV39,DEVDSC BRB 300$ 90$: CMPB DEVID,#^D37 BNEQ 100$ MOVQ DEV37,DEVDSC BRB 300$ 100$: CMPB DEVID,#^D65 BNEQ 200$ MOVQ DEV65,DEVDSC BRB 300$ 200$: MOVQ DEVUK,DEVDSC ; This is an unknown device BRB 300$ 210$: CLRB DEVID ; No Device ID was found MOVQ DEVMS,DEVDSC ; Device ID is missing ; Now look for the Hardware address in the SYSID response. 300$: MOVL #4,R3 ; Skip over SYSID header ; Loop through the entries in the SYSID looking for the HWA entry. 310$: CMPW R3,IOSB+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$: MOVB #^XFF,HWA ; Set "no HWA found" 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 #80,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 node in the matching ; cluster with the lowest address. For now we assume all addresses are ; DECnet addresses. We will return the address of the table entry that ; has the smallest address (within the cluster) in R2. If there is no entry ; for this cluster, then we will return a zero in R2. MOVQ R0,-(SP) ; Save R0 and 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 smallest node found so far. TSTL R0 ; Did we find a node yet? BEQL 20$ ; If EQL, no, so save this one CMPW 4(R2),4(R0) ; Is the new one smaller? BGEQU 30$ ; If GEQU, no, so skip this node 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 MOVQ (SP)+,R0 ; Restore R0 and R1 RSB EXIT: BSBW BLANK PUSHAB DNEMSG CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK $DASSGN_S- CHAN=CHNLAV $DASSGN_S- CHAN=CHNRMC $EXIT_S BLANK: ; Print blank line PUSHAB BLNKMSG CALLS #1,G^LIB$PUT_OUTPUT RSB ; 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 MOVL #80,FAOLEN $FAO_S CTRSTR=IOMSG,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=IOSB+4 PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT 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,G^LIB$PUT_OUTPUT 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 ; MOVL #80,FAOLEN ; $FAO_S CTRSTR=NONAME,- ; OUTLEN=FAOLEN,- ; OUTBUF=FAODESC,- ; P1=(R5),- ; P2=#IDDSC ; PUSHAB FAODESC ; CALLS #1,G^LIB$PUT_OUTPUT ; ; 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 ; 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: ; ; 6 bytes of node address ; 2 bytes of cluster group code ; 6 bytes of node name ; 1 byte of DEVICE ID ; 1 byte of spare info ; 8 bytes of DEVICE NAME descriptor ; 6 bytes of hardware address (1st byte is FF if none) NODSIZ = 30 MAXNOD = 1000 NODCNT: .LONG 0 NODTBL: .BLKB MAXNOD*NODSIZ ; Symbolic constants and data structures for storing the Identifier Strings ; from MONLAV.DAT NONAME: .ASCID "!5UW = !AS" 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