/* SERVICE.C    (c) Copyright Roger Bowler, 1999-2009                */
/*              ESA/390 Service Processor                            */

/* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009      */
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009      */

// $Id: service.c 5623 2010-02-09 00:46:57Z fish $

/*-------------------------------------------------------------------*/
/* This module implements service processor functions                */
/* for the Hercules ESA/390 emulator.                                */
/*-------------------------------------------------------------------*/

/*-------------------------------------------------------------------*/
/* Additional credits:                                               */
/*      Corrections contributed by Jan Jaeger                        */
/*      HMC system console functions by Jan Jaeger 2000-02-08        */
/*      Expanded storage support by Jan Jaeger                       */
/*      Dynamic CPU reconfiguration - Jan Jaeger                     */
/*      Suppress superflous HHC701I/HHC702I messages - Jan Jaeger    */
/*      Break syscons output if too long - Jan Jaeger                */
/*      Added CPI - Control Program Information ev. - JJ 2001-11-19  */
/*-------------------------------------------------------------------*/

#include "hstdinc.h"

#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif

#if !defined(_SERVICE_C_)
#define _SERVICE_C_
#endif

#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#include "sr.h"

#if !defined(_SERVICE_C)

#define _SERVICE_C

/*-------------------------------------------------------------------*/
/* Service processor state data                                      */
/*-------------------------------------------------------------------*/
static  U32     servc_cp_recv_mask;     /* Syscons CP receive mask   */
static  U32     servc_cp_send_mask;     /* Syscons CP send mask      */
static  U32     servc_attn_pending;     /* Attention pending mask    */
static  char    servc_scpcmdstr[123+1]; /* Operator command string   */
static  U16     servc_signal_quiesce_count;
static  BYTE    servc_signal_quiesce_unit;
static  BYTE    servc_sysg_cmdcode;     /* Pending SYSG read command */

#define SCLP_RECV_ENABLED(_type) \
    (servc_cp_recv_mask & (0x80000000 >> ((_type)-1)))

/*-------------------------------------------------------------------*/
/* Reset the service processor to its initial state                  */
/*-------------------------------------------------------------------*/
void sclp_reset()
{
    servc_cp_recv_mask = 0;
    servc_cp_send_mask = 0;
    servc_attn_pending = 0;
    servc_signal_quiesce_count = 0;
    servc_signal_quiesce_unit = 0;
    servc_sysg_cmdcode = 0;

    sysblk.servparm = 0;
}


// #ifdef FEATURE_SYSTEM_CONSOLE
/*-------------------------------------------------------------------*/
/* Raise service signal external interrupt                           */
/* (the caller is expected to hold the interrupt lock)               */
/*-------------------------------------------------------------------*/
void sclp_attention(U16 type)
{
    /* Set pending mask */
    servc_attn_pending |= 0x80000000 >> (type -1);

    /* Ignore request if already pending */
    if (!(IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_PEND)))
    {
        /* Set event pending flag in service parameter */
        sysblk.servparm |= SERVSIG_PEND;

        /* Set service signal interrupt pending for read event data */
        ON_IC_SERVSIG;
        WAKEUP_CPUS_MASK (sysblk.waiting_mask);
    }
}


void sclp_attn_thread(U16 *type)
{

    OBTAIN_INTLOCK(NULL);

    // The VM boys appear to have made an error in not 
    // allowing for asyncronous attentions to be merged
    // with pending interrupts as such we will wait here
    // until a pending interrupt has been cleared. *JJ
    while(IS_IC_SERVSIG)
    {
        RELEASE_INTLOCK(NULL);
        sched_yield();
        OBTAIN_INTLOCK(NULL);
    }

    sclp_attention(*type);

    free(type);

    RELEASE_INTLOCK(NULL);
}


void sclp_attn_async(U16 type)
{
    if(!IS_IC_SERVSIG)
        sclp_attention(type);
    else
    {
    TID sclp_attn_tid;
    U16 *typ;
        typ=malloc(sizeof(U16));
        *typ=type;
        create_thread(&sclp_attn_tid, &sysblk.detattr, sclp_attn_thread, typ, "attn_thread");
    }
}


static U32 sclp_attn_pending(U16 type)
{
U32 pending;

    if(type)
    {
        pending = servc_attn_pending & (0x80000000 >> (type -1));
        servc_attn_pending &= ~pending;
        return pending;
    }
    else
        return servc_attn_pending;
}


/*-------------------------------------------------------------------*/
/* Issue SCP command                                                 */
/*                                                                   */
/* This function is called from the control panel when the operator  */
/* enters an HMC system console SCP command or SCP priority message. */
/* The command is queued for processing by the SCLP_READ_EVENT_DATA  */
/* service call, and a service signal interrupt is made pending.     */
/*                                                                   */
/* Input:                                                            */
/*      command Null-terminated ASCII command string                 */
/*      priomsg 0=SCP command, 1=SCP priority message                */
/*-------------------------------------------------------------------*/
void scp_command (char *command, int priomsg)
{
    /* Error if disabled for priority messages */
    if (priomsg && !SCLP_RECV_ENABLED(SCCB_EVD_TYPE_PRIOR))
    {
        logmsg (_("HHCCP036E SCP not receiving priority messages\n"));
        return;
    }

    /* Error if disabled for commands */
    if (!priomsg && !SCLP_RECV_ENABLED(SCCB_EVD_TYPE_OPCMD))
    {
        logmsg (_("HHCCP037E SCP not receiving commands\n"));
        return;
    }

    /* Error if command string is missing */
    if (strlen(command) < 1)
    {
        logmsg (_("HHCCP038E No SCP command\n"));
        return;
    }

    /* Obtain the interrupt lock */
    OBTAIN_INTLOCK(NULL);

    /* Save command string and message type for read event data */
    strncpy (servc_scpcmdstr, command, sizeof(servc_scpcmdstr));

    /* Ensure termination of the command string */
    servc_scpcmdstr[sizeof(servc_scpcmdstr)-1] = '\0';

    /* Raise attention service signal */
    sclp_attention( priomsg ? SCCB_EVD_TYPE_PRIOR : SCCB_EVD_TYPE_OPCMD );

    /* Release the interrupt lock */
    RELEASE_INTLOCK(NULL);

} /* end function scp_command */


static void sclp_opcmd_event(SCCB_HEADER *sccb, U16 type)
{
static BYTE     const1_template[] = {
        0x13,0x10,                      /* MDS message unit          */
        0x00,0x25,0x13,0x11,            /* MDS routine info          */
             0x0E,0x81,                 /* origin location name      */
                  0x03,0x01,0x00,       /* Net ID                    */
                  0x03,0x02,0x00,       /* NAU Name                  */
                  0x06,0x03,0x00,0x00,0x00,0x00,  /* Appl id         */
             0x0E,0x82,                 /* Destinition location name */
                  0x03,0x01,0x00,       /* Net ID                    */
                  0x03,0x02,0x00,       /* NAU Name                  */
                  0x06,0x03,0x00,0x00,0x00,0x00,  /* Appl id         */
             0x05,0x90,0x00,0x00,0x00,  /* Flags (MDS type = req)    */
        0x00,0x0C,0x15,0x49,            /* Agent unit-of-work        */
             0x08,0x01,                 /* Requestor loc name        */
                  0x03,0x01,0x00,       /* Requestor Net ID          */
                  0x03,0x02,0x00        /* Requestor Node ID         */
        };

static BYTE    const2_template[] = {
        0x12,0x12,                      /* CP-MSU                    */
        0x00,0x12,0x15,0x4D,            /* RTI                       */
             0x0E,0x06,                 /* Name List                 */
                  0x06,0x10,0x00,0x03,0x00,0x00,  /* Cascaded
                                                       resource list */
                  0x06,0x60,0xD6,0xC3,0xC6,0xC1,  /* OAN (C'OCFA')   */
        0x00,0x04,0x80,0x70             /* Operate request           */
        };

static BYTE    const3_template[] = {
        0x13,0x20                       /* Text data                 */
        };

static BYTE    const4_template = {
        0x31                            /* Self-defining             */
        };

static BYTE    const5_template = {
        0x30                            /* Text data                 */
        };

U16 sccb_len;
U16 evd_len;
int event_msglen;
int i;

SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
SCCB_EVD_BK *evd_bk = (SCCB_EVD_BK*)(evd_hdr+1);
BYTE *event_msg = (BYTE*)(evd_bk+1);

    /* Get SCCB length */
    FETCH_HW(sccb_len, sccb->length);

    /* Command length */
    event_msglen = strlen(servc_scpcmdstr);

    /* Calculate required EVD length */
    evd_len = event_msglen + sizeof(SCCB_EVD_HDR) + sizeof(SCCB_EVD_BK);

    /* Set response code X'75F0' if SCCB length exceeded */
    if ((evd_len + sizeof(SCCB_HEADER)) > sccb_len)
    {
        sccb->reas = SCCB_REAS_EXCEEDS_SCCB;
        sccb->resp = SCCB_RESP_EXCEEDS_SCCB;
        return;
    }

    /* Zero all fields */
    memset (evd_hdr, 0, evd_len);

    /* Update SCCB length field if variable request */
    if (sccb->type & SCCB_TYPE_VARIABLE)
    {
        /* Set new SCCB length */
        sccb_len = evd_len + sizeof(SCCB_HEADER);
        STORE_HW(sccb->length, sccb_len);
        sccb->type &= ~SCCB_TYPE_VARIABLE;
    }

    /* Set length in event header */
    STORE_HW(evd_hdr->totlen, evd_len);

    /* Set type in event header */
    evd_hdr->type = type;

    /* Set message length in event data block */
    i = evd_len - sizeof(SCCB_EVD_HDR);
    STORE_HW(evd_bk->msglen, i);
    memcpy (evd_bk->const1, const1_template,
                            sizeof(const1_template));
    i -= sizeof(const1_template) + 2;
    STORE_HW(evd_bk->cplen, i);
    memcpy (evd_bk->const2, const2_template,
                            sizeof(const2_template));
    i -= sizeof(const2_template) + 2;
    STORE_HW(evd_bk->tdlen, i);
    memcpy (evd_bk->const3, const3_template,
                            sizeof(const3_template));
    i -= sizeof(const3_template) + 2;
    evd_bk->sdtlen = i;
    evd_bk->const4 = const4_template;
    i -= 2;
    evd_bk->tmlen = i;
    evd_bk->const5 = const5_template;

    /* Copy and translate command */
    for (i = 0; i < event_msglen; i++)
            event_msg[i] = host_to_guest(servc_scpcmdstr[i]);

    /* Set response code X'0020' in SCCB header */
    sccb->reas = SCCB_REAS_NONE;
    sccb->resp = SCCB_RESP_COMPLETE;
}


void sclp_cpident(SCCB_HEADER *sccb)
{
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb + 1);
SCCB_CPI_BK  *cpi_bk  = (SCCB_CPI_BK*)(evd_hdr + 1);
int i;
char systype[9], sysname[9], sysplex[9];
U64  syslevel;

    if(*(cpi_bk->system_type))
        set_systype(cpi_bk->system_type);
    if(*(cpi_bk->system_name))
        set_sysname(cpi_bk->system_name);
    if(*(cpi_bk->sysplex_name))
        set_sysplex(cpi_bk->sysplex_name);

    for(i = 0; i < 8; i++)
    {
        systype[i] = guest_to_host(cpi_bk->system_type[i]);
        sysname[i] = guest_to_host(cpi_bk->system_name[i]);
        sysplex[i] = guest_to_host(cpi_bk->sysplex_name[i]);
    }
    systype[8] = sysname[8] = sysplex[8] = 0;
    FETCH_DW(syslevel,cpi_bk->system_level);

#if 1
    logmsg(_("HHCCP040I CPI: System Type: %s Name: %s "
             "Sysplex: %s\n"),
        systype,sysname,sysplex);
#else
    logmsg(_("HHC770I Control Program Information:\n"));
    logmsg(_("HHC771I System Type  = %s\n",systype));
    logmsg(_("HHC772I System Name  = %s\n",sysname));
    logmsg(_("HHC773I Sysplex Name = %s\n",sysplex));
    logmsg(_("HHC774I System Level = %16.16" I64_FMT "X\n"),syslevel);
#endif

    losc_check(systype);

    /* Indicate Event Processed */
    evd_hdr->flag |= SCCB_EVD_FLAG_PROC;

    /* Set response code X'0020' in SCCB header */
    sccb->reas = SCCB_REAS_NONE;
    sccb->resp = SCCB_RESP_COMPLETE;
}


/*-------------------------------------------------------------------*/
/* Test whether SCP is enabled for QUIESCE signal                    */
/*                                                                   */
/* This function tests whether the SCP is willing to be notified     */
/* of a system shutdown via the SCLP_READ_EVENT_DATA service call.   */
/*                                                                   */
/* Return code:                                                      */
/*      Zero = SCP not receiving quiesce event notification          */
/*      Non-zero = SCP ready to receive quiesce event notification   */
/*-------------------------------------------------------------------*/
int can_signal_quiesce()
{
    return SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ);
}


/*-------------------------------------------------------------------*/
/* Send QUIESCE signal to SCP                                        */
/*                                                                   */
/* This function is called during system shutdown to notify the SCP  */
/* that a shutdown event is occurring. The shutdown event is queued  */
/* for processing by the SCLP_READ_EVENT_DATA service call, and a    */
/* service signal interrupt is made pending.                         */
/*                                                                   */
/* Input:                                                            */
/*      count and unit values to be returned by SCLP_READ_EVENT_DATA */
/*-------------------------------------------------------------------*/
int signal_quiesce (U16 count, BYTE unit)
{
    /* Error if disabled for commands */
    if (!SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ))
    {
        logmsg (_("HHCCP081E SCP not receiving quiesce signals\n"));
        return -1;
    }

    /* Obtain the interrupt lock */
    OBTAIN_INTLOCK(NULL);

    /* Save delay values for signal shutdown event read */
    servc_signal_quiesce_count = count;
    servc_signal_quiesce_unit = unit;

    sclp_attention(SCCB_EVD_TYPE_SIGQ);

    /* Release the interrupt lock */
    RELEASE_INTLOCK(NULL);

    return 0;
} /* end function signal_quiesce */


static void sclp_sigq_event(SCCB_HEADER *sccb)
{
U16 sccb_len;
U16 evd_len;
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
SCCB_SGQ_BK *sgq_bk = (SCCB_SGQ_BK*)(evd_hdr+1);

    FETCH_HW(sccb_len, sccb->length);
    evd_len = sizeof(SCCB_EVD_HDR) + sizeof(SCCB_SGQ_BK);

    /* Set response code X'75F0' if SCCB length exceeded */
    if ((evd_len + sizeof(SCCB_HEADER)) > sccb_len)
    {
        sccb->reas = SCCB_REAS_EXCEEDS_SCCB;
        sccb->resp = SCCB_RESP_EXCEEDS_SCCB;
        return;
    }

    /* Zero all fields */
    memset (evd_hdr, 0, evd_len);

    /* Update SCCB length field if variable request */
    if (sccb->type & SCCB_TYPE_VARIABLE)
    {
        /* Set new SCCB length */
        sccb_len = evd_len + sizeof(SCCB_HEADER);
        STORE_HW(sccb->length, sccb_len);
        sccb->type &= ~SCCB_TYPE_VARIABLE;
    }

    /* Set length in event header */
    STORE_HW(evd_hdr->totlen, evd_len);

    /* Set type in event header */
    evd_hdr->type = SCCB_EVD_TYPE_SIGQ;

    STORE_HW(sgq_bk->count, servc_signal_quiesce_count);
    sgq_bk->unit = servc_signal_quiesce_unit;

    /* Set response code X'0020' in SCCB header */
    sccb->reas = SCCB_REAS_NONE;
    sccb->resp = SCCB_RESP_COMPLETE;
}


#if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
/*-------------------------------------------------------------------*/
/* Write data to the SYSG console                                    */
/*                                                                   */
/* The datastream to be written to the SYSG console is in the SCCB   */
/* immediately following the Event Data Header. It consists of a     */
/* one-byte local 3270 CCW command code, followed by a 3270 WCC,     */
/* followed by 3270 orders and data.                                 */
/*                                                                   */
/* Input:                                                            */
/*      sccb    Address of SCCB                                      */
/*      evd_hdr Address of event data header within SCCB             */
/* Output:                                                           */
/*      Reason and response codes are set in the SCCB                */
/*                                                                   */
/*-------------------------------------------------------------------*/
void sclp_sysg_write(SCCB_HEADER *sccb)
{
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
U16             evd_len;                /* SCCB event data length    */
U16             sysg_len;               /* SYSG output data length   */
DEVBLK         *dev;                    /* -> SYSG console devblk    */
BYTE           *sysg_data;              /* -> SYSG output data       */
BYTE            unitstat;               /* Unit status               */
BYTE            more = 0;               /* Flag for device handler   */
U16             residual;               /* Residual data count       */
BYTE            cmdcode;                /* 3270 read/write command   */

    /* Calculate the address and length of the 3270 datastream */
    FETCH_HW(evd_len,evd_hdr->totlen);
    sysg_data = (BYTE*)(evd_hdr+1);
    sysg_len = evd_len - sizeof(SCCB_EVD_HDR);

    /* The first data byte is the 3270 command code */
    cmdcode = *sysg_data;

    /* Look for the SYSG console device block */
    dev = sysblk.sysgdev;
    if (dev == NULL)
    {
        PTT(PTT_CL_ERR,"*SERVC",(U32)cmdcode,(U32)sysg_len,0);

        /* Set response code X'05F0' in SCCB header */
        sccb->reas = SCCB_REAS_IMPROPER_RSC;
        sccb->resp = SCCB_RESP_REJECT;
        return;
    }

    /* If it is a read CCW then save the command until READ_EVENT_DATA */
    if (IS_CCW_READ(cmdcode))
    {

        servc_sysg_cmdcode = cmdcode;

        /* Indicate Event Processed */
        evd_hdr->flag |= SCCB_EVD_FLAG_PROC;

        /* Generate a service call interrupt to trigger READ_EVENT_DATA */
        sclp_attn_async(SCCB_EVD_TYPE_SYSG);

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
        return;
    }
    else
    {
        servc_sysg_cmdcode = 0x00;

        /* Execute the 3270 command in data block */
        /* dev->hnd->exec points to loc3270_execute_ccw */
        (dev->hnd->exec) (dev, /*ccw opcode*/ cmdcode,
            /*flags*/ CCW_FLAGS_SLI, /*chained*/0,
            /*count*/ sysg_len - 1,
            /*prevcode*/ 0, /*ccwseq*/ 0, /*iobuf*/ sysg_data+1,
            &more, &unitstat, &residual);

        /* Indicate Event Processed */
        evd_hdr->flag |= SCCB_EVD_FLAG_PROC;

        /* If unit check occured, set response code X'0040' */
        if (unitstat & CSW_UC)
        {
            PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual);
            
            /* Set response code X'0040' in SCCB header */
            sccb->reas = SCCB_REAS_NONE;
            sccb->resp = SCCB_RESP_BACKOUT;
            return;
        }

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
    }
}
    
/*-------------------------------------------------------------------*/
/* Read data from the SYSG console                                   */
/*                                                                   */
/* If the SYSG console has data to send, copy it into the SCCB       */
/* immediately following the Event Data Header. The data consists    */
/* of a 3270 AID byte, followed by a two-byte 3270 cursor address,   */
/* followed by 3270 orders and data.                                 */
/*                                                                   */
/* Output:                                                           */
/*      Data, reason and response codes are set in the SCCB          */
/*                                                                   */
/*-------------------------------------------------------------------*/
void sclp_sysg_poll(SCCB_HEADER *sccb)
{
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
U16             sccblen;                /* SCCB total length         */
U16             evd_len;                /* SCCB event data length    */
U16             sysg_len;               /* SYSG input data length    */
DEVBLK         *dev;                    /* -> SYSG console devblk    */
BYTE           *sysg_data;              /* -> SYSG input data        */
BYTE           *sysg_cmd;               /* -> SYSG input data        */
BYTE            unitstat;               /* Unit status               */
BYTE            more = 0;               /* Flag for device handler   */
U16             residual;               /* Residual data count       */

    dev = sysblk.sysgdev;
    if (dev != NULL)
    {
        /* Zeroize the event data header */
        memset (evd_hdr, 0, sizeof(SCCB_EVD_HDR));

        /* Calculate maximum data length */
        FETCH_HW(sccblen, sccb->length);
        evd_len = sccblen - sizeof(SCCB_HEADER);
        sysg_data = (BYTE*)(evd_hdr+1);
        sysg_len = evd_len - sizeof(SCCB_EVD_HDR);

        /* Insert flag byte before the 3270 input data */
        sysg_cmd = sysg_data;
        sysg_len-=1;
        sysg_data+=1;

        /* Execute previously saved 3270 read command */
        if (servc_sysg_cmdcode)
        {
            *sysg_cmd = 0x00;

            /* Execute a 3270 read-modified command */
            /* dev->hnd->exec points to loc3270_execute_ccw */
            (dev->hnd->exec) (dev, /*ccw opcode*/ servc_sysg_cmdcode,
                /*flags*/ CCW_FLAGS_SLI, /*chained*/0,
                /*count*/ sysg_len,
                /*prevcode*/ 0, /*ccwseq*/ 0, /*iobuf*/ sysg_data,
                &more, &unitstat, &residual);

            servc_sysg_cmdcode = 0;

            /* Set response code X'0040' if unit check occurred */
            if (unitstat & CSW_UC)
            {
                PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual);

                /* Set response code X'0040' in SCCB header */
                sccb->reas = SCCB_REAS_NONE;
                sccb->resp = SCCB_RESP_BACKOUT;
                return;
            }

            /* Set response code X'75F0' if SCCB length exceeded */
            if (more)
            {
                PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual);

                sccb->reas = SCCB_REAS_EXCEEDS_SCCB;
                sccb->resp = SCCB_RESP_EXCEEDS_SCCB;
                return;
            }

            /* Calculate actual length read */
            sysg_len -= residual;
            evd_len = sizeof(SCCB_EVD_HDR) + sysg_len + 1;

            /* Set response code X'0020' in SCCB header */
            sccb->reas = SCCB_REAS_NONE;
            sccb->resp = SCCB_RESP_COMPLETE;
        }
        else
        {
            evd_len = sizeof(SCCB_EVD_HDR) + 1;
            *sysg_cmd = 0x80;

            /* Set response code X'0020' in SCCB header */
            sccb->reas = SCCB_REAS_NONE;
            sccb->resp = SCCB_RESP_COMPLETE;
        }

        /* Update SCCB length field if variable request */
        if (sccb->type & SCCB_TYPE_VARIABLE)
        {
            /* Set new SCCB length */
            sccblen = evd_len + sizeof(SCCB_HEADER);
            STORE_HW(sccb->length, sccblen);
            sccb->type &= ~SCCB_TYPE_VARIABLE;
        }

        /* Set length in event header */
        STORE_HW(evd_hdr->totlen, evd_len);

        /* Set type in event header */
        evd_hdr->type = SCCB_EVD_TYPE_SYSG;
    }
}

/*-------------------------------------------------------------------*/
/* Handle attention interrupt from the SYSG console                  */
/*                                                                   */
/* This function is called by console.c when it receives input       */
/* from the SYSG console. It sets the SYSG read flag and raises      */
/* a service signal external interrupt, which should prompt the      */
/* SCP to issue a SCLP_READ_EVENT_DATA service call to retrieve      */
/* the input data.                                                   */
/*-------------------------------------------------------------------*/
SERV_DLL_IMPORT
void sclp_sysg_attention()
{

    OBTAIN_INTLOCK(NULL);

    sclp_attn_async(SCCB_EVD_TYPE_SYSG);

    RELEASE_INTLOCK(NULL);
}
#endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/


#if defined(_FEATURE_INTEGRATED_ASCII_CONSOLE)
int sclp_sysa_write(SCCB_HEADER *sccb)
{
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
U16 evd_len;
U16 sysa_len;
BYTE *sysa_data;
int i;
    logmsg(D_("SYSA write:"));
    FETCH_HW(evd_len,evd_hdr->totlen);
    sysa_data = (BYTE*)(evd_hdr+1);
    sysa_len = evd_len - sizeof(SCCB_EVD_HDR);
    for(i = 0; i < sysa_len; i++)
    {
        if(!(i & 15))
            logmsg("\n          %4.4X:", i);
        logmsg(" %2.2X", sysa_data[i]);
    }

    if(i & 15)
        logmsg("\n");

    /* Indicate Event Processed */
    evd_hdr->flag |= SCCB_EVD_FLAG_PROC;

    /* Set response code X'0020' in SCCB header */
    sccb->reas = SCCB_REAS_NONE;
    sccb->resp = SCCB_RESP_COMPLETE;  // maybe this needs to be INFO

    //sclp_attention(SCCB_EVD_TYPE_VT220);

    return 0; // write ok
}

int sclp_sysa_poll(SCCB_HEADER *sccb)
{
SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1);

    UNREFERENCED(sccb);
    UNREFERENCED(evd_hdr);
    
    logmsg(D_("VT220 poll\n"));
}
#endif /*defined(_FEATURE_INTEGRATED_ASCII_CONSOLE)*/


/*-------------------------------------------------------------------*/
/* Suspend and resume functions                                      */
/*-------------------------------------------------------------------*/

#define SR_SYS_SERVC_RECVMASK    ( SR_SYS_SERVC | 0x001 )
#define SR_SYS_SERVC_SENDMASK    ( SR_SYS_SERVC | 0x002 )
#define SR_SYS_SERVC_PENDING     ( SR_SYS_SERVC | 0x003 )
#define SR_SYS_SERVC_SCPCMD      ( SR_SYS_SERVC | 0x004 )
#define SR_SYS_SERVC_SQC         ( SR_SYS_SERVC | 0x005 )
#define SR_SYS_SERVC_SQU         ( SR_SYS_SERVC | 0x006 )
#define SR_SYS_SERVC_PARM        ( SR_SYS_SERVC | 0x007 )

int servc_hsuspend(void *file)
{
    SR_WRITE_VALUE(file, SR_SYS_SERVC_RECVMASK, servc_cp_recv_mask, sizeof(servc_cp_recv_mask));
    SR_WRITE_VALUE(file, SR_SYS_SERVC_SENDMASK, servc_cp_send_mask, sizeof(servc_cp_send_mask));
    SR_WRITE_VALUE(file, SR_SYS_SERVC_PENDING, servc_attn_pending, sizeof(servc_attn_pending));
    SR_WRITE_STRING(file, SR_SYS_SERVC_SCPCMD,  servc_scpcmdstr);
    SR_WRITE_VALUE(file, SR_SYS_SERVC_SQC,      servc_signal_quiesce_count,
                                         sizeof(servc_signal_quiesce_count));
    SR_WRITE_VALUE(file, SR_SYS_SERVC_SQU,      servc_signal_quiesce_unit,
                                         sizeof(servc_signal_quiesce_unit));
    SR_WRITE_VALUE(file, SR_SYS_SERVC_PARM,     sysblk.servparm,
                                         sizeof(sysblk.servparm));
    return 0;
}

int servc_hresume(void *file)
{
    size_t key, len;

    sclp_reset();
    do {
        SR_READ_HDR(file, key, len);
        switch (key) {
        case SR_SYS_SERVC_RECVMASK:
            SR_READ_VALUE(file, len, &servc_cp_recv_mask, sizeof(servc_cp_recv_mask));
            break;
        case SR_SYS_SERVC_SENDMASK:
            SR_READ_VALUE(file, len, &servc_cp_send_mask, sizeof(servc_cp_send_mask));
            break;
        case SR_SYS_SERVC_PENDING:
            SR_READ_VALUE(file, len, &servc_attn_pending, sizeof(servc_attn_pending));
            break;
        case SR_SYS_SERVC_SCPCMD:
            SR_READ_STRING(file, servc_scpcmdstr, sizeof(servc_scpcmdstr));
            break;
        case SR_SYS_SERVC_SQC:
            SR_READ_VALUE(file, len, &servc_signal_quiesce_count,
                              sizeof(servc_signal_quiesce_count));
            break;
        case SR_SYS_SERVC_SQU:
            SR_READ_VALUE(file, len, &servc_signal_quiesce_unit,
                              sizeof(servc_signal_quiesce_unit));
            break;
        case SR_SYS_SERVC_PARM:
            SR_READ_VALUE(file, len, &sysblk.servparm, sizeof(sysblk.servparm));
            break;
        default:
            SR_READ_SKIP(file, len);
            break;
        }
    } while ((key & SR_SYS_MASK) == SR_SYS_SERVC);
    return 0;
}

#endif /*!defined(_SERVICE_C)*/

// #endif /*FEATURE_SYSTEM_CONSOLE*/

#if defined(FEATURE_SERVICE_PROCESSOR)
/*-------------------------------------------------------------------*/
/* Architecture-dependent service processor bit strings              */
/*-------------------------------------------------------------------*/
BYTE ARCH_DEP(scpinfo_ifm)[8] = {
                        0
                        | SCCB_IFM0_CHANNEL_PATH_INFORMATION
                        | SCCB_IFM0_CHANNEL_PATH_SUBSYSTEM_COMMAND
//                      | SCCB_IFM0_CHANNEL_PATH_RECONFIG
//                      | SCCB_IFM0_CPU_INFORMATION
#ifdef FEATURE_CPU_RECONFIG
                        | SCCB_IFM0_CPU_RECONFIG
#endif /*FEATURE_CPU_RECONFIG*/
                        ,
                        0
//                      | SCCB_IFM1_SIGNAL_ALARM
//                      | SCCB_IFM1_WRITE_OPERATOR_MESSAGE
//                      | SCCB_IFM1_STORE_STATUS_ON_LOAD
//                      | SCCB_IFM1_RESTART_REASONS
//                      | SCCB_IFM1_INSTRUCTION_ADDRESS_TRACE_BUFFER
                        | SCCB_IFM1_LOAD_PARAMETER
                        ,
                        0
//                      | SCCB_IFM2_REAL_STORAGE_INCREMENT_RECONFIG
//                      | SCCB_IFM2_REAL_STORAGE_ELEMENT_INFO
//                      | SCCB_IFM2_REAL_STORAGE_ELEMENT_RECONFIG
//                      | SCCB_IFM2_COPY_AND_REASSIGN_STORAGE
#ifdef FEATURE_EXPANDED_STORAGE
                        | SCCB_IFM2_EXTENDED_STORAGE_USABILITY_MAP
#endif /*FEATURE_EXPANDED_STORAGE*/
//                      | SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_INFO
//                      | SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_RECONFIG
                        ,
                        0
#if defined(FEATURE_VECTOR_FACILITY) && defined(FEATURE_CPU_RECONFIG)
                        | SCCB_IFM3_VECTOR_FEATURE_RECONFIG
#endif /*FEATURE_VECTOR_FACILITY*/
#ifdef FEATURE_SYSTEM_CONSOLE
                        | SCCB_IFM3_READ_WRITE_EVENT_FEATURE
#endif /*FEATURE_SYSTEM_CONSOLE*/
//                      | SCCB_IFM3_READ_RESOURCE_GROUP_INFO
                        ,
                        0, 0, 0, 0 };

BYTE ARCH_DEP(scpinfo_cfg)[6] = {
                        0
#if defined(FEATURE_HYPERVISOR)
                        | SCCB_CFG0_LOGICALLY_PARTITIONED
#endif /*defined(FEATURE_HYPERVISOR)*/
#ifdef FEATURE_SUPPRESSION_ON_PROTECTION
                        | SCCB_CFG0_SUPPRESSION_ON_PROTECTION
#endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/
//                      | SCCB_CFG0_INITIATE_RESET
#if defined(FEATURE_CHSC)
                        | SCCB_CFG0_STORE_CHANNEL_SUBSYS_CHARACTERISTICS
#endif /*defined(FEATURE_CHSC)*/
#if defined(FEATURE_MOVE_PAGE_FACILITY_2)
                        | SCCB_CFG0_MVPG_FOR_ALL_GUESTS
#endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/
#if defined(FEATURE_FAST_SYNC_DATA_MOVER)
    /* The Fast Sync Data Mover facility is simply a flag which
       indicates that the MVPG instruction performs faster than
       the Asynchronous Data Mover facility (see GA22-1030-03) */
                        | SCCB_CFG0_FAST_SYNCHRONOUS_DATA_MOVER
#endif /*defined(FEATURE_FAST_SYNC_DATA_MOVER)*/
                        ,
                        0
//                      | SCCB_CFG1_CSLO
                        ,
                        0
//                      | SCCB_CFG2_DEVICE_ACTIVE_ONLY_MEASUREMENT
#ifdef FEATURE_CALLED_SPACE_IDENTIFICATION
                        | SCCB_CFG2_CALLED_SPACE_IDENTIFICATION
#endif /*FEATURE_CALLED_SPACE_IDENTIFICATION*/
#ifdef FEATURE_CHECKSUM_INSTRUCTION
                        | SCCB_CFG2_CHECKSUM_INSTRUCTION
#endif /*FEATURE_CHECKSUM_INSTRUCTION*/
                        ,
                        0
#if defined(FEATURE_RESUME_PROGRAM)
                        | SCCB_CFG3_RESUME_PROGRAM
#endif /*defined(FEATURE_RESUME_PROGRAM)*/
#if defined(FEATURE_PERFORM_LOCKED_OPERATION)
                        | SCCB_CFG3_PERFORM_LOCKED_OPERATION
#endif /*defined(FEATURE_PERFORM_LOCKED_OPERATION)*/
#ifdef FEATURE_IMMEDIATE_AND_RELATIVE
                        | SCCB_CFG3_IMMEDIATE_AND_RELATIVE
#endif /*FEATURE_IMMEDIATE_AND_RELATIVE*/
#ifdef FEATURE_COMPARE_AND_MOVE_EXTENDED
                        | SCCB_CFG3_COMPARE_AND_MOVE_EXTENDED
#endif /*FEATURE_COMPARE_AND_MOVE_EXTENDED*/
#ifdef FEATURE_BRANCH_AND_SET_AUTHORITY
                        | SCCB_CFG3_BRANCH_AND_SET_AUTHORITY
#endif /*FEATURE_BRANCH_AND_SET_AUTHORITY*/
#if defined(FEATURE_BASIC_FP_EXTENSIONS)
                        | SCCB_CFG3_EXTENDED_FLOATING_POINT
#endif /*defined(FEATURE_BASIC_FP_EXTENSIONS)*/
/*ZZ*/                  | SCCB_CFG3_EXTENDED_LOGICAL_COMPUTATION_FACILITY
                        ,
                        0
#ifdef FEATURE_EXTENDED_TOD_CLOCK
                        | SCCB_CFG4_EXTENDED_TOD_CLOCK
#endif /*FEATURE_EXTENDED_TOD_CLOCK*/
#if defined(FEATURE_EXTENDED_TRANSLATION)
                        | SCCB_CFG4_EXTENDED_TRANSLATION
#endif /*defined(FEATURE_EXTENDED_TRANSLATION)*/
#if defined(FEATURE_LOAD_REVERSED)
                        | SCCB_CFG4_LOAD_REVERSED_FACILITY
#endif /*defined(FEATURE_LOAD_REVERSED)*/
#if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)
                        | SCCB_CFG4_EXTENDED_TRANSLATION_FACILITY2
#endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/
#if defined(FEATURE_STORE_SYSTEM_INFORMATION)
                        | SCCB_CFG4_STORE_SYSTEM_INFORMATION
#endif /*FEATURE_STORE_SYSTEM_INFORMATION*/
//                      | SCCB_CFG4_LPAR_CLUSTERING
                        | SCCB_CFG4_IFA_FACILITY
                        ,
                        0
#if defined(FEATURE_SENSE_RUNNING_STATUS)
                        | SCCB_CFG5_SENSE_RUNNING_STATUS
#endif /*FEATURE_SENSE_RUNNING_STATUS*/
                        };

BYTE ARCH_DEP(scpinfo_cfg11) =
    0
#if defined(FEATURE_PER3)
        | SCCB_CFGB_PER_3
#endif
        | SCCB_CFGB_LIST_DIRECTED_IPL;

BYTE ARCH_DEP(scpinfo_cpf)[12] = {
                            0
#if defined(FEATURE_INTERPRETIVE_EXECUTION)
#if defined(_370) && !defined(FEATURE_ESAME)
                            | SCCB_CPF0_SIE_370_MODE
#endif /*defined(_370) && !defined(FEATURE_ESAME)*/
                            | SCCB_CPF0_SIE_XA_MODE
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
//                          | SCCB_CPF0_SIE_SET_II_370_MODE
#if defined(FEATURE_IO_ASSIST)
                            | SCCB_CPF0_SIE_SET_II_XA_MODE
#endif /*defined(FEATURE_IO_ASSIST)*/
#if defined(FEATURE_INTERPRETIVE_EXECUTION)
                            | SCCB_CPF0_SIE_NEW_INTERCEPT_FORMAT
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
#if defined(FEATURE_STORAGE_KEY_ASSIST)
                            | SCCB_CPF0_STORAGE_KEY_ASSIST
#endif /*defined(FEATURE_STORAGE_KEY_ASSIST)*/
#if defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)
                            | SCCB_CPF0_MULTIPLE_CONTROLLED_DATA_SPACE
#endif /*defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/
                            ,
                            0
#if defined(FEATURE_IO_ASSIST)
                            | SCCB_CPF1_IO_INTERPRETATION_LEVEL_2
#endif /*defined(FEATURE_IO_ASSIST)*/
#if defined(FEATURE_INTERPRETIVE_EXECUTION)
                            | SCCB_CPF1_GUEST_PER_ENHANCED
#endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/
//                          | SCCB_CPF1_SIGP_INTERPRETATION_ASSIST
#if defined(FEATURE_STORAGE_KEY_ASSIST)
                            | SCCB_CPF1_RCP_BYPASS_FACILITY
#endif /*defined(FEATURE_STORAGE_KEY_ASSIST)*/
#if defined(FEATURE_REGION_RELOCATE)
                            | SCCB_CPF1_REGION_RELOCATE_FACILITY
#endif /*defined(FEATURE_REGION_RELOCATE)*/
#if defined(FEATURE_EXPEDITED_SIE_SUBSET)
                            | SCCB_CPF1_EXPEDITE_TIMER_PROCESSING
#endif /*defined(FEATURE_EXPEDITED_SIE_SUBSET)*/
                            ,
                            0
#if defined(FEATURE_CRYPTO)
                            | SCCB_CPF2_CRYPTO_FEATURE_ACCESSED
#endif /*defined(FEATURE_CRYPTO)*/
#if defined(FEATURE_EXPEDITED_SIE_SUBSET)
                            | SCCB_CPF2_EXPEDITE_RUN_PROCESSING
#endif /*defined(FEATURE_EXPEDITED_SIE_SUBSET)*/
                            ,
                            0
#ifdef FEATURE_PRIVATE_SPACE
                            | SCCB_CPF3_PRIVATE_SPACE_FEATURE
                            | SCCB_CPF3_FETCH_ONLY_BIT
#endif /*FEATURE_PRIVATE_SPACE*/
#if defined(FEATURE_PER2)
                            | SCCB_CPF3_PER2_INSTALLED
#endif /*defined(FEATURE_PER2)*/
                            ,
                            0
#if defined(FEATURE_PER2)
                            | SCCB_CPF4_OMISION_GR_ALTERATION_370
#endif /*defined(FEATURE_PER2)*/
                            ,
                            0
#if defined(FEATURE_WAITSTATE_ASSIST)
                            | SCCB_CPF5_GUEST_WAIT_STATE_ASSIST
#endif /*defined(FEATURE_WAITSTATE_ASSIST)*/
                            ,
                            0, 0, 0, 0, 0, 0
                            } ;

U32  ARCH_DEP(sclp_recv_mask) =
        (0x80000000 >> (SCCB_EVD_TYPE_MSG-1)) |
        (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) |
#if defined(FEATURE_SCEDIO)
        (0x80000000 >> (SCCB_EVD_TYPE_SCEDIO-1)) |
#endif /*defined(FEATURE_SCEDIO)*/
#if defined(FEATURE_INTEGRATED_ASCII_CONSOLE)
        (0x80000000 >> (SCCB_EVD_TYPE_VT220-1)) |
#endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/
#if defined(FEATURE_INTEGRATED_3270_CONSOLE)
        (0x80000000 >> (SCCB_EVD_TYPE_SYSG-1)) |
#endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/
        (0x80000000 >> (SCCB_EVD_TYPE_CPIDENT-1)) ;

U32  ARCH_DEP(sclp_send_mask) =
        (0x80000000 >> (SCCB_EVD_TYPE_OPCMD-1)) |
        (0x80000000 >> (SCCB_EVD_TYPE_STATECH-1)) |
        (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) |
        (0x80000000 >> (SCCB_EVD_TYPE_SIGQ-1)) |
#if defined(FEATURE_SCEDIO)
        (0x80000000 >> (SCCB_EVD_TYPE_SCEDIO-1)) |
#endif /*defined(FEATURE_SCEDIO)*/
#if defined(FEATURE_INTEGRATED_ASCII_CONSOLE)
        (0x80000000 >> (SCCB_EVD_TYPE_VT220-1)) |
#endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/
#if defined(FEATURE_INTEGRATED_3270_CONSOLE)
        (0x80000000 >> (SCCB_EVD_TYPE_SYSG-1)) |
#endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/
        (0x80000000 >> (SCCB_EVD_TYPE_CPCMD-1)) ;


/*-------------------------------------------------------------------*/
/* B220 SERVC - Service Call                                   [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(service_call)
{
U32             r1, r2;                 /* Values of R fields        */
U32             sclp_command;           /* SCLP command code         */
U32             sccb_real_addr;         /* SCCB real address         */
int             i;                      /* Array subscripts          */
U32             realmb;                 /* Real storage size in MB   */
U32             sccb_absolute_addr;     /* Absolute address of SCCB  */
U32             sccblen;                /* Length of SCCB            */
SCCB_HEADER    *sccb;                   /* -> SCCB header            */
SCCB_SCP_INFO  *sccbscp;                /* -> SCCB SCP information   */
SCCB_CPU_INFO  *sccbcpu;                /* -> SCCB CPU information   */
#if defined(FEATURE_MPF_INFO)
SCCB_MPF_INFO  *sccbmpf;                /* -> SCCB MPF information   */
#endif /*defined(FEATURE_MPF_INFO)*/
#ifdef FEATURE_CHANNEL_SUBSYSTEM
SCCB_CHP_INFO  *sccbchp;                /* -> SCCB channel path info */
#else
SCCB_CHSET_INFO *sccbchp;               /* -> SCCB channel path info */
#endif
SCCB_CSI_INFO  *sccbcsi;                /* -> SCCB channel subsys inf*/
U16             offset;                 /* Offset from start of SCCB */
#ifdef FEATURE_CHANNEL_SUBSYSTEM
DEVBLK         *dev;                    /* Used to find CHPIDs       */
U32             chpbyte;                /* Offset to byte for CHPID  */
U32             chpbit;                 /* Bit number for CHPID      */
#endif /*FEATURE_CHANNEL_SUBSYSTEM*/
#ifdef FEATURE_SYSTEM_CONSOLE
SCCB_EVENT_MASK*evd_mask;               /* Event mask                */
SCCB_EVD_HDR   *evd_hdr;                /* Event header              */
U16             evd_len;                /* Length of event data      */
SCCB_MCD_BK    *mcd_bk;                 /* Message Control Data      */
U16             mcd_len;                /* Length of MCD             */
SCCB_OBJ_HDR   *obj_hdr;                /* Object Header             */
U16             obj_len;                /* Length of Object          */
U16             obj_type;               /* Object type               */
SCCB_MTO_BK    *mto_bk;                 /* Message Text Object       */
BYTE           *event_msg;              /* Message Text pointer      */
int             event_msglen;           /* Message Text length       */
BYTE            message[4089];          /* Maximum event data buffer
                                           length plus one for \0    */
U32             masklen;                /* Length of event mask      */
U32             old_cp_recv_mask;       /* Masks before write event  */
U32             old_cp_send_mask;       /*              mask command */
#endif /*FEATURE_SYSTEM_CONSOLE*/


#ifdef FEATURE_EXPANDED_STORAGE
SCCB_XST_MAP    *sccbxmap;              /* Xstore usability map      */
U32             xstincnum;              /* Number of expanded storage
                                                         increments  */
U32             xstblkinc;              /* Number of expanded storage
                                               blocks per increment  */
BYTE            *xstmap;                /* Xstore bitmap, zero means
                                                           available */
#endif /*FEATURE_EXPANDED_STORAGE*/

    RRE(inst, regs, r1, r2);

    PRIV_CHECK(regs);

    SIE_INTERCEPT(regs);

    PTT(PTT_CL_INF,"SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);

    /* R1 is SCLP command word */
    sclp_command = regs->GR_L(r1);

    /* R2 is real address of service call control block */
    sccb_real_addr = regs->GR_L(r2);

    /* Obtain the absolute address of the SCCB */
    sccb_absolute_addr = APPLY_PREFIXING(sccb_real_addr, regs->PX);

    /* Program check if SCCB is not on a doubleword boundary */
    if ( sccb_absolute_addr & 0x00000007 )
        ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);

    /* Program check if SCCB is outside main storage */
    if ( sccb_absolute_addr > regs->mainlim )
        ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);

    /* Point to service call control block */
    sccb = (SCCB_HEADER*)(regs->mainstor + sccb_absolute_addr);

    /* Load SCCB length from header */
    FETCH_HW(sccblen, sccb->length);

    /* Set the main storage reference bit */
    STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_REF;

    /* Program check if end of SCCB falls outside main storage */
    if ( sccb_absolute_addr + sccblen > regs->mainlim + 1)
        ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);

    /* Obtain lock if immediate response is not requested */
    if (!(sccb->flag & SCCB_FLAG_SYNC)
        || (sclp_command & SCLP_COMMAND_CLASS) == 0x01)
    {
        /* Obtain the interrupt lock */
        OBTAIN_INTLOCK(regs);

        /* If a service signal is pending then return condition
           code 2 to indicate that service processor is busy */
        if (IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_ADDR))
        {
            RELEASE_INTLOCK(regs);
            regs->psw.cc = 2;
            return;
        }
    }

    /* Test SCLP command word */
    switch (sclp_command & SCLP_COMMAND_MASK) {

    case SCLP_READ_IFL_INFO:
        /* READ_IFL_INFO is only valid for processor type IFL */
        if(sysblk.ptyp[regs->cpuad] != SCCB_PTYP_IFL)
            goto invalidcmd;
        else
            goto read_scpinfo;

    case SCLP_READ_SCP_INFO:
        /* READ_SCP_INFO is only valid for processor type CP */
        if(sysblk.ptyp[regs->cpuad] != SCCB_PTYP_CP)
        {
#ifdef OPTION_MSGCLR
            logmsg("<pnl,color(lightred,black)>");
#endif
            logmsg("HHCCP090W The configuration has been placed into a system check-stop state because of an incompatible service call\n\n");
            goto docheckstop;
            /*
             * Replace the following 2 lines with
             * goto invalidcmd
             * if this behavior is not satisfactory
             * ISW 20081221
             */
        }

    read_scpinfo:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Set response code X'0300' if SCCB length
           is insufficient to contain SCP info */
        if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_SCP_INFO)
                + (sizeof(SCCB_CPU_INFO) * MAX_CPU))
        {
            sccb->reas = SCCB_REAS_TOO_SHORT;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        sccbscp = (SCCB_SCP_INFO*)(sccb+1);
        memset (sccbscp, 0, sizeof(SCCB_SCP_INFO));

        /* Set main storage size in SCCB */
        realmb = sysblk.mainsize >> 20;
        STORE_HW(sccbscp->realinum, realmb);
        sccbscp->realiszm = 1;
        sccbscp->realbszk = 4;
        STORE_HW(sccbscp->realiint, 1);

#if defined(_900) || defined(FEATURE_ESAME)
        /* SIE supports the full address range */
        sccbscp->maxvm = 0;
        /* realiszm is valid */
        STORE_FW(sccbscp->grzm, 0);
        /* Number of storage increments installed in esame mode */
        STORE_DW(sccbscp->grnmx, realmb);
#endif /*defined(_900) || defined(FEATURE_ESAME)*/

#ifdef FEATURE_EXPANDED_STORAGE
        /* Set expanded storage size in SCCB */
        xstincnum = sysblk.xpndsize /
                    (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
        STORE_FW(sccbscp->xpndinum, xstincnum);
        xstblkinc = XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT;
        STORE_FW(sccbscp->xpndsz4K, xstblkinc);
#endif /*FEATURE_EXPANDED_STORAGE*/

#ifdef FEATURE_VECTOR_FACILITY
        /* Set the Vector section size in the SCCB */
        STORE_HW(sccbscp->vectssiz, VECTOR_SECTION_SIZE);
        /* Set the Vector partial sum number in the SCCB */
        STORE_HW(sccbscp->vectpsum, VECTOR_PARTIAL_SUM_NUMBER);
#endif /*FEATURE_VECTOR_FACILITY*/

        /* Set CPU array count and offset in SCCB */
        STORE_HW(sccbscp->numcpu, MAX_CPU);
        offset = sizeof(SCCB_HEADER) + sizeof(SCCB_SCP_INFO);
        STORE_HW(sccbscp->offcpu, offset);

#if defined(FEATURE_MPF_INFO)
        /* Set MPF array count and offset in SCCB */
        STORE_HW(sccbscp->nummpf, MAX_CPU-1);
#endif /*defined(FEATURE_MPF_INFO)*/
        offset += sizeof(SCCB_CPU_INFO) * MAX_CPU;
        STORE_HW(sccbscp->offmpf, offset);

        /* Set HSA array count and offset in SCCB */
        STORE_HW(sccbscp->numhsa, 0);
#if defined(FEATURE_MPF_INFO)
        offset += sizeof(SCCB_MPF_INFO) * MAX_CPU-1;
#endif /*defined(FEATURE_MPF_INFO)*/
        STORE_HW(sccbscp->offhsa, offset);

        /* Build the MPF information array after the CPU info */
        /* Move IPL load parameter to SCCB */
        get_loadparm (sccbscp->loadparm);

        /* Set installed features bit mask in SCCB */
        memcpy(sccbscp->ifm, ARCH_DEP(scpinfo_ifm), sizeof(sccbscp->ifm));

        memcpy(sccbscp->cfg, ARCH_DEP(scpinfo_cfg), sizeof(sccbscp->cfg));
        /* sccbscp->cfg11 = ARCH_DEP(scpinfo_cfg11); */
#if defined(_900) || defined(FEATURE_ESAME)
        if(sysblk.arch_z900)
            sccbscp->cfg[5] |= SCCB_CFG5_ESAME;
#endif /*defined(_900) || defined(FEATURE_ESAME)*/
                        ;

        /* Build the CPU information array after the SCP info */
        sccbcpu = (SCCB_CPU_INFO*)(sccbscp+1);
        for (i = 0; i < MAX_CPU; i++, sccbcpu++)
        {
            memset (sccbcpu, 0, sizeof(SCCB_CPU_INFO));
            sccbcpu->cpa = i;
            sccbcpu->tod = 0;
            memcpy(sccbcpu->cpf, ARCH_DEP(scpinfo_cpf), sizeof(sccbcpu->cpf));
            sccbcpu->ptyp = sysblk.ptyp[i];

#if defined(FEATURE_CRYPTO)
//          sccbcpu->ksid = SCCB_KSID_CRYPTO_UNIT_ID;
#endif /*defined(FEATURE_CRYPTO)*/

#ifdef FEATURE_VECTOR_FACILITY
            if(IS_CPU_ONLINE(i) && sysblk.regs[i]->vf->online)
                sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_INSTALLED;
            if(IS_CPU_ONLINE(i) && sysblk.regs[i]->vf->online)
                sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_CONNECTED;
            if(!IS_CPU_ONLINE(i))
                sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_STANDBY_STATE;
#endif /*FEATURE_VECTOR_FACILITY*/

        }

#if defined(FEATURE_MPF_INFO)
        /* Define machine capacity */
        STORE_FW(sccbscp->rcci, 10000);
        /* Fill in the MP Factors array */
        sccbmpf = (SCCB_MPF_INFO*)(sccbcpu);
        get_mpfactors((BYTE*)sccbmpf);
#endif /*defined(FEATURE_MPF_INFO)*/

        /* Set response code X'0010' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_INFO;

        break;
        docheckstop:
            ARCH_DEP(checkstop_config)();
            RELEASE_INTLOCK(regs);
            longjmp(regs->progjmp,SIE_NO_INTERCEPT);
            break;

    case SCLP_READ_CHP_INFO:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Set response code X'0300' if SCCB length
           is insufficient to contain channel path info */
        if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_CHP_INFO))
        {
            sccb->reas = SCCB_REAS_TOO_SHORT;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

#ifdef FEATURE_S370_CHANNEL
        /* Point to SCCB data area following SCCB header */
        sccbchp = (SCCB_CHSET_INFO*)(sccb+1);
        memset (sccbchp, 0, sizeof(SCCB_CHSET_INFO));
#else
        /* Point to SCCB data area following SCCB header */
        sccbchp = (SCCB_CHP_INFO*)(sccb+1);
        memset (sccbchp, 0, sizeof(SCCB_CHP_INFO));
#endif

#ifdef FEATURE_CHANNEL_SUBSYSTEM
        /* Identify CHPIDs installed, standby, and online */
        for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
        {
            chpbyte = dev->devnum >> 11;
            chpbit = (dev->devnum >> 8) & 7;

            sccbchp->installed[chpbyte] |= 0x80 >> chpbit;
            if (dev->pmcw.flag5 & PMCW5_V)
                sccbchp->online[chpbyte] |= 0x80 >> chpbit;
            else
                sccbchp->standby[chpbyte] |= 0x80 >> chpbit;
        }
#endif /*FEATURE_CHANNEL_SUBSYSTEM*/

#ifdef FEATURE_S370_CHANNEL
        /* For S/370, initialize identifiers for channel set 0A */
        for (i = 0; i < 16; i++)
        {
            sccbchp->chanset0a[2*i] = 0x80;
            sccbchp->chanset0a[2*i+1] = i;
        } /* end for(i) */

        /* Set the channel set configuration byte */
        sccbchp->csconfig = 0xC0;
#endif /*FEATURE_S370_CHANNEL*/

        /* Set response code X'0010' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_INFO;

        break;

    case SCLP_READ_CSI_INFO:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Set response code X'0300' if SCCB length
           is insufficient to contain channel path info */
        if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_CSI_INFO))
        {
            sccb->reas = SCCB_REAS_TOO_SHORT;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        sccbcsi = (SCCB_CSI_INFO*)(sccb+1);
        memset (sccbcsi, 0, sizeof(SCCB_CSI_INFO));

        sccbcsi->csif[0] = 0
#if defined(FEATURE_CANCEL_IO_FACILITY)
                        | SCCB_CSI0_CANCEL_IO_REQUEST_FACILITY
#endif /*defined(FEATURE_CANCEL_IO_FACILITY)*/
                        | SCCB_CSI0_CONCURRENT_SENSE_FACILITY
                        ;

        /* Set response code X'0010' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_INFO;

        break;

#ifdef FEATURE_SYSTEM_CONSOLE
    case SCLP_WRITE_EVENT_DATA:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        evd_hdr = (SCCB_EVD_HDR*)(sccb+1);
        FETCH_HW(evd_len,evd_hdr->totlen);

        switch(evd_hdr->type) {

        case SCCB_EVD_TYPE_MSG:
        case SCCB_EVD_TYPE_PRIOR:

            /* Point to the Message Control Data Block */
            mcd_bk = (SCCB_MCD_BK*)(evd_hdr+1);
            FETCH_HW(mcd_len,mcd_bk->length);

            obj_hdr = (SCCB_OBJ_HDR*)(mcd_bk+1);

            while (mcd_len > sizeof(SCCB_MCD_BK))
            {
                FETCH_HW(obj_len,obj_hdr->length);
                if (obj_len == 0)
                {
                    sccb->reas = SCCB_REAS_BUFF_LEN_ERR;
                    sccb->resp = SCCB_RESP_BUFF_LEN_ERR;
                    break;
                }
                FETCH_HW(obj_type,obj_hdr->type);
                if (obj_type == SCCB_OBJ_TYPE_MESSAGE)
                {
                    mto_bk = (SCCB_MTO_BK*)(obj_hdr+1);
                    event_msg = (BYTE*)(mto_bk+1);
                    event_msglen = obj_len -
                            (sizeof(SCCB_OBJ_HDR) + sizeof(SCCB_MTO_BK));
                    if (event_msglen < 0)
                    {
                        sccb->reas = SCCB_REAS_BUFF_LEN_ERR;
                        sccb->resp = SCCB_RESP_BUFF_LEN_ERR;
                        break;
                    }

                    /* Print line unless it is a response prompt */
                    if (!(mto_bk->ltflag[0] & SCCB_MTO_LTFLG0_PROMPT))
                    {
                        for (i = 0; i < event_msglen; i++)
                        {
                            message[i] = isprint(guest_to_host(event_msg[i])) ?
                                guest_to_host(event_msg[i]) : 0x20;
                        }
                        message[i] = '\0';
#ifdef OPTION_MSGCLR
                        if(evd_hdr->type == SCCB_EVD_TYPE_MSG)
                        {
                          if(mto_bk->presattr[3] == SCCB_MTO_PRATTR3_HIGH)
                            logmsg("<pnl,color(lightyellow,black),keep>%s\n", message);
                          else
                            logmsg ("<pnl,color(green,black)>%s\n", message);
                        }
                        else
                          logmsg ("<pnl,color(lightred,black),keep>%s\n", message);
#else
                        logmsg ("%s\n", message);
#endif
                    }
                }
                mcd_len -= obj_len;
                obj_hdr=(SCCB_OBJ_HDR *)((BYTE*)obj_hdr + obj_len);
            }

            /* Indicate Event Processed */
            evd_hdr->flag |= SCCB_EVD_FLAG_PROC;

            /* Set response code X'0020' in SCCB header */
            sccb->reas = SCCB_REAS_NONE;
            sccb->resp = SCCB_RESP_COMPLETE;

            break;


        case SCCB_EVD_TYPE_CPIDENT:
            sclp_cpident(sccb);
            break;

#if defined(FEATURE_SCEDIO)
        case SCCB_EVD_TYPE_SCEDIO:
            ARCH_DEP(sclp_scedio_request)(sccb);
            break;
#endif /*defined(FEATURE_SCEDIO)*/

#if defined(FEATURE_INTEGRATED_3270_CONSOLE)
        case SCCB_EVD_TYPE_SYSG:
            sclp_sysg_write(sccb);
            break;
#endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/


#if defined(FEATURE_INTEGRATED_ASCII_CONSOLE)
        case SCCB_EVD_TYPE_VT220:
            sclp_sysa_write(sccb);
            break;
#endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/


        default:

            PTT(PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),evd_hdr->type);

            if( HDC3(debug_sclp_unknown_event, evd_hdr, sccb, regs) )
                break;

            /* Set response code X'73F0' in SCCB header */
            sccb->reas = SCCB_REAS_SYNTAX_ERROR;
            sccb->resp = SCCB_RESP_SYNTAX_ERROR;

            break;

        }

        break;

    case SCLP_READ_EVENT_DATA:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        evd_hdr = (SCCB_EVD_HDR*)(sccb+1);

        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_PRIOR) && sclp_attn_pending(SCCB_EVD_TYPE_PRIOR))
        {
            sclp_opcmd_event(sccb, SCCB_EVD_TYPE_PRIOR);
            break;
        }

        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_OPCMD) && sclp_attn_pending(SCCB_EVD_TYPE_OPCMD))
        {
            sclp_opcmd_event(sccb, SCCB_EVD_TYPE_OPCMD);
            break;
        }


#if defined(FEATURE_SCEDIO)
        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SCEDIO) && sclp_attn_pending(SCCB_EVD_TYPE_SCEDIO))
        {
            ARCH_DEP(sclp_scedio_event)(sccb);
            break;
        }
#endif /*defined(FEATURE_SCEDIO)*/


#if defined(FEATURE_INTEGRATED_3270_CONSOLE)
        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SYSG) && sclp_attn_pending(SCCB_EVD_TYPE_SYSG))
        {
            sclp_sysg_poll(sccb);
            break;
        }
#endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/


#if defined(FEATURE_INTEGRATED_ASCII_CONSOLE)
        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_VT220) && sclp_attn_pending(SCCB_EVD_TYPE_VT220))
        {
            sclp_sysa_poll(sccb);
            break;
        }
#endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/

        if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ) && sclp_attn_pending(SCCB_EVD_TYPE_SIGQ))
        {
            sclp_sigq_event(sccb);
            break;
        }

        PTT(PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);

        if( HDC3(debug_sclp_event_data, evd_hdr, sccb, regs) )
            break;

        /* Set response code X'62F0' if events are pending but suppressed */
        if(sclp_attn_pending(0))
        {
            sccb->reas = SCCB_REAS_EVENTS_SUP;
            sccb->resp = SCCB_RESP_EVENTS_SUP;
            break;
        }
        else
        {
            /* Set response code X'60F0' if no outstanding events */
            sccb->reas = SCCB_REAS_NO_EVENTS;
            sccb->resp = SCCB_RESP_NO_EVENTS;
        }

        break;


    case SCLP_WRITE_EVENT_MASK:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        evd_mask = (SCCB_EVENT_MASK*)(sccb+1);

        /* Get length of single mask field */
        FETCH_HW(masklen, evd_mask->length);

        /* Save old mask settings in order to suppress superflous messages */
        old_cp_recv_mask = servc_cp_recv_mask & ARCH_DEP(sclp_send_mask) & SCCB_EVENT_CONS_RECV_MASK;
        old_cp_send_mask = servc_cp_send_mask & ARCH_DEP(sclp_recv_mask) & SCCB_EVENT_CONS_SEND_MASK;

        for (i = 0; i < 4; i++)
        {
            servc_cp_recv_mask <<= 8;
            servc_cp_send_mask <<= 8;
            if ((U32)i < masklen)
            {
                servc_cp_recv_mask |= evd_mask->masks[i+(0*masklen)];
                servc_cp_send_mask |= evd_mask->masks[i+(1*masklen)];
            }
        }

        if((servc_cp_recv_mask & ~ARCH_DEP(sclp_recv_mask))
          || (servc_cp_send_mask & ~ARCH_DEP(sclp_send_mask)))
            HDC3(debug_sclp_unknown_event_mask, evd_mask, sccb, regs);

        /* Write the events that we support back */
        memset (&evd_mask->masks[2 * masklen], 0, 2 * masklen);
        for (i = 0; (i < 4) && ((U32)i < masklen); i++)
        {
            evd_mask->masks[i+(2*masklen)] |= (ARCH_DEP(sclp_recv_mask) >> ((3-i)*8)) & 0xFF;
            evd_mask->masks[i+(3*masklen)] |= (ARCH_DEP(sclp_send_mask) >> ((3-i)*8)) & 0xFF;
        }

        /* Issue message only when supported mask has changed */
        if ((servc_cp_recv_mask & ARCH_DEP(sclp_send_mask) & SCCB_EVENT_CONS_RECV_MASK) != old_cp_recv_mask
         || (servc_cp_send_mask & ARCH_DEP(sclp_recv_mask) & SCCB_EVENT_CONS_SEND_MASK) != old_cp_send_mask)
        {
            if ((servc_cp_recv_mask & SCCB_EVENT_CONS_RECV_MASK) != 0
                || (servc_cp_send_mask & SCCB_EVENT_CONS_SEND_MASK) != 0)
                logmsg (_("HHCCP041I SYSCONS interface active\n"));
            else
                logmsg (_("HHCCP042I SYSCONS interface inactive\n"));
        }

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;

        break;
#endif /*FEATURE_SYSTEM_CONSOLE*/

#ifdef FEATURE_EXPANDED_STORAGE
   case SCLP_READ_XST_MAP:

        /* Set the main storage change bit */
        STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE;

        /* Set response code X'0100' if SCCB crosses a page boundary */
        if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) !=
            ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK))
        {
            sccb->reas = SCCB_REAS_NOT_PGBNDRY;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Calculate number of blocks per increment */
        xstblkinc = XSTORE_INCREMENT_SIZE / XSTORE_PAGESIZE;

        /* Set response code X'0300' if SCCB length
           is insufficient to contain xstore info */
        if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_XST_MAP)
                + xstblkinc/8)
        {
            sccb->reas = SCCB_REAS_TOO_SHORT;
            sccb->resp = SCCB_RESP_BLOCK_ERROR;
            break;
        }

        /* Point to SCCB data area following SCCB header */
        sccbxmap = (SCCB_XST_MAP*)(sccb+1);

        /* Verify expanded storage increment number */
        xstincnum = sysblk.xpndsize /
                    (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT);
        FETCH_FW(i, sccbxmap->incnum);
        if ( i < 1 || (U32)i > xstincnum )
        {
            sccb->reas = SCCB_REAS_INVALID_RSC;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        /* Point to bitmap */
        xstmap = (BYTE*)(sccbxmap+1);

        /* Set all blocks available */
        memset (xstmap, 0x00, xstblkinc/8);

        /* Set response code X'0010' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_INFO;

        break;

#endif /*FEATURE_EXPANDED_STORAGE*/

#ifdef FEATURE_CPU_RECONFIG

    case SCLP_CONFIGURE_CPU:

        i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT;

        /* Return invalid resource in parm if target does not exist */
        if(i >= MAX_CPU)
        {
            sccb->reas = SCCB_REAS_INVALID_RSCP;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        /* Add cpu to the configuration */
        configure_cpu(i);

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
        break;

    case SCLP_DECONFIGURE_CPU:

        i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT;

        /* Return invalid resource in parm if target does not exist */
        if(i >= MAX_CPU)
        {
            sccb->reas = SCCB_REAS_INVALID_RSCP;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        /* Take cpu out of the configuration */
        deconfigure_cpu(i);

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
        break;

#ifdef FEATURE_VECTOR_FACILITY

    case SCLP_DISCONNECT_VF:

        i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT;

        /* Return invalid resource in parm if target does not exist */
        if(i >= MAX_CPU || !IS_CPU_ONLINE(i))
        {
            sccb->reas = SCCB_REAS_INVALID_RSCP;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        if(sysblk.regs[i]->vf->online)
            logmsg(_("CPU%4.4X: Vector Facility configured offline\n"),i);

        /* Take the VF out of the configuration */
        sysblk.regs[i]->vf->online = 0;

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
        break;

    case SCLP_CONNECT_VF:

        i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT;

        /* Return invalid resource in parm if target does not exist */
        if(i >= MAX_CPU)
        {
            sccb->reas = SCCB_REAS_INVALID_RSCP;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        /* Return improper state if associated cpu is offline */
        if(!IS_CPU_ONLINE(i))
        {
            sccb->reas = SCCB_REAS_IMPROPER_RSC;
            sccb->resp = SCCB_RESP_REJECT;
            break;
        }

        if(!sysblk.regs[i]->vf->online)
            logmsg(_("CPU%4.4X: Vector Facility configured online\n"),i);

        /* Mark the VF online to the CPU */
        sysblk.regs[i]->vf->online = 1;

        /* Set response code X'0020' in SCCB header */
        sccb->reas = SCCB_REAS_NONE;
        sccb->resp = SCCB_RESP_COMPLETE;
        break;

#endif /*FEATURE_VECTOR_FACILITY*/

#endif /*FEATURE_CPU_RECONFIG*/

    default:
    invalidcmd:

        PTT(PTT_CL_INF|PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);

        if( HDC3(debug_sclp_unknown_command, sclp_command, sccb, regs) )
            break;

        /* Set response code X'01F0' for invalid SCLP command */
        sccb->reas = SCCB_REAS_INVALID_CMD;
        sccb->resp = SCCB_RESP_REJECT;

        break;

    } /* end switch(sclp_command) */

    /* If immediate response is requested, return condition code 1 */
    if ((sccb->flag & SCCB_FLAG_SYNC)
        && (sclp_command & SCLP_COMMAND_CLASS) != 0x01)
    {
        regs->psw.cc = 1;
        return;
    }

    /* Set service signal external interrupt pending */
    sysblk.servparm &= ~SERVSIG_ADDR;
    sysblk.servparm |= sccb_absolute_addr;
    ON_IC_SERVSIG;

    /* Release the interrupt lock */
    RELEASE_INTLOCK(regs);

    /* Set condition code 0 */
    regs->psw.cc = 0;

} /* end function service_call */


#endif /*defined(FEATURE_SERVICE_PROCESSOR)*/


#if !defined(_GEN_ARCH)

#if defined(_ARCHMODE2)
 #define  _GEN_ARCH _ARCHMODE2
 #include "service.c"
#endif

#if defined(_ARCHMODE3)
 #undef   _GEN_ARCH
 #define  _GEN_ARCH _ARCHMODE3
 #include "service.c"
#endif

#endif /*!defined(_GEN_ARCH)*/
