The DISK1 program will read and dump records from our DASD volume. Most of the work will be done in a subroutine called DUMPREC. It will read a block given a CCHHR address and dump the contents to the printer.
DUMPREC DS 0H ST R14,DUMPRCXT SAVE RETURN ADDRESS * LA R1,CCWSEEK POINT TO CCW CHAIN ST R1,72 SAVE INTO CAW LA R2,X'345' DISK DEVICE ADDRESS SIO 0(R2) START I/O BNZ ERR1 BRANCH IF SIO NOT ACCEPTED * WAIT TIO 0(R2) WAIT FOR I/O COMPLETION BZ DUMP GO DUMP RECORD BC 1,ERR2 BRANCH IF ERROR B WAIT KEEP WAITING...
By now this code should look pretty familiar. We save the caller’s return address. Next we store the address of our CCW program into the CAW and then issue the SIO. We use TIO to wait for the I/O to complete.
DUMP DS 0H MVC CSW,64 SAVE CSW FOR LATER * @PRINT '----- CSW ------' @DUMP CSW,10 @PRINT ' ' @PRINT '-----DATA BUFFER-----' * SLR R3,R3 ZERO R3 ICM R3,B'0011',CCWREAD+6 GET CCW DATA LENGTH SLR R1,R1 ZERO R1 ICM R1,B'0011',CSW+6 GET RESIDUAL LENGTH SR R3,R1 CALCULATE LENGTH READ * @DUMP INBUF,(R3) * @PRINT ' ' @PRINT ' ' * L R14,DUMPRCXT SAVE RETURN ADDRESS BR R14 RETURN TO CALLER
After the DASD I/O is complete we save the CSW because it will be overwritten when we issue I/O to the printer. We use our @DUMP macro to format the storage containing our saved CSW.
Next we get the residual length value from the CSW and subtract it from the length value in our read CCW. This gives us the actual length of the data that was read. (For example if we attempted to read 100 bytes of data and the residual length was 40 – we would have actually read 60 bytes of data).
We then format the contents of the I/O data buffer and then return to the caller.
DS 0D CCWSEEK DC X'07',AL3(MBBCCHHR+1),AL1(@CCW#CC),X'00',AL2(6) CCWSRCH DC X'31',AL3(MBBCCHHR+3),AL1(@CCW#CC),X'00',AL2(5) DC X'08',AL3(CCWSRCH),AL1(@CCW#CC),X'00',AL2(0) CCWREAD DC X'06',AL3(INBUF),AL1(@CCW#SLI),X'00',AL2(2048) * *
Our CCW program begins with a Seek (x’07’). It is followed by a Search ID Equal (x’31’) and a TIC (x’08) to search for the specific record we want to read. Finally we use a Read Data (x’06’) to read the data area of the record.
We specify Command Chaining on all CCW’s except the last. Our Read CCW has the SLI since we don’t expect our requested length to match the actual data length.
DS XL((((*-BEGIN+16)/16)*16)-(*-BEGIN)) CSW DC D'0' * * +0+1+2+3+4+5+6+7 * M B B C C H H R ********** X'0000000000000001' * MBBCCHHR DS 0X MBB DC X'000000' CCHHR DS 0X CC DC X'0000' HH DC X'0000' R DC X'01' *
The strange looking DS XL statement is used to align the address to a multiple of 16 bytes. We use a similar DS to align the I/O buffer to an even multiple of 256 (so when we format the buffer the beginning address is XXXXX00).
MVI R,1 READ RECORD 1 @PRINT '------- CC=00 HH=00 R=1 --------' BAL R14,DUMPREC * MVI R,2 READ RECORD 2 @PRINT '------- CC=00 HH=00 R=2 --------' BAL R14,DUMPREC
First we dump record R1 and R2 (IPL1 and IPL2) Since the CCHH is already set to cylinder 0 and Head 0 all we have to do is specify the record number.
MVI R,3 READ RECORD 3 @PRINT '------- CC=00 HH=00 R=2 --------' BAL R14,DUMPREC * MVC VTOCADDR,INBUF+11 SAVE VTOC ADDRESS FROM VOL RECORD * MVC CCHHR(5),VTOCADDR READ FIRST VTOC RECORD @PRINT '------- VTOC FMT 4 DSCB --------' BAL R14,DUMPREC
Next we read record 3 which is the volume label. The CCHHR address of the VTOC is saved and then moved into our DASD block address MBBCCHHR area. We can then read and dump the Format 4 DSCB data area.
[Next – DISK1 Assembly Listing]