A Sample program to generate FDRinstant Statements
This SAS program generates FDRinstant statements to invoke flashcopy on IBM's ESS DASD. It should easy to adapt it to other kinds of disks. It assumes that the ESS box has been configured in a standard way, see the ESS TIPS pages for tips on how to configure a shark.
The outline process is
Get a list of all online disks from a DCOLLECT
Assign a dummy storage pool to non-sms volumes.
Delete all storage pools which do not need backup
Determine the flashcopy target UCB
create JCL
The SAS code
This code is supplied on an as-is basis, as a suggested way of doing things. It will need some tailoring for your site, and must be thoroughly tested before it goes anywhere near production. If you have a better way, or better code, I'm always willing to learn.
OPTIONS NODATE NONUMBER REUSE=YES WORKTERM MISSING=' ';
/* GET LIST OF ALL ONLINE VOLUMES, THEN SPLIT INTO SMS & non-SMS */
DATA VOLA_LST; /* ALL ONLINE VOLUMES */
SET SASDB.DCOLVOLS (KEEP=
DCVSGTCL /* STORAGE GROUP */
DCVDVNUM /* UCB */
DCVVOLSR); /* VOLSER */
/* GET RID OF VOLUMES WHICH NEVER NEED BACKUP */
IF DCVVOLSR =: 'SP' THEN DELETE; /* SPARE VOLUMES */
RENAME DCVSGTCL=STORGRP;
RENAME DCVVOLSR=VOLSER;
RENAME DCVDVNUM=UNIT;
PROC SORT;
BY DCVVOLSR;
DATA VOLN_LST; /* ALL NON_SMS VOLUMES */
SET VOLA_LST;
IF STORGRP ¬= '' THEN DELETE;
DATA VOLS_LST; /* ALL SMS VOLUMES */
SET VOLA_LST;
IF STORGRP = '' THEN DELETE;
/* ALLOCATE DUMMY STORAGE GROUPS to non-SMS disks
DSKPARMS is a pds member which contains lists of non-sms disks
and a dumptype, used to group the disks into dummy pools, for example
* pool volume
CA CAT001
SP SYSRS1 */
DATA DSKPARMS;
INFILE DSKPARMS;
INPUT COMMENT £ 1 @;
IF COMMENT = '*' THEN DO;
DELETE;
DROP COMMENT;
END;
ELSE DO;
INPUT DUMPTYPE £ 5-6
VOLSER £ 12-17;
END;
IF VOLSER = ' ' THEN DELETE; /* BLANK LINES */
PROC SORT;
BY VOLSER;
DATA NON_SMS;
MERGE DSKPARMS (IN=F1) VOLN_LST (IN=F2);
BY VOLSER;
STORGRP = "NONSMS" || DUMPTYPE;
IF F1=1 AND F2=0 THEN DO;
PUT '********************************************************';
PUT '* *';
PUT '* NON-FATAL ERROR IN SAS MODULE *';
PUT '* *';
PUT '* VOLSER ' VOLSER ' SPECIFIED IN FILE *';
PUT '* DMGT.PROD.CONTROL(ABRNSMSP) *';
PUT '* BUT IT DOES NOT EXIST ONLINE. *';
PUT '* *';
PUT '********************************************************';
DELETE;
END;
IF F1=0 AND F2=1 THEN DO;
PUT '********************************************************';
PUT '* *';
PUT '* FATAL ERROR IN SAS MODULE *';
PUT '* *';
PUT '* VOLSER ' VOLSER ' MISSING FROM FILE *';
PUT '* DMGT.PROD.CONTROL(ABRNSMSP) *';
PUT '* SO WE DONT KNOW WHAT TO DO WITH IT *';
PUT '* *';
PUT '********************************************************';
ABORT RETURN 16;
END;
DROP DUMPTYPE;
/* GET A LIST OF ALL VOLUMES WITH DATA, NOW ALL WITH STORAGE
GROUPS, BY COMBINING SMS & NON-SMS */
DATA ALL_VOLS;
SET NON_SMS VOLS_LST;
PROC SORT;
BY STORGRP;
/* EXTRACT INFO ON WHAT TO DO WITH STORAGE POOLS
THEN DELETE POOLS WHICH DONT NEED BACKUP. Storage pool info
is held in a PDS member, an example is shown below
* dump? pool comment
X DB2DBPD DATABASES imagecopied
F PBVLRG01 GENERAL LARGE ALLOCATIONS */
DATA STORGRPS;
INFILE SGPARMS;
INPUT COMMENT £ 1 @;
IF COMMENT = '*' THEN DO;
DELETE;
DROP COMMENT;
END;
ELSE DO;
INPUT BACKUP £3
STORGRP £5-12;
IF STORGRP = ' ' THEN DELETE; /* BLANK LINES */
END;
PROC SORT;
BY STORGRP;
DATA VLSG_LST; /* MERGE VOLUME & STORAGE GROUP INFO */
MERGE STORGRPS (IN=F1) ALL_VOLS (IN=F2);
BY STORGRP;
IF F1=1 AND F2=0 THEN DO;
PUT '***********************************************';
PUT '* *';
PUT '* NON-FATAL ERROR IN SAS MODULE *';
PUT '* STORAGE POOL ' STORGRP ' DEFINED IN *';
PUT '* DMGT.MASTER,CONTROL(ABRPOOLS) AND IT HAS *';
PUT '* NO VOLUMES ASSIGNED TO IT *';
PUT '* *';
PUT '***********************************************';
DELETE;
END;
IF F1=0 AND F2=1 THEN DO;
PUT '**********************************************';
PUT '* *';
PUT '* ERROR IN SAS MODULE *';
PUT '* *';
PUT '* STORAGE POOL ' STORGRP ' EXISTS, BUT HAS *';
PUT '* NO ENTRY IN DMGT.PROD.CONTROL(ABRPOOLS) *';
PUT '* PLEASE ADD IT WITH THE CORRECT BACKUP *';
PUT '* INSTRUCTION *';
PUT '* CURRENT VOLUME IS ' VOLSER ' *';
PUT '* *';
PUT '**********************************************';
ABORT RETURN 16;
END;
IF BACKUP = 'X' THEN DELETE;
/* WORK OUT THE FLASH COPY ADDRESS FOR EACH DISK
The first bit is a bit of a fiddle to cope with hex
addresses, Write the hex data out to a file, then
read it back in character format. If you know of an
easy way to convert hex to char, PLEASE mail me. */
DATA TEMP;
SET VLSG_LST;
FILE SAST1 NOPRINT;
PUT @2 UNIT @7 VOLSER @16 STORGRP @30 BACKUP;
DATA FDRFLASH;
INFILE SAST1;
INPUT @2 UNIT HEX4.
BOX £2
LCU £3
VOLSER £7-12
STORGRP £16-23
BACKUP £30;
ATTRIB UNIT FORMAT=HEX4.;
ATTRIB FUNIT FORMAT=HEX4.;
/* ARRAYS ARE EITHER 48 3390-3 DISKS, OR 24 3390-9 */
SELECT(BOX);
WHEN('8') DO; /* ESS1 */
SELECT (LCU);
WHEN('0') FUNIT = UNIT + 24; /* 3390-9 ARRAYS */
WHEN('B') FUNIT = UNIT + 24;
OTHERWISE FUNIT = UNIT + 48; /* 3390-3 ARRAYS */
END; /* OF SELECT */
END;
WHEN('6') DO; /* ESS4 */
SELECT (LCU);
WHEN('A') FUNIT = UNIT + 48; /* 3390-3 ARRAYS */
WHEN('B') FUNIT = UNIT + 48;
WHEN('C') FUNIT = UNIT + 48;
WHEN('D') FUNIT = UNIT + 48;
OTHERWISE FUNIT = UNIT + 24; /* 3390-9 ARRAYS */
END;
END;
WHEN(' ') DELETE;
OTHERWISE DO;
PUT '*****************************************';
PUT '* *';
PUT '* ERROR IN SAS MODULE *';
PUT '* *';
PUT '* YOU ARE TRYING TO FLASHCOPY ' VOLSER ' *';
PUT '* IN STORAGE POOL ' STORGRP ' *';
PUT '* WITH ADDRESS ' UNIT ' *';
PUT '* *';
PUT '* IF YOU HAVE ADDED A NEW FLASHCOPY *';
PUT '* CAPABLE SUBSYSTEM, THEN IT MUST BE *';
PUT '* ADDED INTO DMGT.PROD.SAS(ABRBKFLP) *';
PUT '* YOU WILL ALSO NEED TO GET MORE *';
PUT '* FLASH COPY JOBS SCHEDULED *';
PUT '* *';
PUT '* *';
PUT '*****************************************';
ABORT RETURN 16;
END;
END;
/* CREATE FDRFLASH COMMANDS, ONE SET OF EACH DASD LCU */
DATA TEMP;
SET FDRFLASH;
BLCU = BOX || LCU;
DROP BOX UNIT STORGRP;
PROC SORT;
BY BLCU;
DATA FLASHOUT;
SET TEMP;
LENGTH OUTFILE £ 50;
ATTRIB N FORMAT=Z2. LENGTH=2;
RETAIN N 00 OLD_BLCU ' ';
IF BLCU ¬= OLD_BLCU THEN NEW_JOB='Y';
OLD_BLCU = BLCU;
IF NEW_JOB = 'Y' THEN GOTO HEAD;
BODY:
IF N < 10 THEN M='0'|| N;
ELSE M=N;
OUTFILE='DMGT.PROD.CONTROL(X4FLBC'||M||')';
OUTFILE=COMPRESS(OUTFILE);
FILE FDRFLASH NOPRINT FILEVAR=OUTFILE;
PUT @2 'MOUNT'
@12 'VOL='
@16 VOLSER
@22 ',FLASHUNIT='
@33 FUNIT;
RETURN;
/* THIS BIT GETS INVOKED WHEN WE START A NEW ARRAY */
HEAD:
N+1;
/* IF EXTRA FLASH CAPABLE DASD IS ADDED, CHANGE */
/* THE COUNTER BELOW, AND THE ERROR MESSAGE */
IF N > 48 THEN DO;
FILE SASLOG;
PUT '*****************************************';
PUT '* *';
PUT '* ERROR IN SAS MODULE *';
PUT '* *';
PUT '* YOU HAVE TRIED TO CREATE MORE THAN *';
PUT '* 48 FDRFLASH JOBS, AND ONLY 48 JOBS *';
PUT '* ARE SCHEDULED. YOU NEED TO SPEAK TO *';
PUT '* THE SCHEDULERS QUICKLY *';
PUT '* *';
PUT '*****************************************';
ABORT RETURN 16;
END;
IF N < 10 THEN M='0'|| N;
ELSE M=N;
OUTFILE='DMGT.PROD.CONTROL(X4FLBC'||M||')';
OUTFILE=COMPRESS(OUTFILE);
FILE FDRFLASH NOPRINT FILEVAR=OUTFILE;
PUT @2 'FCOPY TYPE=AUTO,DSNENQ=USE,ENQERR=NO SMSPROT=NONE';
/* CREATE REAL PROCLIB MEMBERS FOR USED ARRAYS */
IF N < 10 THEN M='0'|| N;
ELSE M=N;
M=COMPRESS(M);
OUTFILE='DMGT.PROD.PROCLIB(X4FLBC'||M||')';
OUTFILE=COMPRESS(OUTFILE);
FILE PROCLIB NOPRINT FILEVAR=OUTFILE;
PUT @1 '//STEP1 EXEC PGM=FDRABR';
PUT @1 '//TAPE1 DD DUMMY';
PUT @1 '//SYSPRINT DD *';
PUT @1 '//SYSPRIN1 DD SYSOUT=*';
PUT @1 '//SYSUDUMP DD SYSOUT=*';
GOTO BODY;
/* CREATE DUMMY PROCLIB MEMBERS FOR BLANK ARRAYS */
/* 48 jobs are scheduled to run in OPC, but they */
/* may not all be used. The JCL in the OPC library */
/* looks like
//X4FLBC01 JOB (Backup),CLASS=4,
// MSGCLASS=X,MSGLEVEL=(1,1)
//INCLIB JCLLIB ORDER=(DMGT.PROD.PROCLIB)
//JCLIN INCLUDE MEMBER=X4FLBC01
which points it to the user libraries
*/
DATA _NULL_;
SET FLASHOUT (KEEP=N) END=LAST; /* GET N COUNTER FROM LAST RECORD */
IF LAST ¬= 1 THEN DELETE;
DO WHILE (N<48);
N+1;
LINK NEWJOB;
END;
NEWJOB:
IF N < 10 THEN M='0'|| N;
ELSE M=N;
OUTFILE='DMGT.PROD.PROCLIB(X4FLBC'||M||')';
OUTFILE=COMPRESS(OUTFILE);
FILE PROCLIB NOPRINT FILEVAR=OUTFILE;
PUT @1 '//STEP1 EXEC PGM=IEFBR14';
PUT @1 '//DD1 DD DUMMY ';
RETURN;