Introduction
Every site has this challenge and we all find different ways around the problem: How can I generate a list of DB2 subsystems defined to my current LPAR and whether they are active or not?
It may be that you want to know exactly that but more commonly this is the sort of thing that is needed to support a DB2 tools panel, validating which services are genuinely available.
Typically we find that customers resort to hard coded lists in the panel verification e.g.
VER(&SSID,NB,LIST,DG91,DGA1,DGB1)
In this example we have three DB2s listed (DG91,DGA1 and DGB1) which all happen to be the first members of data sharing groups. What happens if we need to run the second member of DB90 (DG92) on this LPAR? What if we create a new data sharing group?
Determining what DB2 services are defined to your LPAR can be done in a number of ways. This blog outlines an approach which can be used on any site with DB2 for z/OS.
Some Control Blocks
Inevitably, finding this information will require some gentle control block surfing. The good new is that these are all well understood and documented.
When we define a subsystem to z/OS we apply the details to the IEFSSNxx PARMLIB member. These entries are used by z/OS during IPL processing to build the subsystem vector table, which is a chain of control blocks, one for each formal MVS subsystem.
Each entry in the vector table is a SSCVT control block (SSCT) and as well as names and chaining pointers, also includes a couple of “user” fields. When we define DB2 in IEFSSNxx, the entries look like this:
SUBSYS SUBNAME(DBB1)
INITRTN(DSN3INI) INITPARM(‘DSN3EPX,-DBB1,S,DBB0’)
The INITRTN (DSN3INI) is driven at IPL (or SETSSI ADD) to do any setup initialisation. In the case of DB2 one of the things that it does is build the ERLY control block and hang this off the first of the SSCT user fields. So now we know why the contents of the SDSNLINK are usually referred to as ERLY-code.
Part of the DSN3INI population/build actions for the ERLY include saving the configuration options (cf INITPARM) and loading additional modules. This means that the parms can all be found recorded in the ERLY.
Note also that ERLY is the stepping off/anchor point for all of DB2’s control blocks that support it’s operation. As an example, the SCOM (which exists in the MSTR address space) is chained from the ERLY once it’s created (at subsystem startup).
Figure 1 – Control Block Chaining
It’s worth noting that MQ on z/OS is largely based on DB2 for z/OS. As a result it also has an ERLY (same ID and eyecatcher) and SCOM pointer. To differentiate between MQ subsystems and DB2 ones, check that the ERLY interface module name is DSN3EPX (as in INITPARM in the IEFSSNxx entry) rather than CSQ3EPX for MQ.
Details of each of these control blocks can be found in:
- PSA : SYS1.MACLIB(IHAPSA)
- CVT : SYS1.MACLIB(CVT)
- JESCT : SYS1.MACLIB(IEFJESCT)
- SSCT : SYS1.MACLIB(IEFJSCVT)
- ERLY : Layout in SDSNSAMP(DSNWCBDS)
Some Code
The following is some example Rexx code that walks these control blocks to report all of the DB2 subsystems defined on an LPAR and whether they are active or not:
/* Rexx -------------------------------------------------------------*/
/* */
/* DB2SSIDS */
/* ======== */
/* Return the status of all DB2 subsystems defined on this LPAR. */
/* */
/* Parms : None */
/* */
/* Output : A line for each subsystem that is defined on the LPAR of */
/* the following form: */
/* */
/* ssid { ACTIVE } */
/* */
/* i.e. each subsystem is listed and is flagged as ACTIVE */
/* if running. */
/* */
/*-------------------------------------------------------------------*/
/* */
/* James Gill - November 2014 */
/* */
/*-------------------------------------------------------------------*/
numeric digits 20
psa = 0 /* psa absolute address */
psa_cvt = 16 /* psa->cvt ptr offset */
cvt_jesct = 296 /* cvt->jesct ptr offset */
jesct_sscvt = 24 /* jesct->sscvt ptr offset */
sscvt_sscvt = 4 /* sscvt->next sscvt ptr offset */
sscvt_ssid = 8 /* sscvt subsystem id offset */
sscvt_ssvt = 16 /* sscvt->ssvt */
sscvt_suse = 20 /* subsystem user field (->ERLY) */
sscvt_syn = 24 /* has table synonym pointer */
sscvt_sus2 = 28 /* subsystem user field */
sscvt_eyec = 0 /* sscvt eyecatcher offset */
erly_id = 0 /* ERLY block identifier ( = x'A5') */
erly_size = 2 /* ERLY block size (= x'A8') */
erly_eyec = 4 /* ERLY block eyecatcher */
erly_ssid = 8 /* DB2 subsystem id */
erly_mstr = 12 /* MSTR STC name */
erly_pclx = 20 /* PC LX value */
erly_ssvt = 34 /* ptr back to SSVT */
erly_ssgp = 38 /* ptr to DSN3SSGP (= 0 is subsystem is down) */
erly_scom = 56 /* ptr to SCOM (subsys communication block) */
erly_modn = 84 /* DSN3EPX */
cvt = c2d(storage(d2x(psa + psa_cvt),4))
jesct = c2d(storage(d2x(cvt + cvt_jesct),4))
sscvt = c2d(storage(d2x(jesct + jesct_sscvt),4))
do while sscvt /= 0
subsystem = storage(d2x(sscvt + sscvt_ssid),4)
ssctssvt = c2d(storage(d2x(sscvt + sscvt_ssvt),4))
ssctsuse = c2d(storage(d2x(sscvt + sscvt_suse),4))
ssctsyn = c2d(storage(d2x(sscvt + sscvt_syn),4))
ssctsus2 = c2d(storage(d2x(sscvt + sscvt_sus2),4))
if ssctsuse /= 0 then do /* pointing to ERLY? */
erly = ssctsuse
erlyid = c2x(storage(d2x(erly + erly_id),2))
if erlyid = "00A5" then do /* id = ERLY */
erlysize = c2d(storage(d2x(erly + erly_size),2))
erlyeyec = storage(d2x(erly + erly_eyec),4)
if erlyeyec = "ERLY" then do /* eyecatcher = ERLY */
modn = strip(storage(d2x(erly + erly_modn),8))
if modn = "DSN3EPX" then do
scom = c2d(storage(d2x(erly + erly_scom),4))
if scom = 0 then say subsystem
else say subsystem" ACTIVE"
end
end
end
end
sscvt = c2d(storage(d2x(sscvt + sscvt_sscvt),4))
end
return