.TITLE MONHWA .IDENT /V1.2/ ; This program will dump information about all nodes sending a SYSID. It ; listens to the Remote Console multicast to gather information about nodes. ; 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 ; Modification history ; ; 1.2 David Gagne ; 04 Allow for three digit device types ; 03 Display nodes in numerical order after swapping bytes ; 02 Add more options - display one device, select sort ; 01 Add many more devices ; 1.1 David Gagne ; 01 Add DEQTA device ; 1.0 David Gagne ; 01 Initial creation ; QIO data structures for the MOP (SYSTEM ID) channel. ; P2 parameter buffer for starting the channel. SIDPARM: .WORD NMA$C_PCLI_PTY ; Protocol Type .LONG ^X0260 .WORD NMA$C_PCLI_MCA ; Multicast address .WORD 8 .WORD NMA$C_LINMC_SET .BYTE ^XAB,00,00,02,00,00 SIDPARMLEN = .-SIDPARM SIDPARMDSC: .LONG SIDPARMLEN .ADDRESS SIDPARM ; Read buffer for receiving System IDs RCVBUF: .BLKB 1504 RCVBUFLEN = .-RCVBUF ; Place to store incoming P5 buffer (the frame header) RCVP5: RCVDA: .BLKB 6 RCVSA: .BLKB 6 RCVPT: .BLKB 2 ; Message structures ; General message buffer FAODESC: FAOLEN: .LONG 80 .ADDRESS FAOBUF FAOBUF: .BLKB 80 HDRMSG1: .ASCID "MONHWA - Ethernet HWA monitoring program. Version 1.2" INPMSG1: .ASCID "Monitor requests available:" INPMSG2: .ASCID " 1) Display all SYSID messages" INPMSG3: .ASCID " 2) Display SYSID messages from one device type" INPMSG4: .ASCID " any other input will stop the program" INPMSG5: .ASCID "Sorting methods available:" INPMSG6: .ASCID " 1) Sorted by Hardware Address" INPMSG7: .ASCID " 2) Sorted by Physical Address" INPMSG8: .ASCID " 3) Sorted by Device" INPMSG9: .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 "MONHWA complete. Thank you for your continued support." BLNKMSG: .ASCID "" ; Output strings for monitoring all periodic SYSID messages M1HDR0: .ASCID " Monitor output from periodic SYSID messages" M1HDR1: .ASCID " -------------------------------------------" M1HDR2: .ASCID " Hardware Address Device Physical Address Node #" M1HDR3: .ASCID " ----------------- -------- ----------------- -------" M1INFO: .ASCID " " M1HWA: .ASCID "!XB-!XB-!XB-!XB-!XB-!XB" M1DTYP: .ASCID "!3UB=!AS" M1ADDR: .ASCID "!XB-!XB-!XB-!XB-!XB-!XB" M1NODE: .ASCID "!2UB.!UW " M1NNOD: .ASCID " " M1NONE: .ASCID " There were no SYSID messages found." M2HDR: .ASCID " Address usage summary" M2SUM1: .ASCID " Nodes using their hardware address: !4UW" M2SUM2: .ASCID " Nodes using a DECnet address: !4UW" M2SUM3: .ASCID " Nodes using their another address: !4UW" M2SUM4: .ASCID " ----------------------------------------" M2SUM5: .ASCID " Total number of nodes found: !4UW" M3HDR1: .ASCID " Device usage summary" M3HDR2: .ASCID " Device Amount" M3HDR3: .ASCID " ------ ------" M3INFO: .ASCID " !5AS !5UW" ; Running totals for address usage SUMHWA: .WORD 0 SUMDEC: .WORD 0 SUMOTH: .WORD 0 ; Strings for various device names DEV001: .ASCID "DEUNA" DEV003: .ASCID "DECNA" DEV005: .ASCID "DEQNA" DEV011: .ASCID "DELUA" DEV013: .ASCID "MSLAN" DEV017: .ASCID "DS100" DEV021: .ASCID "DEBET" DEV023: .ASCID "DEBNA" DEV025: .ASCID "PCLAN" DEV033: .ASCID "DS200" DEV035: .ASCID "DS500" DEV037: .ASCID "DELQA" DEV039: .ASCID "DESVA" DEV043: .ASCID "DEPCA" DEV045: .ASCID "LTM " DEV047: .ASCID "DESNC" DEV060: .ASCID "DS300" DEV065: .ASCID "DEBNI" DEV066: .ASCID "DEMNA" DEV072: .ASCID "DP250" DEV075: .ASCID "DEQTA" DEV076: .ASCID "LB150" DEV104: .ASCID "KFE52" DEV112: .ASCID "LPS20" DEV114: .ASCID "DWT-1" DEVUNK: .ASCID "Unkwn" DEVMIS: .ASCID "Misng" DEVTBL: .BYTE 1 .WORD 0 .ADDRESS DEV001 .BYTE 3 .WORD 0 .ADDRESS DEV003 .BYTE 5 .WORD 0 .ADDRESS DEV005 .BYTE 11 .WORD 0 .ADDRESS DEV011 .BYTE 13 .WORD 0 .ADDRESS DEV013 .BYTE 17 .WORD 0 .ADDRESS DEV017 .BYTE 21 .WORD 0 .ADDRESS DEV021 .BYTE 23 .WORD 0 .ADDRESS DEV023 .BYTE 25 .WORD 0 .ADDRESS DEV025 .BYTE 33 .WORD 0 .ADDRESS DEV033 .BYTE 35 .WORD 0 .ADDRESS DEV035 .BYTE 37 .WORD 0 .ADDRESS DEV037 .BYTE 39 .WORD 0 .ADDRESS DEV039 .BYTE 43 .WORD 0 .ADDRESS DEV043 .BYTE 45 .WORD 0 .ADDRESS DEV045 .BYTE 47 .WORD 0 .ADDRESS DEV047 .BYTE 60 .WORD 0 .ADDRESS DEV060 .BYTE 65 .WORD 0 .ADDRESS DEV065 .BYTE 66 .WORD 0 .ADDRESS DEV066 .BYTE 72 .WORD 0 .ADDRESS DEV072 .BYTE 75 .WORD 0 .ADDRESS DEV075 .BYTE 76 .WORD 0 .ADDRESS DEV076 .BYTE 104 .WORD 0 .ADDRESS DEV104 .BYTE 112 .WORD 0 .ADDRESS DEV112 .BYTE 114 .WORD 0 .ADDRESS DEV114 .BYTE 0 .WORD 0 DEVMSG: .WORD 0 ; Number of missing device IDs DEVDSC: .BLKQ 1 ; General device name descriptor DEVID: .BLKB 1 ; Device ID from SYSID response HWA: .BLKB 6 ; Device HWA from SYSID response CNTADR: .BLKL 1 ; Address of device counter ; Buffers, variables, and strings for the time control of the program HOURS: .BYTE 0 ; Storage of requested input MINUTES:.BYTE 0 SECONDS:.BYTE 0 ; 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: " PPRMT: .ASCID "Which sorting method would you like: " 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: " DPRMT: .ASCID "Which device (number) would you like displayed: " APRMT: .ASCID "Enter the address of the node (ex: AA-00-04-00-75-4C): " 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 REQNUM: .BLKB 1 SRTNUM: .BLKB 1 DEVNUM: .BLKB 1 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 Remote Console CHNRMC: .BLKL 1 .ENTRY START,^M<> ; Assign the channel 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 20$ ; 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=CHNRMC ; or 2) One device is prefered BLBS R0,ASSIGN_OK ; If success, exit the loop 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 ; No device was found. 20$: 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 channel for listening to SYSID messages. $QIOW_S FUNC=#,- CHAN=CHNRMC,- IOSB=IOSB,- P2=#SIDPARMDSC BLBS R0,START_REQ_OK BRW ERROR START_REQ_OK: MOVL IOSB,R0 BLBS R0,START_IO_OK BRW ERROR START_IO_OK: ; 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 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 12$ ; 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 ; Save the request number. If it's invalid, exit 11$: BRW 24$ 12$: MOVB R1,REQNUM BEQL 11$ CMPB R1,#2 BGTRU 11$ ; Find out how they want it sorted. BSBW BLANK PUSHAB INPMSG5 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG6 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB INPMSG7 CALLS #1,G^LIB$PUT_OUTPUT CMPB REQNUM,#2 ; If request 2, then skip next message BEQL 13$ PUSHAB INPMSG8 CALLS #1,G^LIB$PUT_OUTPUT 13$: PUSHAB INPMSG9 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK ; Read the user's input to our prompt for the sorting method. MOVL #2,INPSTRDSC ; Set number of bytes to read PUSHAB INPSIZ ; Push input size parameter PUSHAB PPRMT ; 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 sorting number. CLRL R1 ; Start with zero in test number CLRL R2 ; Clear # of input characters done 14$: 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 14$ ; Check next character ; Save the sorting method number and if it's not valid, exit. 20$: MOVB R1,SRTNUM ; Store the sorting method number BEQL 24$ ; If zero, then bad so exit CMPB R1,#3 BGTRU 24$ ; If more than 3, then bad so exit BLSSU 25$ ; If 1 or 2 then okay CMPB REQNUM,#2 ; If 3 and not request 2, then okay BNEQ 25$ 24$: BRW EXIT ; Bad value so exit ; Clear the per-test global variables. 25$: CLRB HOURS CLRB MINUTES CLRB SECONDS CLRL NODCNT CLRW SUMDEC CLRW SUMHWA CLRW SUMOTH ; Loop to zero each device total in the device table. MOVAB DEVTBL,R5 ; Start at beginning of table 30$: TSTB (R5) ; End of table? BEQL 40$ ; If EQL, yes CLRW 1(R5) ADDL #7,R5 ; Skip this entry BRB 30$ ; Loop for more devices ; Now perform the appropriate test based on the test number. 40$: CMPB REQNUM,#1 ; Check if test #1 BNEQ 50$ ; If NEQ, no BSBW TEST_1 ; Do test BRW GET_TEST ; Check for another test to run 50$: CMPB REQNUM,#2 ; Check if test #2 BNEQ 60$ ; If NEQ, no BSBW TEST_2 ; Do test BRW GET_TEST ; Check for another test to run ; Not a supported test, so exit. 60$: BRW EXIT ; Not any of above, so exit TEST_1: ; Find out how long they want to listen for SYSID messages and then start ; listening. BSBW GET_TIME BSBW BLANK BSBW SET_TIME BSBW BLANK ;========================================================================== ; Print the header PUSHAB M1HDR0 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR1 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK ; Collect SYSID information until we've either filled our data area or until ; we've listened for the requested amount of time. BSBW COLLECT ; Now print the results and loop for another monitor request. BSBW PRTBL BSBW PRADR CMPB #2,REQNUM ; If this is request 2, don't BEQL 10$ ; print the device summary BSBW PRDEV 10$: RSB TEST_2: ; Read the user's input to our prompt for the device number. BSBW BLANK MOVL #3,INPSTRDSC ; Set number of bytes to read PUSHAB INPSIZ ; Push input size parameter PUSHAB DPRMT ; 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 device 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 ; Save the device number and use TEST_1 to finish the rest of this request. 20$: MOVB R1,DEVNUM BRW TEST_1 COLLECT: ; Collect SYSID information until we've either filled our data area or until ; we've listened for the requested amount of time. ; 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 RSB ; Else return 10$: CMPL TIME,ENDTIM ; Check low longword BLSSU 20$ ; If LSSU, continue RSB ; Else return ; Try to read another SYSID message. 20$: $QIOW_S FUNC=#IO$_READVBLK!IO$M_NOW,- CHAN=CHNRMC,- IOSB=IOSB,- P1=RCVBUF,- P2=#RCVBUFLEN,- P5=#RCVP5 BLBS R0,RCV_REQ_OK BRW ERROR RCV_REQ_OK: MOVZWL IOSB,R0 BLBS R0,RCV_IO_OK CMPW R0,#SS$_ENDOFFILE BEQL COLLECT BRW ERROR RCV_IO_OK: ; Check if this is a multicast message. If not, throw it away and look for ; another message. If this is not a SYSTEM ID message, then throw it away. BLBC RCVDA,COLLECT ; Ignore packet if sent to physical CMPB RCVBUF,#7 ; Is this a SYSTEM ID message? BNEQ COLLECT ; If NEQ, no, read another ; Get the information about this node. If it's not in the table yet, add it. ; Both the HWA and the physical address must match for it to already be in ; the table. This allows us to capture information about nodes that run ; with multiple physical addresses and physical addresses that run on ; multiple nodes. BSBW GET_IDHWA ; Get the Device ID and HWA CMPB HWA,#^XFF ; Was there a HWA? BNEQ 10$ ; If yes, continue BRW COLLECT ; If none, don't list this one ; If we are doing test 2 and if this is the wrong device type, throw the ; SYSID message away. 10$: CMPB #2,REQNUM ; Is this test 2? BNEQ 15$ ; If NEQ, no CMPB DEVID,DEVNUM ; Is this a device we want? BEQL 15$ ; If EQL, yes BRW COLLECT ; Else discard SYSID 15$: MOVAL NODTBL,R4 ; Get beginning of table MOVL NODCNT,R5 ; Get number of entries to compare BEQL ADDNODE ; If none yet, just add this one 20$: CMPL HWA,(R4) ; HWA match? BNEQ 30$ ; If NEQ, no match on this entry CMPW HWA+4,4(R4) ; HWA match? BNEQ 30$ ; If NEQ, no match on this entry CMPL RCVSA,16(R4) ; PHA match? BNEQ 30$ ; If NEQ, no match on this entry CMPW RCVSA+4,20(R4) ; PHA match? BNEQ 30$ ; If NEQ, no match on this entry BRW COLLECT ; Identical entry, ignore this SYSID 30$: ADDL #NODSIZ,R4 ; Get next entry in the table SOBGTR R5,20$ ; Look at more entries ; This is a new SYSID, so add it to the table. ADDNODE: MOVL HWA,(R4)+ ; Add HWA MOVW HWA+4,(R4)+ MOVB DEVID,(R4)+ ; Add device ID TSTB (R4)+ MOVQ DEVDSC,(R4)+ ; Add Device name descriptor MOVL RCVSA,(R4)+ ; Add Physical address MOVW RCVSA+4,(R4) INCW @CNTADR ; One more of this specific device INCL NODCNT ; One more node in the table CMPL NODCNT,#MAXNOD ; Table full? BGEQU 10$ ; If EQL, yes, so return BRW COLLECT ; Else read another SYSID 10$: RSB PRTBL: ; Print the results. If no entries were found, just print that none were ; found. MOVL NODCNT,R5 ; Get the number of nodes BNEQ 10$ ; If some exist, print table ; else print none found message ;========================================================================== ; Print the "no nodes found" message PUSHAB M1NONE CALLS #1,G^LIB$PUT_OUTPUT RSB ;========================================================================== ; Print the table header 10$: PUSHAB M1HDR2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M1HDR3 CALLS #1,G^LIB$PUT_OUTPUT 20$: BSBW GET_NODE ; Get a node MOVL R2,R4 ; Any found? BNEQ 21$ ; If NEQ, yes RSB ;========================================================================== ; Get the hardware address into the table string 21$: MOVL #80,FAOLEN $FAO_S CTRSTR=M1HWA,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=0(R4),- P2=1(R4),- P3=2(R4),- P4=3(R4),- P5=4(R4),- P6=5(R4) MOVQ R4,-(SP) MOVC3 FAOLEN,FAOBUF,M1INFO+8+4 MOVQ (SP)+,R4 ;========================================================================== ; Get the Ethernet controller ID and name into the table string MOVL #80,FAOLEN MOVQ 8(R4),DEVDSC $FAO_S CTRSTR=M1DTYP,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=6(R4),- P2=#DEVDSC MOVQ R4,-(SP) MOVC3 FAOLEN,FAOBUF,M1INFO+8+4+19 MOVQ (SP)+,R4 ; If the HWA is the same as the physical address, then the rest of the ; table string can be left blank. CMPL (R4),16(R4) ; Addresses the same? BNEQ 25$ ; If NEQ, no CMPW 4(R4),20(R4) ; Addresses the same? BNEQ 25$ ; If NEQ, no MOVQ R4,-(SP) MOVC5 #0,FAOBUF,#^A' ',#27,M1INFO+8+4+19+11 MOVQ (SP)+,R4 INCW SUMHWA ; Another node using its HWA BRW 29$ ;========================================================================== ; Get the physical address into the table string 25$: MOVL #80,FAOLEN $FAO_S CTRSTR=M1ADDR,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=16(R4),- P2=17(R4),- P3=18(R4),- P4=19(R4),- P5=20(R4),- P6=21(R4) MOVQ R4,-(SP) MOVC3 FAOLEN,FAOBUF,M1INFO+8+4+19+11 MOVQ (SP)+,R4 ;========================================================================== ; Get the node number in the table string if the PHA is a DECnet address CMPL #^X000400AA,16(R4) ; Is this a DECnet address? BEQL 27$ ; If EQL, yes, so print it MOVQ R4,-(SP) MOVC5 #0,FAOBUF,#^A' ',#7,M1INFO+8+4+19+11+20 MOVQ (SP)+,R4 INCW SUMOTH ; Another node using some other address BRW 29$ 27$: MOVZWL 20(R4),R0 BICW #^XFC00,R0 MOVZBL 21(R4),R1 ASHL #-2,R1,R1 MOVL #80,FAOLEN $FAO_S CTRSTR=M1NODE,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R1,- P2=R0 MOVQ R4,-(SP) MOVC3 #7,FAOBUF,M1INFO+8+4+19+11+20 MOVQ (SP)+,R4 INCW SUMDEC ; Another node using a DECnet address ;========================================================================== ; Print the table string 29$: PUSHAB M1INFO CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== CLRL 8(R4) ; This entry has been printed BRW 20$ PRADR: ; Print the address totals. ;========================================================================== ; Print the header PUSHAB M2HDR CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK ;========================================================================== ; Print the SUMS MOVL #80,FAOLEN $FAO_S CTRSTR=M2SUM1,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=SUMHWA PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M2SUM2,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=SUMDEC PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M2SUM3,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=SUMOTH PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M2SUM4 CALLS #1,G^LIB$PUT_OUTPUT MOVL #80,FAOLEN $FAO_S CTRSTR=M2SUM5,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=NODCNT PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB PRDEV: ; Print the device totals. ;========================================================================== ; Print the header PUSHAB M3HDR1 CALLS #1,G^LIB$PUT_OUTPUT BSBW BLANK PUSHAB M3HDR2 CALLS #1,G^LIB$PUT_OUTPUT PUSHAB M3HDR3 CALLS #1,G^LIB$PUT_OUTPUT ;========================================================================== ; Print the device totals MOVAB DEVTBL,R5 ; Start at beginning of table ; Loop printing each device in the device table. 10$: TSTB (R5) ; End of table? BEQL 20$ ; If EQL, yes MOVL 3(R5),R6 ; Get the address of the descriptor MOVL #80,FAOLEN $FAO_S CTRSTR=M3INFO,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=R6,- P2=1(R5) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ADDL #7,R5 ; Skip this entry BRB 10$ ; Loop for more devices ; Now print the number of unknown devices. 20$: MOVL #80,FAOLEN $FAO_S CTRSTR=M3INFO,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#DEVUNK,- P2=1(R5) PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT ; Now print the number of missing devices. MOVL #80,FAOLEN $FAO_S CTRSTR=M3INFO,- OUTLEN=FAOLEN,- OUTBUF=FAODESC,- P1=#DEVMIS,- P2=DEVMSG PUSHAB FAODESC CALLS #1,G^LIB$PUT_OUTPUT RSB GET_IDHWA: ; Get the node's device ID, device name, and HWA. This is done by looking ; at the message received. The message contains a 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 message 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. Another field initialized is the ; CNTADR field which will contain the address of the counter which should ; be incremented if this SYSID is unique. ; 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 RCVBUF(R3),#^D100 ; Is this the device ID entry? BEQL 30$ ; If EQL, yes MOVZBL RCVBUF+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 RCVBUF(R3),DEVID ; Store the Device ID MOVAB DEVTBL,R5 ; Start at beginning of table 40$: TSTB (R5) ; End of table? BEQL 200$ ; If EQL, yes CMPB DEVID,(R5)+ ; Device number match? BEQL 50$ ; If EQL, yes ADDL #6,R5 ; Skip to next entry BRB 40$ ; Check next entry ; We found a match in the table. 50$: MOVL R5,CNTADR ; Save address of counter TSTW (R5)+ ; Skip the device count MOVQ @(R5),DEVDSC ; Save descriptor BRB 300$ 200$: MOVAL 1(R5),CNTADR ; Save address of counter MOVQ DEVUNK,DEVDSC ; This is an unknown device BRB 300$ 210$: MOVAL DEVMSG,CNTADR ; Save address of counter CLRB DEVID ; No Device ID was found MOVQ DEVMIS,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 RCVBUF(R3),#^D7 ; Is this the HWA entry? BEQL 330$ ; If EQL, yes MOVZBL RCVBUF+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 RCVBUF(R3),HWA ; Store first longword MOVW RCVBUF+4(R3),HWA+4 ; Store last word RSB 340$: MOVB #^XFF,HWA ; Set "no HWA found" 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_NODE: ; Locate the next node in the table to be printed. We will locate the node ; using the appropriate sorting mechanism. Once a node has been displayed ; (returned), we will zero the device descriptor field. So when we are ; looking for the next noe We will skip over nodes that have a zero in their ; device descriptor field. 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 SRT_LOOP: TSTL 8(R2) ; Is this a valid entry? BNEQ 10$ ; If NEQ, yes BRW SRT_NEXT ; Else no ; Use the appropriate sorting mechanism. 10$: CMPB SRTNUM,#2 BLSS SRT_1 BEQL SRT_2 BRB SRT_3 ; If this is the first entry found, just store it. Else compare it with the ; smallest found so far. Note that we will compare the lowest order byte ; first and the highest order byte last. This will display the addresses ; in the order desired. SRT_1: TSTL R0 ; Did we find a node yet? BEQL 20$ ; If EQL, no, so save this one CMPB (R2),(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 1(R2),1(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 2(R2),2(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 3(R2),3(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 4(R2),4(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 5(R2),5(R0) ; Is the new one smaller? BGEQU SRT_NEXT ; If GEQU, no, so skip this node 20$: MOVL R2,R0 ; Save this as the smallest node BRB SRT_NEXT ; If this is the first entry found, just store it. Else compare it with the ; smallest found so far. Note that we will compare the lowest order byte ; first and the highest order byte last. This will display the addresses ; in the order desired. SRT_2: TSTL R0 ; Did we find a node yet? BEQL 20$ ; If EQL, no, so save this one CMPB 21(R2),21(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 20(R2),20(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 19(R2),19(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 18(R2),18(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 17(R2),17(R0) ; Is the new one smaller? BGTRU SRT_NEXT ; If GTRU, no, so skip this node BLSSU 20$ ; If LSSU, yes, so save it CMPB 16(R2),16(R0) ; Is the new one smaller? BGEQU SRT_NEXT ; If GEQU, no, so skip this node 20$: MOVL R2,R0 ; Save this as the smallest node BRB SRT_NEXT ; If this is the first entry found, just store it. Else compare it with the ; smallest found so far. SRT_3: TSTL R0 ; Did we find a node yet? BEQL 20$ ; If EQL, no, so save this one CMPB 6(R2),6(R0) ; Is the new one smaller? BGEQU SRT_NEXT ; If GEQU, no, so skip this node 20$: MOVL R2,R0 ; Save this as the smallest node BRB SRT_NEXT ; Skip to next node and continue if there are more nodes to look at. SRT_NEXT: ADDL #NODSIZ,R2 ; Skip to next entry in table INCL R1 ; Bump node counter CMPL R1,NODCNT ; Are we done? BGEQU 10$ ; If GEQU, yes, so exit BRW SRT_LOOP ; Else loop 10$: 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=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 ; 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 hardware address ; 1 byte of DEVICE ID ; 1 byte of spare info ; 8 bytes of DEVICE NAME descriptor ; 6 bytes of physical address ; 4 bytes of address of device counter NODSIZ = 26 MAXNOD = 1000 NODCNT: .LONG 0 NODTBL: .BLKB MAXNOD*NODSIZ .END START