“The Happy Mainframe” or “WWzD: What Would z Do?”
I am happy to welcome David Staudacher, who begins a series of blogs about solving problems with elegant, succinct assembler code – code that System z itself would write (if it could). David has been writing Mainframe code in Assembler and COBOL for over 35 years, in both vendor software and business application environments. He is currently employed with the State Employees’ Credit Union of North Carolina and co-manages the “Mainframe Assembler Professionals” and “Mainframe [COBOL, etc] Experts” Groups on LinkedIn.
Problem: Read Error on Newly Allocated, Empty Sequential Disk Files
Example:
// EXEC PGM=IEFBR14
//NEWFILE DD SPACE=(TRK,1),DSN=&&FILE,RECFM=FB,LRECL=80,DISP=(,PASS)
//REPRO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE DD DISP=SHR,DSN=&&FILE
//OUTFILE DD SYSOUT=*,DCB=*.INFILE
//SYSIN DD *
REPRO INFILE(INFILE) OUTFILE(OUTFILE)
/*
Result:
PROCSTEP RC EXCP
NEWFL 00 4
REPRO 12 24
…with:
IEC141I 013-34,IGG0191I,,,INFILE
http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/IEA2M7C0/3.70 – IEC141I
Basically, there’s no EOF mark and no DCB information in the DSCB because the file was never OPENed for Output, even though RECFM and LRECL were specified in the JCL.
Essential Solution: A program to use with file allocation (rather than IEFBR14), sufficient just to Open and Close the file, thus creating a valid and usable DSCB.
Using this OPEN/CLOSE program instead of IEFBR14 …
// EXEC PGM=PSINIT “PSINIT” = (P)hysical (S)equential (INIT)ialization
//NEWFILE DD SPACE=(TRK,1),DSN=&&FILE,RECFM=FB,LRECL=80,DISP=(,PASS)
//REPRO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE DD DISP=SHR,DSN=&&FILE
//OUTFILE DD SYSOUT=*,DCB=*.INFILE
//SYSIN DD *
REPRO INFILE(INFILE) OUTFILE(OUTFILE)
/*
… now everything is hunky-dory:
PROCSTEP RC EXCP
NEWFL 00 9
REPRO 00 26
This is an excellent opportunity to “make the Mainframe happy” with some “elegant machine code” written in Assembler!
The essential solution can be accomplished with as little as one DCB, six machine instructions and a fullword aligned 4-byte Parameter List (DCB pointer with option bits in the high-order byte):
(1) The DCB is: DCB DSORG=PS,DDNAME=NEWFILE,MACRF=W
Note: The DCB here specifies “MACRF=W
”, which makes this a BSAM DCB.
A QSAM DCB (MACRF=PM or PL) would work just as well, but since we only need OPEN and CLOSE, simple BSAM works just fine.
The DDNAME parameter (here = “NEWFILE”) must also match the DDNAME used in the JCL.
(2) The fullword-aligned Parameter List (in 4 contiguous bytes) is:
- Fullword Alignment:
DC 0F’0’
- Option Bits:
DC X’8F’
(see “Bit Settings for OPEN (SVC 19) and Bit settings for CLOSE (SVC 20)” below for bit meanings) - DCB Pointer:
DC AL3(DCB)
From “MVS Diagnosis Reference” (GA22-7588), the relevant option byte bit settings for the necessary OPEN (SVC 19) and CLOSE (SVC 20) in this case are:
Bit Settings for OPEN (SVC 19) Bit Settings for CLOSE (SVC 20) 1... .... = Last entry indicator
.... 1111 = OUTPUT1... .... = Last entry indicator
Notice how there is no overlap using these particular bit settings. Thus, the same Parameter List can be used forboth OPEN and CLOSE.
(3) The Six Machine Instructions are:
-
X’4120bddd’
– Load R2 with the Address of the Parameter List (’bddd’is the Base+Displacement Parameter List address, determined at assembly time).Note: Loading R1 would be sufficient, but subsequent SVC 19 modifies R1 so the less volatile R2 is used instead so address can be easily reloaded for CLOSE (SVC 20). X’1812’
– Load R1 with address of required Parameter List for SVC 19 (OPEN).X’0A13’
– Issue SVC 19 (OPEN).X’1812’
– Reload R1 with address of required Parameter List for SVC 20 (CLOSE).X’0A14’
– Issue SVC 20 (CLOSE).X’07FE’
– BR 14
This solution, unlike most written in so-called “high level” languages, will work with any sequential disk file, of any valid record length and any Record Format.
Specific and essential DCB information, like RECFM, LRECL and BLKSIZE, are obtained via JCL and SMS defaults rather than hardcoded in the program. Nice!
Here’s the Assembly ready code then, exactly as the machine might write it, with:
(1) A “USING
” on R15 (R15 = Base) since the machine “knows” R15 contains the Entry address at runtime.
(2) A label “PLIST
” on the Parameter List, giving the displacement so the address can be calculated at runtime.
(3) A label “DCB
” on the DCB, so “AL3(DCB)
” will contain the DCB address at runtime.
PSINIT CSECT
USING PSINIT,15 R15 = BASE
LA 2,PLIST R2 -> PARMLIST
LR 1,2 R1 -> PARMLIST
SVC 19 ISSUE OPEN SVC
LR 1,2 R1 -> PARMLIST
SVC 20 ISSUE CLOSE DCB
BR 14 RETURN
PLIST DC 0F’0’,X'8F',AL3(DCB)
DCB DCB DSORG=PS,DDNAME=NEWFILE,MACRF=W
END PSINIT
Knowing the machine code generated by the “MF=E” forms of the OPEN and CLOSE macros, and the “MF=L” form of OPEN, the Assembly code can be simplified even further to just 9 statements…
PSINIT CSECT
USING PSINIT,15 R15 = BASE
LA 2,PLIST R2 -> PARMLIST
OPEN MF=(E,(2)) OPEN FILE
CLOSE MF=(E,(2)) CLOSE FILE
BR 14 RETURN
PLIST OPEN MF=L,(DCB,OUTPUT)
DCB DCB DSORG=PS,DDNAME=NEWFILE,MACRF=W
END PSINIT
… which generate exactly the same load module.
– “OPEN MF=(E,(2))
” generates “LR 1,2
” and “SVC 19
”.
– “CLOSE MF=(E,(2))
” generates “LR 1,2
” and “SVC 20
”.
– “OPEN MF=L,(DCB,OUTPUT)
” generates “DC 0F’0’
”, “AL1(143)
” and “AL3(DCB)
”. (note: “AL1(143)” = “X'8F'
”)
NEXT: The same solution using AMODE 31 with an external DCB module, loaded dynamically at runtime.