Now we can look at using EXCP channel programming to read a partitioned dataset. We will start with the structure of the directory. The directory consists of a set of 256 byte blocks, each with an 8 byte key. The number of directory blocks is determined when the PDS is initially allocated. An EOF mark occurs immediately following the last directory block.
+-+-----+ +-+-----+ +-+-----+ +-+-----+ +---+ |K| Dir | |K| Dir | |K| Dir | |K| Dir | ... |EOF| +-+-----+ +-+-----+ +-+-----+ +-+-----+ +---+
Each directory block begins with a 2 byte value indicating how many bytes in the block are used for directory information (including the 2 bytes for the length). Member entries begin immediately following the length.
+--+--------+--------+--------+ +--------+-------+ |LL|Mbr-1 |Mbr-2 |Mbr-3 | ... |Mbr-n |00...00| +--+--------+--------+--------+ +--------+-------+
Member entries are variable in length. There is a fixed portion which is always present followed by optional User Data. The user data area is between 0 and 62 bytes.
+--------+---+-+-----------+ |Mbr-Name|TTR|C| User Data | +--------+---+-+-----------+
The fixed portion of the member entry is 12 bytes. The first eight bytes contain the member name. The next three bytes contain a TTR pointer to the beginning block of the entry. The C field contains the size of the user data (in half words) in bits 3 through 7 (x’1F’). If bit 0 is set the entry is an Alias. To get the size of the user data we locially AND the C field with a mask of x’1F’ and then multiply by 2.
Member entries are stored in ascending sequence. The key contains the highest member name contained in the block. The logical end of the directory is marked with a member name of x’FFFFFFFFFFFFFFFF’.
The key allows us to locate the directory block containing a specific entry without having to read through the contents of every block. By using a Search Key High or Equal the correct directory block can be quickly located.
DC X'69',AL3(MBRNAME),X'40',X'40',AL2(8) Search Key Equal or High DC X'08',AL3(*-8),X'40',x'00',AL2(0) TIC back to Search DC X'06',AL3(IOBUF),X'00',X'00',AL2(256) Read Data
If we run this channel program against a PDS we should expect the I/O to either complete successfully and read a block of data or it should terminate with a No Record Found condition. Anything else should indicate some type of error condition. This technique depends on the logical EOF in the PDS directory (x’FFFFFFFFFFFFFFFF’) since the Search CCW will not detect the EOF record.
If the record is not found we need to continue our search on the next track of the dataset. We can update our Seek address (MBBCCHHR) and reissue the I/O. This should continue until a record is located and read or an exceptional condition occurs (indicating the PDS structure is damaged).
If our dataset is allocated on a cylinder boundry we can use the multi-track seach command to serach an entire cylinder at a time.
DC X'E9',AL3(MBRNAME),X'40',X'40',AL2(8) Search Key Equal or High Multi-Track DC X'08',AL3(*-8),X'40',x'00',AL2(0) TIC back to Search DC X'06',AL3(IOBUF),X'00',X'00',AL2(256) Read Data
If the I/O terminates with a No Record Found condition we update our Seek address to the next cylinder of the dataset. To do this we would add the number of tracks in a cylinder to our relative track address (in the case of a 3350 we would add 30 tracks).
This brings up the question of how do we know if our dataset is allocated in tracks or cylinders. The answer is found in the DEB extent information. Our routine to convert from TTR to MBBCCHHR uses the DEB extent information but I did not present any details, just the code to do the conversion. Here is the format of a DEB extent entry.
X - File Mask AL3 - UCB Address XL2 - BIN XL2 - Extent Begin CC XL2 - Extent Begin HH XL2 - Extent End CC XL2 - Extent End HH FL2 - Number of Tracks In This Extent
The File Mask is the parameter for a Set File Mask CCW. We have already looked at the Set File Mask parameters but here is a quick refresh of the bits we are interested in.
01.. .... - Do Not Allow Write ...1 1... - Do Not Allow Seek Cyl or Seek Head ...1 0... - Do Not Allow Seek Cyl (Seek Head allowed)
Below is an extent entry from a DEB.
58001E68 000000EB 001000EB 0019000A
The file mask tells us the dataset is opened for input only (write commands not allowed). Because Seek Cyl/Head is not allowed we can tell our dataset was allocated in tracks and multi-track commands are not allowed. The UCB address of the dasd device is 001E68. The BIN is always x’0000′. The extent begins at Cylinder x’00EB’ Track x’0010′ and ends at Cylinder x’00EB’ Track x’0019′ and there are 10 (x’000A’) tracks in the extent.
Here is the extent entry for a dataset allocated in cylinders.
50001E68 000001AE 000001AE 001E001E
Notice that here the file mask allows Seek Head so we can use multi-track commands.
EXCP05 – Read PDS Member
Find Block Containing Member Entry
*********************************************************************** * FIND DIRECTORY BLOCK * * ENTRY: R1 = A(CL8'MEMBER NAME') * * EXIT: R15 = RC * 0 - ENTRY LOCATED * 8 - ERROR * R1 = A(DIR BLOCK) * ***********************************************************************
Will will call our routine with register 1 containing the address of an 8-byte member name. On exit register 15 will contain a return of 0 if a block was located that may contain the member entry. A return code of zero does not mean the directory entry exists. It only means that IF the entry exists it will be in the block returned. Any other condition returns a value of 8 as the return code and indicates some type of error has occured. Register 1 will contain a pointer to the buffer containing the block that may contain the entry.
FINDBLK DS 0H ST R14,XTFIBLK SAVE RETURN ADDRESS * MVC SRCHNAME,0(R1) COPY MEMBER NAME TO SEARCH PARM
We begin by saving the return address and then moving the member name to our search key area used by our Search CCW.
MVI DIRSRCH,X'69' SEARCH KEY HI/EQ MVI MULTITRK,0 CLEAR MULTITRACK FLAG LA R2,EXCPDCB POINT TO DCB L R2,44(,R2) POINT TO DEB LA R2,32(,R2) FIRST EXTENT INFO SLR R1,R1 IC R1,0(R2) GET FILE MASK N R1,=A(X'18') ISOLATE SEEK HEAD C R1,=A(X'10') ALLOW SEEK HEAD NOP FINDB010 NO - BRANCH BNE FINDB010 NO - BRANCH * MVI MULTITRK,1 INDICATE MULTI-TRACK ALLOWED MVI DIRSRCH,X'E9' SEARCH KEY HI/EQ M/T FINDB010 DS 0H
Now we determine if we can use the Multi-Track form of our search. We begin by defaulting to the non-multitrack command code. We also clear the flag byte that indicates multitrack in use. We check the file mask in the DEB to determine if Seek Head is allowed and if so we update the flag byte and the Search command code.
Notice the NOP instruction. I included this so I could change it to an unconditional branch that forces the search to operate in non-multitrack mode for testing even if the dataset is allocated in cylinders.
LA R7,0 RELATIVE TRACK NUMBER * FINDB020 DS 0H LR R1,R7 RELATIVE TRACK NUMBER BAL R14,GETCCHH CONVERT TO MBBCCHHR LTR R15,R15 CHECK RETURN CODE BNZ FINDBXT8 - BRANCH IF NO GOOD * MVC IOBSEEK(8),MBBCCHHR MVI IOBSEEK+7,0 PUT IN RECORD NUMBER * LA R1,DIRSRCH POINT TO CHANNEL PROGRAM ST R1,IOBCCWAD SAVE INTO IOB * XC ECB,ECB CLEAR ECB EXCP IOB ISSUE I/O REQUEST * WAIT 1,ECB=ECB WAIT FOR I/O TO COMPLETE * BAL R14,PRINTIOB GO FORMAT IOB
We being by setting our relative track number to zero. The PDS directory always beings on the first track of the dataset. We then calculate the MBBCCHHR and update the IOB seek address. We put the address of our channel program into the IOB. This is necessary since we use the same IOB with different channel programs for reading directory blocks and data blocks. We then schedule the I/O request and wait for it to complete.
DIRSRCH DC X'69',AL3(SRCHNAME),X'40',X'00',AL2(8) DIRTIC DC X'08',AL3(DIRSRCH),X'40',X'00',AL2(0) DIRREAD DC X'06',AL3(DIRBLKIO),X'00',X'00',AL2(256)
Here is our channel program to find and read the directory block. Note that we do not set the Suppress Length Indication (SLI) bit in the Read CCW. Directory blocks are always 256 bytes in length and an incorrect length condition indicates some type of error.
* CLI IOBECBAD,X'7F' NORMAL COMPLETION BE FINDBXT0 YES - FOUND OUR BLOCK * CLI IOBECBAD,X'41' DEVICE STATUS AVAILABLE BNE FINDBXT8 NO - ERROR * TM IOBCSWFL,X'02' UNIT CHECK BNO FINDBXT8 NO - ERROR * TM IOBSENSE+1,X'08' NO RECORD FOUND BNO FINDBXT8 NO - ERROR * CLI MULTITRK,1 MULTITRACK ENABLED BNE FINDB030 NO - NEXT TRACK * A R7,=F'30' 3350 HAS 30 TRK/CYL B FINDB020 GO SEARCH NEXT CYL * * FINDB030 DS 0H A R7,=F'1' SEARCH NEXT B FINDB020 TRACK
If the I/O completed normally then we have successfuly located and read a directory block. We can return the block to the caller. Otherwise we check for Unit Check and No Record Found indicating we reached the end of a track or cylinder without locating the requested block. If we are in multitrack mode we update our relative track address to the next cylinder. Here I have hardcoded a value of 30 since a 3350 has 30 tracks/cyl. If we are not in multitrack mode we update to the next track and continue our search.
A PDS directory that exceedes one cylinder would be very large. A 3350 track will hold 36 directory blocks. Since there are 30 tracks/cyl a cylinder would contain 1,080 directory blocks.
FINDBXT0 DS 0H LA R15,0 SET RC LA R1,DIRBLKIO POINT TO I/O BUF B FINDBEXT AND EXIT * * FINDBXT8 DS 0H LA R15,8 SET RC B FINDBEXT AND EXIT * * FINDBEXT DS 0H L R14,XTFIBLK RESTORE RETURN ADDRESS BR R14
And finally our exit points. For a successful read we set the return code to zero and load the address of the I/O buffer into register 1.
Find Directory Entry In Directory Block
*********************************************************************** * FIND DIRECTORY ENTRY * * ENTRY: R1 = A(CL8'MEMBER NAME') * * EXIT: R15 = RC * 0 - ENTRY LOCATED * 4 - ENTRY NOT LOCATED * 8 - ERROR * R1 = A(DIR ENTRY) * ***********************************************************************
Here is our routine to locate a directory entry in a PDS directory block. On entry register 1 contains a pointer to the member name. A return code of zero indicates the entry was found and the address of the entry is returned in register 1. A return code of 4 indicates the entry does not exist and a return code of 8 indicates an error has occured.
FINDMBR DS 0H ST R14,XTFIMBR SAVE RETURN ADDRESS * BAL R14,FINDBLK GO FIND DIR BLOCK LTR R15,R15 CHECK RC BNZ FINDMXT4 BRANCH IF ERROR
We being by saveing the return address. Next we call the FINDBLK routine to locate the block that will contain the entry if it exists.
SLR R3,R3 ICM R3,B'0011',0(R1) GET LENGTH OF DIRECTORY DATA S R3,=F'2' ADJUST OUT LENGTH FLD LA R2,2(,R1) POINT TO FIRST ENTRY
We begin the search of the directory block by loading the number of bytes remaining into register 3 and loading register 2 with a pointer to the first member entry. As we continue processing the block R3 will contain the remainding number of bytes and R2 will point to the current member entry being processed.
FINDM010 DS 0H LTR R3,R3 END OF DATA BNP FINDMXT4 YES - ENTRY NOT FOUND * CLC 0(8,R2),SRCHNAME ENTRY WE ARE LOOKING FOR? BE FINDMXT0 YES - BRANCH * SLR R1,R1 ICM R1,B'0001',11(R2) GET C FIELD N R1,=A(X'1F') LENGTH OF USER DATA IN HALFWORDS SLL R1,1 MULTIPLY BY 2 A R1,=F'12' ADD IN FIXED SIZE * AR R2,R1 NEXT ENTRY SR R3,R1 ADJUST LENGTH B FINDM010 LOOP BACK
Here is the loop that searches for the member entry. We begin by checking to see if there are any more entries to process. If not then the entry was not found. Next the current entry name is compared to the search name which was saved in the FINDBLK routine. If it matches we found the entry and we are done. If not match we load the C field of the TTRC field into R1. We AND against a mask to keep only the length of the user data and use a SLL to multiply the value by 2 since it is in half words. Next the fixed size is added to obtain the total length of the entry. We adjust our current entry pointer and length remaining and then loop back.
FINDMXT0 DS 0H LA R15,0 SET RC LR R1,R2 POINT TO DIR ENTRY B FINDMEXT AND EXIT * * FINDMXT4 DS 0H LA R15,4 SET RC B FINDMEXT AND EXIT * * FINDMEXT DS 0H L R14,XTFIMBR RESTORE RETURN ADDRESS BR R14
Here are the exit points where the return code is set and if successful the address of the entry is returned in register 1.
Find Routine Driver
FIND DS 0H ST R14,XTFIND SAVE RETURN ADDRESS * MVC PL09MBR,0(R1) SAVE MEMBER NAME BAL R14,FINDMBR FIND DIR ENTRY LTR R15,R15 WAS IT LOCATED BZ FIND020 YES - BRANCH
Here is a testing routine to drive our find member process. On entry R1 points to the member name to be located. The find member routine will be called and the results will be printed.
* MVI PL09RC,C'4' SET RC IN MESSAGE C R15,=F'4' WAS RC=4 BE FIND010 * MVI PL09RC,C'8' SET RC=8 FIND010 DS 0H LA R1,=C' ' LA R15,1 BAL R14,PRINT PRINT BLANK LINE LA R1,PL09 LA R15,PL09L BAL R14,PRINT PRINT RC LINE SLR R1,R1 INDICATE MBR NOT FOUND B FINDXT EXIT
If the return code from FINDMBR was not zero we print a message with the member name and the RC.
FIND020 DS 0H ST R1,XBLKAD SAVE PTR TO MEMBER ENTRY * SLR R3,R3 ICM R3,B'0001',11(R1) C FIELD N R3,=A(X'1F') USER SLL R3,1 DATA LEN LA R3,12(,R3) ST R3,XBLKLEN LENGTH TO DUMP
If found we save the pointer to the entry and calculate the entry length.
* LA R1,=C' ' LA R15,1 BAL R14,PRINT PRINT BLANK LINE * MVI PL09RC,C'0' LA R1,PL09 LA R15,PL09L BAL R14,PRINT PRINT RETURN CODE LINE * LA R1,XBLKAD L R15,=V(XDUMP) BALR R14,R15 DUMP MEMBER ENTRY L R1,XBLKAD RESTORE DIR ENTRY ADDRESS B FINDXT * FINDXT DS 0H L R14,XTFIND RESTORE RETURN ADDRESS BR R14
Finally a status message is printed and the directory entry is dumped.
Testing The Find Routine
LA R1,=CL8'ACCOUNT' BAL R14,FIND FIND MEMBER * LA R1,=CL8'MSTRJCL' BAL R14,FIND FIND MEMBER * LA R1,=CL8'ZZZZZZZZ' BAL R14,FIND FIND MEMBER
We load R1 with the address of a member name and call the driver. I am using SYS1.LINKILB for testing since it has a large number of directory entries. ACCOUNT is located in the first directory block and MSTRJCL is located in the last. I also did a locate of ZZZZZZZZ which does not exist and should return RC=4.
Reading Member Data
*********************************************************************** * READ A BLOCK BY TTR * * ENTRY: R1 = 0TTR * * EXIT: R15 = RC * 0 - BLOCK SUCCESSFULLY READ * 4 - NO RECORD FOUND * 8 - EOF * 12 - ERROR * R0 = BLOCK SIZE * R1 = DATA * ***********************************************************************
On entry register 1 contains the TTR of the block to be read. On exit R0 will contain the size of the block read and R1 will point to the data in the I/O buffer. R15 contains a return code.
READTTR DS 0H STM R14,R12,12(R13) SAVE CALLERS REGISTERS LA R14,SAVERTTR CHAIN ST R13,4(,R14) ON ST R14,8(,R13) SAVE LR R13,R14 AREA * LR R7,R1 SAVE TTR
We being by saving the caller’s registers and establishing a new save area. The TTR is copied into R7.
LR R1,R7 RELATIVE TRACK NUMBER SRL R1,8 SHIFT OFF R (KEEP TT) BAL R14,GETCCHH CONVERT TO MBBCCHHR LTR R15,R15 CHECK RETURN CODE BNZ READTXTC - BRANCH IF NO GOOD * LA R1,READSRCH POINT TO CHANNEL PROGRAM ST R1,IOBCCWAD SAVE INTO IOB * MVC IOBSEEK(8),MBBCCHHR STCM R7,B'0001',IOBSEEK+7 PUT IN RECORD NUMBER
The relative track number is converted into a Seek Address. The address of the channel program for reading a block is placed in the IOB as is the full Seek address.
READSRCH DC X'31',AL3(IOBSRCH),X'40',X'00',AL2(5) READTIC DC X'08',AL3(READSRCH),X'40',X'00',AL2(0) READREAD DC X'06',AL3(*-*),X'20',X'00',AL2(19069)
Here is the channel program to read a block. Notice we attempt to read a block of the maximum size for a 3350. The SLI bit is set. This will allow us to read a block of unknown length.
XC ECB,ECB CLEAR ECB EXCP IOB ISSUE I/O REQUEST * WAIT 1,ECB=ECB WAIT FOR I/O TO COMPLETE * BAL R14,PRINTIOB GO FORMAT IOB * CLI IOBECBAD,X'7F' NORMAL COMPLETION BE READTXT0 YES - FOUND OUR BLOCK
Now we issue the EXCP and wait for the I/O to complete. We then check see see if a block was successfully read.
CLI IOBECBAD,X'41' DEVICE STATUS AVAILABLE BNE READTXTC NO - ERROR * TM IOBCSWFL,X'01' UNIT EXCEPTION BO READTXT8 YES - EOF RC=8 * TM IOBCSWFL,X'02' UNIT CHECK BNO READTXTC NO - ERROR * TM IOBSENSE+1,X'08' NO RECORD FOUND BO READTXT4 YES - RC=4 B READTXTC ELSE - ERROR
Next we check to see if device status is available in the IOB. If not we return an error condition. We then check for Unit Exception indicating an End Of File condition. Finally we check for a No Record Found condition. If none of these we return an error status.
READTXT0 DS 0H LA R15,0 SET RC SLR R1,R1 SLR R0,R0 ICM R0,B'0011',READREAD+6 READ SIZE FROM CCW ICM R1,B'0011',IOBRESDL RESIDUAL SIZE FROM CSW SR R0,R1 CALC RECORD SIZE READ ICM R1,B'0111',READREAD+1 DATA BUFFER ADDRESS B READTEXT AND EXIT
If a record was read we calculate the size by subtracting the CWS Residual value from the size in the Read CCW.
READTXT4 DS 0H LA R15,4 SET RC B READTEXT AND EXIT * * READTXT8 DS 0H LA R15,8 SET RC B READTEXT AND EXIT * * READTXTC DS 0H LA R15,12 SET RC B READTEXT AND EXIT * * READTEXT DS 0H L R13,4(,R13) L R14,12(,R13) LM R2,R12,28(R13) BR R14
And finally the exit code.
Read Block Test Routine
LA R1,=CL8'IEFBR14' BAL R14,FIND FIND MEMBER * LTR R1,R1 ANY DIR ENTRY BZ EXIT NO - EXIT * SLR R2,R2 ICM R2,B'0111',8(R1) GET TTR ST R2,CURTTR SAVE CURRENT TTR
We being by loacating the directory entry for a PDS memeber. I chose to use IEFBR14 for this test. We get the TTR pointer to the first block of the member from the directory entry.
RDMBR010 DS 0H L R1,CURTTR CURRENT BLOCK TTR BAL R14,READTTR GO READ BLOCK * B *+4(R15) BRANCH ON RC B RDMBR020 - READ SUCCESSFUL B RDMBR030 - NO RECORD FOUND B RDMBR040 - EOF B RDMBR050 - ERROR
Next we call our READTTR routine to read a block by TTR. A branch table is used to evaluate the return code.
RDMBR020 DS 0H ST R0,XBLKLEN SAVE BLOCK LEN ST R1,XBLKAD SAVE BLOCK ADDRESS LA R1,=C' ' LA R15,1 BAL R14,PRINT PRINT BLANK LINE LA R1,XBLKAD L R15,=V(XDUMP) BALR R14,R15 DUMP BLOCK * SLR R1,R1 ICM R1,B'0001',CURTTR+3 GET CURRENT RECORD LA R1,1(,R1) INCREMENT RECORD STCM R1,B'0001',CURTTR+3 SAVE BACK B RDMBR010 GO READ NEXT RECORD
If a block was successfully read we save the ponter to the data and the data length so we can dump the block. We then increment the record number in our current TTR pointer.
RDMBR030 DS 0H SLR R1,R1 ICM R1,B'0011',CURTTR+1 GET CURRENT TRACK LA R1,1(,R1) INCREMENT TRACK STCM R1,B'0011',CURTTR+1 SAVE TRACK MVI CURTTR+3,1 RECORD 1 B RDMBR010 GO READ NEXT RECORD
A No Record Found condition indicates we have read all the records on the current track. In this case we increment the current relative track number and reset the current record to one.
RDMBR040 DS 0H LA R1,=C' ' LA R15,1 BAL R14,PRINT PRINT BLANK LINE * * 1...5...10...15...20...25 LA R1,=C'*** END OF FILE ***' LA R15,19 BAL R14,PRINT PRINT EOF MESSAGE B EXIT
For End Of File we just print a message and exit.
RDMBR050 DS 0H LA R1,=C' ' LA R15,1 BAL R14,PRINT PRINT BLANK LINE * * 1...5...10...15...20...25 LA R1,=C'*** I/O ERROR ***' LA R15,17 BAL R14,PRINT PRINT ERR MSG B EXIT
For an I/O Error we print a message and exit.
Program Execution Output
I/O REQUEST COMPLETION CODE = 7F CSW = 0969F8 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 0000 ( 0) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000D5000000 BYTES READ = 0100 ( 256) FIND MEMBER = <ACCOUNT > RC = 0 0000 C1C3C3D6 E4D5E340 00FA1B2C 00FA2100 00000000 C2E20010 58105800 00008800 0020 00010000
Here is the eight-byte member name followed by the TTR (x’00FA1B’) and C (x’2C’). The remainder is the user data section that contains information about the load module.
I/O REQUEST COMPLETION CODE = 7F CSW = 0969F8 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 0000 ( 0) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000D5000000 BYTES READ = 0100 ( 256) FIND MEMBER = <MSTRJCL > RC = 0 0000 D4E2E3D9 D1C3D340 0122022C 01220700 00000000 03F20003 C003C000 00008800 0020 00010000
Here is the find output for MSTRJCL.
I/O REQUEST COMPLETION CODE = 7F CSW = 0969F8 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 0000 ( 0) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000D5000000 BYTES READ = 0100 ( 256) FIND MEMBER = +ZZZZZZZZ+ RC = 4
Here is the output for a member name that does not exist.
I/O REQUEST COMPLETION CODE = 7F CSW = 0969F8 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 0000 ( 0) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000D5000000 BYTES READ = 0100 ( 256) FIND MEMBER = RC = 0 0000 C9C5C6C2 D9F1F440 0103162C 01040400 00000000 C3F20000 08000800 00008800 0020 00010000
Here is the find output for IEFBR14.
I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4A55 (19,029) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001316 BYTES READ = 0028 ( 40) 0000 20000000 00010020 00000000 00000000 07000000 00000000 C9C5C6C2 D9F1F440 0020 00000000 01000004 I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4982 (18,818) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001317 BYTES READ = 00FB ( 251) 0000 80FA0100 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0020 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 LINES 000975C0-00097640 SAME AS ABOVE 00E0 00000000 00000000 00000000 00000000 00000000 00000000 000000 I/O REQUEST COMPLETION CODE = 41 CSW = 096A00 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0005 ( 5) --- DEVICE STATUS = CE DE UC --- CHANNEL STATUS = IL SENSE = 0008 SEEK = 00000000DD001318 I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4A6B (19,051) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001401 BYTES READ = 0012 ( 18) 0000 801102F5 F7F5F2E2 C3F1F0F4 40030873 346F I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4A69 (19,049) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001402 BYTES READ = 0014 ( 20) 0000 80138800 0278349F 0BD9E2C9 F4F0F9F5 F0F2F8F4 I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4A69 (19,049) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001403 BYTES READ = 0014 ( 20) 0000 0D000000 00040000 06000000 40000008 00020008 I/O REQUEST COMPLETION CODE = 7F CSW = 096A10 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 4A75 (19,061) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001404 BYTES READ = 0008 ( 8) 0000 1BFF07FE F0F4F1F4 I/O REQUEST COMPLETION CODE = 41 CSW = 096A10 DEV STAT = 0D CHAN STAT = 00 RESIDUAL = 4A7D (19,069) --- DEVICE STATUS = CE DE UE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000DD001405 *** END OF FILE ***
Here is the output from reading the data blocks for the PDS member IEFBR14.
I/O REQUEST COMPLETION CODE = 41 CSW = 0969E8 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0008 ( 8) --- DEVICE STATUS = CE DE UC --- CHANNEL STATUS = IL SENSE = 0008 SEEK = 00000000D5000000 I/O REQUEST COMPLETION CODE = 41 CSW = 0969E8 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0008 ( 8) --- DEVICE STATUS = CE DE UC --- CHANNEL STATUS = IL SENSE = 0008 SEEK = 00000000D5000100 I/O REQUEST COMPLETION CODE = 41 CSW = 0969E8 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0008 ( 8) --- DEVICE STATUS = CE DE UC --- CHANNEL STATUS = IL SENSE = 0008 SEEK = 00000000D5000200 I/O REQUEST COMPLETION CODE = 7F CSW = 0969F8 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 0000 ( 0) --- DEVICE STATUS = CE DE --- CHANNEL STATUS = SENSE = 0000 SEEK = 00000000D5000300 BYTES READ = 0100 ( 256) FIND MEMBER = RC = 0 0000 D4E2E3D9 D1C3D340 0122022C 01220700 00000000 03F20003 C003C000 00008800 0020 00010000
Here is the output for finding MSTRJCL when multitrack mode is disabled (remember the NOP to force non-multitrack). This time it takes four EXCP I/O requests to locate the block instead of the one EXCP when searching a cylinder at a time.