.title zqdrv QUEUE ACP PSEUDO DEVICE DRIVER .IDENT /2.4/ .RAD50 /2.4/ ;.begin.doc ************************** begin.doc ; ; .c ;MODULE ; .c ;^&ZQDRV\& ; .nf ; .x ZQDRV>Defined ; Source:ZQDRV.MAC ; Designer :EARL LAKIA ; Author :EARL LAKIA ; Date of last update:06-JAN-87 ; Revision level :2.4 ; ; .SK ; .fill ; .SK ; Description: ; .sk ; This is the pseudo device driver for allowing the ; connection of the QUEACP with application tasks. This driver ; is pretty simple; it only does address relocation and the ; like valid only when the requesting task is the current task. ; NOTE: No special buffers are relocated, just the normal ; buffer address specified in a transfer function. This ; driver also provides for the normal I/O queuing of I/O ; requests that we desire for the queue process ACP. ; When a task exits, this driver is always called and ; the driver will allocate a piece of pool and queue ; a "fake" I/O packet to the ACP. This fake packet will tell the ; ACP to look for any message ids that were possibly ; connected to by this task and disconnect the task from them. ; ; ; .NOFILL ; ; THE QIO CALL IS: ; QIO$ FNC,LUN,EFN,PRI,ISB,AST, ; ; ; .fill ; .LIST ; .le;IO.WVB- Write a message to a specified message id queue. ; .list ; .le;P1= Message buffer address. ; .le;P2= Byte count of user message. ; .le;P3= Address of message id buffer (16 bytes long). ; .le;P4= Destroyed when id buffer relocated. ; .le;P5= Type of message (0= deletable if queue is full, 1= not deletable). ; .els ; .le;IO.WVB+1- Same as IO.WVB, but only used by the routing task, RTRRSX, ; to bypass writing a new header when the message is received from the ; remote node. ; .le;IO.RVB- Read a message from a specified message id queue. ; .list ; .le;P1= Message buffer address. ; .le;P2= Byte count of user buffer to receive message. ; .le;P3= Address of message id buffer (16 bytes long). ; .els ; .le;IO.ACR- Connect a message id queue to a task. ; .list ; .le;P1= Address of message id buffer (16 bytes long). ; .le;P2= 16. ; .le;P3= Event flag to set when the number of messages in the ; queue goes from zero to one. ; .els ; .le;IO.ACW- Acknowlege a message read from a message id queue. ; .list ; .le;P1= Address of message id buffer (16 bytes long). ; .le;p2= 16. ; .le;P3= Internal ID. (This id was returned when a read ; occurred in the upper byte of the I/O status word. It ; is a sequential number that is simply checked as a ; sequence number.) ; .els ; .le;IO.RNA- Replace read but not acknowleged message back at ; beginning of the message id queue. ; .list ; .le;P1= Address of message id buffer (16 bytes long). ; .le;P2= 16. ; .els ; .le;IO.DEL- Delete a specified number of messages without acknowledging ; from a message id queue. ; .list ; .le;P1= Address of message id buffer (16 bytes long). ; .le;p2= 16. ; .le;P3= Number of messages to be deleted. ; .els ; .le;IO.RAT- Read message id queue list head. ; .list ; .le;P1= Buffer address to receive list head (see MIDDEF). ; .le;P2= Byte count of user buffer. ; .LE;P3= Address of message id buffer (16 bytes long). ; .els ; .le;IO.ACE- Read the MAQUEUE header. ; .list ; .le;P1= Buffer address to receive queue header (see QHDDEF). ; .le;P2= Byte count of user buffer. ; .els ; .le;IO.APC- Mount/dismount the desired pseudo device unit with ; the ACP (IO.APC!1= Mount, IO.APC!2= Dismount). ; .le;IO.DAC- Set up exit handling I/O rundown function. This ; I/O never completes. The ACP is called with a new packet ; when the task exits which will clean up in the event the task ; attached to a message id. This function must be called prior to ; any calls to connect to a message id. ; .le;IO.KIL- Standard device functioning. ; .le;IO.ATT- Standard device functioning. ; .le;IO.DET- Standard device functioning. ; .els ; .FILL ; .SK ; Possible error codes: ; .LIST 1,' ' ; .le;IE.IFC (-02) -- Invalid function code. ; .le;IE.SPC (-06) -- Bad buffer address. ; .le;IE.DNA (-07) -- ZQ: device not mounted. ; .le;IE.WLK (-12) -- A connect request has been received from a task that ; does not have a pending I/O. Subroutine INITQ was probably not called ; to set up the task exit handlers. ; .le;IE.LCK (-27) -- Trying to mount ZQ: device when aleady mounted; trying ; to dismount ZQ: device when already dismounted. ; .le;IE.ILL (-42) -- The ACP is not installed in the system. ; .le;IE.NFW (-69) -- ACP not found in system task directory when trying to ; mount ZQ: device. ; .le;IE.IQU (-91) -- Trying to mount ZQ: device with a task that is not ; marked as an ACP. ; .els ; end.doc ****************************** end.doc .page ; ; PARAMETERS NEEDED FOR THIS DRIVER ; ZQCNT=1 ; NUMBER OF ZQ DEVICES ; .MCALL PKTDF$,ABODF$,DEVDF$,TCBDF$,HWDDF$ PKTDF$ HWDDF$ TCBDF$ DEVDF$ ABODF$ .IF NDF,R$$MPL .ERROR ; THIS DRIVER ONLY WORKS ON MPLUS SYSTEMS .ENDC .MCALL KRBDF$,CTBDF$ KRBDF$ GTPKT$ ; ; DRIVER DISPATCH.TABLE ; ; .GLOBL $ZQTBL $ZQTBL: DDT$ ZQ,ZQCNT,NONE ; NO INPUT OR OUTPUT INTERRUPTS .PAGE ; ; UCB OF DEVICE ; ZQUCBA: .WORD 0 ; UNIT STATUS FOR ZQ0: ; ; TABLE OF LEGAL FUNCTION CODES AND RELOCATION ; REQUIREMENTS ; FNCTBL: .WORD IO.RVB .WORD P3REL .WORD IO.WVB .WORD P3REL .WORD IO.ACR .WORD TSTIOS .WORD IO.ACW .WORD NOREL .WORD IO.RNA .WORD NOREL .WORD IO.DEL .WORD NOREL .WORD IO.RAT .WORD P3REL .WORD IO.ACE .WORD NOREL .WORD IO.APC .WORD MNTDIS ; MOUNT/DISMOUNT .WORD IO.DAC .WORD QUEIT ; ONLY FUNCTION CODE THAT GET'S QUEUED .WORD 0 ; LIST TERMINATOR ; ; THE NAME OF OUR ACP ; R50ACP: .RAD50 /QUEACP/ .PAGE ; ; DRIVER INITIALZATION CODE ; ; This drivr has the UC.QUE bit set in the device tables ; such that we may relocate some of the addresses that ; are in the parameter list. The executive will only ; relocate those buffers where p1= buffer, p2= byte count. ; All other buffers will require that we do the relocation and ; for non standard calls, we must have the control bit set ; so that the executive does not try to relocate the non ; present buffer. ; ; ; THE DEVICE DEPENDENT DATA IN THE I/O PACKET LOOKS LIKE THE FOLLOWING: ; FOR TRANSFER TYPE (IE: P1= BUFF, P2= COUNT) ; I.PRM ; I.PRM+2 ADDRESS DOUBLE WORD FOR DATA BUFFER ; I.PRM+4 BYTE COUNT FOR DATA TRANSFER ; I.PRM+6 P3 ; I.PRM+10 P4 ; I.PRM+12 P6 ; I.PRM+14 P7 ; ; INPUT FROM EXEC: ; R1= ADDRESS OF I/O PACKET ; R4= ADDRESS OF SCB ; R5= ADDRESS OF UCB ; ZQINI:: MOV #FNCTBL,R3 ; FUNCTION TABLE ADDRESS MOV I.FCN(R1),R4 ; GET FUNCTION BIC #377,R4 ; ONLY WANT UPPER HALF NO MODIFIERS 10$: TST (R3) ; AT END OF LIST? BNE 15$ ; NO MOV #IE.IFC&377,R0 ; ERROR CODE= INVALID FUNCTION BR 20$ ; GO RETURN 15$: CMP (R3)+,R4 ; IS THIS THE FUNCTION BEING REQUESTED? BNE 30$ ; NO CALL @(R3) ; GO DO REQUIRED WORK BCC 50$ ; EVERYTHING OK, THEN QUEUE IT MOV #IE.SPC&377,R0 ; RETURN ERROR CODE, BAD BUFFER ADDRESS 20$: MOV R1,R3 ; GET I/O PACKET ADDRESS CLR R1 ; BYTE COUNT= 0 CALLR $IOFIN ; RETURN ERROR CODE TO USER AND EXIT 30$: TST (R3)+ ; POINT TO NEXT FUNCTION CODE BR 10$ ; GO SEE IF NEXT MATCH ; ; EVERYTHING WAS OK, NOW QUEUE THE PACKET TO OURSELVES. THIS ; WILL ACTUALLY CAUSE A QUEUE TO THE ACP WHEN THE GET PACKET IS ; EXECUTED BY THE MAIN LINE CODE. ; ; R4= SCB ; R1= I/O PACKET ; 50$: MOV R1,R3 ; COPY I/O PACKET ADDRESS MOV I.UCB(R1),R5 ; GET UCB MOV U.ACP(R5),R0 ; GET ACP TCB ADDRESS BNE 60$ ; ACP THERE? 55$: MOVB #IE.ILL,R0 ; BOGUS ERROR CODE CLR R1 CALLR $IOFIN 60$: CMP R50ACP,T.NAM(R0) ; MATCH ON ACP NAMES? BNE 55$ CALL $EXRQF ; QUEUE TO ACP RETURN .PAGE ; ; QUEUE THIS I/O PACKET TO OURSELVES, WE NEVER DEQUEUE THEM EXCEPT ; ON THE I/O CANCEL. ; FUNCTION CODE: IO.DAC ; R5= UCB ; R1=I/O PACKET ; (SP)= RET ADDR. QUEIT: MOV U.SCB(R5),R0 ; LIST HEAD= SCB CALL $QINSP ; QUEUE TO OURSELVES BY PRIORITY TST (SP)+ ; POP RET ADDR RETURN ; BUT WE NEVER DEQUEUE IT !!!! .PAGE ; ; CONNECT FOR A OF A MESSAGE ID READ, ; MAKE SURE HAVE AN OUTSTANDING I/O PACKET. ; (SP)= RET ADR ; R5= UCB ; R1= I/O PACKET ; TSTIOS: MOV U.SCB(R5),R4 ; GET SCB 10$: MOV (R4),R2 ; TRAVERSE THE SCB I/O LIST BEQ 30$ ; AT END, OOPS MOV R2,R4 ; COPY FOR NEXT TRAVERSE CMP $TKTCB,I.TCB(R2) ; DO WE HAVE A PENDING I/O FOR THIS ; TASK? BNE 10$ ; NOT THIS PACKET JMP NOREL ; YES, THEN OK TO LET HIM CONNECT 30$: TST (SP)+ ; POP RET. ADDR MOV R1,R3 ; GET I/O PACKET ADDR. MOVB #IE.WLK&377,R0 ; ERROR CODE CALLR $IOFIN ; DONE WITH THIS TURKEY .PAGE ; ; CHECK/RELOCATE PARAMETER P3 WHICH IS THE MESSAGE ; ID BUFFER (SHOULD BE 16 BYTES) READABLE ; ; R5= UCB ; (SP)= RETURN ADDRESS ; P3REL: BITB #US.MNT!US.MDM,U.STS(R5) ; IS DEVICE DISMOUNTED? OR MARKED BEQ 5$ ; NO, ITS OK TST (SP)+ ; POP RET. ADDR. MOV R1,R3 MOV #IE.DNA&377,R0 ; NO, RETURN DEVICE NOT ATTACHED CLR R1 CALLR $IOFIN ; ALL DONE THIS PACKET 5$: MOV R1,-(SP) ; SAVE I/O PACKET ADDRESS MOV I.PRM+6(R1),R0 ; STARTING ADDRESS MOV #16.,R1 ; SIZE OF BUFFER CALL $CKBFR ; CHECK THE BUFFER BCC 10$ ; WAS IT VALID MOV (SP)+,R1 ; RESTORE R1 RETURN ; LET MAINLINE RETURN ; ; RELOCATE THE BUFFER AND STORE BACK IN THE I/O PACKET ; 10$: MOV (SP),R1 ; RESTORE R1 MOV I.PRM+6(R1),R0 ; GET VIRTUAL ADDRESS TO RELOCATE CALL $RELOC ; RELOCATE THE ADDR OF THE CONTROL BUFR MOV (SP),R3 ; I/O PACKET ADDRESS MOV R1,I.PRM+6(R3) ; STORE DISPLACEMENT MOV R2,I.PRM+10(R3) ; AND DISP. IN BLOCK MOV (SP)+,R1 ; RESTORE R1 CLC ; SET SUCCESS RETURN .PAGE ; ; NO RELOCATION, HOWEVER, THE DEVICE MUST BE MOUNTED ; (SP)= RET ADDR ; R5= UCB ; R1= I/O PACKET ADDR. ; NOREL: BITB #US.MNT!US.MDM,U.STS(R5) ; IS DEVICE DISMOUNTED? OR MARKED BEQ 5$ ; NO, ITS OK TST (SP)+ ; POP RET. ADDR. MOV R1,R3 MOV #IE.DNA&377,R0 ; NO, RETURN DEVICE NOT ATTACHED CLR R1 CALL $IOFIN ; ALL DONE THIS PACKET RETURN ; GO GET ANOTHER PACKET 5$: CLC RETURN .PAGE ; ; MOUNT/DISMOUNT COMMANDS THEY ARE HANDLED STRICKLY BY THIS ROUTINE ; IF MOUNT, THEN FIND THE TASK IN THE SYSTEM TASK DIRECTORY ; AND REQUEST THE TASK TO RUN. FOR DISMOUNT, MARK THE DEVICE AS ; MARKED FOR DISMOUNT AND QUEUE THE REQUEST TO THE ACP WHICH WILL ; EVENTUALLY ACTUALLY SET THE US.MNT BIT AND CLEAR THE AP5 ; MAPPING LOCATION (U.ACP). ; MNTDIS: TST (SP)+ ; POP RETURN ADDRESS, WE DONT RETURN CMPB #1,I.FCN(R1) ; IS THIS A MOUNT COMMAND BNE 70$ ; NO, ; ; MOUNT; FIND QUEACP'S TCB, REQUEST IT TO RUN. THE INITIALIZATION ; CODE FOR THIS ACP WILL CLEAR THE US.MNT FLAG, AND STORE IT'S ; TCB ADDRESS ; BITB #US.MNT,U.STS(R5) ; ARE WE CURRENTLY DISMOUNTED BNE 50$ ; YES, THEN OK TO MOUNT 40$: MOV #IE.LCK&377,R0 ; ERROR CODE 45$: MOV R1,R3 CLR R1 CALL $IOFIN ; ALL DONE RETURN ; GO GET NEXT PACKET ; ; NOT MOUNTED, THEN MOUNT BY REQUESTING THE ACP TO RUN ; 50$: BISB #US.VV,U.STS(R5) ; SET VOLUME VALID BIT MOV #R50ACP,R3 ; RAD50 NAME CALL $SRSTD ; SEE IF FOUND BCC 55$ ; FOUND HIM MOV #IE.NFW&377,R0 ; ERROR CODE BR 45$ 55$: BIT #T3.ACP,T.ST3(R0) ; IS FOUND TASK REALLY AN ACP? BNE 60$ ;YES MOV #IE.IQU&377,R0 ; ERROR BR 45$ ; GO RETURN STATUS 60$: ; ; R0= TCB ; R1= PACKET ; CALL $EXRQP ; REQUEST THE ACP TO DO THE WORK ; INCLUDING THE I/O DONE RETURN ; SEE IF MORE WORK ; ; DISMOUNT ; 70$: BITB #US.MDM!US.MNT,U.STS(R5) ; ARE WE CURRENTLY DISMOUNTED ; OR MARKED FOR DISMOUNT? BNE 40$ ; ALREADY DISMOUNTED BISB #US.MDM,U.STS(R5) ; MARK DISMOUNT IN PROGRESS BICB #US.VV,U.STS(R5) ; CLEAR VOLUME VALID BIT MOV U.ACP(R5),R0 ; GET TCB OF ACP BEQ 50$ ; WHAT NOT FOUND? BR 60$ ; FOUND, GO SEND REQUEST TO THE ACP .PAGE ; ; I/O CANCEL- ; ; R5= UCB ; R4= SCB ; R3= CONTROLLER INDEX ; R2= undefined ; R1= ADDRESS OF TCB OF CURRENT TASK ; R0= ADDRESS OF CURRENT I/O PACKET (FROM S.PKT, THIS ; MAY NOT VALID IF U.STS DOES NOT SHOW IT AS BEING ; ACTIVE WITH I/O. ; ; The module IOKIL only cancels the entries after S.LHD, not the ; one pointed to by S.LHD. Since we also request to be notified ; if any I/O packet has been removed, we may be called even for ; I/O packets that have already been dethreaded. ; ZQCAN:: TSTB T.IOC(R1) ; TEST I/O COUNT FOR ZERO BNE 5$ ; IF I/O COUNT IS ZERO, THEN THIS IS ; AN ASSIGN LUN DIRECTIVE, NO ; I/O PACKET EXISTS RETURN ; SO RETURN 5$: MTPS #PR0 ; ENABLE INTERUPTS MOV R1,-(SP) ; SAVE R1 ; ; THE FOLLOWING CODE IS STOLLEN FROM THE $IOKILL FOR FLUSHING ; I/O TO THIS UNIT. NOTE: WE DON'T TEST UCB ON SCB THREAD AS ; WE ONLY HAVE A SINGLE UCB. ; 10$: MOV U.SCB(R5),R4 ; GET SCB MOV R4,R3 ; COPY ADDR. OF I/O QUEUE LIST HEAD 20$: MOV R3,R2 ; SAVE ADDR. OF CURRENT ENTRY MOV (R2),R3 ; GET ADDR. OF NEXT ENTRY BEQ 40$ ; END OF LIST 30$: CMP R1,I.TCB(R3) ; IS THIS PACKET FOR THIS TASK? BNE 20$ ; NO. MOV (R3),(R2) ; YES, REMOVE FROM THREADED LIST BNE 35$ ; NO NEW LAST POINTER TO UPDATE MOV R2,2(R4) ; SET NEW LAST POINTER 35$: MOV #IE.ABO&377,R0 ; STATUS CLR I.AST(R3) ; NO AST CALL $IOFIN ; COMPLETE THIS I/O BR 10$ ; GO SEE IF ANOTHER FOR THIS TASK ; NORMALLY THERE SHOULDN'T BE ; ; WE WANT TO SEND A SPECIAL PACKET ; TO THE ACP TO LET IT KNOW THAT THIS TASK IS EXITING. ; 40$: TST U.ACP(R5) ; IS THE ACP PRESENT? BEQ 70$ ; NO, THEN MUST NOT BE MOUNTED CMP U.ACP(R5),R1 ; ACP EXITING? BEQ 70$ ; YES, THEN DON'T SEND TO IT BITB #US.MNT!US.MDM,U.STS(R5) ; IS DEVICE DISMOUNTED? OR MARKED BNE 70$ ; YES, THEN DON'T SEND TO IT MOV R5,-(SP) ; SAVE UCB MOV #I.LGTH,R1 ; GET AN I/O PACKET FROM PRIMARY POOL CALL $ALOCB ; GET THE PACKET BCS 65$ ; GOT A PACKET? NO, THEN GIVE UP ; ; NOW FILL IN THE ALLOCATED PACKET AS IF IT WERE AN I/O PACKET ; (WELL SOMEWHAT). SINCE THE TCB FOR THIS TASK MAY NOT BE ; PRESENT WHEN THIS PACKET IS DEQUED BY THE ACP, STORE THE ; RAD50 TASK NAME. ; ; R0= ALLOCATED PACKET ; MOV (SP),R5 ; RESTORE UCB MOV R0,R1 ; NEED R1= PACKET MOV #IO.DAC,I.FCN(R1) ; FUNCTION CODE MOV 2(SP),R3 ; GET TCB OF EXITING TASK MOV R3,I.TCB(R1) ; STORE TCB ADDRESS OF TASK EXITING MOV T.NAM(R3),I.PRM(R1) ; STORE RAD50 TASK NAME UPPER MOV T.NAM+2(R3),I.PRM+2(R1) ; STORE RAD 50 TASK NAME LOWER MOV R5,I.UCB(R1) ; UCB ADDRESS MOV U.ACP(R5),R0 ; TCB OF ACP CALL $EXRQF ; QUEUE IT TO THE ACP 65$: TST (SP)+ ; POP R5 70$: TST (SP)+ ; POP R1 RETURN ; DONE, LET ACP FINISH ; ; TIMEOUT ENTRIES ; (NOT USED BY THIS DO NOTHING DRIVER) ZQOUT:: RETURN ; ; POWER FAIL OR BOOT ENTRY ; ; R5= UCB ; R4= SCB ; R3= INDEX ; ZQPWF:: MOV R5,ZQUCBA ; ; MARK THE DEVICE AS NOT MOUNTED ; BICB #US.MDM,U.STS(R5) ; CLEAR MARKED FOR DISMOUNT BISB #US.MNT,U.STS(R5) ; SET NOT MOUNTED CLR U.ACP(R5) ; CLEAR TCB ADDRESS FOR ACP TSTB U.UNIT(R5) ; IS THIS ZQ0: BEQ 10$ ; YES BISB #US.BSY,U.STS(R5) ; MARK DEVICE AS BUSY 10$: RETURN ; ; CONTROLLER STATUS CHANGE? SHOULDN'T HAPPEN FOR THIS TYPE OF DEVICE ; ZQKRB:: RETURN ; ; UNIT STATUS CHANGE, NO CONTROLLERS, SHOULDN'T OCURR FOR THIS TYPE OF ; DEVICE. ; ; ZQUCB:: RETURN .END