/* rexx */ /* TRACE I */ /*-------------------------------------------------------------------*/ /* Parse comma delimited "CQUERY DEVN(x'nnnn') UNFORMAT" data */ /*-------------------------------------------------------------------*/ /* EXEC NAME: PPRCSTAT */ /* DATE WRITTEN: 07/30/2008 */ /* AUTHOR: Bruce R. Gillispie - Tech Support - zSeries BRG */ /* DESCRIPTION: EXEC to CQUERY PPRC Device Pair's "A" to "B" status */ /* INVOCATION: ISPF opt 6, enter PPRCSTAT for current GDG */ /* ISPF opt 6, enter PPRCSTAT n for -n GDG (max of 129)*/ /* UPDATES: 03/21/12 brg - upd add info if error on meaning of */ /* susp(n) and rc not 13 for paths */ /* 03/17/12 brg - chg layout of parsing vars for easy */ /* read & error checking. */ /* Setup: /* 1. Store list of UCBs in CNTL member /* CQUERY DEVN(x'nnnn') UNFORMAT /* 2. Run Batch TSO to issue CQUERY display commands /* and store results into Data Set (GDG) /* 3. Execue PPRCSTAT Rexx to build summary view /* /* Disclaimer: /* The "PPRCSTAT" utility IS NOT in the Public Domain Freeware Software. /* You may use the "PPRCSTAT" utility AT YOUR OWN RISK, it is provided for /* your enjoyment and neither the Author or his Employer provides any /* warranty for its use. /* /* Please leave author name and internet e-mail address in the comment section /* /* Author: /* Bruce R. Gillispie /* gillispi@texasrock.com /* /*-------------------------------------------------------------------*/ /* call routine section */ /* ----------------------------------------------------------------- */ Parse Arg A1 /* if a1 blank gdg(0) selected */; call house_keeping call gdg_realname call alloc_files call read_input_rec call close_input_file call alloc_wrkfile call parse_data call pull_detail_recs call count_percent call build_report call display_rpt call close_work_file exit 00 /* */ /* --------------------------------------------------------- */ /* Parse "CQUERY DEVN(x'nnnn') UNFORMAT" data */ /* maintain comma delimited data to simplify processing */ /* --------------------------------------------------------- */ parse_data: do i = 1 to record.0 parse var record.i w1.i . Select when substr(w1.i,1,5) = 'TIME-' then do parse var record.i w1.i push ' '; push w1.i end when substr(w1.i,1,6) = 'VOLUME' then do nrecs = nrecs + 1 i = i + 1 /* pos to ucb, type, and state record */ parse var record.i w1.i','w2.i','w3.i','w4.i','. ; make_rec.nrecs = w1.i || ',', || w2.i || ',', || w3.i || ',', || w4.i || ','; i = i + 2 /* pos to ports and rc record */ parse var record.i .','w5.i','w6.i','w7.i','w8.i','. ; make_rec.nrecs = make_rec.nrecs, || w5.i || ',', || w6.i || ',', || w7.i || ',', || w8.i || ','; i = i + 1 /* pos to track and precent record */ parse var record.i w9.i','w10.i','w11.i','. ; make_rec.nrecs = make_rec.nrecs, || w9.i || ',', || w10.i || ',', || w11.i || ','; /* 03/29/2010 brg add Suspend error routine */ /*1234+1234+1*/ if substr(make_rec.nrecs,14,5) = 'SUSP(' then do errnum = errnum + 1; errmsg.errnum = make_rec.nrecs; end /* 03/18/2012 brg add Simplex error routine */ /*1234+12*/ if substr(make_rec.nrecs,7,7) = 'SIMPLEX' then do errnum = errnum + 1; errmsg.errnum = make_rec.nrecs; end if substr(make_rec.nrecs,41,2) <> '13', | substr(make_rec.nrecs,53,2) <> '13' then do errnum = errnum + 1; errmsg.errnum = make_rec.nrecs; end end Otherwise iterate i End end i if errnum <> '0' then do queue ' ------------------------------------------------- ' queue ' 'errnum 'units flagged for review... ' queue ' Check RC values and look for Susp(n) or Simplex ' queue ' do a find on "errors" to locate start of report. ' queue ' ------------------------------------------------- ' queue ' ' end make_rec.0 = nrecs; /* number of usable records for 2nd parse */ return retcode; /* --------------------------------------------------------- */ /* 2nd parse - disgard unwanted data */ /* --------------------------------------------------------- */ pull_detail_recs: procedure expose, make_rec. ucb. port1. prc1. port2. prc2. tleft. ttrk. pcent., total_trks total_trks_left stat1.; do a=1 to make_rec.0 parse var make_rec.a , /* parsed combined data */ ucb.a',' , /* device ucb - A side */ .',' , /* unused type, Primary */ stat1.a',' , /* PPRC state Pending, Susp(n) */ .',' , /* unused state, act or unact */ port1.a',' , /* ficon port local and remote */ prc1.a ',' , /* return code state from path */ port2.a',' , /* ficon port local and remote */ prc2.a',' , /* return code state from path */ tleft.a',' , /* number of tracks out of sync */ ttrk.a',' , /* total tracks on device */ pcent.a',' ; /* percent device in sync */ /* ----------------------------------------------- */ /* 03/17/2012 BRG - its a starting point... */ /* error routine for Suspend or Simplex units */ /* make math vars number to prevent abend */ /* ----------------------------------------------- */ if datatype(ttrk.a) <> 'NUM' then ttrk.a = 0; if datatype(tleft.a) <> 'NUM' then tleft.a = 0; /* ----------------------------------------------- */ total_trks = total_trks + ttrk.a; total_trks_left = total_trks_left + tleft.a; end return /* --------------------------------------------------------- */ /* build display screen */ /* --------------------------------------------------------- */ build_report: utot = p100+p090+p080+p070+p060+p050+p040+p030+p020+p010+p000; t_GBs = ((total_trks * 56664)/(10**9)) t_GBs_l = ((total_trks_left * 56664)/(10**9)) p_full = ((t_GBs-t_GBs_l) / t_GBs) * 100 /* percent full */ /* ------------------------------------------------------- */ queue 'Giga Bytes of Data to PPRC....: ', right(format(t_GBs,4,2),7); /* ------------------------------------------------------- */ queue ' Data in Sync....: ', right(format(t_GBs,4,2) - format(t_GBs_l,4,2),7), right(format(p_full,4,2),8)'%'; /* ------------------------------------------------------- */ queue ' Data out of Sync: ', right(format(t_GBs_l,4,2),7), right(100 - format(p_full,4,2),8)'%'; queue ' '; queue ' Unit % counts..... 100% ='right(p100,5) queue ' 90% ='right(p090,5) queue ' 80% ='right(p080,5) queue ' 70% ='right(p070,5) queue ' 60% ='right(p060,5) queue ' 50% ='right(p050,5) queue ' 40% ='right(p040,5) queue ' 30% ='right(p030,5) queue ' 20% ='right(p020,5) queue ' 10% ='right(p010,5) queue ' 0% ='right(p000,5) queue ' Number of Units........ ='right(utot,5) queue ' ' /* ------------------------------------------------------- */ /* add detail data */ /* ------------------------------------------------------- */ queue '-------------------------------------------------------------------'; queue 'UCB PFCASFCA RC PFCASFCA RC TrksOut Tot-Trk %in PPRC State' queue '----+----1----+----2----+----3----+----4----+----5----+----6----+--'; do a=1 to make_rec.0 queue ucb.a ||' '||, /* device ucb - A side */ port1.a||' '||, /* ficon port local and remote */ prc1.a ||' '||, /* return code state from path */ port2.a||' '||, /* ficon port local and remote */ prc2.a ||' '||, /* return code state from path */ tleft.a||' '||, /* number of tracks out of sync */ ttrk.a ||' '||, /* total tracks on device */ pcent.a||' '||, /* percent device in sync */ stat1.a; /* PPRC state Pending XD is norm*/ end if errnum <> '0' then do queue '= errors ==================================================='; queue ' Susp(n) or Simplex or Path value needs review... '; queue ' '; queue ' if recovery is needed, review member RESYNC in the '; queue ' Your.DataSet.CMDS library. '; queue ' '; queue ' create/use a new member in the Your.DataSet.CMDS'; queue ' library with only the units to be recovered. '; queue ' '; queue ' Search for "return code" to find meaning of error '; queue '============================================================'; queue '----+----1----+----2----+----3----+----4----+----5----+----6----+--'; do b = 1 to errnum queue errmsg.b end call RCstate /* State return code information */ call RCpath /* Path return code infromation */ end queue ''; "execio * DISKW $tmplib$"; "execio 0 diskw $TMPLIB$ (FINIS"; return /* --------------------------------------------------------- */ /* Use CQUERY data to findout whats where... */ /* --------------------------------------------------------- */ count_percent: do i = 1 to make_rec.0 Select when pcent.i = '100' then do p100 = p100 + 1; iterate i; end when pcent.i < '100' & pcent.i >='090' then do p090 = p090 + 1; iterate i; end when pcent.i < '090' & pcent.i >='080' then do p080 = p080 + 1; iterate i; end when pcent.i < '080' & pcent.i >='070' then do p070 = p070 + 1; iterate i; end when pcent.i < '070' & pcent.i >='060' then do p060 = p060 + 1; iterate i; end when pcent.i < '060' & pcent.i >='050' then do p050 = p050 + 1; iterate i; end when pcent.i < '050' & pcent.i >='040' then do p040 = p040 + 1; iterate i; end when pcent.i < '040' & pcent.i >='030' then do p030 = p030 + 1; iterate i; end when pcent.i < '030' & pcent.i >='020' then do p020 = p020 + 1; iterate i; end when pcent.i < '020' & pcent.i >='010' then do p010 = p010 + 1; iterate i; end when pcent.i < '010' & pcent.i >='000' then do p000 = p000 + 1; iterate i; end Otherwise iterate i End End i return /* ------------------------------------------------------- */ /* Find most recent input GDG */ /* ------------------------------------------------------- */ /* Many thanks to Doug Nadel for sharing realname with us. */ /* http://www.sillysot.com/mvs/ */ /* ------------------------------------------------------- */ gdg_realname: if A1 = '' then do a1 = 0 ddin = realname('Your.DataSet.CQUERY.ALLDASD('A1')') end else do if datatype(A1) <> 'NUM' |, /* gota be number */ A1 <= '0' |, /* more than zero too */ A1 > '129' /* less than 130 */ then do say ' ' say ' Invalid selection input received, this routine expects: ' say ' number input range of 1 to 129 ' say ' ' say ' FYI... invalid input received was: ' A1 say ' ' exit 99 end else ddin = realname('Your.DataSet.CQUERY.ALLDASD(-'A1')') end return /* -------------------------------------------------------- */ /* Clean up and init a few vars */ /* -------------------------------------------------------- */ house_keeping: ADDRESS MVS "DELSTACK" a = 0 errmsg.= '' errnum = 0 nrecs = 0 p000 = 0 p010 = 0 p020 = 0 p030 = 0 p040 = 0 p050 = 0 p060 = 0 p070 = 0 p080 = 0 p090 = 0 p100 = 0 t_GBs = 0 t_GBs_l = 0 total_trks = 0 total_trks_left = 0 ttrk = 0 return /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Allocate Input files */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ alloc_files: dsname = ddin ; Address 'TSO' "ALLOC F(INPCNTL), DA('" || dsname || "') ", "SHR REUSE"; retcode = rc; /* Save the return code */ if retcode <> 0 /* Did it work ?? */ then do; /* no, tell them */ Say "Allocation failed with rc=" retcode; Say "For the DDIN File " dsname; return retcode; end; return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Read Input records into a Stem */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ read_input_rec: drop record. ; /* uninitialize variable */ "execio * diskr INPCNTL (STEM record."; "execio 0 diskr INPCNTL (FINIS"; return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Close Input file */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ close_input_file: Address 'TSO' 'FREE F(INPCNTL)' return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Allocate Work file */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ alloc_wrkfile: address TSO msg_status = MSG("OFF"); "FREE FI($TMPLIB$)"; "FREE ATTRLIST(DCB)"; msg_status = MSG("ON"); "ATTRIB DCB RECFM(F) LRECL(133) BLKSIZE(0)"; "ALLOC F($TMPLIB$) UNIT(VIO) SP(35,35) TRACK USING(DCB) NEW" return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Display Rpt using Library Services */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ display_rpt: "ISPEXEC LMINIT DATAID(LMID) DDNAME($TMPLIB$)" "ISPEXEC edit DATAID(&LMID)" "ISPEXEC LMFREE DATAID(&LMID)" return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Close Work file */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ close_work_file: "execio 0 diskw $TMPLIB$ (FINIS"; Address 'TSO' 'FREE F($TMPLIB$)' return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Signal On Error Routine */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ error: say '----------------------------------------------------------- ' say ' The return code from the command on line' SIGL 'is:' RC say '----------------------------------------------------------- ' call close_work_file call close_input_file exit 13; return retcode; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Return Codes from Path connection */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ RCpath: queue '------------------------------------------------------------'; queue ' Path return code information '; queue '------------------------------------------------------------'; queue ' 00=NO PATH '; queue ' 01=ESTABLISHED ESCON '; queue ' 02=INIT FAILED '; queue ' 03=TIME OUT '; queue ' 04=NO RESOURCES AT PRI '; queue ' 05=NO RESOURCES AT SEC '; queue ' 06=SERIAL# MISMATCH '; queue ' 07=SEC SSID MISMATCH '; queue ' 08=ESCON LINK OFFLINE '; queue ' 09=ESTABLISH RETRY '; queue ' 0A=PATH ACTIVE TO HOST '; queue ' 0B=PATH TO SAME CLUSTR '; queue ' 10=CONFIG ERROR '; queue ' 13=ESTABL FIBRE PTH <--- normal '; queue ' 14=FIBRE PATH DOWN '; queue ' 15=FIBRE RETRY EXCEED '; queue ' 16=SEC ADPTR INCPBL '; queue ' 17=SEC ADPTR UNAVAIL '; queue ' 18=FIBRE LOGIN EXCEED '; queue ' 1B=FIBRE DEGRADED '; queue ' 1C=FIBRE REMOVED '; queue ' FF=UNABLE TO DETERMINE '; return retcode; RCstate: queue '------------------------------------------------------------'; queue ' State return code information '; queue '------------------------------------------------------------'; queue 'Indicates whether the PPRC volume is in simplex, pending, '; queue 'duplex, suspended (suspend(n)), extended distance pending XD'; queue 'or extended distance susp(n).xd state. The value n for '; queue 'SUSPEND is one of the following: '; queue ' '; queue ' (3) - The PPRC volume pair was suspended by a host command '; queue ' to the primary site storage control. '; queue ' * Normal if you are DR testing or have issued a suspend'; queue ' volume cmd for some other reason. '; queue ' (4) - The PPRC volume pair was suspended by a host command '; queue ' to the recovery site storage control. '; queue ' (5) - A command issued by the primary site '; queue ' storage control to the recovery site storage control '; queue ' has suspended the pair. Only a recovery site storage '; queue ' control returns value 5. '; queue ' (6) - Internal conditions within either storage control '; queue ' have suspended the pair. Either storage control '; queue ' returns value 6. '; queue ' (7) - The transition of the recovery volume to the simplex '; queue ' state has suspended the pair. Only a primary site '; queue ' storage control returns value 7. '; queue ' (8) - The primary site storage control has suspended the '; queue ' pair as a result of abnormal conditions within the '; queue ' recovery site storage subsystem. These conditions may'; queue ' involve the storage control, its attached disk '; queue ' devices, and the ESCON paths between the two sites. '; queue ' The primary site storage control detects and reports '; queue ' this condition. '; queue ' (9) - Either an IPL, or a power interruption '; queue ' to either storage control, have suspended the pair. '; queue ' The storage control that received the interruption '; queue ' returns value 9. '; queue ' (A) - A CGROUP command with the FREEZE parameter '; queue ' has suspended the pair. You must query a primary '; queue ' device to receive value A. '; return retcode;