The I/O Interrupt Routine is called from the low-level interrupt handler in the Nucleus module.  The low-level handler saves the registers and interrupt PSW into the current TCB before transferring control to the IOIR.

000000                                5 TXXIOIR  CSECT ,
000000 18CF                           6          LR    R12,R15            SET BASE
                            00000     7          USING TXXIOIR,R12                REGISTER
                                      8 * 
                            00000     9          USING @TCB,R4
                                     10 *
000002 1F11                          11          SLR   R1,R1              ZERO R1
000004 BF13 401A      0001A          12          ICM   R1,B'0011',TCBPSW+2   GET UNIT CUA FOR INTERRUPT
                                     13 *

The address of the device generating the interrupt is obtained from the interrupt PSW.

000008 5850 0010      00010          14          L     R5,16              CVT ADDRESS
00000C 5855 0008      00008          15          L     R5,CVTUCB-@CVT(R5)  POINT TO UCB LIST
                            00000    16          USING @UCB,R5
000010                               18 UCB010   DS    0H 
000010 D501 C11C 5004 0011C 00004    19          CLC   =X'FFFF',UCBCUA     END OF UCB LIST
000016 4780 C110      00110          20          BE    IOHND060              UNKNOWN DEVICE
                                     21 *
00001A BD13 5004      00004          22          CLM   R1,B'0011',UCBCUA   UCB FOR INTERRUPT 
00001E 4780 C02A      0002A          23          BE    UCB020                YES - CONTINUE
                                     24 * 
000022 5850 5000      00000          25          L     R5,UCBNEXT          POINT TO NEXT UCB
000026 47F0 C010      00010          26          B     UCB010              LOOP BACK

The UCB table is searched to locate the UCB associated with the interrupt.

00002A                               29 UCB020   DS    0H 
00002A D207 501C 0040 0001C 00040    30          MVC   UCBCSW,CSW-@LOWCORE SAVE CSW 
000030 58A0 500C      0000C          31          L     R10,UCBIOB          POINT TO IORB
000034 12AA                          32          LTR   R10,10               IS THERE ONE 
000036 4780 C0F6      000F6          33          BZ    IOHND040               NO - BRANCH 
                                     34 * 
                            00000    35          USING @IORB,R10
                                     36 *
00003A 9180 A020      00020          37          TM    IORBFLAG,IORBFSEN   RESCHEDUE TO GET SENSE INFO
00003E 4710 C0AC      000AC          38          BO    IOHND010              YES - SKIP NORMAL PROCESSING
                                     39 *
000042 D207 A024 501C 00024 0001C    40          MVC   IORBCSW,UCBCSW      COPY CSW INTO IORB
000048 D500 C11E 5021 0011E 00021    41          CLC   =X'80',UCBCSW+5     PCI ?
00004E 4710 C09E      0009E          42          BO    PCI010                YES - BRANCH
                                     43 *  
000052 927F A021      00021          44          MVI  IORBECBC,X'7F'       PRIME I/O COMPLETION CODE
000056 D503 C118 5020 00118 00020    45          CLC  =C'0C00',UCBCSW+4    DEV END + CHAN END
00005C 4780 C0AC      000AC          46          BE   IOHND010                YES - GOOD COMPLETION
                                     47 * 
000060 9241 A021      00021          48          MVI  IORBECBC,X'41'       ERROR COMPLETION CODE 
000064 9102 A024      00024          49          TM   IORBCSW,X'02'        UNIT CHECK ? 
000068 47E0 C0AC      000AC          50          BNO  IOHND010               NO - SKIP SENSE

When the UCB is located the CSW is saved into the UCB.  A check is done to see if there is an outstanding I/O request for this device.  If there is no outstanding request we branch to process an unsolicited interrupt.  We then check to see is this is a reschedule of the IORB to get sense data.  If it is a reschedule we can skip the normal processing.

Normal processing starts by copying the CSW into the IORB.  A check is then done to see if the interrupt is a result of a Program Controlled Interrupt flag set in a CSW.  If so we branch to call the PCI routine specified in the IORB.  Next we check for good completion indicated by Device End + Channel End in the CSW.  If not we set the ECB completion code to x’41’ and then examine the CSW to see if a Unit Check is indicated.  If so we will issue a sense request to the device.

00006C 9680 A020      00020          52          OI   IORBFLAG,IORBFSEN    INDICATE SENSE IN PROGRESS
                                     53 *
000070 4110 A022      00022          54          LA   R1,IORBSEN0          SENSE AREA
000074 5010 A02C      0002C          55          ST   R1,IORBWORK           BUILD SENSE CCW
000078 9204 A02C      0002C          56          MVI  IORBWORK,X'04'        CMD=SENSE 
00007C 4110 0002      00002          57          LA   R1,2                  LENGTH=2 
000080 5010 A030      00030          58          ST   R1,IORBWORK+4
000084 9220 A030      00030          59          MVI  IORBWORK+4,X'20'      SLI
                                     60 * 
000088 4110 A02C      0002C          61          LA   R1,IORBWORK           POINT TO SENSE CCW 
00008C 5010 0048      00048          62          ST   R1,CAW-@LOWCORE       SAVE INTO CAW 
000090 1F11                          63          SLR  R1,R1                 CLEAR R1
000092 BF13 5004      00004          64          ICM   R1,B'0011',UCBCUA    GET UNIT ADDRESS 
000096 9C00 1000      00000          65          SIO   0(R1)
00009A 47F0 C106      00106          66          B     IOHND050             AND EXIT

We begin by setting the bit in the IORB to indicate sense in progress.  We then build a Sense CCW in the work area and then issue a SIO to the device to obtain the first two bytes of sense data.

00009E                               69 PCI010   DS    0H
00009E 4110 A000      00000          70          LA    R1,@IORB             POINT TO IORB
0000A2 58F0 A018      00018          71          L     R15,IORBPCI          GET PCI ROUTINE ADDR
0000A6 05EF                          72          BALR  R14,R15              CALL IT
0000A8 47F0 C106      00106          73          B     IOHND050             AND EXIT

Here we handle a PCI interrupt by calling the PCI routine specified in the IORB.

0000AC                               76 IOHND010 DS    0H
0000AC 4110 A000      00000          77          LA    R1,@IORB           POINT TO IORB
0000B0 58F0 A014      00014          78          L     R15,IORBDIE        DIE ROUTINE ADDRESS
0000B4 05EF                          79          BALR  R14,R15            CALL DIE
                                     80 *
0000B6 18BA                          81          LR    R11,R10            SAVE IORB ADDRESS 
                                     82 *
0000B8                               83 IOHND020 DS    0H
0000B8 58A0 A000      00000          84          L     R10,IORBNEXT       POINT TO NEXT IORB ON CHAIN
0000BC 50A0 500C      0000C          85          ST    R10,UCBIOB         UPDATE IOB CHAIN OFF UCB
                                     86 *
0000C0 12AA                          87          LTR   R10,R10            ANOTHER IORB TO SCHEDULE
0000C2 4780 C0D8      000D8          88          BZ    IOHND030             NO - BRANCH
                                     89 * 
0000C6 5810 A00C      0000C          90          L     R1,IORBCCW         GET CCW
0000CA 5010 0048      00048          91          ST    R1,CAW-@LOWCORE    SAVE INTO CAW
0000CE 1F11                          92          SLR   R1,R1              ZERO R1
0000D0 BF13 5004      00004          93          ICM   R1,B'0011',UCBCUA  GET DEVICE ADDRESS 
0000D4 9C00 1000      00000          94          SIO   0(R1)

Now we are ready to call the DIE routine specified in the IORB.  We can then remove the IORB from the UCB queue and check to see if there is another IORB to process.  If so we issue the SIO for the request.

0000D8                               96 IOHND030 DS    0H 
0000D8 18AB                          97          LR    R10,R11            RESTORE IORB ADDRESS
0000DA 5840 A010      00010          98          L     R4,IORBTCB         GET TCB TO DISPATCH
0000DE 5810 0010      00010          99          L     R1,16              CVT
0000E2 5810 1004      00004         100          L     R1,CVTTASKQ-@CVT(,R1) PONIT TO TCB QUEUE = A(WAIT TCB)
0000E6 5820 1000      00000         101          L     R2,TCBNEXT-@TCB(,R1)  NEXT TCB 
0000EA 5020 4000      00000         102          ST    R2,0(,R4)          CHAIN ON
0000EE 5040 1000      00000         103          ST    R4,0(,R1)                  NEW TCB
0000F2 47F0 C106      00106         104          B     IOHND050           AND EXIT

Final processing consists of adding the TCB specified in the IORB to the Task Queue.  We chain it on immediately after the Wait Task TCB.

0000F6                              107 IOHND040 DS    0H 
0000F6 58F0 5010      00010         108          L     R15,UCBINTR        UCB INTERRUPT ADDRESS
0000FA 12FF                         109          LTR   R15,R15            BRANCH 
0000FC 4780 C106      00106         110          BZ    IOHND050                 IF NONE
                                    111 *
000100 4110 5000      00000         112          LA    R1,@UCB            POINT TO UCB
000104 05EF                         113          BALR  R14,R15            CALL INTERRUPT ROUTINE

Here we handle an unsolicited interrupt.  If an interrupt routine is specified in the UCB we branch to it passing the address of the UCB in Register 1.

000106                              116 IOHND050 DS    0H
000106 58F0 0014      00014         117          L     R15,20                  MVT 
00010A 58F0 F004      00004         118          L     R15,MVTDISP-@MVT(,R15)     DISPATCHER
00010E 07FF                         119          BR    R15
                                    120 *
000110                              122 IOHND060 DS    0H
000110 47F0 C106      00106         123          B     IOHND050

Eventually we exit back to the Dispatcher.

[Next – ]