MVS TOOLS AND TRICKS OF THE TRADE FEBRUARY 2003 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. TRICKS WITH TAPES - PART III - USING EXCP This month, I'll be able to show you something that will give you great joy to use. We all know that much of the thrill we get from programming, is to be able to "make the machine dance", which means that the computer will listen to what you tell it to do. After we've finished with today's subject, you'll be able to start making a tape drive dance, and tell it what to do. If you follow this lesson out, and look at some of the coding examples we'll refer to, you too will begin to experience the same enormous pleasure that I've been able to get, from manipulating a tape on a tape drive, and making it do just about anything I want. Most of the tape work I do personally, is the copying and modification of tapes, so there aren't that many of the 3480 (or 3490) opcodes which I personally use often. But once the door has been opened, and you know the basic techniques, the sky is the limit, and you'll be able to exploit nearly the full capabilities of the tape drive, if you want to do that. The key to doing this, to manipulating a tape on a tape drive, is to learn to use the EXCP access method for tapes. EXCP for tapes is really quite simple to set up, and once you see how it's done, all the intimidating thoughts that you may have had in your own mind, that "EXCP is hard", will melt away, and you'll just start having fun. Doing EXCP to tapes, is just a little bit different from "regular programming", in that you have to issue instructions to the hardware, directly. Even though that may sound difficult, it isn't. It's really just writing Assembler code. If you're not frightened by writing Assembler code, you've got the "battle with the phantom" won already. But if the thought of writing Assembler code scares you a bit, I can reassure you that this is really very easy Assembler coding. And you can also copy from the many available coding examples. You can find several programs to copy code from, on File 229 of the CBT Tape Collection of free software, whose URL is www.cbttape.org. Programs to look at, are COPYMODS, COPYFILE, COPYSLNL, and COPYNLNL. You can also find good code on File 193 (the TCOPY program). When you look at this code, don't confuse yourself will all the stuff that formats the information obtained from the tape. Concentrate instead, on the EXCP macro instructions themselves, and on what they refer to directly. So let's get down to business, and start explaining what we have to do. SETTING UP EXCP TO TAPE The EXCP macro executes an I/O operation, and this can be to any device: a tape drive, or a disk drive, or a CTC, or even a card reader or card punch. The Operation Codes for CCWs (Channel Command Words) which "talk" to each device, are described in the hardware manuals for the device, and not in the MVS manuals that we're used to looking at. So finding out about which Operation Codes to use, is a more difficult task than most, because you have to obtain the IBM Hardware Manuals cd-rom to get them. I referred to the old 3480 manual (GA32-0042), to keep things simple, and I've supplied a list of Operation Codes for the 3480 tape drives, in Figure 4, to make these codes more accessible. The bottom line is, that you EXCP an IOB (an Input Output Block). The IOB (illustrated in Figure 2) basically refers to a CCW or a chain of CCWs (to supply the list of operations to be done), the DCB of the file to be referenced, and an eight-byte area to contain the CSW (Channel Status Word) that will display the results of the I/O operation. The CCW itself contains the reference to the buffer area in your computer storage, where the tape data is to be placed, or written from. And the rest of the IOB basically contains a few bytes of flag bits. You can see a bunch of CCWs in Figure 1, where I've collected all the CCW chains that are used by the COPYMODS program from File 229 of the CBT Tape collection of free software. So again, you EXCP an IOB. And all the stuff you want to do, has to be referenced by fields in the IOB and its CCWs. That's half of the basics. The other half, is that you have to execute a WAIT macro after you do the EXCP, to tell your program when the EXCP has finished doing its work, and not to proceed further until that I/O is complete. The WAIT macro posts its results to a fullword of storage known as an ECB (or Event Control Block). And when the ECB has a X'7F' in its first byte, that's a signal to our program, that the I/O operation has completed successfully. One more piece of information necessary in an I/O operation, is the exception conditions, such as end-of-file or end-of-data on a READ, end-of-tape on a READ or a WRITE, or if a tape mark has been encountered on a READ. That information is reflected in status bits of the CSW, as returned in the IOB. Please look at Figure 3 to see a sample of Assembler code which executes a READ operation for a block of tape data, and copies up to 64K bytes into a 64K buffer area in storage referred to by location INAREA. The actual number of bytes read by the operation, is calculated and moved to a halfword location called BYTESCOP. We'll now explain what happens here, in more detail. HOW YOU READ AND WRITE DATA ON A TAPE At this point, I'll try and step you through the process of reading a block of data from an input tape, and writing the same block of data to an output tape. The DDNAMEs referring to both tapes are IN for the input tape, and OUT1 for the output tape, as referred to in Figure 5. We assume that both DCBs have already been OPENed in our program. Please look at Figure 3, to see the block of code which does the tape block READ. The code does an EXCP on the INIOB, an IOB which was set up to point to the input tape and the input buffer area and execute a READ CCW, with the opcode of X'02'. This is immediately followed by a WAIT macro, which refers to the same ECB that is mentioned inside the IOB that was just EXCP'ed. After the WAIT has completed (this is automatic in the program--you don't have to code anything there), you can then test whether the I/O was good. Before we do that, though, I have to answer the question of how many bytes the READ operation will move. This is normally coded explicitly in the fourth field of the CCW, on a READ operation. If you look in Figure 1, at the INCCW, you'll see X'FFFF' or 65535 bytes coded there. When we're READing a block of data from a tape, we don't know that there are exactly 65535 bytes in it. Usually there are far less. So what do we do? Actually, the designers of the I/O subsystem in MVS have made provision for that. You code the maximum number of bytes you think you may want to READ, but you also turn on the X'2000' bit in the third field, which is known as the SILI bit. When the SILI bit is on in a READ CCW, the READ operation will read as many bytes as there are in the current tape block, up to the maximum coded in the fourth field. And if it encounters less than the maximum, it will tell you how many bytes less, in a halfword field in the CSW area of the IOB. That field is called the "residual count". The number of bytes actually moved, is the maximum from the fourth field, minus the residual count. If you look at the code in Figure 3, you'll see that this is what the code actually does. Almost everyone asks the question: "Why do you determine the number of bytes moved, in such a silly (no pun intended) way? Why doesn't the operating system return that number of bytes directly?" My guess would be, that the I/O subsystem plugs the maximum number of bytes into the CSW before the move takes place, and as bytes are moved, the number in the CSW is subtracted from, until it gets to zero, and that's the signal for the move to be finished. With the SILI bit on, the move can finish before the CSW residual byte count gets to zero, so wherever the move stops, the number which is left in the CSW, has to be subtracted from the maximum, to indicate the count of bytes actually moved. I guess that was the easiest way to program the I/O so you knew you were done. This was programmed in 1964, and we still have to live with it. Now let's get back to the rest of our code in Figure 3. Just after the WAIT, we test a bit INCSW+4,X'01', which would signal a UNIT EXCEPTION, if it was on. That means (usually) that we've read a Tape Mark. So if we're copying a tape, we're at the end of a file, so we have to count the file, and write a Tape Mark to the output tape. If there's no unit exception, we check the first byte of the ECB for a X'7F', which signals correct completion of the I/O operation. Once that is verified, we go look at the residual count in the CSW, and calculate the number of bytes in the block that was just read. To WRITE all this data out to an output tape, it's very simple. We take the count of bytes moved from the BYTESCOP halfword, and put it into the fourth field of the WRITE CCW. For a WRITE CCW, this count has to be exact, even though the SILI bit is on. Now, since the second field of the WRITE CCW points to the same buffer area where the data was just put, so we just EXCP the OUTIOB, referring to the WRITE CCW, and upon correct completion, the data gets written out as a block, to the output tape. It's that simple, except for handling error conditions. See the code in the COPYMODS program at labels INERR and OUTERR for further details about how to handle READ and WRITE errors. OTHER TAPE OPERATIONS USING EXCP If you look at the list of opcodes I've mentioned in Figure 4, you'll see that there's quite a world of things you can program with a tape on a tape drive. And of course you want to see an explanation of how to use all these opcodes. If you can't get the 3480 manual I mentioned above, because it's too old, you can get the 3490E equivalent, called "IBM 3490 Magnetic Tape Subsystem Hardware Reference" (GA32-0127). And that has pretty much the same explanations in it, as the older 3480 manual. Programming techniques for the other opcodes follow the same sort of idea that we've shown for the READ and WRITE opcodes, except that sometimes you have to be careful with the quantity in the "bytes moved" halfword (fourth field) of the CCW. If you're writing a Tape Mark, it's advisable to set that field to X'0000' or X'0001', although the "real tape" hardware doesn't strictly require that. I found out that the OS/2 virtual tape emulator, and its equivalent for Hercules virtual tapes, is very particular about the bytes moved field, when you're not actually executing opcodes that move bytes. In any case, I've given you a start here. And I hope many of you will find a lot of fulfilment in learning how to manipulate tapes on tape drives. If you follow these ideas out, I guarantee you'll get a lot of joy. And even if not, this discussion has opened your eyes. Best of luck to all of you. See you next month! * * * * * * * * * * * * * * * * * * * * * * * Figure 1. A group of CCWs Coded in an Assembler Program. For good measure, I'm showing a Transfer in Channel CCW (a CCW "branch instruction") too. This group of CCWs runs all the operations used by the COPYMODS program from File 229 of the CBT Tape. These CCWs do not all execute as a chain. The chaining bit (X'4000' in the third field of each CCW shown) says that after executing this CCW operation, the tape drive should execute the next one too. But if this bit is turned off (when the third field reads X'2000' instead of X'6000'), then the chain stops there. Opcode Buffer Control Bytes Opcode (Hex) Address Bits Moved Interpretation INCCW DC X'02',AL3(INAREA),X'2000',X'FFFF' Read * end of chain OUTCCW DC X'01',AL3(INAREA),X'2000',X'FFFF' Write * end of chain REWCCW DC X'07',AL3(INAREA),X'6000',X'FFFF' Rewind DC X'03',AL3(INAREA),X'2000',X'FFFF' No Operation * end of chain BACKCCW DC X'2F',AL3(INAREA),X'6000',X'FFFF' Backspace 2 files BK1FCCW DC X'2F',AL3(INAREA),X'6000',X'FFFF' Backspace one file DC X'03',AL3(INAREA),X'2000',X'FFFF' No Operation * end of chain BK1BCCW DC X'27',AL3(INAREA),X'6000',X'FFFF' Backspace block DC X'03',AL3(INAREA),X'2000',X'FFFF' No Operation * end of chain BYPDCCW DC X'27',AL3(INAREA),X'6000',X'FFFF' Backspace Block DC X'3F',AL3(INAREA),X'6000',X'FFFF' Forward Space File DC X'2F',AL3(INAREA),X'6000',X'FFFF' Backspace over T.M. DC X'03',AL3(INAREA),X'2000',X'FFFF' No Operation * end of chain * For Good Measure, here's how you do a branch with CCW chains. TIC DC X'08',AL3(TGTCCW),X'4000',X'0001' Transfer in Channel * i.e. Branch to TGTCCW * * * * * * * * * * * * * * * * * * * * * * * Figure 2. The ECB and IOB, as they may appear in an Assembler Program. The IOB is what gets executed, and the ECB tells you when the I/O execution has finished. Here there are two of these--one for the input tape READ, and one for the output tape WRITE. * ----------------------------------------------------------------- * INECB DC F'0' ECB for Input Tape * ----------------------------------------------------------------- * * IOB for Input Tape INIOB DC X'02000000' DC A(INECB) Address of ECB that gets posted INCSW DC 2F'0' Status after IO operation (CSW) INCCWPT DC A(INCCW) Address of CCW (possibly a chain) DC A(IN) Address of DCB for File DC F'0' DC X'00010000' * ----------------------------------------------------------------- * OUTECB DC F'0' ECB for Output Tape * ----------------------------------------------------------------- * * IOB for Output Tape OUTIOB DC X'02000000' DC A(OUTECB) Address of ECB that gets posted OUTCSW DC 2F'0' Status after IO operation (CSW) OUTCCWPT DC A(OUTCCW) Address of CCW (possibly a chain) OUTDCBPT DC A(OUT1) Address of DCB for File DC F'0' DC X'00010000' * * * * * * * * * * * * * * * * * * * * * * * Figure 3. This is a block of code from the COPYMODS program, which does a READ of a block of data from a tape, and then tells you how many bytes were in the block that we just read. The buffer where the data is copied, is referred to in the CCW (and is called INAREA in this program). * First, we're going to READ a block of data from the INPUT tape. EXCP INIOB Do the READ (you EXCP an IOB) WAIT ECB=INECB Wait for READ until ECB is posted TM INCSW+4,X'01' Test the CSW if a T.M. was encountered BO READIN1 YES CLI INECB,X'7F' Otherwise, did READ complete normally? BNE INERR NO -- ERROR * Now, we're going to WRITE this same data to the OUTPUT tape. MVI OUTCCW,X'01' Set OUTPUT CCW to WRITE * So we calculate the number of bytes in the block we just read. * LH R2,INCCW+6 R2=READ LENGTH - (works only up to 32K) * The following instructions work to 64K XC FULLWORK,FULLWORK CLEAR AREA COMPLETELY MVC HALFWORK(2),INCCW+6 Maximum bytes to move from CCW. L R2,FULLWORK LOAD R2 WITH FULL LOW ORDER * LH R3,INCSW+6 R3=RESIDUAL BYTE COUNT (works only up to 32K) * The following instructions work to 64K MVC HALFWORK(2),INCSW+6 Residual byte count - bytes not moved L R3,FULLWORK LOAD R3 WITH FULL LOW ORDER SR R2,R3 Subtracting gives actual bytes moved STH R2,BYTESCOP SAVE QUANTITY OF BYTES COPIED * * . . . . . etc. * FULLWORK DS 0F Upper halfword is zeroes. DC H'0' HALFWORK DC H'0' Lower halfword is work area. * BYTESMVD DS 0F FULLWORD OF CURRENT BYTES MOVED BYTESCOH DC H'0' HI ORDER - SHOULD BE ALWAYS ZERO BYTESCOP DC H'0' CURRENT NUMBER OF BYTES COPIED FROM INPUT * * * * * * * * * * * * * * * * * * * * * * * * Figure 4. Operation Codes for a 3480 Tape Drive. This information comes from IBM Manual GA32-0042, IBM 3480 Magnetic Tape Subsystem Reference: Channel Commands, Status and Sense Bytes, and Error Recovery Procedures. Operation Code Meaning of the Operation (one byte in Hex) B7 Assign 27 Backspace Block 2F Backspace File E3 Control Access 97 Data Security Erase 17 Erase Gap 37 Forward Space Block 3F Forward Space File 9F Load Display 4F Locate Block DB Mode Set 03 NOP (No Operation) 02 Read 0C Read Backward 22 Read Block ID 12 Read Buffer 24 Read Buffered Log 07 Rewind 0F Rewind and Unload 04 Sense E4 Sense ID 34 Sense Path Group ID AF Set Path Group ID C3 Set Tape-Write-Immediate 5B Suspend Multipath Reconnection 43 Synchronize C7 Unassign 01 Write 1F Write Tape Mark 00 Test I/O * * * * * * * * * * * * * * * * * * * * * * * Figure 5. The DCB Macro as coded to refer to a TAPE device, and to use EXCP as the access method. We normally to not need an EXLST parameter in this DCB, but I want to do a RDJFCB to find out information about the file we're looking at, and the RDJFCB needs an EXLST parameter to refer to an area where the JFCB can be copied into our program. You see that the same kind of DCB is coded for an input tape or an output tape, with EXCP. The opcode in each CCW will determine what is actually done to the file. YOU have all of the control, depending on what CCWs you code. IN DCB MACRF=(E),DDNAME=IN,DEVD=TA,DSORG=PS,RECFM=U, X EXLST=INEXLST OUT1 DCB MACRF=(E),DDNAME=OUT1,DEVD=TA,DSORG=PS,RECFM=U, X EXLST=OUTEXLST