TITLE QSRADM -- System Administrative Functions SUBTTL Larry Samberg 6 Jan 77 ;***Copyright (C) 1976, Digital Equipment Corp., Maynard, MA.*** SEARCH QSRMAC ;PARAMETER FILE PROLOGUE(QSRADM) ;GENERATE NECESSARY SYMBOLS COMMENT \ STOPCDs found in QSRADM UCW USE COUNT WRONG \ SUBTTL Module Storage and Constants MSGPDB: BLOCK IPCHSZ ;PDB FOR SENDING MESSAGES MSGMSG: BLOCK RCK.SZ ;MESSAGE BLOCK FOR RCK (FOR NOW) CNVPTR: POINT 6,CNVSTN(S1),5 POINT 6,CNVSTN(S1),11 POINT 6,CNVSTN(S1),17 POINT 6,CNVSTN(S1),23 POINT 6,CNVSTN(S1),29 POINT 6,CNVSTN(S1),35 ;THE TABLE FOR CONVERSION STARTS OUT AS IDENTITY, CHANGED BY FUNCTION 17 CNVSTN: BYTE(6) 0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20,21 BYTE(6) 22,23,24,25,26,27,30,31,32,33,34,35,36,37,40,41,42,43 BYTE(6) 44,45,46,47,50,51,52,53,54,55,56,57,60,61,62,63,64,65 BYTE(6) 66,67,70,71,72,73,74,75,76,77 SUBTTL Initialization Entry ;CALLED DURING QUASAR INITIALIZATION TO INITIALIZE THE ADMINISTRATIVE ; DATABASE. A$INIT:: PUSHJ P,I$NOW## ;GET NOW!! MOVEM S1,G$ITEM+$$STAR ;SAVE IT POPJ P, ;AND RETURN SUBTTL Administrative Message Handlers ;THE MESSAGE HANDLERS ARE TOP LEVEL ROUTINES WHICH PROCESS THE ; VARIOUS MESSAGES THAT ARE SENT TO QUASAR. THEY ARE ; CALLED DIRECTLY OUT OF THE MAIN PROCESSING LOOP WITH ; ACCUMULATOR "M" POINTING TO THE FIRST WORD OF THE MESSAGE. ; THE MESSAGE HANDLERS HAVE FULL USE OF ALL ACCUMULATORS ; EXCEPTING "M" AND THE "P" REGS. INTERN A$HELLO ;FUNCTION 1 -- HELLO INTERN A$RCK ;FUNCTION 15 -- REQ FOR CHECKPOINT(*) INTERN A$ROUTE ;FUNCTION 17 -- ROUTE INTERN A$COUNT ;FUNCTION 20 -- COUNT INTERN A$CANSWER ;FUNCTION 21 -- COUNT ANSWER(*) ;(*) REQUEST FOR CHECKPOINT AND COUNT ANSWER ARE SENT BY QUASAR ; THESE ARE NOT CALLED FROM THE MAIN LOOP BUT RATHER: ; ; REQUEST FOR CHECKPOINT IS CALLED FROM THE SCHEDULING ROUTINES ; COUNT ANSWER IS CALLED FROM THE COUNT FUNCTION SUBTTL HELLO -- Function 1 ;THE HELLO MESSAGE IS SENT TO QUASAR BY ONE OF THE KNOWN SYSTEM ; COMPONENTS UNDER THREE CIRCUMSTANCES, THE FIRST BEING PROGRAM ; STARTUP, THE SECOND, A STATUS CHANGE AND THE THIRD, PROGRAM ; SHUTDOWN. A$HELLO: PUSHJ P,.SAVE1## ;SAVE P1 LOAD T1,.MSTYP(M),MS.CNT ;GET THE MESSAGE SIZE CAIGE T1,HEL.SZ ;AT LEAST BIG ENOUGH? PJRST E$MTS## ;NO, INDICATE MESSAGE TOO SHORT PUSHJ P,I$WHEEL## ;SEE IF CALLER IS AN OPERATOR JUMPE S1,E$IPE## ;ISN'T, CANNOT BECOME A KNOWN COMPONENT LOAD S1,HEL.ST(M),HELVER ;GET PROGRAMS VERSION OF QSRMAC CAIE S1,%%.QSR ;BETTER BE THE SAME AS MINE PJRST E$WVN## ;ISN'T, GIVE WRONG VERSION ERROR LOAD S1,HEL.SD(M) ;GET SIXBIT DEVICE TO SCHEDULE LOAD S2,HEL.ST(M),HELDSN ;GET SPOOLERS DEFAULT STATION PUSHJ P,I$MIDS## ;CONVERT TO INTERNAL DEVICE SPEC PJUMPE S1,E$IFD## ;GIVE NAK IF BAD STORE S1,HEL.SD(M) ;NOW IS IN INTERNAL FORM HELL.1: MOVE S1,G$SND## ;GET PID OF CURRENT SENDER PUSHJ P,GETPSB ;FIND HIS PSB MOVE P1,S1 ;STORE ADDRESS OF PSB IN P1 SKIPE PSBPID(P1) ;IS IT A NEW ONE? JRST HELL.2 ;NO, MUST BE STATUS CHANGE LOAD S1,HEL.SD(M) ;GET SCH DEVICE IDS PUSHJ P,Q$FHDR## ;FIND THE QUEUE HEADER JUMPE S1,HELL.6 ;NO SUCH QUEUE!!! STORE S1,PSBSTS(P1),PSYHDR ;STORE THE HEADER'S ADDRESS MOVE T2,G$SND## ;GET SENDER'S PID MOVEM T2,PSBPID(P1) ;AND STORE IT IN THE PSB MOVE T2,HEL.ST(M) ;GET STATUS WORD TXNE T2,HELSTC ;STATUS CHANGE JRST HELL.5 ;YES, IGNORE IT JRST HELL.4 ;TRANSFER THE REST AND RETURN ;HERE WHEN WE RECEIVE HELLO MESSAGE FROM A "KNOWN" PID HELL.2: MOVE T2,HEL.ST(M) ;GET THE STATUS WORD TXNE T2,HELBYE ;IS IT A GOODBYE MESSAGE? PJRST KILPSB ;YES, GO DO IT TXNE T2,HELSTC ;NO, IS IT A STATUS CHANGE? JRST HELL.4 ;YES, STORE THE REST OF THE MESSAGE ;HERE WHEN WE RECEIVE A HELLO FROM A KNOWN PROGRAM. WE ASSUME THE ; PROGRAM ABENDED AND HAS BEEN RESTARTED, SO WE FORCE A ; GOODBYE FOLLOWED BY A NEW HELLO. HELL.3: PUSHJ P,KILPSB ;BYE.... JRST HELL.1 ;HI..... ;HERE TO STORE ALL INFORMATION WHICH WILL BE STORED ON BOTH ; HELLO MESSAGES AND STATUS CHANGE MESSAGES. ; HELL.4: MOVE T2,HEL.NM(M) ;GET THE PROGRAM NAME MOVEM T2,PSBNAM(P1) ;AND STORE IT MOVE T2,HEL.SD(M) ;DEVICE FOR WHICH TO SCHEDULE MOVEM T2,PSBSDV(P1) ;STORE MOVE T2,HEL.PD(M) ;PROCESSING DEVICE MOVEM T2,PSBPDV(P1) ;STORE MOVE T2,HEL.I1(M) ;GET INFORMATION WORD 1 LOAD T3,PSBSTS(P1),PSYHDR ;GET ADDRESS OF THE QUEUE HEADER LOAD T3,.QHTYP(T3),QH.TYP ;GET QUEUE TYPE CAIN T3,.QHTOU ;IS IT AN OUTPUT QUEUE ANDX T2,FRMSK1 ;MASK TO UNIQUE FORMS TYPE MOVEM T2,PSBIN1(P1) ;STORE IT MOVE T2,HEL.I2(M) ;GET INFO WORD 2 MOVEM T2,PSBIN2(P1) ;AND STORE IT MOVE T2,HEL.I3(M) ;GET INFO WORD 3 MOVEM T2,PSBIN3(P1) ;AND STORE IT LOAD T2,HEL.ST(M),HELSCH ;GET SCHEDULING FLAG STORE T2,PSBSTS(P1),PSYSCH ;SET FOR SCHEDULER LOAD T2,HEL.ST(M),HELFRZ ;GET FROZEN FORMS INDICATOR STORE T2,PSBSTS(P1),PSYFRZ ;SET FOR FORMS CHANGER LOAD T2,HEL.ST(M),HELLLP ;GET LOWER CASE PRINTER BIT STORE T2,PSBSTS(P1),PSYLLP ;SET ACCORDINGLY LOAD T2,HEL.ST(M),HELRDE ;GET ABILITY TO DO RDE JOBS STORE T2,PSBSTS(P1),PSYRDE ;AND STORE IT POPJ P, ;AND RETURN ;HERE TO RETURN THE PSB WE ARE POINTING TO IN P1. THIS IS DONE ; IF WE ENCOUNTER AN INCONSISTENCY IN A HELLO MESSAGE AFTER ; WE'VE ALLOCATED A PSB. HELL.5: PUSHJ P,E$NKC## ;STATUS CHANGE FROM UNKNOWN PROGRAM SKIPA ;SKIP THE OTHER ERROR HELL.6: PUSHJ P,E$UQS## ;UNKNOWN QUEUE SPECIFIED MOVEI H,HDRPSB## ;LOAD ADDRESS OF HEADER MOVE AP,P1 ;LOAD ADDRESS OF PSB PJRST M$RFRE## ;RETURN IT TO FREE SPACE SUBTTL REQUEST FOR CHECKPOINT -- Function 15 ;REQUEST FOR CHECKPOINT IS CALLED BY THE SCHEDULING LOOP TO SEND THE ; CHECKPOINT REQUEST TO A KNOWN COMPONENT. ; ;CALLED WITH T1 = THE PID TO SEND TO A$RCK: MOVEI AP,MSGPDB ;POINT TO THE PDB FOR THE SEND MOVEM T1,.IPCFR(AP) ;STORE THE RECEIVERS PID ZERO .IPCFL(AP) ;NO FLAGS MOVE T1,[RCK.SZ,,MSGMSG] ;MACRO WONT LET ME DO IT ANY OTHER WAY MOVEM T1,.IPCFP(AP) ;STORE LENGTH AND ADDRESS MOVX T1, MOVEM T1,MSGMSG+.MSTYP ;STORE FUNCTION AND MESSAGE LENGTH TXO AP,IPS.ID ;DONT SEND IF OTHERS QUEUED FOR PID PJRST C$SEND## ;SEND THE MESSAGE AND RETURN SUBTTL ROUTE -- Function 17 ;CALLED TO HANDLE "ROUTE" MESSAGE FROM MAIN LOOP. A$ROUTE: LOAD S1,.MSTYP(M),MS.CNT ;SIZE OF MESSAGE CAIGE S1,ROU.SZ ;MINUMUM SIZE PJRST E$MTS## ;MESSAGE TOO SHORT PUSHJ P,I$WHEEL## ;CALLER MUST BE A WHEEL PJUMPE S1,E$IPE## ;INSUFFICIENT PRIVS LOAD S1,ROU.ST(M),RO.ORG ;ORIGINAL STATION (TABLE ENTRY) LOAD TEMP,ROU.ST(M),RO.NEW ;NEW ROUTING CAIG S1,^D63 ;MAXIMUM STATION NUMBER CAILE TEMP,^D63 ;FOR EITHER NUMBER PJRST E$NOR## ;RANGE CHECK ERROR IDIVI S1,6 ;SPLIT INTO INDICES DPB TEMP,CNVPTR(S2) ;STORE NEW STATION INFORMATION POPJ P, ;AND ALL DONE SUBTTL COUNT -- Function 20 ;COUNT MESSAGE IS SENT TO QUASAR BY A WHEEL TO REQUEST A COUNT-ANSWER ; CONTAINING ALL OF QUASAR'S INTERESTING COUNTERS. A$COUNT: PUSHJ P,I$WHEEL ;IS USER A WHEEL? PJUMPE S1,E$IPE## ;NO, INSUFICIENT PRIVS LOAD S1,G$NOW## ;GET NOW STORE S1,G$ITEM##+$$NOW ;SAVE IT JRST A$CANSWER ;GIVE HIM THE ANSWER SUBTTL CANSWER -- Function 21 ;A$CANSWER IS CALLED BY THE COUNT MESSAGE CODE TO SEND A COUNT-ANSWER ; MESSAGE TO THE CURRENT SENDER. A$CANSWER: $COUNT (MCAN) ;NUMBER OF COUNTANSWER MESSAGES PUSHJ P,M$ACQP## ;GET A PAGE PG2ADR AP ;MAKE AN ADDRESS MOVE S1,AP ;COPY OVER THE ADDRESS PUSHJ P,.ZPAGA## ;AND ZERO THE PAGE MOVSI S1,CAN.SZ ;GET LEN,,0 HRRI S1,.QOCAN ;GET LEN,,FUNCTION STORE S1,.MSTYP(AP) ;STORE IT IN THE MESSAGE MOVSI S1,G$ITEM## ;GET START ADDRESS HRRI S1,CAN.BL(AP) ;GET DEST ADDRESS BLT S1,CAN.BL+NITEMS(AP) ;BLT THE MESSAGE ADR2PG AP ;CONVERT TO A PAGE NUMBER HRLI AP,1000 ;PUT IN PAGE LENGTH MOVEM AP,MSGPDB+.IPCFP ;STORE IN THE PDB MOVEI AP,MSGPDB ;POINT TO THE PDB MOVX S1,IP.CFV ;GET PAGE MODE BIT MOVEM S1,.IPCFL(AP) ;STORE IN PDB MOVE S1,G$SND## ;GET PID OF SENDER MOVEM S1,.IPCFR(AP) ;SAVE AS RECEVIER PJRST C$SEND## ;SEND IT SUBTTL Global Routines ;THE FOLLOW ARE ADDITIONAL GLOBAL ROUTINES FOUND IN THIS MODULE ; OTHER THAN THE TOP-LEVEL MESSAGE HANDLERS. INTERN A$KLPD ;KILL OFF A PSB GIVEN ITS PID INTERN A$FPSB ;FIND A PSB GIVEN A PID INTERN A$CSTN ;DO ACTUAL STATION RE-ROUTING SUBTTL A$KLPD -- Routine to kill a PSB given its PID ;A$KLPD IS CALLED TO "KILL" A PSB ENTRY. A$KLPD IS CALLED ; WITH THE PID OF THE PSB TO BE KILLED (E.G. WHEN A SEND TO ; A KNOWN COMPONENT FAILS WITH "UNKNOWN PID"). ; ;CALL WITH ARGUMENT IN S1 A$KLPD: SAVE AP ;SAVE CALLERS REGISTERS SAVE H ; "" PUSHJ P,A$FPSB ;FIND THE PSB GIVEN THE PID PJUMPE S1,.POPJ## ;RETURN IF NOT THERE PJRST KILPSB ;KILL THE PSB ENTRY AND RETURN SUBTTL A$FPSB -- Subroutine to find a PSB ;A$FPSB IS CALLED WITH A PID IN S1. IT SCANS THE PSB LIST ; LOOKING FOR A MATCH. IF ONE IS FOUND, THE ADDRESS ; OF THE PSB IS RETURNED IN S1, ELSE S1 IS RETURNED ; CONTAINING 0. A$FPSB: MOVEI H,HDRPSB## ;ADDRESS OF PSB QUEUE HEADER MOVE S2,S1 ;COPY ARGUMENT TO S2 LOAD S1,.QHLNK(H),QH.PTF ;GET ADDRESS OF FIRST FPSB.1: JUMPE S1,.POPJ## ;RETURN IF LAST ONE (OR NONE) CAMN S2,PSBPID(S1) ;MATCH? POPJ P, ;YES, RETURN WITH ADDRESS IN S1 LOAD S1,.QELNK(S1),QE.PTN ;GET POINTER TO NEXT JRST FPSB.1 ;AND LOOP SUBTTL A$CSTN -- Do station re-routing ;THIS ROUTINE IS CALLED WITH S1 CONTAINING A UDS. THIS UDS IS RETURNED ; (IN S1) WITH THE STAION FIELD MODIFIED TO REFLECT ANY RE-ROUTING ; DONE ON THE ORIGINAL STATION. A$CSTN: PUSH P,S1 ;SAVE ORIGINAL SPEC LOAD S1,S1,DV.STN ;EXTRACT STATION NUMBER IDIVI S1,6 ;SPLIT INTO INDICES LDB S1,CNVPTR(S2) ;LOAD NEW STATION STORE S1,0(P),DV.STN ;INSERT NEW INTO SPEC POP P,S1 ;RESTORE POPJ P, ;AND RETURN UPDATED UDS SUBTTL Utility Routines ; GETPSB -- FIND OR CREATE A PSB GIVEN A PID ; KILPSB -- KILL A SPECIFIED PSB SUBTTL GETPSB -- Routine to get a PSB ;GETPSB IS CALLED WITH A PID IN S1. IT CALLS A$FPSB TO SEE IF ; THE PID IS ALREADY KNOWN, AND IF SO IT RETURNS ITS ADDRESS ; IN S1. IF NOT, A NEW PSB IS GOTTEN AND ZEROED AND ITS ; ADDRESS IS RETURNED IN S1. ; GETPSB: PUSHJ P,A$FPSB ;FIND KNOWN PID PJUMPN S1,.POPJ## ;FOUND IT GETP.1: MOVEI H,HDRPSB ;LOAD ADR OF PSB HEADER PUSHJ P,M$GFRE## ;GET A FREE CELL MOVE S1,AP ;COPY ITS ADDRESS INTO S1 HRLI S2,PSBBGN(AP) ;GET ADDRESS OF FIRST WORD HRRI S2,PSBBGN+1(AP) ;GET ADDRESS OF SEC WORD ZERO PSBBGN(AP) ;CLEAR THE FIRST WORD BLT S2,PSBSIZ-1(AP) ;CLEAR THE REST OUT PUSH P,S1 ;SAVE THE ANSWER PUSHJ P,M$ELNK## ;LINK IN THE PSB POP P,S1 ;RESTORE THE ANSWER POPJ P, ;AND RETURN SUBTTL KILPSB -- Routine to kill a PSB given its address ;CALL KILPSB WITH THE ADDRESS OF THE PSB TO BE KILLED IN S1. KILPSB ; CLEARS ANY DEAD INTERLOCKS FOR THE PSB, AND RETURNS IT TO THE ; PSB FREE SPACE. KILPSB: SAVE H ;SAVE H SAVE AP ;AND AP MOVE T1,S1 ;AND PUT ARGUMENT THERE KILP.0: LOAD S1,PSBSTS(T1),PSYNJP ;GET NUMBER OF JOBS BEING PROCESSED JUMPE S1,KILP.3 ;RETURN WHEN DONE MOVEI H,HDRUSE## ;POINT TO THE USE QUEUE LOAD AP,.QHLNK(H),QH.PTF ;GET GET THE FIRST KILP.1: SKIPN AP ;IS THERE ONE? STOPCD(UCW,FATAL) ;++USE COUNT WRONG MOVE S1,PSBPID(T1) ;YES, GET PSB'S PID CAMN S1,.QEPID(AP) ;INTERLOCKING THIS JOB? JRST KILP.2 ;YUP, GO CLEAR THE INTERLOCK LOAD AP,.QELNK(AP),QE.PTN ;NO, GET POINTER TO NEXT JRST KILP.1 ;AND LOOP KILP.2: LOAD S1,.QESTN(AP),QE.RQP ;GET THE RQP ADDI S1,TBLHDR## ;CONVERT TO QUEUE HEADER ADDRESS ZERO .QEPID(AP) ;CLEAR THE INTERLOCK PUSHJ P,M$MOVE## ;MOVE IT BACK TO PROC QUEUE PUSHJ P,S$RUSE## ;TELL SCHED (T1 IS ARG TO KILPSB) JRST KILP.0 ;AND LOOP KILP.3: MOVEI H,HDRPSB## ;LOAD HEADER FOR PSB QUEUE MOVE AP,T1 ;COPY OVER PSB ADDRESS PJRST M$RFRE## ;AND RELEASE THE PSB END