/*  CPUID -- Display CPU information from REXX                       */
/*      article in TSO TIMES, Fall 1993, by John Andrisan            */
/*      of IBM ISSC subdivision in Long Beach California             */
/*********************************************************************/
/* A TSO REXX Exec to get information aobut CPUs from the MVS        */
/* control blocks: DVT, SMCA, CSD, PCCAVT, and PCCA; then show CPU   */
/* number, id serial number, type, SMF id letter, and anything else  */
/* that looks interesting.                                           */
/*                                                                   */
/* The control block chain that I want to follow:                    */
/*   location 10x --> CVT                                            */
/*        CVT+C4x  -->  SMCA                                         */
/*            SMCA+16 contains the SMF id                            */
/*        CVT+294x -->  CSD                                          */
/*            CSD+4, +8 and + 10 contain                             */
/*              some interesting cpu counts                          */
/*        CVT+2FCx -->  PCCAVT                                       */
/*            PCCAVT+0   -->  PCCA for CPU 0                         */
/*            PCCAVT+4   -->  PCCA for CPU 1                         */
/*            ... etc.                                               */
/*            PCCAVT+60  -->  PCCA for CPU 15                        */
/*            PCCA+4   contains the cpu id, serial#, type            */
/*            PCCA+24    -->  virtual PSA                            */
/*            PCCA+28    -->  real PSA                               */
/*********************************************************************/
/* ---------begin available "The REXX Macros Toolbox" only portion*/
   "CLS"  /* clear screen*/
   say '----- information obtained via  WHICH CPU ------'
  "WHICH CPU"
   say ' '
   say '----- information from CPUID -- Display CPU information'
/* ------------ end available "The REXX Macros Toolbox" only portion*/
arg what .
if what='?' then do  /* offer the user some help */
     say '  use: COMMAND ===> CPUID'
     say '     No parms are required'
     say '  You will be shown the SMF id letter defining this system,'
     say '     the CPU id, serial number, and CPU type of each CPU,'
     say '  This exec (CPUID) only works on TSO.'
end
if address() /='TSO' then do
   say 'This exec only works in MVS/TSO.'
   exit 4
end
call init            /* set up some constants */
CVT=storage('10',4)
CVT=bitand(CVT,'7FFFFFFF'x)   /* zero high bit */
SMCA=storage(d2x(c2d(CVT)+x2d('C4')),4)    /* get to SMCA */
SMCA=bitand(SMCA,'7FFFFFFF'x)
SMCASID=storage(d2x(c2d(SMCA)+16),4)
say 'SMF id=' SMCASID
CSD=storage(d2x(c2d(CVT)+x2d('294')),4)     /* get to CSD    */
CSD=bitand(CSD,'7FFFFFFF'x)                 /* zero high bit */
               /* the counts shown next may change whil you run*/
nr_cpus=c2d(storage(d2x(c2d(CSD)+10),2))    /* get nr cur alive */
say 'nr cpus currently alive:' nr_cpus      /* whatever that is */
job_avail_cpus=x2b(c2x(storage(d2x(c2d(csd)+4),2)))
say count_bits(job_avail_cpus) 'available for jobs'
srb_avail_cpus=x2b(c2x(storage(d2x(c2d(csd)+8),2)))
say count_bits(srb_avail_cpus) 'available for srbs'
cur_alive_cpus=x2b(c2x(storage(d2x(c2d(CSD)+10),2)))
say count_bits(cur_alive_cpus) 'currently alive'
say ' '
PCCAAVT=storage(d2x(c2d(CVt)+x2d('2FC')),4)  /* get to PCCAVT */
PCCAAVT=bitand(PCCAAVT,'7FFFFFFF'x)             /* zero high bit*/

say '-----CPU--------------  PSA       PSA              '
say '#  ver id serial  type  vaddr     raddr     status:'
do i=0 to 60 by 4
   PCCA=storage(d2x(c2d(PCCAAVT)+i),4)     /* get the i-th PCCA */
   PCCA=bitand(PCCA,'7FFFFFFF'x)             /* zero high bit */
   if PCCA=='00000000'x then iterate i    /* avoid empty entry */
   info=storage(c2x(PCCA),32)
   if substr(job_avail_cpus,i%4+1,1)='1' then jobs='jobs'
   else jobs='no-jobs'
   if substr(srb_avail_cpus,i%4+1,1)='1' then srbs='srbs'
   else jobs='no-srbs'
   if substr(cur_alive_cpus,i%4+1,1)='1' then alive='alive'
   else alive='no-alive'
   /*       as run "The REXX Macros Toolbox" 1993/12/16
   SMF id= H901
   nr cpus currently alive: 5
   5 available for jobs
   5 available for srbs
   2 currently alive

   -----CPU--------------  PSA       PSA
   #  ver id serial  type  vaddr     raddr     status:
   00  52  0 12495   3090  8000F6F0  00157240  jobs srbs no-alive
   01  52  1 12495   3090  7800F9F0  00134030  jobs srbs no-alive
   02  52  2 12495   3090  0000F980  0002F040  jobs srbs no-alive
   03  52  3 12495   3090  0000F960  00068040  jobs srbs no-alive
   04  52  4 12495   3090  1000F7F0  000A2040  jobs srbs no-alive
   05  a:  9 &             00070C30  0080007B  no-srbs srbs no-alive
     */
   say ,
       /*cpu number:*/ right(i%4,2,'0')' ',
       /*cpu ver :  */ substr(info,5,2)' ',
       /*cpuid:     */ substr(info,7,1),
       /*cpu serial:*/ substr(info,8,5)'  ',
       /*cpu type:  */ substr(info,13,4)' ',
       /*PSA vaddr:*/  c2x(substr(info,24,4))' ',
       /*PSA raddr:*/  c2x(substr(info,28,4))' ',
             /* the status shown next may change while you run*/,
       /*status:*/    jobs srbs alive
end
exit 0
/* ------------------- subroutines ---------------------- */
count_bits:
  arg bit_string .
  bit_sum = 0
  do bit=1 to length(bit_string)
    if substr(bit_string,bit,1)='1' then bit_sum=bit_sum + 1
  end
  return(bit_sum)
  X2B:  /* X2B is a function for hex to binary string conversion*/
  arg arg .
  bitout=''
  do i=1 to length(arg)
      t=substr(arg,i,1)
      bitout=bitout||hex.t
  end
  return bitout
  init:  /* constants needed in x2b */
  hex.0='0000'; hex.1='0001'; hex.2='0010'; hex.3='0011';
  hex.4='0100'; hex.5='0101'; hex.6='0110'; hex.7='0111';
  hex.8='1000'; hex.9='1001'; hex.A='1010'; hex.B='1011';
  hex.C='1100'; hex.D='1101'; hex.E='1110'; hex.F='1111';
  return