MVS TOOLS AND TRICKS OF THE TRADE November 1992 Sam Golob MVS Systems Programmer sbgolob@cbttape.org Sam Golob is a Senior Systems Programmer HOW I FOLLOWED MY OWN ADVICE, AND, HOW NOT TO UPGRADE JES2 EXITS. In our last two columns, we discussed two clists that are very useful in SMP/E related areas. The first clist called PTF, uses the TSO command called REVIEW from the CBT Tape to look at all your received ptfs. The idea is to use your SMPPTS dataset as a data repository to keep accurate information about recent system fixes. The second clist, called SMPETSO, runs SMP/E in the foreground for the purpose of doing quick CSI inquiries and UCLIN adjustments. These clists are illustrated in the two figures. This month, I'd like to tell a true-to-life story about how I used my own tools. The installation I'm now at, runs MVS/ESA 4.1 with JES2 4.1.0. They have a JES2 Exit 1 routine which produces customized separator pages for all non-FSSMODE printouts. I've been told that this routine stopped working properly at the ESA 3.1.1 level. At the 4.1 level, it started getting 0C4 abends at random intervals. Clearly, something had to be done about the coding of this exit. THE PROBLEM WITH JES EXIT UPGRADES. I have to preface this discussion with the usual "method" of quickly upgrading JES2 exits from one JES2 release to another. This method has been used since JES2 exits have been available, and we're probably all "guilty" of exploiting it most of the time. The idea is to obtain IBM's "conversion notebook" or whatever documentation they've distributed to outline the changes (and pitfalls) of the new JES2 release. Then you assemble your old JES2 exit using the new JES2 macros you've just installed. Finally, you fix any assembly errors that happen, following the hints and instructions in the conversion document. Then you "run the sucker" and if it doesn't bomb, you put it into production. I'm exaggerating just a wee bit, but you can probably see what is wrong with this picture. In this process, there's no study as to just how the exit works. It's all "external" and mechanical, and it assumes that IBM hasn't changed any of the logic interfacing with what the exit does. That's a very false assumption, since an installation's customized exit can do almost anything, and ultimately, it seems prudent for the systems programmers to understand what mechanisms and processes their JES exits are actually using. Our case seemed typical of the above mismanagement. Tracing the immediate cause of the 0C4 abends was the first problem. I got help from several sources worth mentioning, one of whom was our esteemed fellow NaSPA member Tom Bryant, but I'll leave that discussion for another time. For now, I'll tell you what caused the abends, and how I followed my own advice to go about fixing them. My particular case was rather specific, but my methods are so general, that you'll undoubtedly derive considerable benefit by looking over my shoulder. RDT ENTRIES, AND HOW THEY'RE SEARCHED. Our abends were caused by a change in the construction of JES2's RDT or Remote Destination Table entries. The RDT defines remote printer addresses to JES2. Our exit needed to read the RDT so the separator page could display the remote node and destid of the printer being used to print the job. Our exit was trying to read the RDT the "old way", across a contiguous block of storage. But IBM had actually changed the RDT's construction so it needed to be read another way, through entry chaining across non-contiguous pages. IBM made that change, to allow for dynamic adding of new remote destids through $ADD operator commands. Our installation services 2200 remote printers, with the RDT table covering 14 scattered pages in storage. The disparity between contiguous reading, and non-contiguous construction of the RDT table caused our exit to occasionally cross the page boundaries and try to look at storage that JES2 hadn't GETMAIN'ed, resulting in the abend 0C4's. What does this have to do with our two clists? Once the problem was diagnosed, I had to determine the correct method of actually reading the RDT so I could fix our exit. From looking at the dump, the RDT was a hodgepodge. Whole pages were being GETMAIN'ed for RDT use. Each page had a heading marker. It was not clear if the heading marker was used to read the RDT entries, or just to tag pages earmarked for RDT use. Entries were scattered across pages, usually crowded toward the end of the page, and often an entry would point to the next entry several pages away. I had to discover what IBM really wanted here. To solve my own problem with the user code, I wanted to imitate IBM's code exactly, or else we'd continue to get errors. So in order to discover IBM's ways, I had to look at IBM's code. But how do I find examples of IBM's code, at the correct maintenence level? Each RDT entry is described by the JES2 macro called $RDT. I used the SMPETSO clist to quickly find the UMID (update level) of this macro. It was at PTF level UY76237. The $RDT macro in our exit's assembly listing had been marked at OY47804. A LIST SYSMOD inquiry to SMPETSO revealed that apar BY47804 was indeed superseded by ptf UY76237, so we were looking at the current level of the $RDT macro. My next deduction was that if IBM was indeed introducing a new construction of an RDT entry with ptf UY76237, they also would have to change their own code to read the RDT the new way. I'd bet that good old ptf UY76237 probably ALSO changed any JES2 code which had to read the RDT. That would be a good place for me to learn how to do the same thing for my exit's code. I don't have to mention that my next step was to use the PTF clist to look at the actual text of ptf UY76237. To find IBM code that had been changed, I scanned the ptf for ++SRCUPD (source update) SMP statements to look for likely examples. A promising update was to the module HASPIRRE that is a component of HASPINIT. Another quick use of the SMPETSO clist showed me that the HASPIRRE module was at RMID (replacement level) UY76237, and that the HASPIRRE source had UY76237 as its highest numbered UMID. This indicated that an assembly listing of HASPIRRE would probably produce a coding example that I could copy for our exit's use. Since UY76237 hadn't been ACCEPTed yet, I went to the SMPSTS to get the source code. I assembled the code, using the SMPMTS as the highest concatenated macro library, and was soon in possession of an assembly listing. This listing quickly revealed that the RDT was correctly searched by a 3-instruction loop, which ended in a zero pointer to the next RDT entry. Case closed and problem solved. We have another happy ending to a perplexing system problem. SO WHAT DO WE LEARN? IBM introduces a lot of code rewrites and SPE's (Small Programming Enhancements) in ptfs. If you'll look at the actual text of a such a ptf, you'll have the basis of learning everything that IBM needed to do with its own code, to make any necessary changes. There couldn't be a better learning example than that. Of course, we were helped immensely by the fact that JES2 is (still) distributed in source code. We can fully exploit these techniques while looking at JES2 or JES3 problems. What could we gain from this method if the changes were in object module form only and the ptf contains only object modules? In this forum, I can't recommend disassembling IBM's object decks. But I can recommend learning how to READ object decks, or I can recommend linkediting them and use zapping tools to discover their contents. That is the subject of another session. See Fred Schuff's article in the May 1992 issue of "Technical Support" on the linkage editor. Fred also talks there about some of the structure of object decks. More practically, we can point out that a ptf can always be examined for the EXACT NAMES of all the components it affects. If you examine the actual ptf closely, you can learn a lot about what really was changed, and how it was changed. You are in possession of the actual changes, the "genuine article". This is much better than only looking at the cover letter. Any changes to macros, which are in source update form, or to source, if present, can shed additional light on a problem resulting from IBM maintenance. So to summarize: Examining a ptf directly (through the PTF clist) and examining SMP/E entries directly (through the SMPETSO clist) are essential techniques for good system detective work. I am a great believer in not getting my information secondhand (from ISPF SMP/E inquiries) if it is available firsthand, from the ptfs and SMP/E entries themselves. Learn ABOUT your system FROM your system! Good luck in these and all future endeavors. I'll see you next month. * * * * * * * * * * * * * * * * * * * * * * * Figure 1. THE "PTF" INQUIRY CLIST. This clist, which takes advantage of the capabilities of the "REVIEW" TSO command on the CBT MVS Tape (File 134 for source and File 135 for load), is extremely simple, but extremely useful. Assemble REVIEW from File 134 or copy the load module from File 135 and have fun. PROC 1 SYSM REVIEW 'SMPE.SMPPTS(&SYSM)' /* /* This assumes that your PTS dataset is called SMPE.SMPPTS. /* /* Assuming the member name of this clist is PTF, and it resides /* in a library in the SYSPROC ddname concatenation of your TSO /* session, you merely execute %PTF UY78914 to look at ptf UY78914. /* It's that simple. PF3 to end. You're back where you were. /* * * * * * * * * * * * * * * * * * * * * * * * FIGURE 2. THE SMP/E INQUIRY CLIST. WE'LL CALL THIS CLIST "SMPETSO". This CLIST invokes SMP/E in the foreground under TSO exactly the same way as it would run in the background in batch. Input of commands and output of results go to the terminal. Since there might be quite a few lines of output, it is preferred to run this CLIST in TSO "Session Manager mode", which can preserve and print up to several thousand lines of TSO output. See your TSO/E Customization Guide or this column in last month's issue on how to set up your TSO session to run in Session Manager mode. PROC 0 VOLID CSI('SMPE.GLOBAL.CSI') UNIT(DISK) TYPE(SYS1) NOLOG - SYSOUT LOGDISP(MOD) NOPTS LIST() /** YES OR NO **/ SET VOLID = XRS003 /* SMP-CONTROLLED PACK */ IF LIST = YES THEN CONTROL LIST ELSE IF LIST = NO THEN CONTROL NOLIST CONTROL PROMPT WRITE *********************************************************** WRITE * * WRITE * WELCOME TO THE SMP INQUIRY SYSTEM. THIS MEANS * WRITE * MAKE INQUIRIES ONLY ........ * WRITE * * WRITE *********************************************************** WRITE WRITE T Y P E = &TYPE WRITE WRITE FOREGROUND EXECUTION OF SMP/E WRITE WRITE SYSTEM DEFAULT ====> &TYPE WRITE WRITE TYPE = &TYPE MVS SP 4.1.0 DFP/ESA WRITENR ENTER DESIRED TYPE ====> READ ANS IF &LENGTH(&STR(&ANS)) ^= 0 THEN SET TYPE=&STR(&ANS) IF &TYPE = SYS1 THEN SET VOLID = XRS003 /* TARGET PACK */ IF &TYPE = SYS1 THEN SET DIST = SMPDL1 /* DLIB PACK */ WRITE WRITE YOU HAVE SPECIFIED &TYPE AS THE SYSTEM. WRITE TARGET = &VOLID ---- DISTRIBUTION = &DIST WRITE ERROR GO TO ENDALL ATTN GO TO ENDALL ALLOC FI(SMPLIST) DA(*) ALLOC FI(SMPCNTL) DA(*) ALLOC FI(SMPRPT) DUMMY IF &NOLOG = NOLOG THEN ALLOC FILE(SMPLOG) DUMMY /* NO SMP LOG */ ELSE ALLOC FI(SMPLOG) &LOGDISP KEEP DA('SMPE.GLOBAL.SMPLOG') IF &NOPTS ^= NOPTS AND TYPE = SYS1 + THEN ALLOC FI(SMPPTS) SH REUSE DA('SMPE.GLOBAL.SMPPTS') IF &SYSOUT = SYSOUT THEN ALLOC FI(SMPOUT) SYS(T) /* HELD CLASS */ ELSE ALLOC FI(SMPOUT) DA(*) CALL 'SYS1.LINKLIB(GIMSMP)' 'CSI=&CSI' ENDALL: ERROR OFF ATTN OFF FREE FI(SMPLIST SMPRPT SMPCNTL SMPLOG SMPOUT SMPPTS) END