Lesson 4. Exercises.

We have 3 exercises for you.  For each, we have first to give an introduction that explains the situation.

Read a MACLIB member.

A CMS MACLIB (Macro Library) has following internal structure:

      +-----------------------+
    +-! LIBPDS                !
    ! +-----------------------+
    ! ! MACRO1                !
    ! !                       !
    ! !                       !
    ! + - - - - - - - - - - - +
    ! ! MACRO2                !
    ! !                       !
    ! !                       !
    ! !                       !
    ! + - - - - - - - - - - - +
    ! ! MACRO3                !
    ! !                       !
    ! !                       !
    ! !                       !
    ! +-----------------------+
    +>! MACRO1  --> MACRO2 -->!
      ! MACRO3  -->           !
      +-----------------------+

The first record has following layout:

           1         2         3
  1...+....0....+....0....+....0....
  LIBPDSnnnnnnpppp....

where:

The index records contain one or more macro names (8 characters), followed by the record pointer (8 characters, binary notation) to the start of the macro definition.

The macros are separated from each other by a record starting with '61FFFF61'x.

This is enough information for you to let you code the procedure described below.

Extract a macro from a MACLIB

Write a procedure that extracts a specific macro from a MACLIB.  Of course, you could do it with the aid of some CMS commands (like PUNCH or MACLIST), but this time we expect you to use REXX File I/O methods.

Your procedure can use any of the File I/O methods explained in the text.  Maybe it's good to review the advantages and disadvantages of the different methods before to choose one for the exercise.

The command format should be:

   GETMAC maclib_fn macro

where maclib_fn is the filename of the macro library, and macro is the name of the macro you want to extract.

Note
You can find plenty of MACLIB files on your S-disk.  You should 'stress-test' your procedure on one of the largest ones (DMSOM MACLIB).

Your procedure should thus perform these logical steps:

  1. Accept the parameters and verify the completeness.
  2. Verify if the MACLIB exists on any accessed disk.
  3. Read the first record of the MACLIB and extract the pointer to the index.
  4. Locate and extract the index record that contains the macro name (if not found, error message to the user)
  5. Parse the index record to extract the starting record number for the macro.
  6. Read the records of the macro till the separator is found.
  7. Put the macro in a file macro MACRO on your A-disk.

When you have written yours, you may take the time to review our commented solutions.


How to Determine CP/CMS Function Levels

    by Steven L. Jones

Why this article and exercise ?

This article was extracted from the IBM VM Software Newsletter of 1st Quarter 1991.

The article serves as introduction to the exercise, but contains valuable information on itself.  You may be faced with the problem of determining the system on which you want to run your procedures.

The exercise mainly serves to teach you some less used REXX functions that do bit-manipulation.  You will also be confronted with binary and hexadecimal notations, which may be a good review.  This exercise is not too difficult.

Foreword on the article.

In order to understand some terms in the article, let's review 2 machine instructions for those of you that don't know much about internal principles of operations.

Supervisor Call or SVC.

This instruction can be used by an application program to request services from the operating system (the supervisor).  In most of our virtual machines, the supervisor is CMS.

The format of the SVC instruction is simple:

       SVC  nn

where nn is a number that applies to a convention for the supervisor.  For example, SVC 204 is the instruction a program should use to ask CMS to execute another program or command. 

The conventions are different for each operating system.  SVC 06 asks an OS/390 system to call another program, while this same number means terminate processing when issued on a VSE/ESA system (or on CMS with SET DOS ON).

CMS also knows a bit about VSE/ESA and OS/390 and simulates these SVC routines.  By default, CMS supposes you run OS/390 programs.  If you want to run VSE programs, then you have to SET DOS ON.

SVC instructions are normally imbedded in assembler macros.  So, for example, the CMS macro CMSCALL will prepare a parameter list and then issue the SVC 204.

Diagnose instruction

This instruction allows an operating system to request special services from the hardware.  For a virtual machine, the hardware is CP, and thus, in VM, the diagnose instruction was selected to let a virtual machine request functions from CP.

The diagnose instruction has no mnemonic assembler code, so one has to code the operation code instead, such as:

      DC    X'83',Rx,Ry,nn

(this is a simplified format, you'll find a more complete example in the text).  Rx and Ry are registers that provide or receive data and nn is again a convention for communication with CP.

For example, diagnose X'08' allows a program to issue CP commands, diagnose X'14' allows to manipulate spool data (such as reading a RDR file) and diagnose X'64' allows to load or purge shared segments.

The text talks about diagnose X'00' by which one can ask CP for the system level.

REXX provides the built-in functions DIAG() and DIAGRC(), which support many, but not all, diagnose code functions.

Determining the Functional Level of CP

It is often necessary for an application to determine the availability or behavior of certain commands, Diagnose Codes, or architecture-sensitive information that affects its execution.  There are several methods for obtaining this type of information.  Some of the methods have however, the potential to break the application when it is ported to a new release or version of CP.

Note that some parts of the article are a bit obsolete now, as all VM systems should now at least run at VM/ESA level 2.2.0, as this is the first release that is Y2K compliant.

What to Avoid

There are two common methods of determining CP functional information that should be avoided.  These two methods are:

  1. QUERY CPLEVEL
  2. The eight byte System Name at offset zero in the output returned by Diagnose X'00'.

QUERY CPLEVEL

Here are some examples of the output returned by QUERY CPLEVEL on various versions of VM:

      VM/SP RELEASE 6, SERVICE LEVEL 610
      VM/XA SP Release 21, service level 0000
      VM/ESA Release 1, Service Level 000 - 370 Feature
      VM/ESA Release 1, service level 0629
      VM/ESA Release 2.1, service level 9404

The two pieces of information most commonly used from the output returned by QUERY CPLEVEL are:

  1. Product Name
  2. Release Number

The product name is normally compared to literal constants such as VM/XA or VM/SP so that different actions can be taken based on the result of the comparison.  The release number is used to determine if an application is executing on a release that supports a specific function.  Each release of CP adds new functions, so that applications that desire to exploit one, while still be able to work on earlier releases, need to determine the system level on which they execute.  Programs may for example test for the availability of APPC/VM (was not on VM/XA), TSAF (was not on VM/XA), CMS Pipelines (was not on VM/ESA 1.0), specific Diagnose Codes, or new CP System Services.


The product name returned by QUERY CPLEVEL should not be used for product determination because applications must recode whenever a new VM product name is introduced.

For example, any application that coded a test of the product name returned by QUERY CPLEVEL such as the following:

     Parse Value Diag(8,'QUERY CPLEVEL') With ProdName .
     If ProdName = 'VM/XA'   /* Do we have XA-architecture? */
        Then Call DOXA

is subject to breakage on VM/ESA because the product name will be VM/ESA, causing the test to fail.  In most cases, however, the architectural considerations are the same for VM/ESA as they are for VM/XA, and you would want the test to succeed.  Code similar to the above in applications prior to VM/ESA must now be recoded in order to support VM/ESA properly.

This misuse of the QUERY CPLEVEL (or the Diagnose X'00' as explained later) is one of the main reasons why some program products fail to run on VM/ESA, and not because they are technically not able to run in that environment.

The above is not an isolated case.  There is a similar problem with VM/SP because of the VM/ESA-370 feature.

A test such as :

     Parse Value Diag(8,'QUERY CPLEVEL') With ProdName .
     If ProdName = 'VM/SP'       /* Do we have VM/SP system */
        Then Call DOVMSP

will lead to incorrect results on the VM/ESA-370 feature because the system name returned by QUERY CPLEVEL will be VM/ESA.  An additional problem with the VM/ESA 370 feature is that the product name for the 370 feature is the same as for the ESA feature.  Both features are named VM/ESA.  Returning to our output examples for VM/ESA:

      VM/ESA Release 1, Service Level 000 - 370 Feature
      VM/ESA Release 1, service level 0629

you can see that in order to determine if you are executing on the 370 feature, an additional test must be made for the character string 370 Feature, which appears as the last two tokens of the output.  This increases the complexity of the coding, particularly for assembler applications.

Similar breakages could occur in the future if new VM product names are introduced and applications are using hard coded character strings to identify products.

Diagnose X'00' System Name

Diagnose X'00' returns following information:
System name 8 bytes EBCDIC.  See discussion below.
Environment 3 bytes HEXA.  If bit 0 of first byte is '1' then VM runs in an LPAR.  Other bits are reserved and zero.
Version code 1 byte HEXA, the version code from the CPUID.
Reserved 4 bytes with reserved bits or less important info
Userid 8 bytes EBCDIC, the userid issuing the diagnose.
Product Bit Map 8 bytes HEXA, see discussion below.
Time Zone 4 bytes HEXA, represent the time zone differential in seconds from GMT.
Release Info 4 bytes HEXA : byte 1 is release number, byte 2 is release modification level and bytes 3-4 are service level.

The system name is the first eight bytes of the output returned by Diagnose X'00'.  It will be one of the following: VM/SP, VM/XA SF, VM/XA SP, or VM/ESA.  The system name returned by Diagnose X'00' is used for the same purpose as the product name returned by QUERY CPLEVEL: to determine whether the control program is 370 or XA (ESA), but the Diagnose X'00' system name is less informative than the QUERY CPLEVEL product name.  For example, it is not possible to distinguish between VM/SP and VM/SP HPO, nor between the VM/ESA 370 Feature and the VM/ESA ESA Feature, using only the Diagnose X'00' system name.

The dangers of using the Diagnose X'00' system name are the same as for the QUERY CPLEVEL product name.

Breakage can also occur when the release number returned by Diagnose X'00' is used.  For example, an APAR to VM/XA SP 2.1 changed the release number from 21 to 2.1.  Either of these values may be returned, depending whether the APAR that made the change in the QUERY CPLEVEL output, is applied.

What to Use Instead ?

The previous discussion has demonstrated why you should not use QUERY CPLEVEL or the system name returned by Diagnose X'00' to determine the functional level of CP.  Instead, use the Program Product Bit Map returned by Diagnose X'00'.

How to Use the Program Product Bit Map ?

The Program Product Bit Map is an eight-byte field that starts at offset X'18' (24 decimal) in the data returned by Diagnose X'00'.  The Program Product Bit Map has a unique bit for each functional enhancement to CP that affects externals or other major changes such as SPEs (Small Program Enhancements).  Each release of VM will have a unique bit in the Program Product Bit Map.

In addition to the bit that designates the release of CP that an application is executing on, all previous release bits will also be on.  Thus the Program Product Bit Map is cumulative.  This means that for VM/SP 6, the bits for all previous releases of VM/SP (VM/SP 5 through BSEPP) are set to '1' as well as the bit for VM/SP 6.  This point is significant in that once you have determined whether the control program is 370 or XA (ESA) a single bit can be tested to determine if you are executing on a specific release of CP or higher.  This is usually the test that is done to determine if a particular function desired is available.  An example of this will be discussed later.

The first bit (bit 0 of byte 0) of the Program Product Bit Map is special in that it is used to determine if the CP is 370 (VM/SP, HPO, VM/ESA-370) or XA (VM/XA, VM/ESA-ESA).  If this bit is "on" (1), the CP is 370 ; if it is "off" (0), it is XA or ESA-ESA.
Once the data has been captured from Diagnose X'00', bit 0 of byte 0 is all that is necessary to determine if the CP being executed on, has 370 or XA (ESA) capability.

Therefore, unlike QUERY CPLEVEL or the system name contained in Diagnose X'00', the Program Product Bit Map is not subject to breakage due to changes in product names or format of the release level number.  Once a particular bit is determined to be the initial indicator of a desired function and the application is coded to test that bit, the test will remain valid for future releases.

Definition of the Bits in the Bit Map

The definition of the bits that are contained in the Diagnose X'00' Program Product Bit Map is as follows:

Definition of the VM/SP (VM/ESA-370) Program Product Bit Map:


        Program Product Bit Map :  VM/SP, VM/SP HPO, VM/ESA-370

   Byte 0      Byte 1     Byte 2     Byte 3     Byte 4 ...
  1111 1110  1111 1111  1111 1011  1111 1111  0000 0000 ...
  ^^^^ ^^^   ^^^^ ^^^^  ^^^^ ^ ^^  ^^^^ ^^^^             Byte 3
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!!! !!!+-- X'01' VM/SP Secure Origin ID
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!!! !!+--- X'02' VM/SP in LPAR mode with monitor changes
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!!! !+---- X'04' Dispatcher Request Queue Changes (VM35119)
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!!! +----- X'10' VM/ESA Release 1.5
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!!+------- X'10' VM/ESA Release 1
  !!!! !!!   !!!! !!!!  !!!! ! !!  !!+-------- X'20' VM/SP Release 6
  !!!! !!!   !!!! !!!!  !!!! ! !!  !+--------- X'40' VM/SP and HPO with 3380 Model K support
  !!!! !!!   !!!! !!!!  !!!! ! !!  +---------- X'80' VM/SP and HPO with 3380 AD4/AE4 support
  !!!! !!!   !!!! !!!!  !!!! ! !!                Byte 2
  !!!! !!!   !!!! !!!!  !!!! ! !+--- X'01' Free Storage Enhance -SPE- running
  !!!! !!!   !!!! !!!!  !!!! ! +---- X'02' VM/SP HPO Release 6.0
  !!!! !!!   !!!! !!!!  !!!! +------ X'08' VM/SP HPO Release 5.0
  !!!! !!!   !!!! !!!!  !!!!
  !!!! !!!   !!!! !!!!  !!!+-------- X'10' HPO 3.4 Scheduler Monitor Changes
  !!!! !!!   !!!! !!!!  !!+--------- X'20' VM/SP HPO Release 4.2
  !!!! !!!   !!!! !!!!  !+---------- X'40' VM/SP HPO Release 4.0
  !!!! !!!   !!!! !!!!  +----------- X'80' VM/SP HPO VDLE Support
  !!!! !!!   !!!! !!!!                Byte 1
  !!!! !!!   !!!! !!!+--- X'01' VM/SP HPO 3880 Model 21 Support
  !!!! !!!   !!!! !!+---- X'02' VM/SP HPO Release 3.6
  !!!! !!!   !!!! !+----- X'04' VM/SP HPO Release 3.4
  !!!! !!!   !!!! +------ X'08' VM/SP HPO Release 3.2
  !!!! !!!   !!!+-------- X'10' VM/SP HPO Release 3.0
  !!!! !!!   !!+--------- X'20' VM/SP HPO Release 2.5
  !!!! !!!   !+---------- X'40' VM/SP HPO Release 2.0
  !!!! !!!   +----------- X'80' VM/SP HPO Release 1.0
  !!!! !!!            Byte 0
  !!!! !!+--- X'02' VM/SP Release 5.0
  !!!! !+---- X'04' VM/SP Release 4.0
  !!!! +----- X'08' VM/SP Release 3.0
  !!!+------- X'10' VM/SP Release 2.0
  !!+-------- X'20' VM/SP Release 1.0
  !+--------- X'40' SEPP
  +---------- X'80' BSEPP 1.2

Notes:

  1. These bits are cumulative.  For example, if your system is VM/SP Release 6, the bits would be on for all releases of VM/SP, giving you X'FE0000E000000000'.
  2. If your system is VM/SP HPO, all VM/SP bits up to the VM/SP HPO Release will also be on because VM/SP is a prerequisite for VM/SP HPO.
    Thus, if your system was VM/SP HPO Release 5.0 and has all of the listed features, this would give you X'FEFFF80000000000'.
  3. Bit 0 of byte 0 will always be on (1) for VM/SP, VM/SP HPO, and VM/ESA-370 feature.  Bit 0 of byte 0 will always be off (0) for VM/XA SF, VM/XA SP, and VM/ESA-ESA feature.

Definition of the VM/XA (VM/ESA-ESA) Program Product Bit Map


        Program Product Bit Map :  VM/XA SF, VM/XA SP, VM/ESA-ESA

     Byte 0     Byte 1     Byte 2     Byte 3    Byte 4 ...
    0111 1111  1111 1111  0000 0000  0000 0000  ...

     ^^^ ^^^^  ^^^^ ^^^^     Byte 2
     !!! !!!!  !!!! !!!+ X'10' VM/ESA Version 2 Release 3.0
     !!! !!!!  !!!! !!+- X'20' VM/ESA Version 2 Release 2.0
     !!! !!!!  !!!! !+-- X'40' YEAR 2000 Support
     !!! !!!!  !!!! +--- X'80' VM/ESA Version 2 Release 1.0
     !!! !!!!  !!!!         Byte 1
     !!! !!!!  !!!+----- X'10' VM/ESA Version 1 Release 2.2
     !!! !!!!  !!+------ X'20' VM/ESA Version 1 Release 2.1
     !!! !!!!  !+------- X'40' VM/ESA Version 1 Release 2.0
     !!! !!!!  +-------- X'80' VM/ESA Version 1 Release 1.1
     !!! !!!!
     !!! !!!!               Byte 0
     !!! !!!+----------- X'01' VM/ESA Version 1 Release 1.0
     !!! !!+------------ X'02' Secure Origin ID SPE
     !!! !+------------- X'04' VM/XA SP Release 2.1
     !!! +-------------- X'08' APSS SPE
     !!+---------------- X'10' VM/XA SP Release 2.0
     !+----------------- X'20' VM/XA SP Release 1.0
     +------------------ X'40' VM/XA SF Release 2.0

Notes:

  1. These bits are cumulative as shown below:
        VM/ESA 2.2.0          Cumulative bits = '7FFE000000000000'x
        VM/ESA Year 2000 Sup  Cumulative bits = '7FFC000000000000'x
        VM/ESA 2.1.0          Cumulative bits = '7FF8000000000000'x
        VM/ESA 1.2.2          Cumulative bits = '7FF0000000000000'x
        VM/ESA 1.2.1          Cumulative bits = '7FE0000000000000'x
        VM/ESA 1.2.0          Cumulative bits = '7FC0000000000000'x
        VM/ESA 1.1.1          Cumulative bits = '7F80000000000000'x
        VM/ESA 1.1.0          Cumulative bits = '7F00000000000000'x
        Secure Origin ID SPE  Cumulative bits = '7E00000000000000'x
        VM/XA SP Release 2.1  Cumulative bits = '7C00000000000000'x
        APSS SPE              Cumulative bits = '7800000000000000'x
        VM/XA SP Release 2.0  Cumulative bits = '7000000000000000'x
        VM/XA SP Release 1.0  Cumulative bits = '6000000000000000'x
        VM/XA SF Release 2.0  Cumulative bits = '4000000000000000'x
    
  2. Bit of byte 0 will always be off (0) for VM/XA SF, VM/XA SP, and VM/ESA.  Bit 0 of byte 0 will always be on (1) for VM/SP, VM/SP HPO, and VM/ESA-370 feature.

It is therefore possible to determine a specific release of VM with two tests.  The first test is to determine if CP is 370 or XA (ESA).  The second one is to test the bit for the specific release where the function you desire was introduced.

Suppose you needed to determine if the CP you were executing on supported TSAF at a VM/SP 6 level of function.  This would include:

A test similar to the following could be used:

    ************************************************************
    * Determine if we have TSAF at the VM/SP 6 level or higher *
    ************************************************************
            SPACE 1
            LA    R13,WORKAREA        A(diag x'00' responsebuffer)
            LA    R14,40              Length of Diagnose Response Buffer
            SPACE 1
            DC    0H'0',X'83',AL.4(R13,R14),Y(X'00')   Diagnose X'00'
            SPACE 1
            TM    24(R13),X'80'       Is this VM/XA or VM/ESA-ESA?
            BZ    TRYXA               Yes: check for VM/ESA 1.0 or later
            TM    27(R13),X'20'       No: is it VM/SP 6 or later?
            BO    GOTFUNC             Yes: we have the desired function
            B     NOFUNC              No: the function is not available
    TRYXA   EQU   *
            TM    24(R13),X'01'       Is this VM/ESA-ESA 1.0 or later?
            BZ    NOFUNC              No: VM/XA does not support TSAF
    GOTFUNC EQU   *                   The function we want is available
             .
             .
             .
    WORKAREA DS   XL40                Diagnose X'00' Response Buffer

Well, this is assembler.  Many of you will not be able to understand this.  We kept the text as it was.  But we will ask you to code a similar thing in REXX at the end of this topic...
unless you now prefer to learn assembler...

This method is far superior to checking the output from QUERY CPLEVEL, which can have unexpected values such as VM/XA SP Release 21 for Release "2.1".

Determining the Functional Level of CMS

Using QUERY CMSLEVEL Output

The functional level of CMS may be obtained through the QUERY CMSLEVEL command.  The third token of the message contains the functional level.  When used from an assembler application via CMSCALL, QUERY CMSLEVEL returns the functional level in bits 8-15 of General Register 1.  This byte may be mapped with the CMSLEVEL macro.

Examples of the message returned by QUERY CMSLEVEL are:

          VM/SP Release 5, Service Level 000
          VM/XA CMS 5.5, Service Level 000
          VM/XA CMS 5.6, Service Level 000
          VM/SP Release 6, Service Level 000
          CMS Level 7, Service Level 000
          CMS Level 8, Service Level 000
          CMS Level 10, Service Level 404

The data returned in GPR 0 and GPR 1 for QUERY CMSLEVEL when invoked via CMSCALL is as follows:

            QUERY CMSLEVEL Loads R0 with the following:
            +----------------------------------------+
            !   R0 is loaded with the fullword at    !
       R0 = !    USERLVL in NUCON. This field is     !
            !        Reserved for the user.          !
            +----------------------------------------+
            0                                       31

            QUERY CMSLEVEL loads R1 with the following:
            +----------+---------+-------------------+
            ! Reserved !         !                   !
       R1 = ! for      ! Release ! Service Level     !
            ! future   ! Number  !                   !
            ! use      !         !                   !
            +----------+---------+-------------------+
            0           8         16                31

Byte 1 (Release Number) returned in GPR 1 will have one of the following values, as mapped by the CMSLEVEL Macro:

        VMR6   EQU  X'00' - VM/370 RELEASE 6
        VMBSEP EQU  X'01' - VM/BSEP RELEASE 2
        VMSEP  EQU  X'02' - VM/SEP RELEASE 2
        VMSP1  EQU  X'03' - VM/SP RELEASE 1
        VMSP2  EQU  X'04' - VM/SP RELEASE 2
        VMSP3  EQU  X'05' - VM/SP RELEASE 3
        VMSP4  EQU  X'06' - VM/SP RELEASE 4
        VMSP5  EQU  X'07' - VM/SP RELEASE 5
        VMSP55 EQU  X'08' - VM/SP RELEASE 5.5
        VMSP56 EQU  X'08' - VM/SP RELEASE 5.6
        VMSP6  EQU  X'09' - VM/SP RELEASE 6
        CMS7   EQU  X'0A' - VM/ESA 1.1.0; CMS level 7
        CMS8   EQU  X'0B' - VM/ESA 1.1.1; CMS level 8
        CMS9   EQU  X'0C' - VM/ESA 1.2.0; CMS level 9
        CMS10  EQU  X'0D' - VM/ESA 1.2.1; CMS level 10
        CMS11  EQU  X'0E' - VM/ESA 1.2.2; CMS level 11
        CMS12  EQU  X'0F' - VM/ESA 2.1.0; CMS level 12
        CMS13  EQU  X'10' - VM/ESA 2.2.0; CMS level 13
        CMS14  EQU  X'11' - VM/ESA 2.3.0; CMS level 14
        CMS14  EQU  X'12' - VM/ESA 2.4.0; CMS level 15

An example of an assembler program obtaining the Release Number from R1 is:

   ********************************************************************
   * R5 Contains the address of a work area                           *
   ********************************************************************
            SPACE 1
            LA    R1,LVLPLIST                CMSLEVEL Tokenized plist
            CMSCALL PLIST=(1),ERROR=CMSERR   QUERY CMSLEVEL
            STCM  R1,B'0100',KEEPLVL         Save CMSLEVEL for later
            LR    R1,R5                      Location for LINERD plist
            MVC   0(LINRDSIZ,R1),LRPLIST     Initialize LINERD plist
            LA    R5,LINRDSIZ(R5)            Location of response buffer
            LA    R6,80                      Size of the buffer
            SPACE 1
            LINERD DATA=((R5),(R6)),ERROR=CMSERR,MF=(E,(R1))
            SPACE 1
             ...
   LVLPLIST DC    CL8'QUERY'
            DC    CL8'CMSLEVEL'
            DC    CL8' (STACK'
            DC    XL8'FFFFFFFFFFFFFFFF'
            SPACE 1
   LRPLIST  LINERD MF=L
   LINRDSIZ EQU   *-LRPLIST

Notes:

  1. QUERY CMSLEVEL issues the message to the console unless the STACK option is used.
  2. LINERD removes the message from the stack, as it is not needed.  The information required was returned in R1 from QUERY CMSLEVEL.
  3. LINERD modifies its plist.  Therefore it must be built in free storage to run in a saved segment.  Otherwise, the inline form of LINERD could be used.

Additional Considerations for QUERY CMSLEVEL

Applications should not use the first token of the message text from QUERY CMSLEVEL, as it is not reliable with respect to CP or VM product determination.  For example, CMS 5.5 running on VM/SP 5 gives a first token of "VM/XA".  In addition, VM/ESA 1.0 changed the first token to "CMS" from "VM/ESA."

Also, REXX applications parsing output from QUERY CMSLEVEL with a template such as:

     Address Command 'QUERY CMSLEVEL (STACK'
     Parse Pull . 'Release' Lvl ',' .

are subject to breakage on releases other than VM/SP 5 or VM/SP 6 because the trigger 'Release' does not appear in the output for other releases of CMS.

A good example of a REXX program using the message output is:

        Address Command 'QUERY CMSLEVEL (STACK'
        Parse Pull . . LvlNum ',' .

Summary

In summary, use the Program Product Bit Map returned by Diagnose X'00' to determine the functional characteristics of the CP you are executing on.  Do not use CP QUERY CPLEVEL as a programming interface and do not use the first 8 bytes returned by Diagnose 'X00' to determine the system name.

QUERY CMSLEVEL will return the functional level of CMS in GPR 1, which may be mapped by the CMSLEVEL macro.  A REXX EXEC will need to use the third token of the output returned by QUERY CMSLEVEL via the STACK option.

Don't use QUERY CPLEVEL for determining the CMS level, as VM/ESA now allows to run back level CMS releases under CP, so, CP is not aware of the exact CMS release.


The exercise.

Write a procedure LEVEL EXEC that can accept 3 different parameters:
XACAP returns 1 if your CP is XA capable (31 bit support), else it should return 0.
ESA220 returns 1 if your system is at least at the VM/ESA Version 2, Release 2.0 level (hence Y2K support).  If not, it returns 0.
MACHINE returns the virtual machine mode (370, XA, XC or ESA).  Note that 370 is no longer possible with latest releases of VM/ESA.

The returned values 1 or 0 are for when your procedure is called as a subroutine.  If your procedure is executed from the CMS command line, then an explicit message should be displayed at the terminal.

Example

   > level machine
     Your virtual machine runs in XC mode.

If used as functions, then you could have code such as:

   if level('XACAP') then 'CP XAUTOLOG EREP' ; else 'CP AUTOLOG EREP'
   if level('ESA220') & level('MACHINE')='XC' then...

When you are ready, you can have a look at the commented solution.


Calculate disk usage.

This last exercise is a bit more challenging.  It not only lets you practice File I/O, but also advanced use of REXX arrays.  We suggest you take at least a few minutes to read the following text, and to think about the problems posed by the exercise.

Format of CMS minidisks.

In general, disks are organized in cylinders (CKD) or blocks (FBA).  We'll concentrate only on CKD here.

Each cylinder contains a number of tracks (equal to the number of surfaces in a cylinder).  The tracks have a specific byte capacity depending on the DASD type or architecture.

Note: with the most recent DASD technology, the physical organization of cylinders and tracks may be totally different.  From the users' point of view, however, things remain the same.

The tracks are in turn subdivided in physical blocks.  In CMS, those blocks are created via the FORMAT command.

The image of a track becomes thus something like:

  +--------------+---+--------------+---+--------------+---+----------
  !block 1       !gap!block 2       !gap!block 3       !gap! .....
  +--------------+---+--------------+---+--------------+---+----------

The CMS FORMAT command lets you choose between block sizes of 512 bytes, 1K, 2K or 4K.  All blocks have the same size on a CMS minidisk.  Between the physical blocks there are so called inter-record-gaps.  The more blocks you define on a track, the more gaps there will be, and hence, less space is available for storing data.  For this reason, we tend to choose for large block sizes.

On the other hand, as a CMS file does not share its blocks with another file - the last block is not necessarily filled with data - we tend to choose for smaller block sizes for this second reason.  For example, 2 CMS files of 1 byte each will together consume 2 blocks, or, on a minidisk formatted with 4K blocks, they'll consume 8K, while on a minidisk formatted with 1K blocks, they'll consume only 2K.

In VM we count with cylinders (on CKD device types), not with tracks, and to make life easier, VM provides the $DASD$ CONSTS S file that tells for each type, how many CMS blocks can fit on a cylinder, and how many cylinders are available on the DASD.  For the 3390 type of DASD, the statements look like these:

   blocks4k.3390 = 180               /*   3390    */
   blocks2k.3390 = 315
   blocks1k.3390 = 495
   blocks512.3390 =  735
   cylinders.3390 = 10017
   dasd_type.3390 = 'CKD'

This means that for a 3390 cylinder it is possible to create 180 blocks of 4K, or 495 blocks of 1K.  And there are 10017 cylinders on the largest model of this type DASD (model 3).

The exercise.

Write a procedure that uses the information provided in the $DASD$ CONSTS S file and calculates the cylinder capacities for the various DASD types when formatted with different block sizes.  The output should look like this:

  devtype     !    1K   !    2K   !     4K  !
  ------------+---------+---------+---------+ 
  3330 Bl/cyl !     209 !     114 !      57 !
  3330 KB/cyl !     209 !     228 !     228 !
  3330 KB/vol !  168872 !  184224 !  184224 !
  ------------+---------+---------+---------+ 
  .....
  3390 Bl/cyl !     495 !     315 !     180 !
  3390 KB/cyl !     495 !     630 !     720 !
  3390 KB/vol ! 4958415 ! 6310710 ! 7212240 !
  ------------+---------+---------+---------+ 

We want to have, for each type, and for each block size (you can ignore the 512 bytes size):

  1. the number of blocks that fit on a cylinder
  2. the number of Kilobytes that can be written on a cylinder with that block size
  3. the total number of bytes that fit on a DASD volume with that block size

These are the logical steps for your procedure :

  1. Search for and extract all records starting with the string blocks
  2. Parse the records for DASD types, block sizes and number of blocks.
  3. Search for and extract all records starting with the string cylinders
  4. Parse the records for the number of cylinders per DASD type.
  5. Format the output records and write them to DASD SIZES A

When you are ready, you can have a look at the commented solution.

This was the last exercise for lesson 4.