mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-19 10:15:56 +02:00
336 lines
11 KiB
C
336 lines
11 KiB
C
/* MACHCHK.C (C) Copyright Jan Jaeger, 2000-2012 */
|
|
/* ESA/390 Machine Check Functions */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
/* */
|
|
/* z/Architecture support - (C) Copyright Jan Jaeger, 1999-2012 */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* The machine check function supports dynamic I/O configuration. */
|
|
/* When a subchannel is added/changed/deleted an ancillary */
|
|
/* channel report is made pending. This ancillary channel */
|
|
/* report can be read by the store channel report word I/O */
|
|
/* instruction. Changes to the availability will result in */
|
|
/* Messages IOS150I and IOS151I (device xxxx now/not available) */
|
|
/* Added Instruction processing damage machine check function such */
|
|
/* that abends/waits/loops in instructions will be reflected to the */
|
|
/* system running under hercules as a machine malfunction. This */
|
|
/* includes the machine check, checkstop, and malfunction alert */
|
|
/* external interrupt as defined in the architecture. - 6/8/01 *JJ */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _MACHCHK_C_
|
|
#define _HENGINE_DLL_
|
|
|
|
#include "hercules.h"
|
|
#include "opcode.h"
|
|
|
|
#ifndef _MACHCHK_C
|
|
#define _MACHCHK_C
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Build a Channel Path Reset Channel Report */
|
|
/*-------------------------------------------------------------------*/
|
|
void build_chp_reset_chrpt( BYTE chpid, int solicited, int found )
|
|
{
|
|
U32 crw_erc, crwarray[8], crwcount=0;
|
|
|
|
/* Just return if shutting down */
|
|
if (sysblk.shutdown)
|
|
return;
|
|
|
|
chpid = ((U32)chpid) & CRW_RSID_MASK;
|
|
|
|
/* If a subchannel was found on this path and was reset. Ref:
|
|
SA22-7832 "Channel-Path-Reset-Function-Completion Signaling */
|
|
if (found)
|
|
crw_erc = CRW_ERC_INIT; /* Init'ed, parms unchanged */
|
|
else
|
|
crw_erc = CRW_ERC_RESET; /* Error, parms initialized */
|
|
|
|
/* Build the Channel Path Reset Channel Report */
|
|
crwarray[crwcount++] = (solicited ? CRW_SOL : 0) |
|
|
CRW_RSC_CHPID | CRW_AR | crw_erc | chpid;
|
|
|
|
/* Queue the Channel Report */
|
|
VERIFY( queue_channel_report( crwarray, crwcount ) == 0 );
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Build a device attach Channel Report */
|
|
/*-------------------------------------------------------------------*/
|
|
void build_attach_chrpt( DEVBLK *dev )
|
|
{
|
|
U32 ssid, subchan, crwarray[8], crwcount=0;
|
|
int devlock_obtained;
|
|
|
|
/* Just return if shutting down */
|
|
if (sysblk.shutdown)
|
|
return;
|
|
|
|
/* Retrieve Source IDs */
|
|
devlock_obtained = (try_obtain_lock( &dev->lock ) == 0);
|
|
{
|
|
ssid = ((U32)SSID_TO_LCSS( dev->ssid )) & CRW_RSID_MASK;
|
|
subchan = ((U32)dev->subchan) & CRW_RSID_MASK;
|
|
}
|
|
if (devlock_obtained)
|
|
RELEASE_DEVLOCK( dev );
|
|
|
|
/* Build Subchannel Alert Channel Report */
|
|
crwarray[crwcount++] =
|
|
0
|
|
| (sysblk.mss ? CRW_CHAIN : 0)
|
|
| CRW_RSC_SUBCH
|
|
| CRW_AR
|
|
| CRW_ERC_ALERT
|
|
| subchan
|
|
;
|
|
if (sysblk.mss)
|
|
crwarray[crwcount++] =
|
|
0
|
|
| CRW_RSC_SUBCH
|
|
| CRW_AR
|
|
| CRW_ERC_ALERT
|
|
| (ssid << 8)
|
|
;
|
|
|
|
/* Queue the Channel Report(s) */
|
|
VERIFY( queue_channel_report( crwarray, crwcount ) == 0 );
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Build a device detach Channel Report */
|
|
/*-------------------------------------------------------------------*/
|
|
void build_detach_chrpt( DEVBLK *dev )
|
|
{
|
|
U32 ssid, subchan, crwarray[8], crwcount=0;
|
|
int devlock_obtained;
|
|
|
|
/* Just return if shutting down */
|
|
if (sysblk.shutdown)
|
|
return;
|
|
|
|
/* Retrieve Source IDs */
|
|
devlock_obtained = (try_obtain_lock( &dev->lock ) == 0);
|
|
{
|
|
ssid = ((U32)SSID_TO_LCSS( dev->ssid )) & CRW_RSID_MASK;
|
|
subchan = ((U32)dev->subchan) & CRW_RSID_MASK;
|
|
}
|
|
if (devlock_obtained)
|
|
RELEASE_DEVLOCK( dev );
|
|
|
|
/* Build Subchannel Alert Channel Report */
|
|
crwarray[crwcount++] =
|
|
0
|
|
| (sysblk.mss ? CRW_CHAIN : 0)
|
|
| CRW_RSC_SUBCH
|
|
| CRW_AR
|
|
| CRW_ERC_ALERT
|
|
| subchan
|
|
;
|
|
if (sysblk.mss)
|
|
crwarray[crwcount++] =
|
|
0
|
|
| CRW_RSC_SUBCH
|
|
| CRW_AR
|
|
| CRW_ERC_ALERT
|
|
| (ssid << 8)
|
|
;
|
|
|
|
/* Queue the Channel Report */
|
|
VERIFY( queue_channel_report( crwarray, crwcount ) == 0 );
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Add a Channel Report to the queue */
|
|
/*-------------------------------------------------------------------*/
|
|
int queue_channel_report( U32* crwarray, U32 crwcount )
|
|
{
|
|
OBTAIN_CRWLOCK();
|
|
|
|
if ((sysblk.crwcount + crwcount) > sysblk.crwalloc)
|
|
{
|
|
/* Allocate larger queue */
|
|
U32 newalloc = sysblk.crwalloc + crwcount;
|
|
U32* newarray = malloc( newalloc * sizeof(U32));
|
|
|
|
if (!newarray)
|
|
{
|
|
/* Set overflow in last CRW */
|
|
if (sysblk.crwarray)
|
|
*(sysblk.crwarray + sysblk.crwcount - 1) |= CRW_OFLOW;
|
|
RELEASE_CRWLOCK();
|
|
return -1;
|
|
}
|
|
|
|
/* Copy existing queue to new queue */
|
|
if (sysblk.crwarray)
|
|
{
|
|
memcpy( newarray, sysblk.crwarray, sysblk.crwcount * sizeof(U32));
|
|
free( sysblk.crwarray );
|
|
}
|
|
|
|
/* Start using new queue */
|
|
sysblk.crwarray = newarray;
|
|
sysblk.crwalloc = newalloc;
|
|
}
|
|
|
|
/* Add the new CRWs to the queue */
|
|
memcpy( sysblk.crwarray + sysblk.crwcount, crwarray, crwcount * sizeof(U32));
|
|
sysblk.crwcount += crwcount;
|
|
RELEASE_CRWLOCK();
|
|
|
|
/* Signal waiting CPUs that a Channel Report is pending */
|
|
machine_check_crwpend();
|
|
return 0;
|
|
|
|
} /* end function queue_channel_report */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Indicate CRW pending */
|
|
/*-------------------------------------------------------------------*/
|
|
void machine_check_crwpend()
|
|
{
|
|
/* Signal waiting CPUs that a Channel Report is pending */
|
|
int have_lock = have_lock( &sysblk.intlock );
|
|
if (!have_lock)
|
|
OBTAIN_INTLOCK( NULL );
|
|
ON_IC_CHANRPT;
|
|
WAKEUP_CPUS_MASK (sysblk.waiting_mask);
|
|
if (!have_lock)
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
} /* end function machine_check_crwpend */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Return next Channel Report Word (CRW) */
|
|
/*-------------------------------------------------------------------*/
|
|
U32 get_next_channel_report_word( REGS* regs )
|
|
{
|
|
U32 crw = 0;
|
|
|
|
UNREFERENCED(regs);
|
|
OBTAIN_CRWLOCK();
|
|
ASSERT( sysblk.crwindex <= sysblk.crwcount );
|
|
ASSERT( sysblk.crwcount <= sysblk.crwalloc );
|
|
if (sysblk.crwcount)
|
|
{
|
|
if (sysblk.crwindex < sysblk.crwcount)
|
|
{
|
|
VERIFY((crw = *(sysblk.crwarray + sysblk.crwindex)) != 0);
|
|
sysblk.crwindex++; // (for next time)
|
|
}
|
|
else // (sysblk.crwindex >= sysblk.crwcount)
|
|
{
|
|
sysblk.crwindex = 0;
|
|
sysblk.crwcount = 0;
|
|
}
|
|
}
|
|
RELEASE_CRWLOCK();
|
|
return crw;
|
|
|
|
} /* end function get_next_channel_report_word */
|
|
|
|
#endif /* _MACHCHK_C */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Present Machine Check Interrupt */
|
|
/* Input: */
|
|
/* regs Pointer to the CPU register context */
|
|
/* Output: */
|
|
/* mcic Machine check interrupt code */
|
|
/* xdmg External damage code */
|
|
/* fsta Failing storage address */
|
|
/* Return code: */
|
|
/* 0=No machine check, 1=Machine check presented */
|
|
/* */
|
|
/* Generic machine check function. At the momement the only */
|
|
/* supported machine check is the channel report. */
|
|
/* */
|
|
/* This routine must be called with the sysblk.intlock held */
|
|
/*-------------------------------------------------------------------*/
|
|
int ARCH_DEP(present_mck_interrupt)(REGS *regs, U64 *mcic, U32 *xdmg, RADR *fsta)
|
|
{
|
|
int rc = 0;
|
|
|
|
UNREFERENCED_370(regs);
|
|
UNREFERENCED_370(mcic);
|
|
UNREFERENCED_370(xdmg);
|
|
UNREFERENCED_370(fsta);
|
|
|
|
#ifdef FEATURE_CHANNEL_SUBSYSTEM
|
|
/* If there is a crw pending and we are enabled for the channel
|
|
report interrupt subclass then process the interrupt */
|
|
if( OPEN_IC_CHANRPT(regs) )
|
|
{
|
|
*mcic = MCIC_CP |
|
|
MCIC_WP |
|
|
MCIC_MS |
|
|
MCIC_PM |
|
|
MCIC_IA |
|
|
#ifdef FEATURE_HEXADECIMAL_FLOATING_POINT
|
|
MCIC_FP |
|
|
#endif /*FEATURE_HEXADECIMAL_FLOATING_POINT*/
|
|
MCIC_GR |
|
|
MCIC_CR |
|
|
MCIC_ST |
|
|
#ifdef FEATURE_ACCESS_REGISTERS
|
|
MCIC_AR |
|
|
#endif /*FEATURE_ACCESS_REGISTERS*/
|
|
#if defined(FEATURE_001_ZARCH_INSTALLED_FACILITY) && defined(FEATURE_EXTENDED_TOD_CLOCK)
|
|
MCIC_PR |
|
|
#endif /*defined(FEATURE_001_ZARCH_INSTALLED_FACILITY) && defined(FEATURE_EXTENDED_TOD_CLOCK)*/
|
|
#if defined(FEATURE_BINARY_FLOATING_POINT)
|
|
MCIC_XF |
|
|
#endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/
|
|
MCIC_AP |
|
|
MCIC_CT |
|
|
MCIC_CC ;
|
|
*xdmg = 0;
|
|
*fsta = 0;
|
|
OFF_IC_CHANRPT;
|
|
rc = 1;
|
|
}
|
|
|
|
if(!IS_IC_CHANRPT)
|
|
#endif /*FEATURE_CHANNEL_SUBSYSTEM*/
|
|
OFF_IC_CHANRPT;
|
|
|
|
return rc;
|
|
} /* end function present_mck_interrupt */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* (all ARCH_DEP code should precede this point) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#if !defined( _GEN_ARCH )
|
|
|
|
#if defined( _ARCH_NUM_1 )
|
|
#define _GEN_ARCH _ARCH_NUM_1
|
|
#include "machchk.c"
|
|
#endif
|
|
|
|
#if defined( _ARCH_NUM_2 )
|
|
#undef _GEN_ARCH
|
|
#define _GEN_ARCH _ARCH_NUM_2
|
|
#include "machchk.c"
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* (only NON-arch_dep code after this point) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#endif /* !defined( _GEN_ARCH ) */
|