.TITLE CDDRV .IDENT /2.1/ ; ; VERSION: 2.0 ; ; AUTHORS:DAVID B. (BEN) BURCH ; VICKY WHITE ; ; COMPUTING DEPARTMENT ; FERMI NATIONAL ACCELERATOR LABORATORY ; AUGUST 1982 ; ; THE FOLLOWING IS A BISON GROUP PRODUCTION... ; ; UPDATES: ; ; V2.1 - 12SEP84 - David M. Berg ; - fix CDWPTC to recognize PTC's > 127 ; - mod CDCHK to skip function code comparisons for IO.SPA ; - change all IE.CNR to IE.URJ to restore error code -73 ; - handle interrupts with any link code in CDTRAN, and ; restore CDWAIT from OLD version, in order to avoid ; error return when transmitted block ends at I/O page ; - remove all code conditional on OLD ; ;+ ; FUNCTION: ; ; DR11-W INTERPROCESSOR COMMUNICATIONS DRIVER ; ; INPUTS: ; ; OUTPUTS: ; ; NOTES: ; ;- ; ; MACRO CALLS: ; ------------ ; ; .MCALL DCBDF$,UCBDF$,SCBDF$,HWDDF$,PKTDF$,QIOSY$,INTSV$ .MCALL TCBDF$,CLKDF$,PCBDF$ PCBDF$ TCBDF$ DCBDF$ UCBDF$ SCBDF$ HWDDF$ PKTDF$ QIOSY$ CLKDF$ ; ; LOCAL MACROS: ; ; ALL LOCAL MACROS DEFINED IN CDPREFIX.MAC ; .MCALL DSABL ;DISABLE INTERRUPTS .MCALL ENABL ;RE-ENABLE INTERRUPTS .MCALL TRACE ;SET HIGH PRIORITY AND CALL TRACE ROUTINE .MCALL DISTBL ;DEFINE I/O FUNCTION CODE DISPATCH TABLE .MCALL INTTBL ;DEFINE INTERRUPT LEVEL DISPATCH TABLE .MCALL PUSH ;SAVE REGISTERS ON STACK .MCALL POP ;RESTORE SAVED STUFF FROM STACK .MCALL ASSUME ;GIVE ASSEMBLER ERROR IF WRONG ASSUMPTIONS ; ; GLOBAL SYMBOLS: ; --------------- ; ; ; DEFINE EXECUTIVE SYMBOLS USED BY THIS DRIVER ; .GLOBL $ACHCK,$ALOCB,$DEACB,$FORK,$FORK1,$GTPKT .GLOBL $INTXT,$IODON,$IOFIN,$NONSI,$QASTT,$QINSP .GLOBL $DECLK,$CLINS,$IDLCT,$TKTCB,$PARHD,$TTNS ; ; GLOBAL DATA: ; ------------ ; ; ; DRIVER DISPATCH TABLE ; $CDTBL::.WORD CDCHK ;DEVICE INITIATOR ENTRYPOINT .WORD CDCAN ;CANCEL I/O ENTRYPOINT .WORD CDOUT ;DEVICE TIMEOUT ENTRYPOINT .WORD CDPWF ;DEVICE POWERFAIL ENTRYPOINT ; ; LOCAL DATA: ; ----------- ; ; .IFDF TRCE ; STUFF FOR THE TRACE FEATURE: ; TRCDAT: .BLKW TR.SIZ+1 ;ADD A GUARD WORD. ; AP6: .WORD 0 ;SAVED APR6 MAPPING TRC: .WORD 0 ;BIAS FOR TRACE PARTITION .ENDC ; ; CONTROLLER TABLE ; ; NOTE: THIS IS A MULTICONTROLLER DRIVER, AND AS A RESULT, WE NEED TO ; DEFINE CNTBL FOR THE UCB. ; CNTBL: .BLKW CD$NUM ;ADDRESS OF UNIT CONTROL BLOCK ; .IF GT D$$11W TEMP: .BLKW 1 ;SPACE TO SAVE PS ON INTERRUPT .ENDC ; ; DISPATCH TABLE FOR THE I/O FUNCTION CODES ; ----------------------------------------- .PAGE ; DISTAB: ; ; IO FN ALLOWED STATES TO ACTION ON IE ERROR CODE ; DO I/O BAD STATE CODE ADDR ; ;--------------------------------------------------------------------------- ; ; DISTBL IO.WLB, IDLE, IOQ.D, IE.LDN, CDWLB DISTBL IO.RLB, ASTQUE, PTQ.D, IE.NRP, CDRLB DISTBL IO.SIG, IDLE, IOQ.D, IE.LDN, CDWLB DISTBL IO.CLN, ANY, NONE NONE, CDCLN DISTBL IO.SPA, ANY, NONE IE.PTO, CDSPA DISTBL IO.RPA, ANY, NONE NONE CDRPA DISTBL IO.STU, ANY, NONE NONE CDSTU DISTBL IO.REJ, ASTQUE, FIN.D IE.NRP CDREJ DISTBL IO.AWA, DISCON, FIN.D IE.NDS CDAWA ; ;--------------------------------------------------------------------------- ; ; END OF TABLE - ANY FUNCTION NOT IN TABLE IS ILLEGAL DISEND: DISTBL NONE, NONE, FIN.D IE.IFC NONE ; ;--------------------------------------------------------------------------- .IF GT D$$11W ; ; INTERRUPT LEVEL DISPATCH TABLE ; ------------------------------ ; INTTAB: ; ; STATE CONTROL BITS WHICH MUST CONTROL BITS WHICH MAY CODE ; BE SET IN LINK-CODE BE SET IN LINK-CODE ADDR ; ;----------------------------------------------------------------------- ; INTTBL IDLE CDIDLE INTTBL WTLACK CDWLAK INTTBL WTPTAK CDWPAK INTTBL WTRCWC NONE ANY CDWRWC INTTBL WTSGAK CDWSAK INTTBL TRANSF NONE ANY CDTRAN ;V2.1 INTTBL WAITEM CDWAIT ;V2.1 INTTBL WTPTC CDWPTC INTTBL WTXMWC NONE ANY CDWXWC INTTBL RECPEN NONE ANY CDRECP INTTBL FORKED NONE ANY CDFORK INTTBL ASTQUE NONE NONE GARBGE INTTBL STWAIT NONE ANY CDWSTK INTTBL DOWN NONE NONE GARBGE ; INTEND: ; ; .ENDC .PAGE .SBTTL CDCHK - I/O INITIATOR ENTRY POINT ; ; ;+ ; CDCHK- DR11-W ICD PARAMETER/FUNCTION CHECKING ; ; THIS ROUTINE IS ENTERED FROM THE QUEUE I/O DIRECTIVE WHEN AN I/O ; REQUEST IS RECEIVED FOR THE DR-11W CD DRIVER. CD I/O REQUESTS CONTAIN ; INFORMATION (SUCH AS AST ADDRESSES) THAT MUST BE CHECKED IN THE ; CONTEXT OF THE ISSUING TASK. ; ; THE EXECUTIVE WILL CALL THE DRIVER AT THIS ENTRY POINT WHENEVE A QIO IS ; ISSUED, WHATEVER STATE THE DRIVER IS CURRENTLY IN. THIS IS BECAUSE IN ; U.CTL THE BIT UC.QUE IS SET TO ENSURE ALL PACKETS ARE PASSED TO THE ; DRIVER BEFORE BEING PUT ON THE I/O QUEUE ; ; WHETHER THE I/O PACKET CAN BE IMMEDIATELY SERVICED DEPENDS ON THE ; CURRENT STATE OF THE DRIVER. THIS ROUTINE RAISES PRIORITY TO DEVICE ; PRIORITY TO DETERMINE IF THE DRIVER IS IN THE CORRECT STATE TO PERFORM ; THE FUNCTION SPECIFIED IN THE CURRENT I/O PACKET. ; THERE ARE THE FOLLOWING POSSIBLE OUTCOMES: ; ; A) STATE IS SUITABLE. A JUMP TO THE APPROPRIATE SERVICE CODE IS MADE ; (STILL AT DEVICE PRIORITY). THE SERVICE CODE MUST THEN IMMEDIATELY ; ENSURE THAT ANY STATUS/STATES ARE APPROPRIATELY SET TO INTERLOCK ; WITH THE INTERRUPT CODE BEFORE IT LOWERS PRIORITY ; B) STATE IS NOT SUITABLE. IO IS TERMINATED WITH AN ERROR CONDITION. ; E.G. WHEN AN IMMEDIATE READ PACKET IS HANDLED AND THERE IS NO ; MESSAGE TRANSACTION IN PROGRESS ; C) STATE IS NOT SUITABLE. THE PACKET IS PUT ON THE I/O QUEUE - RAISING ; PRIORITY AGAIN TO DEVICE PRIORITY TO DO THIS - SINCE INTERRRUPT ; CODE MAY RE-QUEUE A PACKET FROM INTERRRUPT LEVEL IN THE CASE WHERE ; IT LOSES ITS BID FOR OWNERSHIP OF THE LINK ON A WRITE REQUEST AND ; IS THE SLAVE MACHINE ; D) STATE IS NOT SUITABLE. THE PACKET IS PUT ON THE PRIVATE I/O QUEUE ; OF THE PDB FOR THE APPROPRIATE PTC. AGAIN ALL QUEUEING IS DONE ; AT DEVICE PRIORITY. ; ; ALL OF THE ABOVE DECISIONS AND DISPATCHES ARE HANDLED BY THE DISPATCH ; TABLE BITS, ERROR CODES AND CODE ADDRESSES ; ; THE STANDARD I/O QUEUE WHOSE LISTHEAD IS IN THE SCB IS MAINTAINED ; WHOLLY BY THE DRIVER ITSELF. THE SYSTEM DEQUEUE ROUTINE $GTPKT ; IS NEVER USED. ; WHEN A TRANSFER QIO FUNCTION IS ACTUALLY IN PROGRESS (IO.RLB,IO.WLB,IO.SIG) ; THEN THE NORMAL FIELDS IN THE UCB ARE FILLED IN, THE CONTROLLER IS ; SET TO BUSY AND THE UNIT BUSY BIT IS SET TO ENABLE STANDARD DEVICE ; TIMEOUT, AND THE ADDRESS OF THE I/O PACKET FOR THE TRANSFER IS SET ; IN FIELD S.PKT OF THE SCB. WHEN THERE IS NO SUCH ; PACKET, AS WHEN RECEIVING A MESSAGE, BEFORE THE READ QIO HAS BEEN ; DONE THEN ONLY THE UNIT IS BUSY BUT THERE IS NO PENDING PACKET. ; TRANSFER FUNCTION PACKETS ARE TERMINATED BY A CALL TO $IODON, ; WHICH THEN RE-SETS THE DEVICE AND UNIT STATUS. ; ; WHEN ANY OTHER TYPE OF I/O FUNCTION IS BEING PROCESSED, THE FIELDS ; IN THE UCB AND SCB DESCRIBED ABOVE ARE NOT USED AND THE CONTROLLER ; BUSY FLAG AND TIMEOUT REMAIN UNTOUCHED. ; SUCH NON-TRANSFER FUNCTION PACKETS ARE TERMINATED BY A CALL TO $IOFIN ; WHICH DOES NOT RESET THE DEVICE. ; ; ALL I/O FUNCTIONS FOR THE INTERNAL COMMUNICATION LINK, INCLUDING ; TRANSFER FUNCTIONS ARE TERMINATED BY A CALL TO $IOFIN. ; THE ONLY EXCEPTION IS THE SEND SIGNAL FUNCTION WHICH TERMINATES ; BY A CALL TO $IODON. THERE ARE ; NO INTERRUPTS FOR THIS CONTROLLER AND UNIT. ; ; DR11-W I/O REQUEST PACKET FORMAT ; ; WORD CONTENT ; ; 0 I/O QUEUE THREAD WORD ; 1 REQUEST PRIORITY, EVENT FLAG NUMBER ; 2 ADDRESS OF THE TCB OF THE REQUESTER TASK ; 3 POINTER TO SECOND LUN WORD IN TASK HEADER ; 4 CONTENTS OF FIRST LUN WORD (UCB) ; 5 I/O FUNCTION CODE ; 6 VIRTUAL ADDRESS OF I/O STATUS BLOCK ; 7 RELOCATION BIAS OF I/O STATUS BLOCK ; 10 I/O STATUS BLOCK ADDR (REAL OF DISPLACEMENT + 140000) ; 11 VIRTUAL ADDRESS OF AST SERVICE ROUTINE ; ; FOR IO.RLB AND IO.WLB FUNCTIONS: ; ; 12 MEMORY EXTENSION BITS FOR I/O BUFFER ; (OR ADDRESS DOUBLEWORD 1ST WORD (KISAR6 VALUE) FOR IC) ; 13 BUFFER ADDRESS FOR TRANSFER ; (OR ADDRESS DOUBLEWORD 2ND WORD (VIRTUAL ADDRESS APR6) FOR IC) ; 14 TOTAL BYTE COUNT TO TRANSFER ; 15 PACKET TYPE CODE OF DESTINATION TASK ; ; FOR IO.SPA AND IO.RPA FUNCTIONS: ; ; 12 PACKET TYPE CODE OF DESTINATION TASK ; 13 AST ADDRESS (FOR IO.SPA ONLY) ; 14,15 NOT USED ; ; FOR IO.SIG FUNCTION: ; ; 12 SIGNAL BYTE (WORD ALIGNED) ; 13 PACKET TYPE CODE ; 14,15 NOT USED ; FOR ALL FUNCTIONS: ; ; 16 NOT USED ; 17 NOT USED ; 20 NOT USED ; ; INPUTS: ; ; R1=ADDRESS OF THE I/O REQUEST PACKET ; R4=ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5=ADDRESS OF THE UCB OF THE CONTROLLER TO BE INITIATED ; ; OUTPUTS: ; ; THE PACKET TYPE CODE VALUE IS CHECKED TO BE IN THE RANGE 0 TO 255. ; THE AST ADDRESS (IF ANY) IS CHECKED TO DETERMINE WHETHER IT LIES ; IN THE TASK'S ADDRESS SPACE. IF IT DOES, THE ADDRESS IS RELOCATED ; AND STORED IN THE I/O PACKET. ; IF THE AST CHECKING FAILED, AN ILLEGAL ADDRESS STATUS IS ; RETURNED AS THE FINAL I/O STATUS OF THE REQUEST ; THE I/O PACKET HAS BEEN DEALT WITH IN ONE OF THE 4 POSSIBLE ; WAYS DESCRIBED ABOVE IN (A) -> (D) ;- CDCHK: MOVB I.FCN+1(R1),R0 ;STRIP SUBFUNCTION FOR ;DISPATCH TABLE TRACE <#8.,U.STA(R5),I.FCN(R1),$TKTCB,R5,R1> MOV R1,R3 ;COPY ADDRESS OF I/O PACKET CMPB #IO.SPA/256.,R0 ;DOES FUNCTION HAVE AST ADDRESS IN P3? BNE 20$ ;IF NE NO MOV I.PRM+2(R3),R0 ;GET VIRTUAL ADDRESS OF AST ENTRYPOINT .IF DF A$$CHK ;IF SYSTEM SUPPORTS CHECKING... MOV #2,R1 ;LENGTH TO BE CHECKED (ONE WORD) CALL $ACHCK ;ADDRESS CHECK AST ENTRYPOINT ;THIS PRESERVES R3 BCC 50$ ;IF CC ADDRESS A.O.K. ;V2.1 MOV #IE.AST,R0 ;SET UNSPECIFIED AST STATUS JMP IOFIN ;EXIT FROM DRIVER .IFF ;IF NO ADDRESS CHECKING... ;V2.1 BR 50$ ;V2.1 .ENDC ;A$$CHK 20$: CMPB #IO.RLB/256.,R0 ;WRITE FUNCTION? BEQ 30$ ;IF SO MUST CHECK PTC FOR VALIDITY CMPB #IO.WLB/256.,R0 ;READ FUNCTION? BEQ 30$ ;IF READ BRANCH TO CHECK PTC CMPB #IO.SIG/256.,I.FCN+1(R3) ;SEND SIGNAL? BNE 50$ BIT #^C377,I.PRM+2(R3) ;CHECK SIGNAL PTC IS IN RANGE 0-255 BNE 40$ BR 50$ 30$: BIT #^C377,I.PRM+6(R3) ;CHECK READ/WRITE PTC IS IN RANGE 0-255 BEQ 50$ 40$: MOV #IE.IPT,R0 JMP IOFIN ;COMPLET I/O WITH ILLEGAL PTC ERROR 50$: JMP CDDISP ;TRY TO DO THE I/O FUNCTION .PAGE .SBTTL CDINI - FORK LEVEL INITIATOR ; ;+ ; ; CDINI - DR11-W INTERPROCESSOR COMMUNICATIONS DEVICE DRIVER INITIATOR ; ; THIS ROUTINE IS ENTERED AT THE END OF EACH TRANSFER I/O OPERATION - TO BEGIN ; THE NEXT OPERATION OR TO HANDLE ANY PENDING REQUEST LINKS. ; IT IS ENTERED ONLY FROM THE FORK LEVEL CODE, WHEN THE DRIVER IS ; APPARENTLY IN THE IDLE STATE. ; ; A CHECK IS MADE FOR PENDING REQUEST LINKS, AT DEVICE PRIORITY. ANY ; INTERRUPTS PRIOR TO RAISING PRIORITY WOULD CAUSE THE PENDING ; REQUEST FLAG TO BE CLEARED, UNLESS THEY WERE ACTUALLY REQUEST LINKS ; THEMSELVES. ; ; IF THERE ARE NO PENDING REQUEST LINKS THEN THE NEXT QUEUED I/O ; PACKET IS DEQUEUED. ONCE IT HAS BEEN DEQUEUED CONTROL PASSES TO ; THE I/O FUNCTION DISPATCHER, AS IF THE I/O PACKET HAD JUST BEEN ; RECEIVED FOR THE FIRST TIME. THERE A DECISION IS MADE, AT DEVICE ; PRIORITY, AS TO WHETHER THE PACKET MAY INDEED BE PROCESSED. I.E. ; IS THE DRIVER STILL IDLE AT THIS TIME, OR HAS THERE BEEN SOME ; INTERVENING INTERRUPT. IF THE DRIVER IS NO LONGER IDLE, THE ; I/O PACKET WILL BE REQUEUED UNTIL A LATER TIME, WHEN THE WHOLE ; PROCESS WILL BE REPEATED. ; ; CDINI: MOV U.SCB(R5),R4 ;MAKE SURE R4 =SCB ADDRESS MOVB S.STS(R4),R0 ;CONTROLLER STATUS BYTE TRACE <#13.,U.STA(R5),U.FLG(R5),U.FFL(R5),R0> .IF GT D$$11W 10$: DSABL CDPR ;DISABLE DEVICE INTERRUPTS TST U.FLG(R5) ;;;DID WE DEFER HANDLING OF A ;;;REQUEST LINK ? BEQ 15$ ;;;BRANCH IF NOT CLR U.FLG(R5) ;;;CLEAR REQUEST PENDING FLAG PUSH #14$ ;;;PUSH A RETURN ADDRESS ON STACK JMP CDIDLE ;;;AND HANDLE REQUEST LINK AS IF IT ;;;HAD JUST COME FROM AN INTERRUPT ; 14$: ENABL ;RE-ENABLE INTERRUPTS JMP CDEXIT ;EXIT FROM DRIVER ; ; NO PENDING REQUEST LINKS - SO TRY TO DEQUEUE ; THE NEXT I/O OPERATION ; 15$: ENABL ;ENABLE INTERRUPTS .ENDC ;D$$11W > 0 CALL DEQPKT ;DQ FROM I/O QUEUE ;IF CARRY CLEAR ON RETURN PACKET ;HAS BEEN DEQUEUED ; R4 = SCB ADDRESS ; R3 = I/O PACKET ADDRESS ; ;NOW SEE IF REALLY CAN HANDLE ; ;THIS I/O PACKET. WE MAY END UP ; ;REQUEUEING IT IF DRIVER STATE ; ;IS NO LONGER IDLE. BCC CDDISP JMP CDEXIT ;IF NO MORE WORK TO DO EXIT ; .PAGE .SBTTL CDDISP - I/O FUNCTION DISPATCHER ; ; ; NOW CHECK IF THE I/O REQUEST CAN BE PROCESSED, USING THE ; DISPATCH TABLE OF FUNCTIONS AND PERMISSIBLE STATES ; IF IT CAN BE DISPATCH TO THE SERVICE CODE, ELSE QUEUE PACKET ; OR TERMINATE I/O ; ; THE CHECK FOR A PERMISSABLE STATE FOR THE CURRENT I/O REQUEST ; IS MADE AT DEVICE PRIORITY. ; ; INPUTS: ; R3 = ADDRESS OF I/O PACKET ; R4 = ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5 = ADDRESS OF THE UNIT CONTROL BLOCK (UCB) ; CDDISP: MOV R3,R1 ;SAVE I/O PACKET ADDRESS IN R1 TOO MOVB I.FCN+1(R3),R0 ;FUNCTION NUMBER MOV #DISTAB,R2 ;START OF DISPATCH TABLE 10$: CMPB R0,(R2) ;MATCH ON FUNCTION CODE? BEQ 100$ ;BRANCH IF FOUND THE FUNCTION ADD #D.SIZ,R2 ;MOVE TO NEXT DIS.TAB ENTRY CMP R2,#DISEND ;END OF TABLE? BLO 10$ ;SCAN THROUGH TABLE ; ; ILLEGAL FUNCTION - NOT IN TABLE ; (SHOULD BE FILTERED BY EXEC - UNLESS OUR CDTAB IS MESSED UP) ; LAST ENTRY IN TABLE DEALS WITH THE ILLEGAL FUNCTION CASE ; 100$: DSABL CDPR ;;;LOCK OUT DEVICE INTERRUPTS BIT D.STA(R2),U.STA(R5) ;;;VALID STATE TO PROCEED? BNE 200$ ;;;IF MATCH ON STATE - OK GO ON ; ; INCORRECT STATE TO PROCESS AT THE MOMENT - DECIDE WHAT TO DO ; ENABL ;RE-ENABLE INTERRUPTS BITB #IOQ.D,D.ACT(R2) ;SHOULD WE Q PACKET TO NORMAL IO/Q BEQ 150$ ;BRANCH IF NOT ; ; QUEUE PACKET ONTO NORMAL I/O QUEUE, UNLESS LINK IS DOWN AND ; RESOURCE WAIT SUBFUNCTION IS NOT SET ; MOV R4,R0 ;SET R0 TO I/O QUEUE LISTHEAD BITB #SF.RSW,I.FCN(R3) ;QUEUE EVEN IF DOWN BEQ 110$ ;IF NOT CHECK IF LINK UP 105$: TRACE <#25.,R3> CALL CDQUE ;QUEUE PACKET 106$: JMP CDEXIT ;THEN EXIT 110$: BIT #,U.STA(R5) ;LINK DOWN OR COMING UP? BEQ 105$ ;IF NONE OF THESE STATES OK TO QUEUE BR 165$ ;ELSE GIVE LINK DOWN ERROR ;AND TERMINATE I/O ; 150$: BITB #PTQ.D,D.ACT(R2) ;QUEUE ONTO PDB PRIVATE QUEUE BEQ 160$ ;BRANCH IF NOT CALL CDPDBQ ;HANDLE READS TO BE QUEUED BCC 106$ ;IF QUEUED OK JUST EXIT BR 180$ ;ELSE TERMINATE I/O IN ERROR ; 160$: BITB #FIN.D,D.ACT(R2) ;TERMINATE I/O? BEQ 170$ ;BRANCH IF NOT ; ; FINISH UP I/O WITH ERROR STATUS GIVEN IN DISPATCH TABLE ; 165$: MOV D.IOS(R2),R0 ;SET R0 TO ERROR STATUS FOR IOFIN BR 180$ ; ; UNKNOWN ACTION - BUGCHECK ; 170$: MOV #IE.BUG,R0 180$: JMP IOFIN ; ; PERFORM ACTION REQUIRED BY I/O FUNCTION REQUEST ; 200$: JMP @D.JMP(R2) ;;;JUMP TO SERVICE CODE ; ; AT THIS POINT WE ARE AT DEVICE PRIORITY AND THE REGISTERS ARE ; SET UP AS FOLLOWS ; R1 = ADDRESS OF I/O PACKET ; R3 = ADDRESS OF I/O PACKET ; R4 = SCB ADDRESS ; R5 = UCB ADDRESS ; THE SERVICE CODE MUST STRAIGHTAWAY DO WHATEVER IT NEEDS TO DO AT ; DEVICE PRIORITY TO ENSURE PROPER INTERLOCK WITH INTERRUPT CODE, THEN ; ENABLE INTERRUPTS AGAIN ; ; .PAGE .SBTTL -- I/O FUNCTION SERVICE ROUTINES -- .SBTTL CDAWA ; ; CDAWA - AWAKEN DRIVER FROM SLEEP. ; ; THIS ROUTINE FIRST CHECKS TO INSURE THAT THERE ARE NO TASKS CONNECTED ; TO THE DR-11W INTERRUPT VECTOR, AND IF NOT IT THEN CONNECTS THE DRIVER ; TO THE VECTOR. IF A CONNECTION STILL EXISTS, AN ERROR STATUS IS RETURNED ; TO THE TASK REQUESTING THE FUNCTION. ; ; INPUTS: ; ; R3=ADDRESS OF THE I/O REQUEST PACKET ; R4=ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5=ADDRESS OF THE UNIT CONTROL BLOCK (UCB) ; ; OUTPUTS: ; IF THE VECTOR IS NOT IN USE, THE ADDRESS OF THE INTERRUPT HANDLER ; FOR THIS DRIVER IS WRITTEN IN THE FIRST WORD OF THE VECTOR, AND ; THE INTERRUPT PS IS WRITTEN IN THE SECOND WORD, AND THE UNIT STATUS ; IS SET TO DOWN READY FOR THE RE-START ROUTINE TO BE CALLED. ; ELSE AN ERROR IS RETURNED TO THE ISSUING TASK. ; CDAWA: ENABL ;ENABLE DEVICE INTERRUPTS MOVB S.VCT(R4),R0 ;GET VECTOR ADDRESS/4 .IFDF ICDRV BEQ 5$ .ENDC .IF GT D$$11W ASL R0 ;RECONSTRUCT VECTOR ADDRESS ASL R0 CMP (R0),#$NONSI ;IS VECTOR IN USE? BEQ 10$ ;IF EQ NO .IFTF 5$: MOV #IE.VIU,R0 ;SET VECTOR IN USE ERROR JMP IOFIN ;TERMINATE I/O OPERATION WITH ERROR .IFT 10$: DSABL PR7 ;;;LOCK OUT ALL INTERRUPTS MOV U.ITB(R5),(R0)+ ;;;SET UP VECTOR PC MOV S.CON(R4),(R0) ;;;SET UP VECTOR PS (CONTROLLER # * 2) ASR (R0) ;;; CONTROLLER # NOW IN LOW 4 BITS BIS #CDPR,(R0) ;;; MASK IN INTERRUPT PRIORITY ENABL ;ENABLE INTERRUPTS AGAIN MOV #DOWN,U.STA(R5) ;SET UNIT STATE="DOWN" MOV #IS.SUC,R0 ;SET SUCCESSFUL COMPLETION CODE CLR R1 TRACE <#9.,U.STA(R5),R5,R0,R1,R3> CALL $IOFIN ;DECLARE END OF I/O OPERATION MOV U.SCB(R5),R4 ;SET UP FOR CDPWF CALL CALLR CDSTAR ;RESTART PROTOCOL (ALL REGISTERS .ENDC ; SHOULD BE SET UP FOR THIS) .PAGE .SBTTL CDRLB ; ; CDRLB - SERVICE IO.RLB REQUESTS ; ; THIS CODE IS ENTERED ONLY IF THERE IS A IO.RLB I/O PACKET TO ; BE PROCESSED AND THE DRIVER IS IN THE STATE "ASTQUE". THE ROUTINE ; CDREAD IS CALLED TO ACTUALLY DECIDE IF THE I/O PACKET DOES IN ; FACT 'MATCH' THE RECEIVE TRANSFER WHICH IS PENDING. FIRSTLY ; THE TASK TCB MUST BE THE SAME AS THAT IN THE PDB FOR THIS PTC. ; SECONDLY THE READ I/O REQUEST ITSELF MUST BE FOR THE CORRECT PTC ; FOR THIS PENDING TRANSFER. IF THESE CONDITIONS ARE NOT SATISFIED ; THEN THE READ IS EITHER QUEUED OR TERMINATED BY CDREAD IN THE SAME ; WAY AS IT WOULD HAVE BEEN HAD THE STATE OF THE DRIVER BEEN OTHER ; THAN "ASTQUE". THE COMMON ROUTINE CDREAD IS ALSO CALLED FROM ; BOTH INTERRUPT AND FORK LEVEL WHEN A SUITABLE I/O PACKET HAS BEEN ; DEQUEUED FROM PRIVATE PDB I/O QUEUE, TO SATISFY A PENDING RECEIVE ; TRANSFER. ; CDRLB: .IF GT D$$11W PUSH R0 ;PUSH DOWN STACK TO PUT PSW ON TOP MOV 2(SP),(SP) ;PUT SAVE PSW ON TOP OF STACK MOV #5$,2(SP) ;PUT RETURN ADDRESS FOR CDREAD ;ON STACK. THIS IS BECAUSE CDREAD ;WILL RESET THE PSW FROM THE SAVED ;PSW ON THE STACK BEFORE DOING ;A RETURN JMP CDREAD ;ESSENTIALLY CALL CDREAD AS A ;SUBROUTINE .IFF CALL CDREAD .ENDC ;D$$11W > 0 ;TO DO ACTUAL PROCESSING 5$: BCS 10$ ;MUST WE END THE I/O JMP CDEXIT ;EXIT IF NOT 10$: JMP IOFIN ;ELSE GO TO DO IOFIN ; ; .PAGE .SBTTL CDREAD ; ; CDREAD - HANDLE READ I/O WHEN TRANSFER IS IN PROGRESS ; THIS MODULE SETS UP THE ADDRESSES OF THE TASK BUFFERS FOR THE PACKET THAT ; IS WAITING TO BE RECEIVED, LOADS THE WORD COUNT REGISTER, AND INTERRUPTS ; THE PARTNER TO BEGIN THE OPERATION. THE PACKET PROCESSED BY THIS MODULE HAS ; NEVER BEEN QUEUED, AND THUS HAS NOT BEEN PROCESSED BY $GTPKT. WE MUST SET ; THE CONTROLLER STATUS TO "BUSY" AND INITIALIZE SOME FIELDS IN THE ; UCB. ; ; INPUTS: (CDREAD) ; R3=ADDRESS OF THE I/O REQUEST PACKET ; R4=ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5=ADDRESS OF THE UNIT CONTROL BLOCK (UCB) ; (SP)=SAVED PROCESSOR STATUS ; THIS ROUTINE BE CALLED FROM EITHER INTERRUPT OR FORK OR I/O ; INITIATOR STATE BUT AT DEVICE PRIORITY ; WHEN IT HAS BEEN CALLED FROM INTERRUPT OR FORK LEVEL CODE, THEN ; THE I/O PACKET IS ONE WHICH HAD BEEN QUEUED. IF THE I/O PACKET IS ; NOT USED TO COMPLETE THE TRANSFER THEN IT WILL ALWAYS BE PUT BACK ; ON A PDB QUEUE. SO IN THAT CASE THE ROUTINE WILL NEVER RETURN WITH ; CARRY SET. ; ; ; OUTPUTS: ; IF THE PACKET SATISFIES THE CURRENT TRANSFER IN PROGRESS THEN ; UCB AND SCB ARE SET UP TO INDICATE BUSY STATUS ; STATE IS SET TO "RECPEN" ; DR-11W IS POINTED AT THE RECEIVE BUFFER ; INTERRUPTS ARE ENABLED ; PARTNER IS INTERRUPTED TO SIGNAL READY CONDITION ; ; IF THE PACKET IS NOT FOR THE CURRENT TRANSFER IN PROGRESS THEN ; THE PACKET MAY BE PUT ON A PDB IO QUEUE OR COMPLETED WITH ; AN ERROR STATUS, DEPENDING ON WHETHER THE 'QUEUE' SUBFUNCTION ; BIT IS SET IN THE READ OR NOT. ; ; THE ROUTINE RETURNS WITH CARRY SET IF I/O IS BE COMPLETED ; ON RETURN FROM THE ROUTINE ; THE ROUTINE RETURNS WITH CARRY CLEAR IF ONLY AN EXIT FROM THE ; DRIVER IS TO BE DONE . I/O PACKET EITHER BEING PROCESSED OR ; HAS BEEN QUEUED TO A PRIVATE PDB I/O QUEUE. CDREAD: MOV U.CPT(R5),R0 ;;;GET ADDRESS OF PDB FOR CURRENT ;;; RECEIVE TRANSFER IN PROGRESS BEQ 23$ ;;;IF PDB SOMEHOW GONE AWAY CMP I.TCB(R3),PT.TCB(R0) ;;;IS REQUESTOR THE OWNER OF THE ;;; CURRENT UNSOLICITED PACKET? BNE 23$ ;;;IF NE NO CMP I.PRM+6(R3),PT.PTC(R0) ;;;CORRECT PTC? BEQ READ ;;;DISPATCH TO TRY TO BEGIN READ ; ; THIS READ QIO IS NOT SUITABLE FOR THE CURRENT PENDING TRANSFER ; 23$: ENABL ;ENABLE DEVICE INTERRUPTS CALL CDPDBQ ;QUEUE TO A PDB IF POSSIBLE RETURN ;RETURN WITH EITHER CARRY SET ;IF MUST DO I/O FIN, OR CARRY ;CLEAR IF I/O ALREADY QUEUED ; ==================================================================== ; ; THIS READ PACKET IS WHAT IS NEEDED TO FINISH THE CURRENT TRANSFER IN ; PROGRESS ; ; HERE WE DO WHAT $GTPKT WOULD HAVE DONE FOR US... ; READ: .IFDF ICDRV TST S.CSR(R4) ;;;INTERNAL DEVICE? BNE 10$ ;;;BRANCH IF DR11W ENABL CALL ICXFR ;;;ELSE USE INTERNAL TRANSFER BR 20$ 10$: .ENDC .IF GT D$$11W CALL RCVPKT ;;;SET UP CONTROLLER AND UNIT ;;;STATUS FOR THE ;;;CURRENT PACKET ; ; NOW, WE BEGIN THE ACTUAL PROCESSING OF THE IO.RLB. EVERYTHING IS AS ; IT WOULD HAVE BEEN IF WE HAD GOTTEN THIS PACKET FROM THE I/O QUEUE. ; MOV #RECPEN,U.STA(R5) ;;;SET STATE RECEIVE PENDING MOV S.CSR(R4),R0 ;;;GET ADDRESS OF DR11-W CSR MOV U.WDC(R5),R3 ;;;GET TRANSMITTERS WC - MAX ;;;PERMITTED WC MOV U.BUF(R5),R1 ;;;MAKE UP CSR TEMPLATE FOR DMA BIS #IE!FNCT1!FNCT2!FNCT3!GO,R1 ;;;NEED TO INTERRUPT PARTNER ;;;WITH WC AND SET GO BIT READY ;;;FOR DMA CALL XMTD ;;;SEND WC AND READY DMA ENABL ;ALLOW DEVICE INTERRUPTS .ENDC 20$: CLC ;READ INITIATED - INDICATE JUST RETURN ; .PAGE .SBTTL CDPDBQ ; ; SUBROUTINE CALLED TO QUEUE A READ I/O PACKET TO A PDB CHAIN IF ; A SUITABLE ONE EXISTS OR TO SET UP AN ERROR STATUS AND SET CARRY ; ON RETURN TO INDICATE THAT PACKET COULD NOT BE QUEUED. ; ; INPUTS: ; R3 = ADDRESS OF I/O PACKET ; R4 = SCB ADDRESS ; R5 = UCB ADDRESS ; ; OUTPUT: ; CARRY CLEAR IF PACKET SUCCESSFULLY QUEUED TO A PDB QUEUE ; CARRY SET IF PACKET NOT QUEUED AND R0 = ERROR CODE ; ; ; CDPDBQ: BITB #SF.RDQ,I.FCN(R3) ;SHOULD THIS READ BE QUEUED? BEQ NOQ ;IF EQ, NO ; ; WE NOW MUST QUEUE THE READ. WE CHECK TO INSURE THAT THE TASK REQUESTING ; THIS OPERATION HAS DECLARED A PACKET TYPE CODE AFFINITY FOR THE PTC ; SPECIFIED IN THE THIRD IOPB WORD. IF THE LINK IS DOWN, WE DO NOT QUEUE ; THE READ UNLESS THE SF.RSW BIT IS SET. ; BITB #SF.RSW,I.FCN(R3) ;SHOULD THIS READ BE QUEUED EVEN ; IF LINK IS DOWN? BNE 240$ ;IF NE YES BIT #DOWN!STWAIT,U.STA(R5) ;IS LINK DOWN? BEQ 240$ ;IF EQ NO MOV #IE.LDN,R0 ;ISSUE LINK DOWN ERROR BR RDERR ;RETURN INDICATING I/O MUST ;BE TERMINATED 240$: MOV U.PTC(R5),R0 ;GET PTC CHAIN LISTHEAD BEQ NOPDB ;IF EQ, THERE ARE NO PDB'S, ERROR 24$: CMP I.PRM+6(R3),PT.PTC(R0) ;IS THIS THE RIGHT PACKET? BEQ 25$ ;IF EQ YES MOV (R0),R0 ;MOVE DOWN CHAIN BNE 24$ ;LOOP UNTIL END OF CHAIN BR NOPDB ;DECLARE ERROR 25$: CMP I.TCB(R3),PT.TCB(R0) ;DOES REQUESTING TASK OWN THE PDB? BNE NOPDB ;IF NE, NO TRACE <#12.,PT.PTC(R0),R3> ADD #PT.IOQ,R0 ;CALC. ADDRESS OF PDB I/O QUEUE HEAD ; ;--------------------------------------------------------------------- ; CDQUE - ROUTINE WITHIN CDREAD ; ; ; NOW QUEUE THE PACKET ON THE APPROPRIATE I/O QUEUE ; R0 IS SET TO THE I/O QUEUE LISTHEAD, WHICH IS EITHER THE ; NORMAL I/O QUEUE (LISTHEAD IN SCB) OR ; A PRIVATE I/O QUEUE (LISTHEAD IN A PDB FOR THIS PTC) ; CDQUE: MOV R3,R1 ;ADDRESS OF PACKET INTO R1 FOR CALL DSABL CDPR ;;;LOCK OUT DEVICE INTERRUPT WHILE ;;;MESSING WITH ANY IO QUEUE CALL $QINSP ;;;INSERT I/O PACKET INTO QUEUE ENABL ;RE-ENABLE DEVICE INTERRUPTS CLC ;INDICATE EXIT FROM DRIVER RETURN ;ON RETURN - NO IOFIN ; ;-------------------------------------------------------------------- ; ; TASK HAS NOT SET PACKET TYPE CODE AFFINITY FOR THIS PTC ; NOPDB: MOV #IE.PTO,R0 ;INFORM TASK OF PACKET TYPE ERROR BR RDERR ;EXIT FROM DRIVER ; ; TASK HAS ISSUED READ QIO WITHOUT QUEUE SUBFUNCTION AND ; IT DOES NOT MATCH THE CURRENT TRANSFER IN PROGRESS - SO MUST ; GIVE "NO READ PENDING" I/O ERROR ; NOQ: MOV #IE.NRP,R0 ;SET NO READ PENDING STATUS RDERR: SEC ;INDICATE MUST COMPLETE I/O RETURN ;BEFORE EXIT FROM DRIVER ; .PAGE .SBTTL CDREJ ; ; CDREJ - PROCESS IO.REJ REQUESTS ; ; THIS MODULE IS ONLY ENTERED WHEN THE DRIVER IS IN THE STATE "ASTQUE" ; THIS MODULE IS EXECUTED WHEN A TASK DOES NOT WANT TO RECEIVE A ; MESSAGE THAT IS WAITING FOR IT. THIS PERMITS THE LINK TO BE ; FREED FOR A REFUSED MESSAGE PRIOR TO THE REQUEST'S NORMAL TIMEOUT. ; IT SENDS A WORD COUNT NACK TO IT'S PARTNER, AND IF THERE IS ANY I/O ; ON THE I/O QUEUE, IT ORS THE WORD COUNT NACK WITH REQUEST LINK. ; THIS SAVES A LINK BID FROM BEING REQUIRED TO BEGIN THE NEXT CYCLE. ; ; INPUTS: ; R1 = ADDRESS OF I/O PACKET ; R3 = ADDRESS OF I/O PACKET ; R4 = SCB ADDRESS ; R5 = UCB ADDRESS ; CDREJ: MOV S.CSR(R4),R0 ;GET CSR ADDRESS .IF DF ICDRV BEQ 20$ .ENDC .IF GT D$$11W MOV U.CPT(R5),R1 ;GET ADDRESS OF PDB FOR CURRENT ; UNSOLICITED PACKET BEQ 29$ ;BRANCH IF ABORTED (GONE AWAY) CMP I.TCB(R3),PT.TCB(R1) ;IS REQUESTOR THE OWNER OF THE CURRENT ; UNSOLICITED PACKET? BNE 29$ ;IF NE NO MOV #WCNACD,R2 ;;;REJECT MESSAGE TST S.LHD(R4) ;;;QUEUE EMPTY? BEQ 10$ ;;;IF EQ, YES ELSE XMTS WAITING BIS #REQLK,R2 ;;;REQUEST LINK AS WELL AS REJECT 10$: CALL XMT ;;;SEND REJECT LINK CODE AND ;;;INTERRUPT PARTNER .ENDC 20$: MOV #IDLE,U.STA(R5) ;;;SET UNIT STATE="IDLE" ENABL ;ALLOW DEVICE INTERRUPTS MOV #IS.SUC,R0 ;SET SUCCESSFUL COMPLETION CODE BR 291$ ; 29$: ENABL ;ALLOW DEVICE INTERRUPTS MOV #IE.NRP,R0 ;GIVE NO READ PENDING ERROR 291$: JMP IOFIN ; .PAGE .SBTTL CDWLB ; ; CDWLB - PROCESS IO.WLB AND IO.SIG REQUESTS ; ; THIS MODULE BEGINS THE PROCESS OF PACKET TRANSMISSION. IT BEGINS THE ; PROCESS OF LINK ARBITRATION, AND STARTS THE OPERATION TIMER. ; ; INPUTS: ; R3= ADDRESS OF I/O REQUEST PACKET ; R4= ADDRESS OF THE STATUS CONTROL BLOCK ; R5= ADDRESS OF THE UCB SPECIFIED IN THE CDINI CALL ; OUTPUTS: ; STATE OF UNIT IS SET TO WAIT-LINK-ACKNOWLEDGE ; OPERATION TIMER IS STARTED ; LINK ARBIRARTION IS BEGUN ; CDWLB: ; 5$: .IF DF ICDRV TST S.CSR(R4) ;;;INTERNAL LINK? BNE 6$ ;;;BRANCH IF DR11W ENABL JMP ICWLB ;;;ELSE DO INTERNAL TRANSFER 6$: .ENDC .IF GT D$$11W ; ; SET UP UNIT AND CONTROLLER FOR CURRENT PACKET ; CALL XMTPKT ; ; BEGIN LINK ARBITRATION ; 10$: MOV #WTLACK,U.STA(R5) ;;;SET WAIT-LINK-ACKNOWLEDGE STATE ;;; (LOCK OUT UNSOLICITED OPERATIONS) MOV S.CSR(R4),R0 ;;;GET ADDRESS OF UNIT'S CSR BIS #RECLCD,U.PRW(R5) ;;;OR REQUEST LINK CODE INTO SAVED ;;; PROTOCOL CONTROL WORD. MOV U.PRW(R5),R2 ;;;REQUEST LINK CODE TO SEND CALL XMT ;;;SEND REQUEST LINK AND INTERRUPT ;;;PARTNER CLR U.PRW(R5) ;CLEAR OLD PROTOCOL CONTROL DATA ENABL ;ALLOW DEVICE INTERRUPTS JMP CDEXIT ;WAIT FOR INTERRUPT OR TIME-OUT .ENDC .PAGE .SBTTL CDSPA ; ; CDSPA - SET A TASK'S PACKET TYPE CODE AFFINITY (IO.SPA) ; ; THIS MODULE PROCESSES REQUESTS TO CREATE A PACKET TYPE CODE AFFINITY ; FOR A TASK. FIRST, IT SCANS THE PTC CHAIN TO INSURE THAT THE REQUESTED ; PTC IS UNOWNED. THEN, IT CUTS A PIECE OUT OF POOL, CREATES A PDB ; FOR THE TASK, AND LINKS IT TO THE END OF THE PTC CHAIN. IF THE PTC IS ; ALREADY OWNED, AND ERROR IS RETURNED TO THE REQUESTING TASK. ; ; INPUTS: ; R1= ADDRESS OF I/O REQUEST PACKET ; R3= ADDRESS OF THE I/O PACKET ; R4= ADDRESS OF THE STATUS CONTROL BLOCK ; R5= ADDRESS OF THE UCB SPECIFIED IN THE CDINI CALL ; ; OUTPUTS: ; A PDB LINKED TO THE PTC CHAIN IF THE REQUESTED PTC IS ; UNOWNED. ELSE AN ERROR IS ISSUED TO THE REQUESTING TASK. ; CDSPA: ENABL ;ENABLE DEVICE INTERRUPTS BIT #^C377,I.PRM(R1) ;CHECK PTC IS IN RANGE 0 TO 255 BEQ 5$ ;BRANCH IF OK MOV #IE.IPT,R0 ;ELSE GIVE ILLEGAL PTC ERROR BR 65$ ;AND TERMINATE I/O 5$: MOV U.PTC(R5),R0 ;GET ADDRESS OF FIRST PDB MOV R5,R3 ;SET TO LISTHEAD ADDRESS SO WILL WORK ADD #U.PTC,R3 ; WITH EMPTY QUEUE. 10$: TST R0 ;ARE WE AT END OF CHAIN? BEQ 50$ ;IF EQ YES CMP I.PRM(R1),PT.PTC(R0) ;IS CURRENT PTC THE ONE WE NEED? BNE 20$ ;IF NE NO MOV #IE.PTO,R0 ;ISSUE PACKET TYPE OWNED ERROR MESSAGE BR 65$ ;LOOP FOR MORE WORK AND END I/O 20$: MOV R0,R3 ;SAVE OLD ADDRESS MOV (R0),R0 ;POINT TO NEXT ENTRY BR 10$ ;LOOP UNTIL FOUND OR END OF CHAIN ; ; NOW WE HAVE DECIDED THAT IT IS OK TO CREATE A NEW PTC AFFINITY. WE MUST ; FIRST GET A POOL BLOCK. ; 50$: PUSH ;SAVE ADDRESS OF LAST PDB ;AND ADDRESS OF I/O PACKET MOV #PTLENG,R1 ;LENGTH OF BLOCK TO BE ALLOCATED CALL $ALOCB ;ALLOCATE THE POOL BLOCK BCC 60$ ;IF CC SUCCESS POP ;CLEAN OFF STACK MOV #IE.NOD,R0 ;SET NO DYMANIC MEMORY ERROR BR 65$ ;LOOP FOR MORE WORK AND END I/O 60$: MOV R1,R2 ;SAVE ALLOCATED PACKET LENGTH POP ;RESTORE ADDRESS OF I/O PACKET CLR (R0) ;NEW PDB IS LAST IN CHAIN MOV I.PRM(R1),PT.PTC(R0) ;PUT PACKET TYPE CODE IN PDB MOV I.TCB(R1),PT.TCB(R0) ;PUT TCB IN PDB MOV I.PRM+2(R1),PT.AST(R0) ;PUT AST ADDRESS IN PDB CLR PT.IOQ(R0) ;FIRST WORD OF RECEIVE I/O QUEUE ZERO MOV R0,PT.IOQ+2(R0) ;SECOND WORD POINTS ADD #PT.IOQ,PT.IOQ+2(R0) ; TO FIRST. (NO NEED TO CHECK CARRY) MOV R2,PT.LEN(R0) ;PUT ACTUAL LENGTH OF PACKET IN PDB MOV R0,(R3) ;LINK PDB INTO CHAIN MOV #2,@I.LN2(R1) ;MARK LUN FOR I/O RUNDOWN CLEANUP MOV #IS.SUC,R0 ;SET SUCCESS STATUS 65$: MOV R1,R3 ;SET R3 TO I/O PKT ADDRESS JMP IOFIN ;LOOP FOR MORE WORK AND END I/O .PAGE .SBTTL CDRPA ; ; CDRPA - REMOVE A PDB FROM THE PDB CHAIN (IO.RPA) ; ; THIS MODULE PROCESSES REQUESTS TO REMOVE A PACKET TYPE CODE AFFINITY ; FOR A TASK. IT SEARCHES THE PTC CHAIN FOR THE PTC REQUESTED, AND IF ; IT IS OWNED BY THE REQUESTING TASK, LINKS IT OUT OF THE CHAIN AND ; RETURNS THE POOL BLOCK TO THE SYSTEM. IF THE PTC DOES NOT EXIST, OR ; IF IT IS NOT OWNED BY THE REQUESTOR, AN ERROR STATUS IS RETURNED. ; IF ANY I/O PACKETS ARE ON THE PDB I/O QUEUE, THE REQUEST IS ABORTED ; WITH AN ERROR. ; ; INPUTS: ; R1= ADDRESS OF I/O REQUEST PACKET ; R3= ADDRESS OF I/I REQUEST PACKET ; R4= ADDRESS OF THE STATUS CONTROL BLOCK ; R5= ADDRESS OF THE UCB SPECIFIED IN THE CDINI CALL ; ; OUTPUTS: ; IF REQUESTOR OWNED THE PDB, THE PDB IS DEALLOCATED. ; IF THE REQUESTOR DID NOT OWN THE PDB, OR IF THE PDB ; DID NOT EXIST, AND ERROR STATUS IS RETURNED. ; CDRPA: ENABL ;ALLOW DEVICE INTERRUPTS BIT #^C377,I.PRM(R1) ;CHECK PTC IS IN RANGE 0 TO 255 BEQ 5$ ;BRANCH IF OK MOV #IE.IPT,R0 ;ELSE GIVE ILLEGAL PTC ERROR BR 115$ ;AND TERMINATE I/O 5$: MOV U.PTC(R5),R0 ;GET ADDRESS OF FIRST PDB MOV R5,R3 ;SET TO LISTHEAD ADDRESS SO WILL WORK ADD #U.PTC,R3 ; WITH EMPTY QUEUE. 10$: TST R0 ;ARE WE AT END OF CHAIN? BEQ 50$ ;IF EQ YES CMP I.PRM(R1),PT.PTC(R0) ;IS CURRENT PTC THE ONE WE NEED? BNE 20$ ;IF NE NO CMP I.TCB(R1),PT.TCB(R0) ;DO WE OWN THE PDB BEQ 100$ ;IF EQ YES MOV #IE.PTO,R0 ;ISSUE PACKET TYPE OWNED ERROR MESSAGE BR 115$ ;LOOP FOR MORE WORK AND END I/O 20$: MOV R0,R3 ;SAVE OLD ADDRESS MOV (R0),R0 ;POINT TO NEXT ENTRY BR 10$ ;LOOP UNTIL FOUND OR END OF CHAIN ; ; PDB DOES NOT EXIST. ISSUE ERROR MESSAGE. ; 50$: MOV #IE.DNE,R0 ;ISSUE DOES NOT EXIST ERROR CODE BR 115$ ;LOOP FOR MORE WORK AND END I/O ; ; WE HAVE FOUND THE PDB, AND WE OWN IT. IF NO I/O IS QUEUED TO THIS PDB, ; LINK IT OUT OF THE CHAIN, AND RETURN THE SPACE TO THE SYSTEM, ELSE ; ISSUE AN ERROR MESSAGE (IE.IOQ) THAT INDICATES THAT I/O IS STILL ; QUEUED TO THIS PDB, AND THAT AN IO.KIL SHOULD BE ISSUED TO PURGE ; THE OUTSTANDING PACKETS. ; 100$: TST PT.IOQ(R0) ;ARE THERE ANY QUEUED PACKETS? BEQ 110$ ;IF EQ NO MOV #IE.IOQ,R0 ;IF YES, ISSUE ERROR MESSAGE BR 115$ ;LOOP FOR MORE WORK AND END I/O 110$: DSABL CDPR ;;;LOCK OUT INTERRUPT WHILE WE ;;;REMOVE THE PDB AND CLEAR THE ;;;CURRENT PDB POINTER IF IT WAS ;;;THIS ONE MOV (R0),(R3) ;;;LINK ENTRY OUT OF CHAIN CMP R0,U.CPT(R5) ;;;IS THIS THE CURRENT PDB IN USE? BNE 111$ ;;;BRANCH IF NO CLR U.CPT(R5) ;;;ELSE MUST INDICATE THAT IT NO ;;;LONGER EXIST - FOR CODE RECEIVING ;;;WC AND TRYING TO Q AST TO TASK 111$: ENABL ;ALLOW INTERRUPTS PUSH R1 ;SAVE I/O PKT ADDRESS MOV PT.LEN(R0),R1 ;GET SIZE OF BLOCK FOR DEALLOCATE CALL CALL $DEACB ;RETURN THE BLOCK POP R1 ;RESTORE I/O PKT ADDRESS INTO R1 MOV #IS.SUC,R0 ;SET SUCCESS STATUS 115$: MOV R1,R3 ;SET R3=I/O PKT ADDRESS FOR IOFIN JMP IOFIN ;END I/O THEN LOOP FOR MORE WORK .PAGE .SBTTL CDCLN ; ; CDCLN - CLOSE LUN ENTRYPOINT (IO.CLN) ; ; WE GET CALLED HERE IF THE CURRENT TASK IS UNDERGOING I/O RUNDOWN. ; WE UNLINK AND RETURN TO POOL ALL PDB'S OWNED BY THE CURRENT TASK. ; NOTE THAT IF ANY I/O IS STILL QUEUED TO ANY OF THE PDB'S THAT WE TRY ; TO DEALLOCATE, WE DO NOT DEALLOCATE THOSE, BUT ISSUE AN ERROR MESSAGE ; IE.IOQ TO INDICATE THAT THE FUNCTION WAS NOT COMPLETED DUE TO THIS ; CONDITION. ; THIS SHOULD NEVER ACTUALLY HAPPEN - SINCE IO.CLN IS NORMALLY ONLY ; CALLED BY THE EXECUTIVE AFTER THE DRIVER HAS ALREADY BEEN CALLED ; AT ITS CANCEL ENTRY POINT TO CANCEL ALL I/O ; IF THE CURRENT PDB FIELD POINTS TO A PDB OWNED BY THE TASK ISSUING ; THIS FUNCTION, WE ZERO THE FIELD TO INDICATE THAT THE TASK IS DEAD. ; ; ; INPUTS: ; R1=ADDRESS OF THE I/O REQUEST PACKET ; R3=ADDRESS OF THE I/O REQUEST PACKET ; R4=ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5=ADDRESS OF THE UNIT CONTROL BLOCK (UCB) ; ; ; ; ; CDCLN: ENABL ;DONT NEED ELEVATED PRIORITY ;EXCEPT WHEN ACTUALLY UNHOOKING ;A PDB MOV R1,R0 ;MOVE PACKET ADDRESS TO R0 MOV I.TCB(R1),R1 ;GET TCB ADDRESS IN R1 MOV U.CPT(R5),R2 ;GET ADDRESS OF CURRENT PDB BEQ 10$ ;IF ZERO, NO CURRENT PDB CMP R1,PT.TCB(R2) ;IS IT OWNED BY CURRENT TASK? BNE 10$ ;IF NE NO CLR U.CPT(R5) ;CLEAR CURRENT PDB 10$: MOV U.PTC(R5),R2 ;GET ADDRESS OF FIRST PDB MOV R5,R3 ;SET TO LISTHEAD ADDR. SO WILL WORK ADD #U.PTC,R3 ; WITH EMPTY QUEUE. MOV #IS.SUC,R4 ;ASSUME SUCCESS 11$: TST R2 ;AT END OF QUEUE? BEQ 100$ ;IF EQ YES CMP R1,PT.TCB(R2) ;IS THIS PDB OWNED BY CURRENT TASK? BNE 30$ ;IF NE NO TST PT.IOQ(R2) ;ANY READS QUEUED? BEQ 12$ ;IF EQ NO MOV #IE.IOQ,R4 ;SET ERROR BR 30$ ;AND DO NOT REMOVE THIS PDB 12$: DSABL CDPR ;;;LOCK OUT DEVICE INTERRUPTS ;;;WHILE UNHOOKING PDB CMP R2,U.CPT(R5) ;;;CLEARED AWAY THE ONE CURRENTLY ;;;IN USE BNE 121$ ;;;BRANCH IF NOT CLR U.CPT(R5) ;;;ELSE INDICATE THAT NO LONGER ;;;EXISTS - FOR RECWC CODE 121$: MOV (R2),(R3) ;;;LINK PDB OUT OF CHAIN ENABL ;ALLOW DEVICE INTERRUPTS AGAIN PUSH ;SAVE REGISTER R0 TO R3 MOV PT.LEN(R2),R1 ;SET UP LENGTH OF BLOCK TO FREE MOV R2,R0 ;SET UP ADDR. OF BLOCK TO FREE CALL $DEACB ;DEALLOCATE BLOCK POP ;RESTORE REGISTERS MOV R3,R2 ;SO THAT (R2) POINTS TO NEXT PACKET 30$: MOV R2,R3 ;SAVE OLD ADDRESS MOV (R2),R2 ;POINT TO NEXT PACKET BR 11$ ;LOOP TILL DONE 100$: CMP #IS.SUC,R4 ;SUCCESS? BNE 101$ ;IF NE NO, DO NOT CLEAR 2ND LUN WORD CLR @I.LN2(R0) ;CLEAR FLAG THAT CALLED US. 101$: MOV R0,R3 ;RESET R3 TO I/O PKT ADDRESS MOV R4,R0 ;DECLARE CLOSE LUN FINISHED JMP IOFIN ;END IO.CLN I/O ;;;; .ENABL LSB .PAGE .SBTTL CDSTU ; ; THIS MODULE PROCESSES REQUEST FOR THE DRIVER STATUS ; WHICH CAN BE SATISFIED AT ANY TIME, IN ANY STATE (IO.STU) ; ; INPUTS: ; R3 = ADDRESS OF I/O REQUEST PACKET ; R4 = SCB ADDRESS ; R5 = ADDRESS OF THE UCB ; ; OUTPUTS: ; THE DRIVER STATUS IS RETURNED IN THE 2ND I/O STATUS WORD ; CDSTU: MOV #IS.SUC,R0 ;SUCCESSFUL COMPLETION OF REQUEST MOV U.STA(R5),R1 ;2ND I/O STATUS WORD JMP IOFIN ;FINISH UP I/O AND EXIT .IF DF ICDRV .PAGE .SBTTL ICWLB ; ; CODE TO HANDLE WRITE LOGICAL BLOCK AND SEND SIGNAL FUNCTIONS ; ON THE INTERNAL LINK ; ; INPUTS: ; R3= ADDRESS OF I/O PACKET ; R4= ADDRESS OF SCB ; R5= ADDRESS OF UCB ; ; OUTPUT: ; THE CURRENT I/O PACKET IS EITHER COMPLETED WITH AN ERROR ; CONDITION IF THERE IS NO RECEIVER FOR THE PACKET TYPE CODE ; OR THE PACKET IS KEPT PENDING AWAITING THE RECEIVERS ; RECEIVE QIO ; OR THE PACKET IS COMPLETED (SIGNAL) AND AN AST FOR THE ; SIGNAL QUEUED TO THE DECLARED RECEIVER FOR THE PTC ; OR IF THE RECEIVER HAS ALREADY ISSUED A READ QIO A ; TRANSFER OF DATE FROM TRANSMITTER TO RECEIVER BUFFER IS ; DONE BY THE CODE AT ICXFR. BOTH I/O PACKETS BEING ; COMPLETED AFTER THE TRANSFER ; ICWLB: MOV R3,S.PKT(R4) ;SAVE XMT PACKET ADDRESS MOV I.PRM+6(R3),R2 ;PTC FOR WRITE QIO CMPB #IO.SIG/256.,I.FCN+1(R3) ;SIGNAL FUNCTION? BNE 10$ MOV I.PRM+2(R3),R2 ;PTC FOR SIGNAL QIO 10$: MOV U.PTC(R5),R0 ;FIND IF THIS PTC HAS BEEN ;DECLARED BY ANY RECEIVER ON ;THIS INTERNAL LINK BEQ 50$ ;IF NO PDBS ON CHAIN - NO RECEIVERS 20$: CMP PT.PTC(R0),R2 ;PTC MATCH? BEQ 100$ ;BRANCH IF MATCH FOUND MOV (R0),R0 ;ELSE CONTINUE DOWN CHAIN BNE 20$ ;UNTIL END OF CHAIN ; ; NO RECEIVER FOR THIS PTC ; 50$: MOV #IE.URJ,R0 ;SET ERROR CODE - NO RECEIVER JMP IOFIN ;TERMINITE I/O IN ERROR ; ; FOUND A RECEIVER FOR THIS PTC ; 100$: INCB S.STS(R4) ;SET CONTROLLER BUSY (IN CASE OF ;ASTQUE STATE TIMEOUT) MOV R0,U.CPT(R5) ;SAVE CURRENT PTC FOR TRANSFER CMPB #IO.SIG/256.,I.FCN+1(R3) ;SIGNAL SEND? BNE 110$ ;BRANCH IF WRITE ; ; SIGNAL TO BE SENT MOV I.PRM(R3),U.WDC(R5) ;SAVE SIGNAL IN WC FIELD OF UCB BIS #NOTWC!SIGNAL,U.WDC(R5) ;SET SIGNAL CODE BITS BR 120$ ; ; BUFFER TO BE TRANSFERRED 110$: MOV I.PRM+4(R3),R2 ;BYTE COUNT FOR TRANSFER ASR R2 ;CONVERT TO WORD COUNT MOV R2,U.WDC(R5) ;SAVE IN WC FIELD OF UCB ; ; SEE IF RECEIVER HAS ALREADY ISSUED READ QIO ; TST PT.IOQ(R0) ;ANY QUEUED PACKETS? BEQ 120$ ;IF NONE MUST QUEUE AST MOV R0,R4 ;SET I/O QUEUE LISTHEAD ADD #PT.IOQ,R4 ; ... CALL DEQPKT ;AND DQ 1ST PACKET MOV U.SCB(R5),R4 ;RESET SCB ADDRESS CALL ICXFR ;DO THE DATA TRANSFER JMP CDEXIT ;AND EXIT ; ; AT THIS POINT ON ENTRY TO TRANSFER CODE ; R3 = RECEIVER PACKET ADDRESS ; S.PKT(R4) = XMITTERS PACKET ADDRESS ; U.WDC = WORD COUNT FOR TRANSFER ; ; NEED TO QUEUE AST TO RECEIVER TASK ; 120$: BISB #US.BSY,U.STS(R5) ;START TIMEOUT COUNT MOV #XMTTMO,S.CTM(R4) ;SET TIMEOUT VALUE TST U.WDC(R5) ;SIGNAL TO BE SENT? BPL 150$ ;BRANCH IF NOT SIGNAL - WORD COUNT ; ; SIGNAL - SO MUST COMPLETE SIGNAL SEND I/O ON CURRENT PACKET (R3) ; WHEN AST HAS BEEN POSTED MOV #IS.SUC,U.IOS(R5) ;SET RETURN ERROR CODE TO SUCCESS MOV #IODONE!ASTQ,U.FFL(R5) ;SET FORK CODE INSTRUCTIONS MOV #IDLE,U.FST(R5) BISB #US.BSY,U.STS(R5) ;START TIMEOUT COUNT MOV #XMTTMO,S.CTM(R4) ;SET TIMEOUT VALUE BR 160$ ; ; WRITE BUFFER TO RECEIVER - QUEUE AST TO INFORM RECEIVER 150$: MOV #ASTQ,U.FFL(R5) ;FORK CODE INSTRUCTIONS MOV #ASTQUE,U.FST(R5) ;SET DRIVER STATE AFTER FORK CODE 160$: JMP FORKD ;USE FORK CODE THOUGH NO NEED ;TO ACTUALLY FORK ; ; AT THIS POINT ON JUMP TO FORK LEVEL CODE ; R3 = ADDRESS OF XMT PACKET OR SIGNAL PACKET ; R4 = ADDRESS OF SCB ; R5 = ADDRESS OF UCB ; U.WDC(R5) IS EITHER THE WORD COUNT OR THE SIGNAL TO BE PASSED ; TO THE RECEIVER TASK IN THE AST ; U.FFL(R5) INDICATES WHETHER TRANSMIT PACKET IS TO BE COMPLETED ; AFTER THE AST HAS BEEN QUEUED OR NOT ; .PAGE .SBTTL ICXFR ; ; CODE TO HANDLE THE TRANSFER OF DATA BETWEEN THE TRANSMITTERS ; BUFFER AND THE RECEIVERS BUFFER ; ; ENTERED WHEN THERE ARE 'MATCHING' XMT AND RECEIVE I/O PACKETS ; OUTSTANDING ; ; INPUTS: ; R3 = RECEIVER I/O PACKET ADDRESS ; R4 = SCB ADDRESS ; R5 = UCB ADDRESS ; S.PKT(R4) CONTAINS THE ADDRESS OF THE MATCHING XMT I/O PACKET ; ; OUTPUTS: ; THE DATA IS TRANSFERRED TO THE RECEIVERS BUFFER AND BOTH XMT ; AND RCV I/O PACKETS ARE COMPLETED ; ; LOCAL STORAGE OF BYTE COUNTS DURING ONE TRANSFER ; XBYTES: .WORD ;BYTES TO TRANSFER ON 1 CALL TO $BLXIO RBYTES: .WORD ;BYTES REMAINING TO TRANSFER ; ICXFR: MOV #IS.SUC,U.IOS(R5) ;DEFAULT I/O STATUS MOV S.PKT(R4),R2 ;XMITTER PKT ADDRESS MOV I.PRM+4(R2),R0 ;BYTE COUNT FOR XMITTER CMP I.PRM+4(R3),R0 ;RECEIVER BYTE COUNT ADEQUATE? BGE 10$ ;BRANCH IF ENOUGH MOV #IE.DAO,U.IOS(R5) ;ELSE WILL HAVE TO REPORT ERROR MOV I.PRM+4(R3),R0 ;AND USE THE SMALLER RCVER BC 10$: PUSH R3 ;SAVE RECEIVER PKT ADDRESS MOV R3,R1 MOV I.PRM(R1),R3 MOV I.PRM+2(R1),R4 ;RECEIVER ADDRESS IN R3,R4 MOV I.PRM(R2),R1 MOV I.PRM+2(R2),R2 ;XMITTER BUFFER ADDRESS IN R1,R2 SUB #20000,R2 ;USE APR5 FOR VIRTUAL ADDRESS PUSH R5 MOV R0,U.IO2(R5) ;SAVE TOTAL BYTES TO TRANSFER 35$: MOV R0,RBYTES ;SAVE TOTAL BYTES REMAINING MOV R0,XBYTES ;TOTAL NO OF BYTES IN XFR CMP R0,#17700 ;MAX NO. OF BYTES FOR $BLXIO ;IS 4K -63 AT ONCE BLE 40$ ;BRANCH IF CAN XFR ALL MOV #17700,R0 ;ELSE DO MAX POSSIBLE MOV R0,XBYTES ;NO. OF BYTES FOR CURRENT XFR LOOP 40$: CALL $BLXIO ;MOV R0 BYTES INTO RECEIVER BUFFER MOV RBYTES,R0 ;RECALCULATE REMAINING BYTES SUB XBYTES,R0 ;R0 = REMAINING TO XFR BLE 45$ ;BRANCH IF ALL DONE ADD #177,R3 ;ELSE RESET SOURCE APR5 ADD #177,R1 ;AND DESTINATION APR6 SUB #17700,R4 ;RESET VIRTUAL ADDRESSES SUB #17700,R2 BR 35$ ; ; ALL BYTES TRANSFERRED ; 45$: POP R5 ;RESTORE R5 POP R3 ;RESTORE RECEIVER PKT ADDRESS MOV U.IOS(R5),R0 ;I/O STATUS CODE (EITHER SUCCESS ;OR DATA OVERRUN) MOV U.IO2(R5),R1 ;NO OF BYTES TRANSFERRED TRACE <#9.,U.STA(R5),R5,R0,R1,R3> CALL $IOFIN ;TERMINATE RECEIVER PACKET MOV U.SCB(R5),R4 ;RESET SCB ADDRESS MOV S.PKT(R4),R3 ;XMIT PACKET ADDRESS MOV U.IOS(R5),R0 ;I/O STATUS CODE MOV U.IO2(R5),R1 ;NO. OF BYTES TRANSFERRED TRACE <#9.,U.STA(R5),R5,R0,R1,R3> CALL $IOFIN ;TERMINATE XMITTER PACKET MOV U.SCB(R5),R4 ;RESET SCB ADDRESS MOV #IDLE,U.STA(R5) ;RESET DRIVER STATE TO IDLE DECB S.STS(R4) ;CLEAR BUSY STATUS BICB #US.BSY,U.STS(R5) ;CLEAR UNIT BUSY FOR TIMEOUT RETURN ; .ENDC .PAGE .SBTTL I/O COMPLETION AND EXIT ; ; INPUTS FOR I/O COMPLETION: ; R0 = I/O STATUS RETURN CODE ; R3 = ADDRESS OF I/O PACKET TO BE COMPLETED ; ; IOFIN : BIC #^C377,R0 ;2ND IO STATUS WORD NOT USED CLR R1 TRACE <#9.,U.STA(R5),R5,R0,R1,R3> CALL $IOFIN ; ; EXIT FROM INITIATOR OR FORK LEVEL CODE OF DRIVER ; CDEXIT: .IFDF ICDRV MOV U.SCB(R5),R4 ;RESET SCB ADDRES TST S.CSR(R4) ;INTERNAL LINK? BNE 10$ CMP U.STA(R5),#IDLE ;IN IDLE STATE NOW? BNE 10$ ;IF NOT EXIT AND WAIT TST (R4) ;ANY PKTS ON I/O QUEUE? BEQ 10$ ;BRANCH IF Q EMPTY JMP CDINI ;IF INTERNAL TRY FOR MORE WORK 10$: ;ELSE EXIT .ENDC TRACE <#3,U.FFL(R5),U.STA(R5)> RETURN .PAGE .SBTTL -- INTERRUPT LEVEL CODE -- .IF GT D$$11W ; ; THE INTERRUPT LEVEL CODE DRIVES THE STATE CHANGES OF THE CD DRIVER ; WHEN IT IS TRANSFERRING DATA BETWEEN MACHINES. ; THE ACTION OF THE DRIVER ON INTERRUPT IS CONTROLLED BY BOTH THE ; STATE OF THE DRIVER AND THE CODE IN THE INPUT DATA REGISTER WHEN ; THE INTERRUPT OCCURS. ; BASICALLY THE INTERRUPT SECTION OF THE CODE IMPLEMENTS THE STATE ; DIAGRAMS OF DS-77 FIGS 1-3. HOWEVER IN ORDER TO IMPLEMENT THIS ; WITHIN THE FRAMEWORK OF A DEVICE DRIVER SOME EXTRA STATES ARE USED. ; THESE ARE "FORKED" AND "ASTQUE" AND "DISCON". ; ; "FORKED" STATE ; --------------- ; ; THE DRIVER GOES TO THE "FORKED" STATE WHENEVER IT NEEDS TO ; A) FINISH UP AN I/O REQUEST PACKET AND (C) ; B) QUEUE AN AST TO A TASK ; C) CHECK IF A NEW I/O REQUEST PACKET CAN NOW BE STARTED ; D) RESTART THE PROTOCOL AFTER A PROTOCOL ERROR ; IT REMAINS IN "FORKED" STATE UNTIL SUCH ACTIONS NEEDED HAVE ; BEEN PERFORMED IN THE FORK LEVEL CODE, AND THEN RE-SETS ITS ; STATE TO ONE OF THE FOLLOWING ; IDLE ; STWAIT - IF WILL SEND A RESTART REQUEST TO PARTNER ; ASTQUE - IF AST HAS BEEN QUEUED TO A TASK ; DISCON - IF THE DRIVER HAS DISCONNECTED FROM THE DEVICE INTERRUPT ; INTERRUPTS AFTER THIS STATE CHANGE WILL THEN CAUSE CHANGES OF STATE ; IN THE DRIVER POSSIBLY, AND POSSIBLY EVEN A CHANGE TO THE FORKED ; STATE AGAIN WHILST STILL IN THE FORK LEVEL CODE. THIS IS COMPLETELY ; PROTECTED CODE HOWEVER, SINCE ANY ATTEMPT TO START NEW I/O IS DONE ; IN CDDISP AT DEVICE PRIORITY, ENSURING THAT THE DRIVER REALLY IS IDLE. ; AND INTERRUPTS IN THE STWAIT STATE ARE IGNORED. ; INTERRUPTS IN THE ASTQUE STATE ARE ALWAYS ILLEGAL AND MUST BE EITHER ; A START REQUEST OR CAUSE A RE-START TO BE DONE. INTERRUPTS IN THE ; STATE "DISCON" ARE IMPOSSIBLE. ; ; "ASTQUE" STATE ; --------------- ; ; THE "ASTQUE" STATE IS AN INTERMEDIATE RECEIVER STATE AFTER WAITING ; FOR A TRANSMITTER WORD COUNT AND BEFORE SENDING BACK ; THE RECEIVERS WORD COUNT AND ACTUALLY STARTING THE DMA ; AND GOING TO THE STATE "RECEIVE PENDING". IT IS ENTERED ONLY IF ; AN I/O REQUEST TO RECEIVE THE CURRENT MESSAGE HAS NOT ALREADY BEEN ; ISSUED AND QUEUED UP BY A TASK. AN AST IS QUEUED TO THE TASK ; INFORMING IT OF THE PENDING MESSAGE TO BE RECEIVED, ITS PACKET TYPE ; CODE, WORD COUNT AND THE DEVICE ON WHICH IT IS ARRIVING. ; ; ; "DISCON" STATE ; --------------- ; ; THE DRIVER GOES TO THE STATE "DISCON" WHEN IT HAS DISOWNED THE ; DEVICE TRAP VECTOR, AFTER A 'SEND AND SLEEP' (IO.WLB WITH SF.SLP ; SUBFUNCTION) OR AFTER A 'RECEIVE AND SLEEP' (IO.RLB WITH SF.SLP ; SUBFUNCTION) I/O HAS BEEN PROCESSED AND COMPLETED. ; .PAGE .SBTTL CDINT - INTERRUPT ENTRY POINT ; .ENDC ; $CDINT - DR-11W INTERRUPT ENTRYPOINT ; $CDINT:: .IF GT D$$11W INTSV$ CD,PR5,D$$11W ;;;GENERATE INTERRUPT SAVE CODE. ; ; AFTER INTSV$: ; ; R4 = CONTROLLER INDEX ONLY IF MORE THAN 1 CONTROLLER ; NOTE THAT THIS IS NEVER MUCH USE TO US... ; R5 = UCB ADDRESS OF INTERRUPTING CONTROLLER ; TEMP = PRE-INTSV$ PS ; CNTBL(R4) = UCB ADDRESS ; ; NOW WE MUST DISPATCH THE DRIVER BASED UPON THE STATE (U.STA) OF THE ; INTERRUPTING DEVICE. ; JSR R3,SAVREG ;;;CALL CO-ROUTINE TO SAVE ;;;REGISTERS R0->R3- WILL AUTOMATICLLY ;;;RESTORE THEM ON EXIT FROM ;;;DRIVER EITHER BY CDINEX OR ;;;EXIT VIA A FORK ; ; FIRST, HOWEVER WE READ OUT THE ERROR REGISTER AND STORE IN IN U.ERR, ; THE INPUT DATA REGISTER AND STORE IT AT U.IDR, ; AND THE CSR AND STORE IT IN U.CW4 FOR USE LATER BY THE ROUTINES THAT ; WE WILL DISPATCH TO. ; ALSO THE LAST DATA READ IN ON DMA IS READ BACK AND SAVED IN U.DAT ; FOR CHECKING IF REALLY GOT A START IN RECEIVE PENDING STATE ; MOV U.SCB(R5),R4 ;;;GET SCB ADDRESS MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS MOV (R0),R1 ;;;GET CSR CONTENTS MOV CDDATA(R0),U.IDR(R5) ;;;SAVE CURRENT CONTENTS IDR MOV R1,U.CW4(R5) ;;;SAVE CSR CONTENTS BIC #^C,R1 ;;;CLEAR ALL BUT FUNCTION AND IE BITS MOV #ERROR,(R0) ;;;SET TO READ ERROR REGISTER MOV (R0),U.ERR(R5) ;;;READ ERROR REGISTER MOV CDDATA(R0),U.DAT(R5) ;;;LAST WORD READ IN ON DMA MOV R1,(R0) ;;;RESET THE CSR ; ; +++ ADD HERE CHECK THAT ERROR BIT HAS BEEN CLEARED OK ; TRACE <#1,U.STA(R5),U.CW4(R5),U.ERR(R5),U.IDR(R5),R5> ; ; NOW WE TEST TO SEE IF WE HAVE BEEN RESTARTED. IF SO, WE INGORE OUR CURRENT ; STATE, ABORT OUR CURRENT I/O OPERATION (IF ANY), SEND A START ACKNOWLEDGE ; TO OUR PARTNER, AND BECOME A SLAVE. ; IF, HOWEVER WE ARE WAITING FOR A STACK, OR IN THE PROCESS OF SENDING ONE, ; WE IGNORE THE START. EITHER OUR TIME OR OUR PARTNER'S TIMER IS STILL ; RUNNING, AND IF THIS DOESN'T WORK WE WILL RESTART IN A FEW TICS... ; IF WE ARE IN FORKED STATE THEN WE HANDLE STARTS SIMPLY BY CHANGING ; THE FINAL STATE TO GO TO AT THE END OF THE FORK TO 'IDLE'. ; AND CANCEL THE DEVICE TIMEOUT. THIS IS OK BECAUSE IF WE WERE ; ALREADY TERMINATING I/O THEN THE I/O STATUS HAD ALREADY BEEN ; DECIDED. ; BIT #START,U.IDR(R5) ;;;RESTART? BEQ 4444$ ;;;IF EQ NO SO DISPATCH BIT #NOTWC,U.IDR(R5) ;;;IS THIS REALLY A START? BNE 4445$ ;;;IF NE, YES 4444$: JMP INTDSP ;;;ELSE, DISPATCH 4445$: CMP #RECPEN,U.STA(R5) ;;;RECEIVE DMA JUST ENDED? BNE 4446$ ;;;BRANCH IF NOT CMP U.DAT(R5),U.IDR(R5) ;;;IS THIS REALLY A START FUNCTION ;;;OR JUST DATA WHICH LOOKS LIK ;;;A START BEQ INTDSP ;;;IF DATA IGNORE IT 4446$: BIT #STWAIT,U.STA(R5) ;;;UNIT WAITING FOR STACK? BEQ 2$ ;;;IF EQ NO MOV #DOWN,U.STA(R5) ;;;GO TO DOWN STATE UNTIL TIMERS ;;;CYCLE US THROUGH THE RESTART ;;;ENTRYPOINT. JMP CDINEX ;;;DISMISS INTERRUPT ; ; =================================================================== ; GENUINE START REQUEST ; =================================================================== ; ; ; REALLY HAVE A START REQUEST AND NOT ALREADY STARTING UP ; 2$: MOV #STAKCD,R2 ;;;START ACKNOWLEDGE CODE MOV U.SCB(R5),R4 ;;;SCB ADDRESS MOV S.CSR(R4),R0 ;;;CSR ADDRESS CALL XMT ;;;SEND START ACK TO PARTNER MOV #SLAVE,U.MSS(R5) ;;;SET SLAVE STATUS MOV #IDLE,U.FST(R5) ;;;WILL ALWAYS GO TO IDLE CMP U.STA(R5),#FORKED ;;;IN FORKED STATE? BNE 5$ ;;;BRANCH IF NOT ; ; IN FORKED STATE, EITHER WAITING TO EXECUTE FORK ROUTINE OR ; INSIDE FORK ROUTINE PERFORMING REQUIRED ACTIONS ; ; AT END OF FORK ROUTINE POSSIBLE STATES ARE: ; IDLE,ASTQUE OR STWAIT ; ALSO POSSIBLE THAT WHEN INTENDING TO FINISH UP IN ASTQUE STATE CAN ; FIND THAT AN I/O PACKET HAS MEANWHILE BEEN QUEUED, SO CAN CARRY ON ; WITH THE TRANSFER. THEN EXIT FROM THE FORK ROUTINE IN "RECPEN" STATE. ; ; NOW WE HAVE RESET THE STATE TO BE THE IDLE STATE, SO AFTER THE ; REQUIRED ACTION OF THE FORK ROUTINE HAS BEEN DONE (EITHER AST ; QUEUED, OR I/O FINISHED UP) THE STATE WILL ALWAYS GO TO IDLE ; ALSO THE TIMEOUT, ON THE CURRENT I/O AND THE BUSY BIT IN THE ; UCB WILL BE CLEARED. THIS IS FOR THE ASTQUE STATE, WHERE WE ; WILL NOW BE ABANDONING THIS TRANSFER, SO NO LONGER NEED THE ; TIMEOUT TO BE RUNNING, OR THE UNIT TO BE BUSY. ; CLRB S.CTM(R4) BICB #US.BSY,U.STS(R5) ;;;CLEAR UNIT BUSY STATUS CLR U.FLG(R5) ;;;CANCEL ANY PENDING REQUEST LINKS CLR U.CPT(R5) ;;;CANCEL CURRENT PDB FOR A PENDING ;;;RECEIVE, IN CASE JUST ABOUT ;;;TO CALL CDREAD FROM FORK LEVEL. BIT #REQLK,U.IDR(R5) ;;;REQUEST LINK WITH START? BEQ 3$ INC U.FLG(R5) ;;;SET FLAG FOR PENDING REQ. LINK ;;;(ONLY DO THIS IN CASE A START ;;;JUST SNEAKED IN AFTER ALREADY ;;;CHECKED THE IDR IN FORK LEVEL CODE) 3$: MOV U.PKT(R5),R3 ;;;WERE WE ABOUT TO START A ;;;NEW WRITE BEQ 4$ ;;;BRANCH IF NOT MOV R4,R0 ;;;ELSE MUST REQUEUE IT CALL CDQUE ;;;REQUEUE THE WRITE CLR U.PKT(R5) ;;;CLEAR PENDING WRITE PACKET CLR U.ACK(R5) ;;;CLEAR ANY PENDING ACKNOWLEDGE 4$: JMP CDINEX ;;;EXIT FROM INTERRUPT ; ; NOT IN FORKED STATE OR ALREADY STARTING ; 5$: 10$: MOV #IODONE,U.FFL(R5) ;;;IF ANY I/O IN PROGRESS ;;;TERMINATE IT WITH ERROR ;;;(MAY NOT BE. E.G IF IN ASTQUE STATE) MOV #IE.LDN,U.IOS(R5) ;;;LINK DOWN STATUS MOV U.IDR(R5),U.IO2(R5) ;;;GIVE OFFENDING START CODE ;;;AS 2ND I/O STATUS WORD JMP FORK ; ;;;; .DSABL LSB .PAGE .SBTTL INTDSP -- INTERRUPT LEVEL DISPATCHER ; ; ALL START REQUESTS HAVE NOW BEEN HANDLED. WE MUST NOW ACT ACCORDING ; TO BOTH THE CURRENT STATE OF THE DRIVER AND THE LINK-CODE IN THE ; IDR AT THE TIME OF INTERRUPT. THE INTERRUPT LEVEL DISPATCH TABLE ; DEFINES FOR EACH STATE OF THE DRIVER, THOSE CONTROL BITS WHICH MUST ; BE SET IN THE IDR AND THOSE CONTROL BITS WHICH ARE ALLOWED TO BE ; SET IN THE IDR. USING THIS DISPATCH TABLE MOST INVALID OR UNEXPECTED ; CODES CAN BE FILTERED OUT AND HANDLED IN A CENTRALISED GARGAGE ; COLLECTION PIECE OF CODE. LINK-CODES WHOSE CONTROL BITS SATISFY THE ; REQUIREMENTS IN THE DISPATCH TABLE ARE PASSED TO THE APPROPRIATE ; SERVICE CODE FOR THE CURRENT STATE OF THE DRIVER. THIS CODE MAY ; THEN ITSELF ON FURTHER EXAMINATION OF THE LINK-CODE DECIDE THAT IT IS ; INVALID AND TRANSFER CONTROL TO GARBGE, OR IT MAY CONTINUE TO PROCESS ; THE CODE AND EFFECT A CHANGE OF STATE OF THE DRIVER BEFORE EXITING ; FROM THE INTERRUPT. ; ; ; NOW DO THE DISPATCH ; ASSUME I.MUSC,2 ;;;MASK OF COMPLEMENT OF MUST BE SET ASSUME I.MUS ,4 ;;;MASK OF MUST BE SET ASSUME I.MAYC,6 ;;;MASK OF MAY NOT BE SET ASSUME I.JMP ,10 ;;;SERVICE CODE ADDRESS ; ; INTDSP: ; MOV U.STA(R5),R0 ;;;CURRENT STATE OF DRIVER MOV U.IDR(R5),R1 ;;;LINK-CODE IN IDR ON INTERRUPT MOV #INTTAB,R2 ;;;START OF DISPATCH TABLE 1$: CMP R0,(R2)+ ;;;FOUND CURRENT STATE IN TABLE? BEQ 10$ ;;;BRANCH IF STATE MATCHES ADD #,R2 ;;;ELSE MOVE TO NEXT ENTRY CMP R2,#INTEND ;;;END OF DISPATCH TABLE? BLO 1$ ;;;BRANCH IF NOT IOT ;;;SHOULD NEVER HAPPEN - UNKONW ;;;STATE 10$: MOV R1,R3 ;;;LINK-CODE IN R3 FOR TESTS BIC (R2)+,R3 ;;;CLEAR ALL EXCEPT MUST BE SET CMP (R2)+,R3 ;;;JUST THOSE WHICH MUST BE SET? BNE 50$ ;;;BRANCH IF NOT - ILLEGAL BIT (R2)+,R3 ;;;ANY NOT ALLOWED BITS SET? BNE 50$ ;;;BRANCH IF YES - ILLEGAL JMP @(R2) ;;;ELSE JUMP TO SERVICE CODE ; ; LINK-CODE FAILED THE TESTS OF BITS WHICH MUST/MAY BE SET ; 50$: JMP GARBGE ;;;GO TO GARBAGE COLLECTOR ; .PAGE .SBTTL -- INTERRUPT LEVEL SERVICE CODE FOR EACH STATE -- .SBTTL RECEIVER STATES ----- .SBTTL CDIDLE ; ; CDIDLE - PROCESS AN UNSOLICITED INTERRUPT. ; ; - ONLY REQUEST LINK LINK-CODES HANDLED HERE ; CDIDLE: TRACE <#15.,U.FFL(R5),U.FLG(R5),U.STA(R5),R5> CLR U.FLG(R5) ;;;CLEAR PENDING REQUEST LINK FLAG CLR U.PRW(R5) ;;;CLEAR OLD PROTOCOL STATUS DATA MOV #WTPTC,U.STA(R5) ;;;SET STATE = WAIT-PACKET-TYPE-CODE MOV #RCVTMO,S.CTM(R4) ;;;START PROCESS TIMER BISB #US.BSY,U.STS(R5) ;;;MARK UNIT BUSY SO TIMEOUT WILL WORK MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS MOV #ACKNCD,R2 ;;;CODE TO SEND TO PARTNER CALL XMT ;;;SEND DATA AND INTERRUPT JMP CDINEX ;;;EXIT FROM INTERRUPT .PAGE .SBTTL CDWPTC ; ; CDWPTC - PROCESS THE WAIT-PACKET-TYPE-CODE STATE ; ; ONLY PTC LINK-CODES ARE HANDLED HERE ; CDWPTC: ; ; LET'S FIND OUT IF THE REQUESTED PTC IS OWNED... ; MOV U.PTC(R5),R1 ;;;PDB LISTHEAD MOV S.CSR(R4),R0 ;;;CSR ADDRESS MOVB U.IDR(R5),R2 ;;;PTC TO FIND 10$: TST R1 ;;;END OF PDB LIST? BEQ 20$ ;;;BRANCH IF END OF LIST ;;;NO SUCH PTC CMPB PT.PTC(R1),R2 ;;;FOUND PTC? ;V2.1 BEQ 30$ ;;;BRANCH IF MATCH FOUND MOV (R1),R1 ;;;ELSE TRY NEXT ENTRY IN ;;;PDB CHAIN BR 10$ ; ; NO SUCH PTC HAS BEEN DECLARED ; 20$: MOV #IDLE,U.STA(R5) ;;;RESET DRIVER STATE TO IDLE MOV #PTCNCD,R2 ;;;PTC NACK CODE TO SEND PARTNER BR 40$ ; ; PTC FOUND IN LIST OF PDB'S - SEND PTC ACK ; 30$: MOV #WTXMWC,U.STA(R5) ;;;STATE IS WAIT-TRANSMITTER-WORD-COUNT MOV R1,U.CPT(R5) ;;;SET UP CURRENT PTC PDB ADDRESS MOV #PTCACD,R2 ;;;PTC ACK CODE TO SEND PARTNER 40$: CALL XMT ;;;SEND ACK OR NACK AND INTERRUPT ;;;PARTNER JMP CDINEX ;;;EXIT FROM INTERRUPT ; .PAGE .SBTTL CDWXWC ; ; CDWXWC - PROCESS THE WAIT-TRANSMITTER-WORD-COUNT (OR SIGNAL) STATE ; ; ALL LINK-CODES RECEIVED ARE HANDLED HERE ; CDWXWC: MOV U.CPT(R5),R0 ;;;CURRENT PDB ADDRESS BNE 111$ ;;;BRANCH UNLESS NON-EXISTANT ; ; TASK HAS GONE AWAY NOW - SEND WC NACK ; MOV S.CSR(R4),R0 ;;;CSR ADDRESS MOV #WCNACD,R2 ;;;WC NACK TO SEND CALL XMT ;;;SEND WC NACK AND INTERRUPT PARTNER MOV #IDLE,U.FST(R5) ;;;GO IDLE AT END OF FORK CLR U.FFL(R5) ;;;ONLY FORKING TO GET MORE WORK BR 10$ ; ; TASK STILL HAS PDB FOR THIS PTC ; 111$: MOV #ASTQUE,U.FST(R5) ;;;SET STATE AT END OF FORK ;;;TO BE ASTQUE ;;;(DEFAULT FOR DMA) MOV U.IDR(R5),U.WDC(R5) ;;;SAVE WC OR SIGNAL BLT 1$ ;;;BRANCH IF SIGNAL TST PT.IOQ(R0) ;;;SEE IF ANY READ'S QUEUED BEQ 2$ CALL CDDQUE ;;;IF SO DQ ONE JMP CDINEX ;;;EXIT FROM INTERRUPT ; ; MUST QUEUE AN AST TO THE TASK TO DELIVER EITHER THE SIGNAL ; OR THE WC OF THE PENDING MESSAGE ; 1$: MOV #IDLE,U.FST(R5) ;;;FOR SIGNAL FINAL STATE WILL ;;;BE IDLE 2$: MOV #ASTQ,U.FFL(R5) ;;;FORK REASON FLAG 10$: JMP FORK .PAGE .SBTTL CDRECP ; ; CDRECP - PROCESS THE RECEIVE PENDING STATE ; ; ALL INTERRUPTS WITH ANY TYPE OF LINK-CODE IN THE IDR ARE HANDLED HERE ; CDRECP: CMP U.IDR(R5),U.DAT(R5) ;;;DID PARTNER SEND US A CODE? BEQ 1$ ;;;IF STILL LAST WORD OF DMA - NO JMP GARBGE ;;;ELSE MUST BE GARBAGE (REMEMBER ;;;ALL STARTS HAVE ALREADY BEEN ;;;FILTERED OUT ; 1$: MOV #IDLE,U.FST(R5) ;;;SET DEFAULT EVENTUAL STATE CLR U.IDR(R5) ;;;NOT A RELEVANT CODE TO EXAMINE ;;;FOR REQUEST LINK OR DELAY AFTER ;;;I/O HAS BEEN COMPLETED IN FORK MOV #EOMSCD,U.PRW(R5) ;;;BEGIN TO BUILD PROTOCOL CONTROL WD. MOV S.PKT(R4),R1 ;;;GET I/O PACKET ADDRESS BITB #SF.SLP,I.FCN(R1) ;;;WAS FUNCTION CODE REC. AND SLEEP? BNE 10$ ;;;IF GOING TO DISCONNECT DONT ;;;EVEN LOOK TO SEE IF MORE WORK TST (R4) ;;;IS I/O QUEUE EMPTY? BEQ 10$ ;;;IF EQ YES BIS #REQLK,U.PRW(R5) ;;;THERE IS WORK, REQUEST LINK CALL DEQPKT ;;;TAKE THE NEXT WRITE PKT OFF ;;;THE I/O QUEUE MOV R3,U.PKT(R5) ;;;SAVE ITS ADDRESS IN UCB MOV #WTLACK,U.FST(R5) ;;;AFTER FORK WILL GO INTO ;;;WAIT-LINK-ACKNOWLEDGE STATE ;;;UNLESS GET A GARBAGE INTERRUP ;;;WHICH WILL REQUEUE PACKET, CLEAR ;;;U.PKT AND CHANGE U.FST CLR U.ACK(R5) ;;;CLEAR SAVED LINK-ACKS COUNTER 10$: MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS TST CDWORD(R0) ;;;IS W.C. ZERO? (WAS IT ALL SENT?) BNE 30$ ;;;IF NE NO - ERROR CMP U.ERR(R5),#1 ;;;ERROR REGISTER SHOULD BE 1 BEQ 40$ ;;;BRANCH IF SO - ALL OK 30$: BIS #EM.FHE,U.PRW(R5) ;;;DELARE FATAL HARDWARE ERROR MOV #IE.FHE,U.IOS(R5) ;;;DECLARE ERROR FOR I/O OPERATION MOV U.ERR(R5),U.IO2(R5) ;;;ERROR REGISTER FOR 2ND IO STATUS BR 600$ ;;;COMPLETE EOM PROCESSING ;;;(DONT DO DISCONNECT IF ERROR) 40$: MOV #IS.SUC,U.IOS(R5) ;;;I/O OPERATION IS A SUCCESS CMP U.WDC(R5),U.QWC(R5) ;;;WAS TRANSMITTERS WC TOO BIG? BLE 50$ ;;;IF SMALLER NO TRUNCATION MOV #IE.DAO,U.IOS(R5) ;;;ELSE REPORT DATA OVERRUN 50$: BIS #EM.SUC,U.PRW(R5) ;;;DELARE SUCCESS TO LINK MOV U.CNT(R5),U.IO2(R5) ;;;BYTE COUNT FOR 2ND I/O STATUS WORD 400$: ;;;AFTER FORK TO IDLE MOV U.PRW(R5),R2 ;;;CODE TO SEND TO PARTNER CALL XMT ;;;SEND EOM CODE AND INTERRUPT ;;;OTHER SIDE BITB #SF.SLP,I.FCN(R1) ;;;WAS FUNCTION CODE REC. AND SLEEP? BEQ 600$ ;;;IF EQ NO ; ; RECEIVE AND SLEEP JUST ENDED - DISCONNECT FROM DEVICE INTERRUPT ; CLR @S.CSR(R0) ;;;TURN OFF DEVICE MOVB S.VCT(R0),R1 ;;;GET VECTOR ADDRESS / 4 ASL R1 ;;;RE-CONSTRUCT THE VECTOR ADDRESS ASL R1 ;;; DITTO MOV (R1),U.ITB(R5) ;;;SAVE INTERRUPT TRANSFER ADDRESS MOV #$NONSI,(R1) ;;;DISCONNECT DEVICE MOV #DISCON,U.FST(R5) ;;;SET STATE = DISCONNECTED ;;; FOR END OF FORK CODE MOV #IS.SLV,U.IOS(R5) ;;;SET DEFAULT SLAVE RETURN STATUS CMP U.MSS(R5),#MASTER ;;;WERE WE LINK MASTER? BNE 600$ ;;;IF NOT MUST BE SLAVE MOV #IS.MAS,U.IOS(R5) ;;;SET MASTER STATUS RETURN 600$: MOV #IODONE,U.FFL(R5) ;;;INDICATE FORK REASON JMP FORK ;;;FORK TO FINISH UP I/O AND ;;;LOOP FOR MORE WORK .PAGE .PAGE .SBTTL TRANSMITTER STATES ----- .SBTTL CDWLAK ; ; CDWLAK - PROCESS THE WAIT-LINK-ACKNOWLEDGE STATE ; ; - ONLY LINK ACKNOWLEDGE OR REQUEST LINK LINK-CODES HANDLED HERE ; CDWLAK: CMP #ACKNCD,U.IDR(R5) ;;;IS CONTENTS OF IDR LINK ACK. CODE? BNE 444$ ;;;IF NE NO BR 10$ ;;;ELSE MAKE STATE TRANSITION 444$: BIT #REQLK,U.IDR(R5) ;;;IS CONTENTS OF IDR REQ. LINK CODE? BEQ 1$ ;;;IF EQ ERROR CMP #SLAVE,U.MSS(R5) ;;;SHOULD WE BACK DOWN? BEQ 1$ ;;;IF EQ YES ;;;WE ARE LINK MASTER, SO IGNORE THIS BR 20$ ;;;EXIT FROM INTERRUPT ; ; REQUEUE THE CURRENT PACKET, CLEAN UP OUR DATABASE SO THAT WE CAN ; PROCESS THE UNSOLICITED INTERRUPT, AND JUMP TO THE UNSOLICITED ; INTERRUPT PROCESSING ENTRYPOINT. ; ; IF THE DATA RECEIVED WAS NOT A REQUEST LINK - REQUEUE THE PACKET ; AND FORK TO RE-START THE PROTOCOL AGAIN ; ; NOTE THAT WE SHOULD REALLY NOT RE-QUEUE THIS PACKET EXCEPT AT ; FORK LEVEL, BUT BECAUSE WE ALWAYS ENQUE/DEQUEUE FOR THIS DRIVER ; AT DEVICE PRIORITY, THIS IS SAFE. ; 1$: MOV R4,R0 ;;;SCB ADDRESS - I/O Q LISTHEAD DECB S.STS(R4) ;;;CLEAR CONTROLLER BUSY CLRB S.CTM(R4) ;;;CANCEL TIMEOUT BICB #US.BSY,U.STS(R5) ;;;CLEAR UNIT BUSY MOV S.PKT(R4),R1 ;;;PACKET ADDRESS IN R1 TRACE <#12.> CALL $QINSP ;;;REQUEUE PACKET ;;;(QINSP PRESERVES R0,R1,R5) MOV R0,R4 ;;;RESET SCB ADDRESS CLR S.PKT(R4) ;;;NO CURRENT ACTIVE I/O PKT ;;;(QINSP PRESERVES R0,R1,R5) BIT #REQLK,U.IDR(R5) ;;;REQUEST LINK CAUSED THIS ;;;RE-QUEUE BEQ 2$ ;;;IF NOT MUST HAVE BEEN JUNK JMP CDIDLE ;;;ELSE PROCESS REQUEST LINK ; ; ; WE HAVE RECEIVED GARBAGE WHILE WAITING FOR LINK ACKNOWLEDGE, WE MUST ; TRY TO RESYNCHRONISE (RESTART). 2$: ; JMP GARBGE ; ; 10$: CLR U.ACK(R5) ;;;CLEAR ANY PENDING ACKS MOV #WTPTAK,U.STA(R5) ;;;SET STATE = WAIT-PACKET-TYPE CODE ;;; -CODE-ACKNOWLEDGE MOV S.PKT(R4),R1 ;;;GET I/O PACKET ADDRESS MOV I.PRM+6(R1),R2 ;;;PTC FROM I/O PACKET CMPB #IO.SIG/256.,I.FCN+1(R1);;;HOWEVER, IS THIS A SIGNAL TYPE I/O? BNE 13$ ;;;IF NOT, JUST FINE. MOV I.PRM+2(R1),R2 ;;;ELSE GET PTC FROM DIFF. PLACE 13$: BIS #NOTWC!PTC,R2 ;;;MASK IN CONTROL BITS MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS CALL XMT ;;;SEND PTC AND INTERRUPT PARTNER 20$: JMP CDINEX ;;;EXIT FROM INTERRUPT ;;;TO WAIT FOR PTC ACK .PAGE .SBTTL CDWPAK ; ; CDWPAK - PROCESS THE WAIT-PACKET-TYPE-CODE-ACKNOWLEDGE STATE ; ; ONLY ACK OR NACK CODES HANDLED HERE ; CDWPAK: CMP #PTCACD,U.IDR(R5) ;;;IS CONTENTS OF IDR PTC ACK. CODE? BEQ 10$ ;;;IF EQ YES MOV U.IDR(R5),U.IO2(R5) ;;;EXACT NACK CODE CMPB #PTCNCD,U.IDR(R5) ;;;IS THIS A PTC NACK? BNE 5$ ;;;IF NOT MUST BE GARBAGE ; ; HANDLE PTC NACK - COMPLETE I/O AND CARRY ON ; MOV #IDLE,U.FST(R5) ;;;STATE AFTER FORK MOV #IODONE,U.FFL(R5) ;;;INDICATE FORK REASON MOV #IE.URJ,U.IOS(R5) ;;;RETURN CONNECTION REJECTED ;;;ERROR STATUS JMP FORK ;;;FORK TO FINISH I/O AND GET ;;;MORE WORK TO DO ; ; HANDLE GARBAGE RECEIVED (UNKNOWN TYPE OF ACK OR NACK) ; - COMPLETE I/O AND RESTART PROTOCOL ; 5$: JMP GARBGE ; ; ; ; PTC ACK RECEIVED - PROCEED WITH TRANSMITTING MESSAGE ; 10$: MOV S.PKT(R4),R1 ;;;GET PACKET ADDRESS MOV S.CSR(R4),R0 ;;;CSR ADDRESS CMPB #IO.SIG/256.,I.FCN+1(R1);;;IS FUNCTION CODE SEND SIGNAL? BEQ 100$ ;;;IF EQ YES MOV #WTRCWC,U.STA(R5) ;;;SET STATE = WAIT-RECEIVER-WORD-COUNT MOV I.PRM+4(R1),R2 ;;;GET BYTE COUNT ASR R2 ;;;CONVERT IT TO A WORD COUNT BR 110$ ; ; THIS PART HANDLES SENDING THE IO.SIG MESSAGE. THE WAY OUR PARTNER ; TELLS THE DIFFERENCE BETWEEN THE SIGNAL AND THE WORD COUNT IS THAT ; THE WORD COUNT IS ALWAYS POSITIVE, AND THE SIGNAL ALWAYS HAS THE ; SIGN BIT SET AND THE BIT "SIGNAL" SET. NOTE THAT THE SIGNAL IS A ; ONE BYTE NUMBER. IF THE CALLER PASSES US A VALUE WITH ANY BITS SET ON ; IN THE HIGH BYTE, WE JUST STRIP THEM. 100$: MOV I.PRM(R1),R2 ;;;GET SIGNAL FLAGS BIC #177400,R2 ;;;STRIP HIGH BYTE OF SIGNAL BIS #NOTWC!SIGNAL,R2 ;;;MASK IN CONTROL BITS MOV #WTSGAK,U.STA(R5) ;;;SET STATE = WAIT-SIGNAL-ACKNOWLEDGE 110$: CALL XMT JMP CDINEX ;;;EXIT FROM INTERRUPT .PAGE .SBTTL CDWRWC ; ; CDWRWC - PROCESS THE WAIT-RECEIVER-WORD-COUNT STATE ; ; ALL LINK-CODES RECEIVED ARE HANDLED HERE ; ; CDWRWC: BIT #NOTWC,U.IDR(R5) ;;;TRANSFER REJECTED? BEQ 5$ ;;;IF EQ NO ; ; NOT A WC RETURNED BY PARTNER ; MOV U.IDR(R5),R2 ;;;CONTENTS OF IDR BIC #REQLK,R2 ;;;CLEAR EXTRA POSSIBLE BITS CMP R2,#WCNACD ;;;DID WE GET A WC NACK BEQ 3$ ;;;IF SO JUST FINISH I/O NEATLY JMP GARBGE ;;;ELSE GOT GARBAGE - RESTART 3$: MOV #IDLE,U.FST(R5) ;;;STATE AFTER FORK MOV #IODONE,U.FFL(R5) ;;;INDICATE FORK REASON MOV U.IDR(R5),U.IO2(R5) ;;;SAVE ACTUAL CODE SENT MOV #IE.REJ,U.IOS(R5) ;;;I/O REJECTED STATUS CODE IN IOSB JMP FORK ;;;FORK TO END I/O AND GET MORE WORK ; ; WC RETURNED BY PARTNER - READY TO DO DMA NOW ; 5$: MOV U.IDR(R5),U.WDC(R5) ;;;SAVE RECEIVERS WORD COUNT ADD #2,U.WDC(R5) ;;;TRANSMITTER WILL DO DMA WITH ;;;TWO MORE WORDS THAN RECEIVER ;;;SO WILL NOT GET END OF DMA INT MOV S.CSR(R4),R0 ;;;GET ADDRESS OF CSR MOV U.BUF(R5),R1 ;;;BUILD CSR TEMPLATE BIS #IE!FNCT3!GO!CYCLE,R1 ;;;NEED TO SET CYCLE AND GO BITS MOV U.WDC(R5),R3 ;;;MAXIMUM PERMITTED WC CALL XMTD ;;;START DMA MOV #TRANSF,U.STA(R5) ;;;SET STATE TO TRANSFER IN PROGRESS JMP CDINEX ;;;EXIT FROM INTERRUPT .PAGE .SBTTL CDWSAK ; ; CDWSAK - PROCESS THE WAIT-SIGNAL-ACKNOWLEDGE STATE. ; ; ONLY END OF MESSAGE TYPE ACK CODES ARE HANDLED HERE ; CDWSAK: CMPB #SIGACD,U.IDR(R5) ;;;IS CONTENTS OF IDR SIGNAL ACK CODE? BEQ 10$ ;;;IF EQ YES MOV #IE.SNA,U.IOS(R5) ;;;SIGNAL NOT ACKNOWLEDGED STATUS MOV U.IDR(R5),U.IO2(R5) ;;;2ND STATUS WORD = ACTUAL CODE RCVD BR 11$ 10$: MOV #IS.SUC,U.IOS(R5) ;;;SUCCESS STATUS CODE CLR U.IO2(R5) ;;;2ND STATUS WORD NOT RELEVANT 11$: MOV #IDLE,U.FST(R5) ;;;STATE AFTER FORK MOV #IODONE,U.FFL(R5) ;;;INDICATE FORK REASON JMP FORK ;FORK TO END I/O AND GET WORK .PAGE .SBTTL CDTRAN ; ; CDTRAN - PROCESS THE TRANSFER IN PROGRESS STATE ; ANY INTERRUPT WITH ANY TYPE OF LINK-CODE IN THE IDR IS HANDLED HERE ;V2.1 ; ; "PER ASPERA AD ASTRA" ; CDTRAN: MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS MOV #WAITEM,U.STA(R5) ;;;STATE = WAIT-END-OF-MESSAGE-ACKNOWLEDGE CMP #-1,CDWORD(R0) ;;;JUST ONE WORD LEFT ;V2.1 BEQ 100$ ;;;IF EQ YES MOV #IE.FHE,U.IOS(R5) ;;;SET FATAL HARDWARE ERROR STATUS MOV U.ERR(R5),U.IO2(R5) ;;;SAVE ERROR REGISTER FOR 2ND STATUS ;;;NOTE THAT THIS IS SAVED IN THE UCB ;;;UNTIL THE EOM IS FINALLY RECEIVED BR 190$ ;;;SCAN INPUT FOR EOM OR OTHER CODES ;V2.1 100$: ;V2.1 MOV #IS.SUC,U.IOS(R5) ;;;DECLARE SUCCESS STATUS FOR I/O ;V2.1 CMP U.WDC(R5),U.QWC(R5) ;;;DID WHOLE MESSAGE GET SENT? ;V2.1 BEQ 101$ ;V2.1 MOV #IE.DAO,U.IOS(R5) ;;;ELSE REPORT DATA OVERRUN ;V2.1 101$: MOV U.CNT(R5),U.IO2(R5) ;;;BYTE COUNT (+ 4 ADDED TO ;V2.1 ;;;INSURE TRANSMITTER DIDNT ;V2.1 ;;;GET END OF DMA INTERRUPT) ;V2.1 SUB #4,U.IO2(R5) ;;;SET 2ND I/O STATUS WORD ;V2.1 ;;;TO TRANSFER BYTE COUNT ;V2.1 190$: ;V2.1 MOV U.WDC(R5),R1 ;;;HAD OUR PARTNER INTERRUPTED ;V2.1 SUB #2,R1 ;;;US PRIOR TO THE CLEARING OF THE ;V2.1 CMP R1,U.IDR(R5) ;;;END OF DMA INTERRUPT? ;V2.1 BNE 200$ ;;;IF NE YES JMP CDINEX ;;;DISMISS INTERRUPT ; ; PARTNER HAS SENT US A CODE ALREADY - CHECK IF ITS AN EOM TYPE CODE. ; 200$: MOV U.IDR(R5),R1 ;;;CODE SENT BIC #^C,R1 ;;;CLEAR ALL BUT EOM TYPE CODE BITS CMP R1,#NOTWC!EOM ;;;CHECK IF EOM TYPE CODE BNE 201$ ;;;IF NOT AN EOM CODE - MUST ;;;BE GARBGE BIT #^C,U.IDR(R5) ;V2.1 ;;;ANY ILLEGAL BITS? ;V2.1 BEQ CDWAIT ;;;IF NOT OK EOM CODE 201$: JMP GARBGE ;;;ELSE HANDLE AS GARBGE .PAGE .SBTTL CDWAIT ; ; CDWAIT - PROCESS THE EOM WAIT STATE ; ; ONLY LEGAL END OF MESSAGE ACK LINK-CODES ARE HANDLED HERE. THEY MAY ; ALSO BE COMBINED WITH A REQUEST LINK . ; CDWAIT: CMPB #EM.SUC,U.IDR(R5) ;;;WAS SUCCESS REPORTED? BEQ 310$ ;;;IF SO, ACCEPT PREVIOUSLY DECLARED ;;; I/O STATUS CMP U.IOS(R5),#IE.FHE ;;;DID WE THINK THAT THERE WAS ;;;AN ERROR TOO? BEQ 310$ ;;;IF SO LEAVE AT HARDWARE ERROR ;;;RETURN STATUE MOV #IE.EME,U.IOS(R5) ;;;DECLARE END OF MESSAGE ERROR MOV U.IDR(R5),U.IO2(R5) ;;;SAVE EOM ERROR CODE AS 2ND ;;;I/O STATUS WORD 310$: ; ; NOW WE TERMINATE THE I/O OPERATION ; MOV #IDLE,U.FST(R5) ;;;SET DEFAULT FINAL STATE ;;;AFTER I/O COMPLETION DONE MOV S.PKT(R4),R1 ;;;GET I/O PACKET ADDRESS BITB #SF.SLP,I.FCN(R1) ;;;WAS FUNCTION CODE SEND AND SLEEP? BEQ 325$ ;;;IF EQ NO CMP #IE.FHE,U.IOS(R5) ;;;WAS THERE A FATAL ERROR BEQ 325$ ;;;IF SO DONT DISCONNECT MOV #IS.SLV,U.IOS(R5) ;;;DEFAULT TO SLAVE RETURN STATUS CMP #MASTER,U.MSS(R5) ;;;WERE WE MASTER BNE 320$ ;;;IF NOT STATUS SET OK MOV #IS.MAS,U.IOS(R5) ;;;ELSE SET TO MASTER STATUS 320$: CLR @S.CSR(R4) ;;;TURN OFF DEVICE MOVB S.VCT(R4),R1 ;;;GET VECTOR ADDRESS / 4 ASL R1 ;;;RE-CONSTRUCT THE VECTOR ADDRESS ASL R1 ;;; DITTO MOV (R1),U.ITB(R5) ;;;SAVE INTERRUPT TRANSFER ADDRESS MOV #$NONSI,(R1) ;;;DISCONNECT DEVICE MOV #DISCON,U.FST(R5) ;;;SET STATE = DISCONNECTED 325$: MOV #IODONE,U.FFL(R5) ;;;INDICATE FORK REASON JMP FORK ;;;FORK TO COMPLETE I/O ;;;AND GET MORE WORK .PAGE .SBTTL CDWSTK - WAIT START ACK ; ; CDWSTK - PROCESS THE WAIT-START-ACKNOWLEDGE STATE ; ; ALL CODES ARE HANDLED HERE ; CDWSTK: CMP #STAKCD,U.IDR(R5) ;;;STACK RECEIVED? BEQ 100$ ;;;IF EQ YES JMP CDINEX ;;;DISMISS INTERRUPT 100$: MOV #MASTER,U.MSS(R5) ;;;WE ARE LINK MASTER CLR U.FFL(R5) ;;;ONLY FORKING TO RESTART WORK MOV #IDLE,U.FST(R5) ;;;GO TO IDLE STATE AFTER FORK JMP FORK .PAGE .SBTTL CDFORK - FORKED STATE ; ; CDFORK - PROCESS THE FORKED STATE ; ; ALL CODES (EXCEPT START) ARE HANDLED HERE ; ; THE CODE MUST BE EITHER A LEGITIMATE REQUEST LINK WHICH HAS ; ARRIVED A LITTLE TOO SOON (DRIVER IS GOING INTO IDLE STATE, BUT ; HASNT REACHED THAT YET) ; OR ELSE THE CODE IS SOME UNEXPECTED GARGAGE ; CDFORK: CMP U.FST(R5),#IDLE ;;;WILL DRIVER BE GOING TO IDLE? BNE 5$ ;;;BRANCH IF NOT ; ; DRIVER ABOUT TO GO TO IDLE STATE - CHECK FOR REQUEST LINK ; CLR U.FLG(R5) ;;;CLEAR PREVIOUS PENDING REQUEST ;;;LINKS IF ANY MOV U.IDR(R5),R0 ;;;CODE SENT BIC #^C,R0 ;;;CLEAR ALL BUT NOTWC AND REQUST ;;;LINK BITS CMP R0,# ;;;REQUEST LINK CODE? BNE 2$ ;;;BRANCH IF NOT REQUEST LINK - ;;;IGNORE THE INTERRUPT BIT #^C,U.IDR(R5) ;;;ANY ILLEGAL BITS? BNE 15$ ;;;IF SO NOT A GOOD REQUEST LINK INC U.FLG(R5) ;;;MAKE SURE REQUEST LINK DOESNT ;;;GET LOST 2$: BR 15$ ;;;EXIT FROM INTERRUPT ; 5$: CMP U.FST(R5),#WTLACK ;;;ABOUT TO WAIT FOR LINK ACK ;;;(SENT REQUEST LINK WITH EOM) BNE 9$ ;;;BRANCH IF NOT ; DRIVER ABOUT TO GO TO WAIT-LINK-ACKNOWLEDGE STATE CMP U.IDR(R5),#ACKNCD ;;;GOT AN ACK (THIS IS THE ONLY ;;;LEGAL RESPONSE) BEQ 8$ MOV U.PKT(R5),R3 ;;;STILL PENDING WRITE PACKET? BEQ 10$ MOV R4,R0 ;;;I/O QUEUE LISTHEAD CALL CDQUE ;;;REQUEUE PACKET CLR U.PKT(R5) ;;;NO LONGER PENDING WRITE BR 10$ 8$: INC U.ACK(R5) ;;;NOTE THAT LINK ACK IS PENDING BR 15$ 9$: CMP U.FST(R5),#ASTQUE ;;;ABOUT TO GO TO ASTQUE STATE? BNE 12$ ;;;BRANCH IF NOT 10$: MOV #STWAIT,U.FST(R5) ;;;IF SO SHOULDNT HAVE GOT THIS ;;;INTERRUPT SO WILL HAVE TO GO ;;;THROUGH A RESTART CLR U.CPT(R5) ;;;IF NOT ALREADY QUEUED AST OR ;;;DEQUEUED READ I/O PACKET. ONCE ;;;INSIDE CDREAD IT IS AT DEVICE ;;;PRIORITY AND STATE WOULD CHANGE ;;;BEFORE INTERRUPT WAS ALLOWED IN. BR 15$ ; 12$: ; MUST BE ABOUT TO GO TO STWAIT STATE - SO INTERRUPT MUST BE GARBAGE ; BUT WILL BE RESTARTING ANYWAY SO IGNORE IT 15$: JMP CDINEX .PAGE .SBTTL GARBGE - ILLEGAL CODE FOR THE CURRENT STATE ; ; GARBGE - HANDLE ALL THE ILLEGAL CODES (OTHER THAN START) WHICH ; MAY ARRIVE ; ; FOR EACH STATE THE MASKS OF OBLIGATORY AND ALLOWABLE TYPES OF ; CODES WHICH MAY BE RECEIVED ARE DEFINED. ON DISPATCH THOSE ; CODES WHICH FAIL THIS TEST ARE AUTOMATICALLY HANDLED HERE. ; IF THE CODE PASSES TO THE SERVICE ROUTINE, THEN THE SERVICE ; ROUTINE MAY ALSO DECIDE THAT THE CODE IS NOT AN ALLOWABLE ONE ; AND THEN ALSO CONTROL PASSES TO THIS ROUTINE AND THE CODE IS ; HANDLED HERE. ; ; IF THE DRIVER IS IN THE 'FORKED' STATE CONTROL WILL NEVER PASS ; TO HERE, SINCE ALL POSSIBLE CODES ARE ALLOWABLE FOR FORKED STATE ; AND ARE HANDLED BY THE SERVICE CODE CDFORK. ; GARBGE: TRACE <#27.,U.IDR(R5),U.WDC(R5),U.DAT(R5),U.ERR(R5),U.STA(R5)> BIT #,U.STA(R5) ;;;ALREADY INSIDE A RE-START ;;;SEQUENCE? BEQ 20$ ;;;BRANCH IF NOT JMP CDINEX ;;;IF RESTARTING IGNORE ;;;THIS INTERRUPT 20$: MOV #IODONE,U.FFL(R5) ;;;FORK TO COMPLETE I/O ;;;AND RESTART PROTOCOL MOV #IE.LDN,U.IOS(R5) ;;;I/O STATUS CODE WILL ;;;BE LINK DOWN MOV U.IDR(R5),U.IO2(R5) ;;;GIVE GARBAGE CODE AS ;;;2ND I/O STATUS WORD CLR U.IDR(R5) ;;;DONT LOOK AT THIS WORD ;;;FOR REQUEST LINK CLR U.FLG(R5) ;;;WILL NOT WANT TO HONOUR ;;;ANY PENDING REQUEST LINKS CLR U.ACK(R5) ;;;WILL NOT WANT TO TAKE ;;;NOTE OF ALREADY ARRIVED ;;;LINK ACKNOWLEDGE MOV #STWAIT,U.FST(R5) ;;;WILL GO TO STWAIT STATE BR FORK .PAGE .SBTTL INTERRUPT EXIT ; ; EXIT FROM INTERRUPT. $INTXT DOES A RETURN WHICH CALLS THE SAVREG ; CO-ROUTINE TO RESTORE REGISTERS, BEFORE CALLING THE INTERRUPT ; SAVE CO-ROUTINE TO EXIT FROM THE ACTUAL INTERRUPT. ; ; ****NOTE **** ; THIS DRIVER RELIES HEAVILY ON THE FACT THAT THE CODE AT $INTXT ; IS SIMPLY A RETURN. AS WELL AS THE CO-ROUTINE TO RESTORE REGISTER ; ON INTERRUPT LEVEL EXIT, THERE ARE 2 PLACES WHERE INTERRUPT LEVEL ; CODE IS 'CALLED' FROM FORK LEVEL CODE, RELYING ON THE FACT THAT ; ON GOING THROUGH CDINEX IN REALITY ONLY A RETURN WILL BE EXECUTED ; THESE TWO PLACES ARE WHEN EITHER A REQUEST LINK, OR A LINK ACK HAS ; BEEN 'PENDED' UNTIL THE FORK LEVEL CODE HAS COMPLETED. ; CDINEX: JMP $INTXT .PAGE .SBTTL FORK -- FORK LEVEL CODE -- ; ; FORK LEVEL CODE ; ; MOST OF THE FORK LEVEL CODE IS EXECUTED IN THE STATE 'FORKED' ; INTERRUPTS IN THE STATE FORKED NEVER CAUSE ANOTHER FORK TO BE ; DONE. THEY ARE EITHER IGNORED OR CAUSE A CHANGE IN THE FINAL ; STATE TO BE SET UP AT THE END OF THE FORK CODE. THEY DO, OF COURSE, ; RESET THE SAVE INPUT DATA REGISTER U.IDR IN THE UCB. THIS AT ALL ; TIMES REFLECTS THE LAST CODE RECEIVED, IF THAT CODE IS INDEED A ; VALID CODE SENT BY THE PARTNER. ; JUST BEFORE THE STATE IS RESET FROM 'FORKED' TO THE NEW STATE ; IF THE NEW STATE IS TO 'IDLE' THEN A CHECK IS DONE TO SEE IF THE ; IDR CONTAINS A REQUEST LINK CODE. IF ONE IS THERE THEN THE FLAG ; U.FLG IN THE UCB IS INCREMENTED ; AFTER THIS THE STATE IS RESET. ; IF GARBAGE OR A START REQUEST COMES IN AFTER THE PENDING REQUEST ; LINK FLAG U.FLG HAS ALREADY BEEN SET, THEN UNLESS THE NEW CODE IS ; A START COMBINED WITH A REQUEST LINK THE FLAG U.FLG WILL BE CLEARED ; IN THE INTERRUPT LEVEL CODE. THE FLAG U.FLG IS FINALLY CHECKED ; AND LINK ACK SENT IF THE FLAG IS SET, AT DEVICE PRIORITY IN CDINI. ; IF ANOTHER REQUEST LINK COMES IN AFTER THE STATE HAS BEEN RESET TO ; TO IDLE AND THE U.FLG FLAG IS SET THEN U.FLG WILL ANYWAY BE CLEARED ; AND THE REQUEST LINK HANDLED BY THE INTERRUPT LEVEL CODE IN THE ; NORMAL WAY ; ; POSSIBLE END STATES AT THE END OF THE FORK CODE ARE: ; IDLE - IF I/O COMPLETED NORMALLY (NOT NECESSARILY SUCCESSFULLY) ; OR SIMPLY TRYING FOR MORE WORK TO DO ; STWAIT - IF MUST GO THROUGH THE RE-START PROCEDURE ; ASTQUE - IF HAVE QUEUED AN AST TO A TASK AND ARE WAITING FOR IT ; TO ISSUE THE READ REQUEST FOR THE PENDING MESSAGE ; DISCON - IF DRIVER HAS DISCONNECTED FROM DEVICE INTERRUPT ; FORK: TRACE <#4,U.FFL(R5),U.STA(R5),U.FST(R5)> ;TRACE ABOUT TO FORK CMP #FORKED,U.STA(R5) ;;;ALREADY FORKED? BNE 1$ ;;;BRANCH IF NO IOT ;;;SHOULD NEVER HAPPEN!! 1$: MOV #FORKED,U.STA(R5) ;;;SET STATE TO FORKED CALL $FORK ;;;FORK .ENDC ;D$$11W > 0 END OF INTERRUPT CODE CONDITIONAL .PAGE ; =================================================================== ; FORK LEVEL CODE ; =================================================================== ; ; R5 = UCB ADDRESS ; R4 = SCB ADDRESS ; TRACE <#16.,U.FFL(R5),U.STA(R5),U.FST(R5)> ;TRACE ENTERED FORK CODE FORKD: BIT #ASTQ,U.FFL(R5) ;MUST WE QUEUE AN AST BEQ 50$ ;BRANCH IF NO ; ; NEED TO QUEUE AN AST TO A TASK ; MOV U.CPT(R5),R0 ;CURRENT PDB BNE 40$ JMP 100$ ;BRANCH IF TASK GONE AWAY ; ; NOTE: BETWEEN HERE AND DISABLING DEVICE INTERRUPTS IN CDDQUE IS THE ; ONLY POINT VULNERABLE TO INTERRUPTS BEING AWKWARD. IF THERE IS ; IS AN INTERRUPT HERE HOWEVER IT CLEANS AWAY THE PDB ADDRESS ; FOR THE CURRENT RECEIVE IN PROGRESS. THEREFORE INSIDE CDREAD ; AT DEVICE PRIORITY U.CPT(R5) IS FOUND TO BE 0 AND THE TRANSFER ; IS NOT CONTINUED. OTHERWISE WE COME BACK FROM CDDQUE IN THE ; STATE "RECPEN" AND WITH THE SCB SET BUSY. ; ;WILL HAVE TO TIMEOUT OF ASTQUE ;STATE IF THAT IS THE NEW STATE 40$: TST PT.IOQ(R0) ;ANY QUEUED READS NOW? BEQ 44$ ;BRANCH IF NO TST U.WDC(R5) ;WC OR SIGNAL BLT 44$ ;IF SIGNAL Q AST ANYWAY CALL CDDQUE ;ELSE DEQ READ AND CARRY ;ON WITH TRANSMISSION TSTB S.STS(R4) ;I/O NOW IN PROGRESS? BEQ 44$ ;ELSE QUEUE AST JMP CDEXIT ;ELSE EXIT AND WAIT FOR ;END OF TRANSFER INTERRUPT ; 44$: MOV #9.*2,R1 ;ALLOCATE CORE BLOCK SIZE FOR ;THIS AST BLOCK. MADE UP OF: ; 5 WORDS AST BLOCK OVERHEAD ; 1 WORD FOR UNIT NUMBER ; 1 WORD FOR WORD COUNT OR SIGNAL ; 1 WORD FOR PTC (ALLOWS MUXING) ; 1 WORD FOR BYTE COUNT OF USER PARAMS CALL $ALOCB ;ALLOCATE THE AST BLOCK BCC 10$ ;IF CARRY CLEAR, BLOCK ALLOCATED ; ; IF WE CANNOT AT THIS POINT ALLOCATE A 9-WORD POOL BLOCK, WE HAVE A ; DISASTER ON OUR HANDS! WE WILL GO DOWN. ; MOV #DOWN,U.STA(R5) ;RESET STATE CALLR CDSTAR ;RESTART AND EXIT ; ; WE HAVE ALLOCATED THE POOL BLOCK. CONTINUE. ; 10$: CLR (R0) ;CLEAR LINK MOV R1,A.CBL(R0) ;STORE LENGTH OF BLOCK MOV #11.*2,A.BYT(R0) ;NUMBER OF BYTES TO ALLOCATE ON STACK ; 7 WORDS FOR SYSTEM ; 4 WORDS FOR OUR PARAMETERS MOV U.CPT(R5),R1 ;GET PDB ADDRESS MOV PT.AST(R1),A.AST(R0) ;STORE AST ADDRESS MOV #4,A.NPR(R0) ;STORE NUMBER OF PARAMETERS MOV U.SCB(R5),R2 ;GET SCB ADDRESS MOVB S.CON(R2),R3 ;GET CONTROLLER INDEX ASR R3 ;CONVERT TO UNIT NUMBER MOV #4*2,A.PRM(R0) ;FIRST PARAMETER IS STACK DIPLACEMENT ; THIS PARAMETER WHEN ADDED TO THE ; STACK POINTER WILL CLEAR THE STACK ; FOR THE AST ROUTINE. MOV PT.PTC(R1),A.PRM+2(R0) ;2ND PARAMETER IS PACKET TYPE CODE ; THIS ALLOWS A ROUTINE TO SPECIFY ; THE SAME AST ROUTINE FOR MORE THAN ; ONE PACKET TYPE CODE AND STILL BE ; ABLE TO TELL WHICH ONE CAUSED THE ; AST. MOV U.WDC(R5),A.PRM+4(R0) ;3RD PARAMETER IS WORD COUNT OR SIGNAL ;NOTE THAT SIGNAL IS NOT MASKED. ;THIS WILL LET THE TASK AST KNOW ;THAT IT IS A SIGNAL AND NOT A WORD ;COUNT. MOV R3,A.PRM+6(R0) ;4TH PARAMETER IS UNIT NUMBER MOV R0,R4 ;SAVE AST BLOCK ADDRESS ; MOV PT.TCB(R1),R0 ;TCB ADDRESS IN R0 FOR $QASTT MOV R4,R1 ;AST BLOCK ADDRESS IN R1 FOR $QASTT PUSH R5 ;SAVE R5 TRACE <#18.,R0,A.AST(R1),A.PRM(R1),A.PRM+2(R1),A.PRM+4(R1),A.PRM+6(R1)> CALL $QASTT ;QUEUE THE AST TO THE TASK POP R5 ;RESTORE R5 TST U.WDC(R5) ;SIGNAL SENT? BGE 100$ ;BRANCH IF WC MOV U.SCB(R5),R4 ;SCB ADDRESS MOV S.CSR(R4),R0 ;CSR ADDRESS .IFDF ICDRV BEQ 50$ ;IF NO PHYSICAL DEVICE .ENDC ;D$$11W > 0 .IF GT D$$11W MOV #SIGACD,R2 ;SIGNAL ACK CODE TO SEND CALL XMT BR 100$ ; ; CHECK IF NEED TO TERMINATE I/O ; .ENDC 50$: BIT #IODONE,U.FFL(R5) ;TERMINATE CURRENT I/O BEQ 100$ ;BRANCH IF NOT TSTB S.STS(R4) ;IF DEVICE IS BUSY I/O IS ;IN PROGRESS - SO CAN DO IODONE BEQ 100$ ;IF NO LONGER ANY I/O DO NOTHING MOV U.IOS(R5),R0 ;SET I/O STATUS 1ST WORD BIC #^C377,R0 MOV U.IO2(R5),R1 ;2ND I/O STATUS WORD MOV S.PKT(R4),R3 ;I/O PACKET ADDRESS TRACE <#10.,U.STA(R5),R5,R0,R1,R3> CALL $IODON ;$IODON TERMINATED I/O AND ;ALSO RESETS THE STATUS OF ;THE DEVICE AND THE UNIT ; ; ALL REAL WORK NOW DONE ; 100$: MOV U.SCB(R5),R4 ;RESET R4=SCB ADDRESS .IF GT D$$11W CMP U.FST(R5),#IDLE ;ARE WE ABOUT TO GO IDLE BNE 200$ ;IF NOT DONT BOTHER WHAT IS ;IS THE INPUT DATA REGISTER BICB #US.BSY,U.STS(R5) ;TO BE SURE TIMER STOPPED IF ;JUST CAME OUT OF ASTQ STATE ;WITHOUT DOING $IODON ; ELSE LOOK AT THE CODE IN THE IDR ON THE LAST INTERRUPT - SAVED IN ; U.IDR OF THE UCB ; 150$: BIT #REQLK,U.IDR(R5) ;REQUEST LINK CODE? BEQ 240$ ;BRANCH IF NO INC U.FLG(R5) ;ELSE SET PENDING REQ LINK FLAG BR 240$ 200$: CMP U.FST(R5),#WTLACK ;ABOUT TO WAIT FOR LINK ACK BNE 240$ ;BRANCH IF NOT ; ; MUST HAVE ALREADY SENT REQUEST LINK FOR NEW I/O . PACKET ADDRESS ; IS IN U.PKT DSABL CDPR ;;;DISABLE INTERRUPTS MOV U.FST(R5),U.STA(R5) ;;;RESET STATE MOV U.PKT(R5),R3 ;;;I/O PACKET ADDRESS BNE 205$ IOT 205$: CALL XMTPKT ;;;SET UP FOR CURRENT XMT PKT TST U.ACK(R5) ;;;ALREADY GOT LINK ACK? BEQ 210$ ;;;IF NOT EXIT TO WAIT FOR IT CALL CDWLAK ;;;ELSE HANDLE AS IF INTERRUPT ;;;JUST CAME IN ;;;ON RETURN STATE WILL BE ;;;WTPTAK 210$: ENABL ;ENABLE DEVICE INTERRUPTS JMP CDEXIT ;EXIT TO WAIT NEXT INTERRUPT ; ; ---NOW RESET THE DRIVER STATE FROM 'FORKED' TO ITS INTENDED ; NEXT STATE. INTERRUPTS NOW WILL HAVE DRASTIC ACTIONS, BUT ; HOPEFULLY WE ARE ALL PROTECTED AGAINST ALL POSSIBLE OUTCOMES ; AS EXPLAINED AT START OF THE INTERRUPT LEVEL CODE ; 240$: .ENDC ;D$11W > 0 MOV U.FST(R5),U.STA(R5) ;RESET TO NEW STATE CMP U.STA(R5),#IDLE ;DO WE SEEM TO BE IDLE NOW? BNE 250$ ;BRANCH IF NOT IDLE ; IN IDLE STATE - AT LEAST WHEN TESTED JMP CDINI ;TRY TO EITHER SATISFY A ;PENDING REQUEST LINK OR START ;ANY QUEUED I/O ; 250$: BIT #,U.STA(R5) ;MUST WE RESTART PROTOCOL? BEQ 300$ ;BRANCH IF NOT ; ; MUST RESTART PROTOCOL - STATE IS EITHER STWAIT , OR WAS STWAIT AND ; WAS THEN INTERRUPTED BY EITHER A START OR SOME GARBAGE ; MOV U.SCB(R5),R4 ;SET UP TO CALL CDSTAR JMP CDSTAR 300$: JMP CDEXIT ;EXIT FROM DRIVER .PAGE .SBTTL CDPWF - POWERFAIL ; ; CDPWF - DEVICE POWERFAIL ENTRYPOINT. ; ; THIS MODULE IS ENTERED ON DRIVER LOAD OR AFTER A SYSTEM POWER FAIL, ; OR IT IS CALLED TO RESTART THE LINK PROTOCOL WHEN A FATAL ERROR ; HAS OCCURRED. NOTE THAT IT DOES NOT REALLY HANDLE THE POWERFAIL ; WELL BECAUSE NONE OF OUR SYSTEMS HAVE BATTERY BACKUP PROTECTION ; AS OF THE TIME OF WRITING, AND IT IS LIKELY THAT WE WILL NEVER ; NEED THIS FEATURE. IF AN I/O IS PENDING AT THE TIME OF A POWER FAIL, ; THE DEVICE IS RESET AND WE WAIT FOR DEVICE TIMEOUT TO OCCUR. AT ANY ; OTHER TIME THAT THIS ROUTINE IS CALLED, THE I/O SHOULD HAVE ALREADY ; BEEN TERMINATED BY THE CALLING ROUTINE. ; ; IT RESETS THE DEVICE STATUS, SETS THE STATE TO DOWN, AND TRIES TO ; RESTART THE LINK PROTOCOL. ; ; INPUTS: ; R5=UCB ADDRESS ; R4=SCB ADDRESS ; R3=CONTROLLER INDEX ; CDPWF: TRACE <#19.,U.STA(R5),U.FLG(R5),U.FFL(R5),U.STS-1(R5),R5> MOV R5,CNTBL(R3) ;SAVE UCB ADDRESS FOR INTERRUPT ; ; CDSTAR - RESTART PROTOCOL IF NECESSARY ; ; CDSTAR: .IFDF TRCE ; ; *** SET UP TRACE PARTITION MAPPING *** ; ; WE TEST HERE TO SEE IF THE COMMON PARTITION CDTRAC HAS BEEN ; CREATED. IF IT HAS, WE PUT IT'S BASE ADDRESS BIAS (P.REL) IN ; OUR UCB AT TRC. ELSE, TRC WILL REMAIN ZERO, INDICATING THAT ; ARE NOT TRACING. WE ALSO BUSY THE PARTITION SO THAT IT CANNOT ; BE REMOVED EXCEPT BY A SYSTEM BOOT OR BY MANUALLY CLEARING ; THE BUSY BIT, AND ALSO SO THAT NOBODY WILL INSTALL ANYTHING ; OVER IT. ; TST TRC ;HAVE WE ALREADY SET UP? BNE 2000$ ;IF NE, YES. SKIP THIS CODE. PUSH ;SAVE R0 AND R1 MOV $PARHD,R0 ;GET PCB CHAIN HEADER 1500$: CMP #^RCDT,P.NAM(R0) ;TEST FIRST HALF NAME BNE 1600$ ;IF NE, KEEP LOOKING CMP #^RRAC,P.NAM+2(R0) ;TEST SECOND HALF NAME BEQ 1710$ ;IF NE, KEEP LOOKING 1600$: BIT #PS.SYS,P.STAT(R0) ;IS THIS A SYSTEM CONTROLLED PAR? BEQ 1800$ ;IF EQ NO TST P.SUB(R0) ;ARE THERE ANY SUB-PARTITIONS? BEQ 1800$ ;IF EQ NO MOV P.SUB(R0),R1 ;GET ADDRESS OF SUB-PARTITION. 1610$: CMP #^RCDT,P.NAM(R1) ;TEST FIRST HALF NAME BNE 1650$ ;IF NE, KEEP LOOKING CMP #^RRAC,P.NAM+2(R1) ;TEST SECOND HALF VALUE BEQ 1700$ ;IF NE, KEEP LOOKING 1650$: MOV P.SUB(R1),R1 ;POINT TO NEXT SUB-PARTITION BNE 1610$ ;IF NE, CHAIN CONTINUES 1800$: MOV P.LNK(R0),R0 ;POINT TO NEXT PARTITION BNE 1500$ ;IF NE, CHAIN CONTINUES BR 1900$ ;IF END OF CHAIN ; ; PARTITION CDTRAC FOUND ; 1700$: MOV R1,R0 ;TRANSFER SUB-PARTITION ADDRESS TO R0 1710$: MOV P.REL(R0),TRC ;SAVE PARTITION RELOCATION MOV P.SIZE(R0),R3 ;SIZE OF PARTITION IN 32 WORD BLKS ASH #5,R3 ;CONVERT TO WORDS MOV #TR.SIZ,R2 ;SIZE OF EACH TRACE ENTRY(WORDS) CLR R1 ;FOR COUNTER OF NO.ENTRIES 1620$: INC R1 ;NEXT ENTRY SUB R2,R3 ;ANY MORE WHOLE ENTRIES? BGE 1620$ ;BRANCH IF YES ; DEC R1 ;R1 = TOTAL NO.OF ENTRIES DEC R1 ;FIRST ENTRY USED AS HEADER DSABL PR7 ;DISABLE INTERRUPTS MOV @#KISAR6,AP6 ;;;SAVE CURRENT MAPPING MOV TRC,@#KISAR6 ;;;MAP PARTITION MOV R2,@#TRCSIZ ;;;LOAD PARTITION SIZE MOV R1,@#TRCNUM ;;;LOAD NUMBER OF ENTRIES CLR @#TRCPTR ;;;POINTER TO FIRST BLOCK MOV #-1,@#TRCTAB ;;;FREE FIRST BLOCK MOV AP6,@#KISAR6 ;;;RESTORE MAPPING ENABL ;RE-ENABLE INTERRUPTS MOV #1,P.BUSY(R0) ;SET PARTITION BUSY SO NOBODY ;TRIES TO LOAD SOMETHING OVER IT. 1900$: POP ;RESTORE R0 AND R1 2000$: .ENDC ;TRCE ; CMP #ASTQUE,U.STA(R5) ;DID WE GET HERE FROM A TIMEOUT ON ;WAITING FOR THE TASK TO DO A READ? BNE 15$ ;BRANCH IF NOT - TO RESTART MOV #IDLE,U.STA(R5) ;ELSE JUST INFORM TRANSMITTER .IF GT D$$11W MOV #WCNACD,R2 ;SEND REJECT CODE JMP 18$ .IFF JMP CDEXIT .ENDC 15$: MOV #FREE,U.MSS(R5) ;RESET MASTER/SLAVE STATUS CLR U.FLG(R5) ;RESET DEFERRED INTERRUPT FLAG CLR U.CPT(R5) ;NO MORE CURRENT PTC CLRB S.CTM(R4) ;CANCEL TIMEOUT CLR U.PRW(R5) ;CLEAR OLD PROTOCOL CONTROL DATA MOV S.CSR(R4),R0 ;;;GET CSR ADDRESS .IFDF ICDRV BNE 14$ ;;;IF PHYSICAL DEVICE MOV #IDLE,U.STA(R5) ;;;IF IC THEN SET TO IDLE JMP CDEXIT ;;;AND QUIT 14$: .ENDC .IF GT D$$11W MOV #DOWN,U.STA(R5) ;SET DOWN STATUS BEFORE ENABLING ;INTERRUPTS CLR (R0) ;CLEAR ANY PENDING INTERRUPTS ; ; IN SOME CIRCUMSTANCES THE DR11W CAN GET INTO A HUNG STATE, WHERE ; THE INTERRUPT ENABLE BIT IS ON BUT THE ERROR BIT NEVER GETS SET ; AND THE DEVICE DOES NOT INTERRUPT. THIS FAILURE SEEMS TO BE ; CAUSED BY A PARTNER TOGGLING THE ATTENTION BIT WHEN THERE IS ; ALREADY AN INTERRUPT PENDING, NOT YET SERVICED. TO GET OUT OF ; THIS HUNG STATE EITHER A BUS INIT OR A SOFTWARE RESET IS NEEDED ; A SOFTWARE RESET CAN BE DONE BY PUTTING THE DEVICE IN MAINTAINENCE ; MODE (SETTING BIT 12 OF THE CSR) AND ON CLEARING THIS BIT THE ; DEVICE IS RESET. HOWEVER AFTER A RESET IF THE INTERRUPT ENABLE ; BIT IS SET 'TOO QUICKLY' IT DOES NOT REMAIN SET. THIS IS THE ; REASON FOR THE DELAY LOOP AFTER RESETTING THE DEVICE BEFORE ENABLING ; INTERRUPTS. PROBABLY 5 INSTRUCTIONS IS SUFFICIENT DELAY BUT 20 ARE ; USED TO BE SURE. ; MOV #MAINT,(R0) ;PUT DEVICE IN MAINTAINENCE MODE CLR (R0) ;RESET DEVICE DELAY 20. ;DO 20 DECREMENT AND BRANCH ;INSTRUCTIONS TO DELAY MOV #IE,(R0) ;RE-ENABLE INTERRUPTS INC U.SCT(R5) ;COUNT NUMBER OF STARTS SENT ; FIRST TIME PWF CALLED NEED TO ALLOCATE A TIMER PACKET ; MOV U.TIM(R5),R0 ;TIMER PACKET ALREADY ALLOCATED? BNE 10$ ;BRANCH IF YES MOV #C.LGTH,R1 ;LENGTH OF CLOCK QUEUE CONTROL BLOCK CALL $ALOCB ;ALLOCATE CLOCK QUEUE BLOCK ; RO POINTS TO ALLOCATED BLOCK BCS 9$ ;IF CC SUCCESSFUL MOV R0,U.TIM(R5) ;SAVE ADDRESS OF TIMER PACKET MOV R5,C.TCB(R0) ;SAVE UCB ADDRESS IN TIMER PKT BR 10$ ; ; OOOPS! WE ARE UNABLE TO RESTART PROTOCOL, SO WE WILL JUST GO TO SLEEP AND ; HOPE THAT WHEN OUR PARTNER TRIES TO WAKE US UP WE HAVE SOME POOL! ; 9$: JMP CDEXIT 10$: MOV #C.SYST,R4 ;SET UP TIMER FOR INTERNAL ONESHOT TST C.SUB(R0) ;TIMER ALREADY RUNNING? BEQ 12$ ;BRANCH IF NOT CALL $CLRMV ;ELSE REMOVE PREVIOUS TIMER ENTRY MOV U.TIM(R5),R0 ;AND RESET ADDRESS (R4 AND R5 ; ARE PRESERVED) 12$: MOV #STKWAI,R2 ;SET UP SHORT TIME OF DELAY. CLR R1 ;CLEAR HIGH ORDER TIME MOV #CDOWN,C.SUB(R0) ;POINT TIMER AT STACK WAIT TMO ADR CALL $CLINS ;QUEUE TIMER PACKET MOV U.SCB(R5),R4 ;RESTORE SCB ADDRESS MOV #STWAIT,U.STA(R5) ;WE ARE NOW WAITING FOR START ACK MOV #STRTCD,R2 ;SEND START CODE TO PARTNER 18$: MOV S.CSR(R4),R0 ;CSR ADDRESS IN R0 .IFDF ICDRV BEQ 20$ .ENDC CALL XMT ;;;SEND CODE AND INTERRUPT PARTNER 20$: JMP CDEXIT .PAGE .SBTTL CDRST - RESTART PROTOCOL TIMER ; ; CDRST - RESTART PROTOCOL TIMER ENTRYPOINT ; ; THIS MODULE IS ENTERED ONLY AS A RESULT OF THE EXPIRATION ON THE ; START PROTOCOL TIMER. IT DETERMINES WHICH UNIT THE START TIMER WAS FOR BY ; LOOKING AT THE C.TCB WORD IN THE CLOCK QUEUE PACKET. IT DETERMINES IF THE ; LINK IS STILL IN THE DOWN STATE, AND IF SO IT SETS UP IT'S REGISTERS AND ; CALLS THE CDPWF ENTRYPOINT. ; ; INPUTS: ; R4 - ADDRESS OF THE CLOCK QUEUE PACKET ; ; CDRST: TRACE <#20.> PUSH ;SAVE REGISTERS CLR C.SUB(R4) ;FREE TIMER BLOCK MOV C.TCB(R4),R5 ;GET UCB ADDRESS CMP #DOWN,U.STA(R5) ;ARE WE STILL WAITING FOR START? BNE 50$ ;IF NE NO MOV U.SCB(R5),R4 ;SET THINGS UP FOR CALL TO CDPWF MOVB S.CON(R4),R3 CALL CDSTAR ;RESTART PROTOCOL 50$: POP ;RESTORE REGISTERS JMP CDMEXT ;BYE! .PAGE .SBTTL CDOWN - LINK DOWN TIMER ; ; CDOWN - THIS CODE EXECUTED ONLY BY THE EXPIRATION OF THE STACK WAIT ; TIMER. IT SETS THE UNITS STATE TO DOWN AND ISSUES A RANDOM TIMER ; TO ALLOW THE OTHER SYSTEM A CHANCE TO RESTART US. WHEN THE RANDOM ; TIMER EXPIRES, WE GET CALLED AT "CDRST", AND WE TRY AGAIN TO RESTART ; THE PROTOCOL ; CDOWN: TRACE <#21.> PUSH ;SAVE REGISTERS CLR C.SUB(R4) ;INDICATE TIMER PACKET FREE MOV C.TCB(R4),R5 ;GET UCB ADDRESS BIT #STWAIT!DOWN,U.STA(R5) ;HAVE WE RECEIVED STACK OR START BEQ 60$ ;IF EQ, YES MOV #DOWN,U.STA(R5) ;SET STATE=DOWN ; MOV R4,R0 ;;;ONLY GOT HERE IF ALREADY HAVE ;;;TIMER BLOCK MOV #C.SYST,R4 ;;;SET UP TIMER FOR INTERNAL ONESHOT MOV $IDLCT,R2 ;;;USE IDLE CYCLE COUNT AS A "RANDOM" ;;;NUMBER OF TICS TO DELAY BEFORE WE ;;;TRY TO SEND ANOTHER START. NOTE THAT ;;;WE NEXT MASK OUT THE UPPER BYTE SO ;;;THAT OUT TIMEOUT IS NOT TOO LONG. ;;;THIS NUMBER IS VERY UNLIKELY TO BE ;;;THE SAME FOR TWO CONNECTED SYSTEMS. BIC #DELMSK,R2 ;;;MASK UPPER BYTE BIS #1,R2 ;;;INSURE AT LEAST 1 TIC CLR R1 ;;;CLEAR HIGH ORDER TIME MOV #CDRST,C.SUB(R0) ;;;POINT TIMER AT PROTOCOL RESTART ADDR CALL $CLINS ;;;QUEUE TIMER PACKET 60$: POP ;RESTORE REGISTERS CDMEXT: TRACE <#7> ;TIMER ROUTINES EXIT .ENDC ;D$$11W > 0 RETURN .PAGE .SBTTL CDOUT - DEVICE TIME-OUT ; ; CDOUT - DEVICE TIMEOUT ENTRYPOINT. ; ; THIS MODULE IS ENTERED WHEN A REQUEST'S TIME OUT COUNT HAS EXPIRED. ; THIS CAN OCCUR AS A RESULT OF A LINK BID FAILURE, THE OTHER MACHINE ; MIGHT CRASH, WE MAY HAVE COME HERE AFTER THE POWER FAILURE ENTRYPOINT ; HAS TURNED OFF THE DEVICE ON US, OR WHEN THE TASK THAT SHOULD HAVE ; SENT US A RECEIVE REQUEST AS A RESULT OF AN AST HAS NOT DUE TO A BUG ; OR BECAUSE IT'S EXECUTION IS FOR SOME REASON BLOCKED. ; ; WE RESET THE DRIVER STATE, AND TERMINATE THE I/O OPERATION WITH ; AN IE.DNR ERROR (NICELY PROVIDED FOR US BY RSX IN R0) ; NOTE THAT SOMETIMES, THERE IS NO I/O IN PROGRESS. ; THIS IS BECAUSE WE MIGHT HAVE SET THE TIMER IN RESPONSE TO A LINK ; REQUEST, AND WE HAVE NOT YET RECEIVED THE I/O REQUEST FROM THE ; DESIGNATED RECEIVER TASK. ; WE THEN SET UP THE REGISTERS AND CALL THE CDPWF ENTRYPOINT. THIS HAS ; THE EFFECT OF RESTARTING THE LINK PROTOCOL. ; ; INPUTS: ; R5=UCB ADDRESS ; R4=SCB ADDRESS ; R3=CONTROLLER INDEX ; R2=ADDRESS OF DEVICE CSR ; R0=I/O STATUS CODE (IE.DNR) ; ; THIS SEGMENT EXECUTED IN FORK STATE AT ELEVATED PRIORITY. ; CDOUT: TRACE <#22.,U.STA(R5),R5> TSTB S.STS(R4) ;;;PACKET VALID? BEQ 100$ ;;;IF EQ NO MOV U.STA(R5),R1 ;;;LOAD DRIVER STATE IN IOSB+2 TRACE <#10.,U.STA(R5),R5,R0,R1,S.PKT(R4)> CALL $IODON ;;;TERMINATE I/O OPERATION 100$: MOV U.SCB(R5),R4 ;;;SET THINGS UP FOR CALL TO CDPWF CALL CDSTAR ;;;RESTART PROTOCOL JMP CDEXIT ;;;EXIT, NOTE THAT THE PROTOCOL ;;;STARTUP PROCESS WILL RESTART ;;;THE DEQUEUEING OF I/O PACKETS. .PAGE .SBTTL CDCAN - CANCEL I/O ; ; CDCAN - CANCEL CURRENT I/O OPERATION ENTRYPOINT ; ; WE GET CALLED HERE TO CANCEL THE I/O IN PROGRESS FOR A TASK. ; ; WE RUN DOWN THE PDB CHAIN, AND ABORT ALL OF THE I/O OPERATIONS ; FOR THIS TASK. THE CODE THAT DOES THIS IS PRETTY MUCH A COPY ; OF THE EXECUTIVE $IOKIL. ; ; NOTE THAT IT WOULD BE HARD TO REALLY CANCEL ANY I/O IN PROGRESS, SO ; WE RETURN AND WAIT FOR THE I/O TO COMPLETE OR TIME-OUT. ; ; INPUTS: ; R5=UCB ADDRESS ; R4=SCB ADDRESS ; R3=CONTROLLER INDEX ; R1=TCB ADDRESS OF CURRENT TASK ; R0=ADDRESS OF ACTIVE I/O PACKET. ; ; CDCAN: TRACE <#23.,U.STA(R5),R1,R0,R5> MOV U.PTC(R5),R4 ;GET PDB LISTHEAD BEQ 10000$ ;IF EQ, NO PDB'S, EXIT 1$: CMP $TKTCB,PT.TCB(R4) ;DOES CURRENT TASK OWN THIS PDB? BNE 51$ ;IF NE, NO 2$: DSABL CDPR ;DISABLE CD DEVICE INTERRUPTS MOV PT.IOQ(R4),R3 ;IS THERE ANYTHING IN THIS QUEUE? BEQ 50$ ;IF EQ, NO MOV $TKTCB,R1 ;PUT TCB OF CURRENT TASK INTO R1 MOV (R3),PT.IOQ(R4) ;TAKE 1ST ONE OFF OF QUEUE BNE 5$ ;IF MORE ON THE QUEUE STILL CLR PT.IOQ+2(R4) ;ELSE CLEAR OUT END OF QUEUE PTR 5$: ENABL MOV #IE.ABO,R0 ;SET FINAL STATUS TO ABORT CLR I.AST(R3) ;MAKE SURE THERE IS NO AST DECLARED TRACE <#9.,U.STA(R5),R5,R0,R1,R3> PUSH R4 ;SAVE R4 - POSITION IN PDB CHAIN CALL $IOFIN ;FINISH I/O REQUEST POP R4 ;RESTORE PDB POINTER BR 2$ ;GO AGAIN 50$: ENABL 51$: MOV (R4),R4 ;LINK TO NEXT PDB BNE 1$ ;LOOP TIL NO MORE PDB'S 10000$: JMP CDEXIT ;EXIT .PAGE .SBTTL -- UTILITY ROUTINES -- .SBTTL DEQPKT ; ; DEQUEUES THE NEXT PACKET FROM AN I/O QUEUE ; DOES THE ACTUAL DEQUEING AT DEVICE PRIORITY TO PROTECT AGAINST ; INTERRUPT LEVEL CODE RE-QUEUEING A PACKET ; ; INPUTS: ; R4 = I/O QUEUE LISTHEAD ; ; OUTPUTS: ; CARRY SET IF NO PACKETS ON I/O QUEUE ; CARRY CLEAR IF PACKET DEQUEUED ; THEN R3 = ADDRESS THE I/O PACKET ; R4 = ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5 = ADDRESS OF THE UCB (UNCHANGED) ; DEQPKT: TST (R4) ;ANY PACKETS ON QUEUE BEQ 20$ ;BRANCH IF NO PACKETS DSABL CDPR ;LOCK OUT DEVICE INTERRUPTS MOV (R4),R3 ;SET ADDRESS OF DEQUEUED PKT IN R3 MOV (R3),(R4) ;NEXT PACKET IS NOW FIRST ONE BNE 10$ ;IF NOT THE LAST PACKET IN QUEUE MOV R4,2(R4) ;ELSE 2ND WORD POINT TO FIRST 10$: ENABL ;ALLOW INTERRUPTS AGAIN TRACE <#26.,R3,I.FCN(R3),I.TCB(R3),R5> CLC ;CLEAR CARRY TO INDICATE SUCCESS RETURN 20$: SEC ;SET CARRY TO SHOW NO PACKETS RETURN ; .PAGE .IFDF TRCE .SBTTL TRACE ; ; TRACE - MODULE TO LOAD TRACE COMMON WITH TRACE BLOCKS ; ; INPUTS: R5 - UCB ADDRESS. ; MUST BE AT PR7 ; TRACE: PUSH ;SAVE REGISTERS MOV @#KISAR6,AP6 ;SAVE CURRENT MAPPING MOV TRC,@#KISAR6 ;MAP APR 6 TO COMMON TST @#TRCFLG ;TRACE ENABLED? BNE 3$ ;IF NE, NO ; ; LOAD COMMON HERE ; MOV #TR.SIZ,R0 ;GET SIZE OF ENTRY MOV @#TRCPTR,R1 ;GET INDEX TO CURRENT ENTRY CALL $MUL ;GET OFFSET (SIZE * TRCPTR) ASL R1 ;CONVERT TO BYTES ADD #TRCTAB,R1 ;ENTRY VIRTUAL ADDRESS NOW IN R1 MOV #TRCDAT,R0 ;TRACE DATA ADDRESS IN R0 MOV #TR.SIZ*2,R2 ;GET SIZE OF ENTRY IN BYTES ADD R0,R2 ;POINT TO START OF NEXT ENTRY MOVB $TTNS,TRCDAT+1 ;MOVE TICS TO TRACE DATA 1$: MOV (R0)+,(R1)+ ;MOVE TRACE DATA INTO COMMON CMP R0,R2 ;ARE WE DONE? BNE 1$ ;IF NE NO INC @#TRCPTR ;ADVANCE POINTER CMP @#TRCPTR,@#TRCNUM ;ARE WE AT END OF TABLE? BEQ 2$ ;IF EQ, YES MOV #-1,(R1) ;SQUASH NEXT ENTRY BR 3$ ;GO HOME 2$: CLR @#TRCPTR ;SET POINTER TO START OF TABLE MOV #-1,@#TRCTAB ;SQUASH NEXT ENTRY 3$: MOV AP6,@#KISAR6 ;RESTORE MAPPING POP ;RESTORE REGISTERS RETURN .ENDC .PAGE ; .SBTTL CDDQUE ; ; CDDQUE - SATISFY AN UNSOLICITED RECEIVE WITH A WAITING PACKET ; ; INPUTS: R5 - UCB ADDRESS ; R4 - ADDRESS OF THE SCB ; R0 - PDB ADDRESS ; ; OUTPUTS: R3 - ADDRESS OF THE I/O REQUEST PACKET ; R4 - ADDRESS OF THE STATUS CONTROL BLOCK (SCB) ; R5 - ADDRESS OF THE UNIT CONTROL BLOCK (UCB) ; ; NOTE: THIS ROUTINE DEQUEUES THE I/O FROM THE PDB, AND ; CALLS THE ROUTINE CDREAD TO START THE RECEIVE I/O OPERATION ; ROUTINE CALLED FROM INTERRUPT LEVEL AND FORK LEVEL CODE ; CDDQUE: MOV PT.IOQ(R0),R3 ;;;GET ADDRESS OF FIRST I/O PACKET MOV (R3),PT.IOQ(R0) ;;;NEXT PACKET IS NEW FIRST PACKET BNE 1$ ;;;BRANCH IF QUEUE NOT EMPTIED MOV R0,PT.IOQ+2(R0) ;;;LIST IS EMPTY, SECOND WORD POINTS ADD #PT.IOQ,PT.IOQ+2(R0) ;;; TO FIRST. 1$: TRACE <#17.,R3,PT.PTC(R0)> PUSH #10$ ;;;PUT RETURN ADDRESS FOR CDREAD ;;;READ ONTO STACK DSABL CDPR ;;;MUST HAVE PSW ON STACK ;;;CDREAD WILL RESET PSW BEFORE ;;;RETURN JMP CDREAD ;;;BEGIN THE I/O ;;;ESSENTIALLY THIS IS A CALL TO CDREAD ; ; WE NEED TO SAVE THE PSW ON THE STACK, SINCE NORMALLY ; CDREAD IS CALLED AT ELEVATED PRIORITY FROM THE DRIVER INITIATOR ; AND THEN LOWERS ITS PRIORITY BEFORE RETURNING ; ; 10$: RETURN .PAGE .IF GT D$$11W .SBTTL XMT ; ; XMT - ROUTINE TO SEND A CODE AND INTERRUPT THE PARTNER ; COMPUTER. ; ; INPUTS: ; R0 = ADDRESS OF THE CSR ; R2 = CODE TO BE SEND TO PARTNER ; ; OUTPUTS: ; ALL REGISTERS UNCHANGED ; XMT: TRACE <#28.,R2> ;TRACE CODE SENT DSABL PR7 ;DISABLE INTERRUPTS AS FNCT2 BIT WHICH ;CAUSES INTERRUPT OF PARTNER MUST NOT ;BE LEFT UP FOR MORE THAN 2 INSTRUCTIONS MOV R2,CDDATA(R0) ;LOAD CODE INTO ODR MOV #IE!FNCT1!FNCT2,(R0) ;INTERRUPT PARTNER MOV #IE!FNCT1,(R0) ;REMOVE INTERRUPTING SIGNAL ENABL ;ENABLE INTERRUPTS RETURN .PAGE .SBTTL XMTD ; ; XMTD - ROUTINE TO SET UP FOR A DMA (EITHER TRANSMIT) OR RECEIVE ; SEND THE WC TO THE PARTNER IN THE ODR, FOR A RECEIVER DMA, AND ; START UP THE DMA BY LOADING UP THE APPROPRIATE REGISTERS AND ; SETTING THE APPROPRIATE BITS IN THE CSR ; ; INPUTS: ; R0 = ADDRESS OF CSR ; R1 = CSR TEMPLATE ; FOR TRANSMITTER DMA = IE!FNCT3!GO!CYCLE ; FOR RECEIVER DMA = IE!FNCT1!FNCT2!FNCT3!GO ; R3 = MAXIMUM PERMITTED WORD COUNT ; ; OUTPUTS: ; DMA IS SET UP READY TO GO AND WORD COUNT SENT TO PARTNER (RECEIVER) ; DMA IS IN PROGRESS (TRANSMITTER) ; ; REGISTERS R1 AND R2 ARE DESTROYED ; XMTD: MOV U.CNT(R5),R2 ;BYTE COUNT FOR CURRENT I/O PACKET ASR R2 ;CONVERT TO WC MOV R2,U.QWC(R5) ;SAVE CURRENT PACKET WORD COUNT CMP R2,R3 ;IS WC IN PACKET > PERMITTED BLOS 5$ ;BRANCH IF NOT - OK TO CARRY ON MOV R3,R2 ;ELSE USE MAXIMUM PERMITTED ASL R3 ;CONVERT TO BYTES MOV R3,U.CNT(R5) ;AND RESET IN UCB BYTE COUNT FIELD 5$: MOV U.BUF+2(R5),CDBUFA(R0) ;LOAD BUFFER ADDRESS REGISTER MOV R2,R3 ;SAVE WORD COUNT NEG R2 ;NEGATE FOR WORD COUNT REGISTER MOV R2,CDWORD(R0) ;LOAD WORD COUNT REGISTER MOV R1,R2 ;DUPLICATE CSR TEMPLATE BIC #,R1 ;DONT SET GO OR CYCLE AT FIRST BIC #FNCT2,R2 ;REMOVE INTERRUPT WHEN SET CYCLE ;AND GO DSABL PR7 ;;;LOCK OUT INTERRUPTS BIT #FNCT2,R1 ;;;SENDING WC TO PARTNER? BEQ 10$ ;;;BRANCH IF NOT MOV R3,CDDATA(R0) ;;;ELSE LOAD WC INTO ODR TRACE <#28.,R3> ;WC SENT 10$: MOV R1,(R0) ;;;SET BITS IN CSR MOV R2,(R0) ;;;SET GO AND CYCLE BITS AND REMOVE ;;;INTERRUPT ENABL RETURN .PAGE .SBTTL SAVREG ; ; SAVREG - CO-ROUTINE TO SAVE REGISTER R0 TO R3 ON THE STACK ; AND CALL THE CALLER ; ; CALLED BY JSR R3,SAVREG SO R3 ALREADY ON THE STACK ; SAVREG: PUSH ;SAVE REST OF REGISTERS CALL (R3) ;CALL THE CALLER ; ;RETURN HERE IN INTERRUPT EXIT OR ;ON RETURN AFTER $FORK CALLED TRACE <#2,U.FFL(R5),U.STA(R5)> ;TRACE INTERRUPT EXIT POP ;RESTORE REGISTERS FROM STACK RETURN ;RETURN TO CALLER OF ORIGINAL ;CALLER ; .ENDC .PAGE .SBTTL XMTPKT,RCVPKT ; ; XMTPKT AND RCVPKT - SET UP THE SCB AND UCB FOR THE CURRENT ; TRANSFER PACKET. SETS UP BUFFER FIELDS AND BYTE COUNTS, SETS ; THE SCB STATUS TO BUSY, AND FOR XMT SET THE UNIT STATUS TO ; BUSY AND SETS UP THE TIMEOUT COUNT (THIS IS DONE EARLIER FOR ; A RECEIVE PACKET). ; ; INPUTS: ; R3 = ADDRESS OF CURRENT I/O PACKET ; XMTPKT: MOV #4,R0 ;FOR XMITTER MUST ADD 2 WORDS TO ;TRANSMIT WORD COUNT. THIS PREVENT ;THE TRANSMITTER FROM GETTING AN ;INTERRUPT AT END OF DMA, UNTIL THE ;RECEIVER SEND THE EOM. THIS WAS ;DONE TO AVOID DR11W HARDWARE 'FEATURE' MOV #XMTTMO,S.CTM(R4) ;SET UP TIMEOUT COUNTER BISB #US.BSY,U.STS(R5) ;SET UNIT BUSY TO ENABLE TIMEOUT BR SETPKT ; ; RCVPKT: CLR R0 ;FOR TRANSFER BYTE COUNT ; SETPKT: ; DO WHAT SYSTEM $GTPKT WOULD HAVE DONE ; MOV R3,S.PKT(R4) ;;;INDICATE CURRENT PACKET MOV I.PRM(R3),U.BUF(R5) ;;;INSERT RELOCATION BIAS IN UCB MOV I.PRM+2(R3),U.BUF+2(R5) ;;;INSERT BUFFER ADDRESS IN UC ADD I.PRM+4(R3),R0 ;;;INSERT BYTE COUNT IN UCB MOV R0,U.CNT(R5) INCB S.STS(R4) ;;;SET CONTROLLER BUSY RETURN .END