/*-------------------------------------------------------------------*/ void ARCH_DEP(diag204_call) (int r1, int r2, REGS *regs) { DIAG204_HDR *hdrinfo; /* Header */ DIAG204_PART *partinfo; /* Partition info */ DIAG204_PART_CPU *cpuinfo; /* CPU info */ #if defined(FEATURE_EXTENDED_DIAG204) DIAG204_X_HDR *hdrxinfo; /* Header */ DIAG204_X_PART *partxinfo; /* Partition info */ DIAG204_X_PART_CPU *cpuxinfo; /* CPU info */ U64 tdis; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ RADR abs; /* abs addr of data area */ U64 dreg; /* work doubleword */ int i; /* loop counter */ struct rusage usage; /* RMF type data */ static U64 diag204tod; /* last diag204 tod */ #if defined(FEATURE_PHYSICAL_DIAG204) static BYTE physical[8] = {0xD7,0xC8,0xE8,0xE2,0xC9,0xC3,0xC1,0xD3}; /* PHYSICAL */ #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ /* Test DIAG204 command word */ switch (regs->GR_L(r2)) { case 0x04: abs = APPLY_PREFIXING (GR_A(r1,regs), regs->PX); /* Program check if RMF data is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if RMF data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 204 data area */ hdrinfo = (DIAG204_HDR*)(regs->mainstor + abs); /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrinfo, 0, sizeof(DIAG204_HDR)); hdrinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrinfo->flags = DIAG204_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrinfo->physcpu,sysblk.cpus); STORE_HW(hdrinfo->offown,sizeof(DIAG204_HDR)); STORE_DW(hdrinfo->diagstck,dreg); /* hercules partition */ partinfo = (DIAG204_PART*)(hdrinfo + 1); memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 1; /* Hercules partition */ partinfo->virtcpu = sysblk.cpus; get_lparname(partinfo->partname); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index=sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ getrusage(RUSAGE_CHILDREN,&usage); partinfo = (DIAG204_PART*)cpuinfo; memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 0; /* Physical machine */ partinfo->virtcpu = sysblk.cpus; memcpy(partinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index = sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #if defined(FEATURE_EXTENDED_DIAG204) /* Extended subcode 5 returns the size of the data areas provided by extended subcodes 6 and 7 */ case 0x00010005: i = sizeof(DIAG204_X_HDR) + ((sizeof(DIAG204_X_PART) + (sysblk.maxcpu * sizeof(DIAG204_X_PART_CPU))) * 2); regs->GR_L(r2+1) = (i + PAGEFRAME_BYTEMASK) / PAGEFRAME_PAGESIZE; regs->GR_L(r2) = 0; break; /* Provide extended information */ case 0x00010006: /* We fall through as we do not have any secondary cpus (that we know of) */ /* Provide extended information, including information about secondary CPUs */ case 0x00010007: /* Program check if RMF data is not on a page boundary */ if ( (regs->GR_L(r1) & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ hdrxinfo = (DIAG204_X_HDR*)MADDR (GR_A(r1,regs), r1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrxinfo, 0, sizeof(DIAG204_X_HDR)); hdrxinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrxinfo->flags = DIAG204_X_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrxinfo->physcpu,sysblk.cpus); STORE_HW(hdrxinfo->offown,sizeof(DIAG204_X_HDR)); STORE_DW(hdrxinfo->diagstck1,(dreg >> 8)); STORE_DW(hdrxinfo->diagstck2,( 0x0000000001000000ULL | (regs->cpuad << 16) | regs->todpr)); /* hercules partition */ partxinfo = (DIAG204_X_PART*)(hdrxinfo + 1); memset(partxinfo, 0, sizeof(DIAG204_PART)); partxinfo->partnum = 1; /* Hercules partition */ partxinfo->virtcpu = sysblk.cpus; get_lparname(partxinfo->partname); get_sysname(partxinfo->cpcname); get_systype(partxinfo->osname); STORE_DW(partxinfo->cssize,sysblk.mainsize); STORE_DW(partxinfo->essize,sysblk.xpndsize); get_sysplex(partxinfo->gr_name); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuxinfo = (DIAG204_X_PART_CPU*)(partxinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ partxinfo = (DIAG204_X_PART*)cpuxinfo; memset(partxinfo, 0, sizeof(DIAG204_X_PART)); partxinfo->partnum = 0; /* Physical machine */ partxinfo->virtcpu = sysblk.cpus; memcpy(partxinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_CHILDREN,&usage); cpuxinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < sysblk.maxcpu; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ default: PTT(PTT_CL_ERR,"*DIAG204",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->GR_L(r2) = 4; } /*switch(regs->GR_L(r2))*/ } /* end function diag204_call */
/*-------------------------------------------------------------------*/ void ARCH_DEP(perform_external_interrupt) (REGS *regs) { PSA *psa; /* -> Prefixed storage area */ U16 cpuad; /* Originating CPU address */ #if defined(FEATURE_VM_BLOCKIO) #if defined(FEATURE_ESAME) RADR servpadr; /* Address of 64-bit block I/O interrupt */ #endif U16 servcode; /* Service Signal or Block I/O Interrupt code */ #endif /* defined(FEATURE_VM_BLOCKIO) */ /* External interrupt if console interrupt key was depressed */ if ( OPEN_IC_INTKEY(regs) && !SIE_MODE(regs) ) { WRMSG (HHC00840, "I"); /* Reset interrupt key pending */ OFF_IC_INTKEY; /* Generate interrupt key interrupt */ ARCH_DEP(external_interrupt) (EXT_INTERRUPT_KEY_INTERRUPT, regs); } /* External interrupt if malfunction alert is pending */ if (OPEN_IC_MALFALT(regs)) { /* Find first CPU which generated a malfunction alert */ for (cpuad = 0; regs->malfcpu[cpuad] == 0; cpuad++) { if (cpuad >= sysblk.maxcpu) { OFF_IC_MALFALT(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Malfuction Alert from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->malfcpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_MALFALT(regs); while (++cpuad < sysblk.maxcpu) { if (regs->malfcpu[cpuad]) { ON_IC_MALFALT(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_MALFUNCTION_ALERT_INTERRUPT, regs); } /* External interrupt if emergency signal is pending */ if (OPEN_IC_EMERSIG(regs)) { /* Find first CPU which generated an emergency signal */ for (cpuad = 0; regs->emercpu[cpuad] == 0; cpuad++) { if (cpuad >= sysblk.maxcpu) { OFF_IC_EMERSIG(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Emergency Signal from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->emercpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_EMERSIG(regs); while (++cpuad < sysblk.maxcpu) { if (regs->emercpu[cpuad]) { ON_IC_EMERSIG(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_EMERGENCY_SIGNAL_INTERRUPT, regs); } /* External interrupt if external call is pending */ if (OPEN_IC_EXTCALL(regs)) { // /*debug*/logmsg (_("External interrupt: External Call from CPU %d\n"), // /*debug*/ regs->extccpu); /* Reset external call pending */ OFF_IC_EXTCALL(regs); /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,regs->extccpu); /* Generate external call interrupt */ ARCH_DEP(external_interrupt) (EXT_EXTERNAL_CALL_INTERRUPT, regs); } /* External interrupt if TOD clock exceeds clock comparator */ if ( tod_clock(regs) > regs->clkc && OPEN_IC_CLKC(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00841, "I"); } ARCH_DEP(external_interrupt) (EXT_CLOCK_COMPARATOR_INTERRUPT, regs); } /* External interrupt if CPU timer is negative */ if ( CPU_TIMER(regs) < 0 && OPEN_IC_PTIMER(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00842, "I", CPU_TIMER(regs) << 8); } ARCH_DEP(external_interrupt) (EXT_CPU_TIMER_INTERRUPT, regs); } /* External interrupt if interval timer interrupt is pending */ #if defined(FEATURE_INTERVAL_TIMER) if (OPEN_IC_ITIMER(regs) #if defined(_FEATURE_SIE) && !(SIE_STATB(regs, M, ITMOF)) #endif /*defined(_FEATURE_SIE)*/ ) { if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00843, "I"); } OFF_IC_ITIMER(regs); ARCH_DEP(external_interrupt) (EXT_INTERVAL_TIMER_INTERRUPT, regs); } #if defined(FEATURE_ECPSVM) if ( OPEN_IC_ECPSVTIMER(regs) ) { OFF_IC_ECPSVTIMER(regs); ARCH_DEP(external_interrupt) (EXT_VINTERVAL_TIMER_INTERRUPT,regs); } #endif /*FEATURE_ECPSVM*/ #endif /*FEATURE_INTERVAL_TIMER*/ /* External interrupt if service signal is pending */ if ( OPEN_IC_SERVSIG(regs) && !SIE_MODE(regs) ) { #if defined(FEATURE_VM_BLOCKIO) /* Note: Both Block I/O and Service Signal are enabled by the */ /* the same CR0 bit. Hence they are handled in the same code */ switch(sysblk.servcode) { case EXT_BLOCKIO_INTERRUPT: /* VM Block I/O Interrupt */ if (sysblk.biodev->ccwtrace) { WRMSG (HHC00844, "I", SSID_TO_LCSS(sysblk.biodev->ssid), sysblk.biodev->devnum, sysblk.servcode, sysblk.bioparm, sysblk.biostat, sysblk.biosubcd ); } servcode = EXT_BLOCKIO_INTERRUPT; #if defined(FEATURE_ESAME) /* Real address used to store the 64-bit interrupt parameter */ #define VM_BLOCKIO_INT_PARM 0x11B8 if (sysblk.biosubcd == 0x07) { /* 8-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { char buf[40]; MSGBUF(buf, "%16.16X", (unsigned) sysblk.bioparm); WRMSG (HHC00845,"I", buf); } /* Set the main storage reference and change bits */ /* for 64-bit interruption parameter. */ /* Note: This is handled for the first 4K page in */ /* ARCH_DEP(external_interrupt), but not for the */ /* the second 4K page used for the 64-bit interrupt */ /* parameter. */ /* Point to 2nd page of PSA in main storage */ servpadr=APPLY_PREFIXING(VM_BLOCKIO_INT_PARM,regs->PX); STORAGE_KEY(servpadr, regs) |= (STORKEY_REF | STORKEY_CHANGE); #if 0 /* Store the 64-bit interrupt parameter */ logmsg (_("Saving 64-bit Block I/O interrupt parm at " "%16.16X: %16.16X\n"), servpadr, sysblk.bioparm ); #endif STORE_DW(regs->mainstor + servpadr,sysblk.bioparm); psa = (void*)(regs->mainstor + regs->PX); } else { #endif /* defined(FEATURE_ESAME) */ /* 4-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { char buf[40]; MSGBUF(buf, "%8.8X", (U32) sysblk.bioparm); WRMSG (HHC00845,"I", buf); } /* Store Block I/O parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,(U32)sysblk.bioparm); #if defined(FEATURE_ESAME) } #endif /* Store sub-interruption code and status at PSA+X'84' */ STORE_HW(psa->extcpad,(sysblk.biosubcd<<8)|sysblk.biostat); /* Reset interruption data */ sysblk.bioparm = 0; sysblk.biosubcd = 0; sysblk.biostat = 0; break; case EXT_SERVICE_SIGNAL_INTERRUPT: /* Service Signal */ default: servcode = EXT_SERVICE_SIGNAL_INTERRUPT; /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00846,"I", sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); } /* end switch(sysblk.servcode) */ /* Reset service parameter */ sysblk.servparm = 0; /* Reset service code */ sysblk.servcode = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (servcode, regs); #else /* defined(FEATURE_VM_BLOCKIO) */ /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { WRMSG (HHC00846,"I", sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); /* Reset service parameter */ sysblk.servparm = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (EXT_SERVICE_SIGNAL_INTERRUPT, regs); #endif /* defined(FEATURE_VM_BLOCKIO) */ } /* end OPEN_IC_SERVSIG(regs) */ } /* end function perform_external_interrupt */