Now that we have successfully managed to read from a DASD device we can build a general purpose subroutine to perform I/O.  We will create a control block to communicate with the I/O routine.  The control block will be called I/O Request (IOR).

IOR      DSECT ,
IORCCW   DS    A             ADDRESS OF CCW
IORUNIT  DS    XL2           DEVICE ADDRESS
IORSIOCC DS    X             SIO CONDITION CODE
         DS    X
IORCSW   DS    XL8           CHANNEL STATUS WORD
IORSENS0 DS    X             SENSE BYTE 0
IORSENS1 DS    X             SENSE BYTE 1
*
IORLEN   EQU   *-IOR

The first two fields are input to the I/O routine and the remainder are output.  The IORCC field points to the CCW chain to execute.  The IORUNIT field contains the device address.  IORSIOCC returns the condition code returned form the SIO instruction.  IORCSW contains a copy of the CSW after the I/O request is complete.  If the I/O operation resulted in a Unit Check condition the I/O subroutine will perform a sense command and save the first two bytes into IORSENS0 and IORSENS1.

The I/O subroutine returns a completion code in Register 15 to indicate the completion status of the I/O request.

**********************************************************************
* XIO - PERFORM I/O SUBROUTINE
*       R1 = A(IOR) I/O REQUEST BLOCK
*       ON EXIT R15 CONTAINS A RETURN CODE
**********************************************************************
*
XIO      DS    0H
         STM   R14,R12,12(R13)    SAVE CALLER'S REGISTERS
         LA    R14,XIOSAVE        POINT TO OUR SAVE ADDRESS
         ST    R14,8(,R13)
         ST    R13,4(,R14)
         LR    R13,R14
*
         LR    R10,R1             IOR BLOCK ADDRESS
         USING IOR,R10
*

We begin by saving the callers registers and then establishing a new save area.  The IOR address is copied into Register 10 and mapped against the IOR DSECT.

         XC    IORSIOCC,IORSIOCC
         XC    IORSENS0(2),IORSENS0
         XC    IORCSW,IORCSW

First the output fields in the IOR are cleared.

         L     R1,IORCCW          POINT TO CCW  CHAIN
         ST    R1,72              SAVE INTO CAW
         SLR   R2,R2
         ICM   R2,B'0011',IORUNIT DEVICE ADDRESS
         SIO   0(R2)              START I/O
         BC    4,SIOCC4           BRANCH IF SIO NOT ACCEPTED
         BC    2,SIOCC2           BRANCH IF SIO NOT ACCEPTED
         BC    1,SIOCC1           BRANCH IF SIO NOT ACCEPTED

The CCW address is saved into the CAW and a SIO is issued against the device.  If the SIO did not complete with CC=8 a SIO CC code is stored in the IOR and the return code is set to 8.

WAITIO   TIO   0(R2)              WAIT FOR I/O COMPLETION
         BC    1,TIOCC1           BRANCH IF ERROR
         BC    7,WAITIO           KEEP WAITING...
*
         MVC    IORCSW,64         SAVE CSW
         CLC    =X'0C00',ORCSW+4  CHANNEL END/DEVICE END
         BE     WAITIO20          YES - GOOD COMPLETION
         TM     IORCSW+4,X'02'    UNIT CHECK?
         BNO    WAITIO15          NO - DON'T NEED TO SO SENSE

A TIO loop is executed to wait for the I/O request to complete.  Once the I/O has completed the CSW copied into the IOR.  If any status bits except Channel End and Device End are set it is considered to be an exceptional condition.

If Unit Check was set we fall through to issue a sense command.

         LA    R1,CCWSENSE
         ST    R1,72              SAVE INTO CAW
         SIO   0(R2)              START I/O
         BC    7,WAITIO99         ERROR
*
WAITIO10 TIO   0(R2)              WAIT FOR I/O COMPLETION
         BC    1,WAITIO99         BRANCH IF ERROR
         BC    7,WAITIO10         KEEP WAITING...
*
         MVC   IORSENS0(2),SENSE  SAVE SENSE BYTES 0 & 1
WAITIO15 DS    0H                 WAIT FOR I/O COMPLETION
         LA    R15,4              SET RC=4
         B     XIOXT

The address of the SENSE CCW is stored into the CAW and a SIO is issued to the device.  A TIO loop is used to wait for the Sense I/O to complete.  The first two bytes of the sense data is stored into the IOR.  We can now exit with a return code of 4.

SIOCC1   DS    0H
         MVI   IORSIOCC,X'01'
         LA    R15,8
         B     XIOXT
*
*
SIOCC2   DS    0H
         MVI   IORSIOCC,X'02'
         LA    R15,8
         B     XIOXT
*
*
SIOCC4   DS    0H
         MVI   IORSIOCC,X'04'
         LA    R15,8
         B     XIOXT
*
*
WAITIO99 DS    0H
TIOCC1   DS    0H
         LA    R15,16
         B     XIOXT
*
*
XIOXT    DS    0H
         L     R1,4(,R13)
         ST    R15,16(,R1)
*
         @PRINT '-------- IOR --------'
         @DUMP IORB,IORLEN
         @PRINT ' '
         @PRINT ' '
*
         L     R13,4(,R13)
         LM    R14,R12,12(R13)    RESTORE CALLER'S REGS
         BR    R14                RETURN TO CALLER

We finally end up at XIOXT with a return code set in Register 15.  Here I save the RC into the callers save area so it will be restored into Register 15 before returning to the caller.  For debugging purposes I have included a dump of the IOR Block. (This is why saving the value in Register 15 was necessary)

[Next – Searching The VTOC]