1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
|
/* DIAGMSSF.C (c) Copyright Jan Jaeger, 1999-2009 */
/* ESA/390 Diagnose Functions */
/*-------------------------------------------------------------------*/
/* This module implements various diagnose functions */
/* MSSF call as described in SA22-7098-0 */
/* SCPEND as described in GC19-6215-0 which is also used with PR/SM */
/* LPAR RMF interface call */
/* */
/* 04/12/1999 Jan Jaeger */
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */
/*-------------------------------------------------------------------*/
#include "hstdinc.h"
#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif
#if !defined(_DIAGMSSF_C_)
#define _DIAGMSSF_C_
#endif
#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#include "service.h"
#if !defined(_DIAGMSSF_C)
#define _DIAGMSSF_C
/*-------------------------------------------------------------------*/
/* MSSF Call service processor commands */
/*-------------------------------------------------------------------*/
#define MSSF_READ_CONFIG_INFO 0x00020001
#define MSSF_READ_CHP_STATUS 0x00030001
/*-------------------------------------------------------------------*/
/* Service Processor Command Control Block */
/*-------------------------------------------------------------------*/
typedef struct _SPCCB_HEADER {
HWORD length; /* Total length of SPCCB */
BYTE resv1[4]; /* Reserved */
HWORD resp; /* Response code */
} SPCCB_HEADER;
#define SPCCB_REAS_COMPLETE 0x00
#define SPCCB_RESP_COMPLETE 0x10
#define SPCCB_REAS_CHECK 0x00
#define SPCCB_RESP_CHECK 0x40
#define SPCCB_REAS_BADLENGTH 0x01
#define SPCCB_RESP_BADLENGTH 0xF0
#define SPCCB_REAS_NOT2KALIGN 0x01
#define SPCCB_RESP_NOT2KALIGN 0x00
#define SPCCB_REAS_UNASSIGNED 0x06
#define SPCCB_RESP_UNASSIGNED 0xF0
/*-------------------------------------------------------------------*/
/* Service Processor Command Control Block */
/*-------------------------------------------------------------------*/
typedef struct _SPCCB_CONFIG_INFO {
BYTE totstori; /* Total number of installed
storage increments. */
BYTE storisiz; /* Storage increment size in
units of one megabyte. */
BYTE hex04; /* This field contains the
value of 04 hex. */
BYTE hex01; /* This field contains the
value of either 01 hex or
02 hex. */
FWORD reserved; /* Reserved. */
HWORD toticpu; /* Total number of installed
CPUs. This number also
specifies the total number
of entries in the CPU-
description list. */
HWORD officpu; /* Offset in the SPCCB to the
first entry in the CPU-
description list. */
HWORD tothsa; /* Total number of machine-
storage areas reserved for
the requesting
configuration. This number
also specifies the total
number of entries in the
machine-storage-area-
description list. */
HWORD offhsa; /* Offset in the SPCCB to the
first entry in the
machine-storage-area-
description list. */
BYTE loadparm[8]; /* Load parameter. This field
conains eight bytes of
EBCDIC information specified
by the operator for the
manually initiated load
function. If the operator
specifies fewer then eight
characters, they are left-
justified and padded on the
right with 40 hex (preferred),
or F0 hex, or 00 hex to
form an eight byte load
parameter. If the operator
does not specify a load
parameter, a default load
parameter is formed,
consisting of F1 hex (preferred),
or 40 hex, or 00 hex, padded
on the right with 40 hex
(preferred), or F0 hex, of
00 hex. The load parameter
is set to this default value
by the activation of the
system-reset-clear key or by
performing certain operator
functions. */
} SPCCB_CONFIG_INFO;
typedef struct _SPCCB_CPU_INFO {
BYTE cpuaddr; /* Rightmost eight bits of the
CPU address */
BYTE todid; /* Identity of the TOD clock
accessed by this CPU */
} SPCCB_CPU_INFO;
typedef struct _SPCCB_HSA_INFO {
BYTE hsasize; /* Bits 1-15 of this field
specify the size of the
area in units of 4K bytes
or 32K bytes. When bit 0
of byte 0 is zero, the
size is in units of 32K
bytes; otherwise, the
size is in units of 4K
bytes. */
BYTE hsaaddr; /* Absolute address of the
start of the machine-
storage area. */
} SPCCB_HSA_INFO;
typedef struct _SPCCB_CHP_STATUS {
BYTE installed[32]; /* Installed-channel-path bit
map. */
BYTE assigned[32]; /* Assigned-channel-path bit
map. */
BYTE configured[32]; /* Configured-channel-path bit
map. */
BYTE reserved[152]; /* Reserved. */
} SPCCB_CHP_STATUS;
typedef struct _DIAG204_HDR {
BYTE numpart; /* Number of partitions */
BYTE flags; /* Flag Byte */
#define DIAG204_PHYSICAL_PRESENT 0x80
HWORD resv; /* Unknown , 0 on 2003,
0x0005 under VM */
HWORD physcpu; /* Number of phys CP's */
HWORD offown; /* Offset to own partition */
DBLWRD diagstck; /* TOD of last diag204 */
} DIAG204_HDR;
typedef struct _DIAG204_PART {
BYTE partnum; /* Logical partition number
starts with 1 */
BYTE virtcpu; /* Number of virt CP's */
HWORD resv1[3];
BYTE partname[8]; /* Partition name */
} DIAG204_PART;
typedef struct _DIAG204_PART_CPU {
HWORD cpaddr; /* CP address */
BYTE resv1[2];
BYTE index; /* Index into diag224 area */
BYTE cflag; /* ??? */
HWORD weight; /* Weight */
DBLWRD totdispatch; /* Total dispatch time */
DBLWRD effdispatch; /* Effective dispatch time */
} DIAG204_PART_CPU;
typedef struct _DIAG204_X_HDR {
BYTE numpart; /* Number of partitions */
BYTE flags; /* Flag Byte */
#define DIAG204_X_PHYSICAL_PRESENT 0x80
HWORD resv1; /* Unknown , 0 on 2003,
0x0005 under VM */
HWORD physcpu; /* Number of phys CP's */
HWORD offown; /* Offset to own partition */
DBLWRD diagstck1; /* TOD of last diag204 */
DBLWRD diagstck2; /* in STCKE format */
BYTE resv2[40];
} DIAG204_X_HDR;
typedef struct _DIAG204_X_PART {
BYTE partnum; /* Logical partition number
starts with 1 */
BYTE virtcpu; /* Number of virt CP's */
BYTE realcpu; /* Number of real CP's */
BYTE pflag;
FWORD mlu;
BYTE partname[8]; /* Partition name */
BYTE cpcname[8]; /* CPC name */
BYTE osname[8]; /* Operating system type */
DBLWRD cssize; /* Central storage size */
DBLWRD essize; /* Expanded Storage size */
BYTE upid;
BYTE resv1[3];
FWORD gr_mlu;
BYTE gr_name[8]; /* Sysplex name? */
BYTE resv2[32];
} DIAG204_X_PART;
typedef struct _DIAG204_X_PART_CPU {
HWORD cpaddr; /* CP address */
BYTE resv1[2];
BYTE index; /* Index into diag224 area */
BYTE cflag; /* ??? */
HWORD weight; /* Weight */
DBLWRD totdispatch; /* Total dispatch time */
DBLWRD effdispatch; /* Effective dispatch time */
HWORD minweight;
HWORD curweight;
HWORD maxweight;
BYTE resv2[2];
DBLWRD onlinetime;
DBLWRD waittime;
FWORD pmaweight;
FWORD polarweight;
BYTE resv3[40];
} DIAG204_X_PART_CPU;
static const char diag224_cputable[]=
{
"CP "
"ICF "
"ZAAP "
"IFL "
"*UNKNOWN* "
"ZIIP "
};
#endif /*!defined(_DIAGMSSF_C)*/
/*-------------------------------------------------------------------*/
/* Process SCPEND call (Function code 0x044) */
/*-------------------------------------------------------------------*/
void ARCH_DEP(scpend_call) (void)
{
sched_yield(); /* Just go to the dispatcher
for a minimum delay */
} /* end function scpend_call */
#ifdef FEATURE_MSSF_CALL
/*-------------------------------------------------------------------*/
/* Process MSSF call (Function code 0x080) */
/*-------------------------------------------------------------------*/
int ARCH_DEP(mssf_call) (int r1, int r2, REGS *regs)
{
U32 spccb_absolute_addr; /* Absolute addr of SPCCB */
U32 mssf_command; /* MSSF command word */
U32 spccblen; /* Length of SPCCB */
SPCCB_HEADER *spccb; /* -> SPCCB header */
SPCCB_CONFIG_INFO *spccbconfig; /* -> SPCCB CONFIG info */
SPCCB_CPU_INFO *spccbcpu; /* -> SPCCB CPU information */
SPCCB_CHP_STATUS *spccbchp; /* -> SPCCB channel path info */
U16 offset; /* Offset from start of SPCCB */
int i; /* loop counter */
DEVBLK *dev; /* Device block pointer */
/* R1 contains the real address of the SPCCB */
spccb_absolute_addr = APPLY_PREFIXING (regs->GR_L(r1), regs->PX);
/* R2 contains the service-processor-command word */
mssf_command = regs->GR_L(r2);
/* Program check if SPCCB is not on a doubleword boundary */
if ( spccb_absolute_addr & 0x00000007 )
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Program check if SPCCB is outside main storage */
if ( spccb_absolute_addr > regs->mainlim )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
// /*debug*/logmsg("MSSF call %8.8X SPCCB=%8.8X\n",
// /*debug*/ mssf_command, spccb_absolute_addr);
/* Point to Service Processor Command Control Block */
spccb = (SPCCB_HEADER*)(regs->mainstor + spccb_absolute_addr);
/* Load SPCCB length from header */
FETCH_HW(spccblen,spccb->length);
/* Mark page referenced */
STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_REF;
/* Program check if end of SPCCB falls outside main storage */
if ( sysblk.mainsize - spccblen < spccb_absolute_addr )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Obtain the interrupt lock */
OBTAIN_INTLOCK(regs);
/* If a service signal is pending then we cannot process the request */
if( IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_ADDR)) {
RELEASE_INTLOCK(regs);
return 2; /* Service Processor Busy */
}
if( spccb_absolute_addr & 0x7ffff800 ) {
spccb->resp[0] = SPCCB_REAS_NOT2KALIGN;
spccb->resp[1] = SPCCB_RESP_NOT2KALIGN;
} else
/* Test MSSF command word */
switch (mssf_command) {
case MSSF_READ_CONFIG_INFO:
/* Set response code X'01F0' if SPCCB length
is insufficient to contain CONFIG info */
if ( spccblen < 64 )
{
spccb->resp[0] = SPCCB_REAS_BADLENGTH;
spccb->resp[1] = SPCCB_RESP_BADLENGTH;
break;
}
/* Point to SPCCB data area following SPCCB header */
spccbconfig = (SPCCB_CONFIG_INFO*)(spccb+1);
memset (spccbconfig, 0, sizeof(SPCCB_CONFIG_INFO));
/* Set main storage size in SPCCB */
spccbconfig->totstori = sysblk.mainsize >> 20;
spccbconfig->storisiz = 1;
spccbconfig->hex04 = 0x04;
spccbconfig->hex01 = 0x01;
/* Set CPU array count and offset in SPCCB */
STORE_HW(spccbconfig->toticpu,MAX_CPU);
offset = sizeof(SPCCB_HEADER) + sizeof(SPCCB_CONFIG_INFO);
STORE_HW(spccbconfig->officpu,offset);
/* Set HSA array count and offset in SPCCB */
STORE_HW(spccbconfig->tothsa,0);
offset += sizeof(SPCCB_CPU_INFO) * MAX_CPU;
STORE_HW(spccbconfig->offhsa,offset);
/* Move IPL load parameter to SPCCB */
get_loadparm (spccbconfig->loadparm);
/* Build the CPU information array after the SCP info */
spccbcpu = (SPCCB_CPU_INFO*)(spccbconfig+1);
for (i = 0; i < MAX_CPU; i++, spccbcpu++)
{
memset (spccbcpu, 0, sizeof(SPCCB_CPU_INFO));
spccbcpu->cpuaddr = i;
spccbcpu->todid = 0;
}
/* Set response code X'0010' in SPCCB header */
spccb->resp[0] = SPCCB_REAS_COMPLETE;
spccb->resp[1] = SPCCB_RESP_COMPLETE;
break;
case MSSF_READ_CHP_STATUS:
/* Set response code X'0300' if SPCCB length
is insufficient to contain channel path info */
if ( spccblen < sizeof(SPCCB_HEADER) + sizeof(SPCCB_CHP_STATUS))
{
spccb->resp[0] = SPCCB_REAS_BADLENGTH;
spccb->resp[1] = SPCCB_RESP_BADLENGTH;
break;
}
/* Point to SPCCB data area following SPCCB header */
spccbchp = (SPCCB_CHP_STATUS*)(spccb+1);
memset (spccbchp, 0, sizeof(SPCCB_CHP_STATUS));
/* Identify CHPIDs used */
for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) {
spccbchp->installed[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7);
spccbchp->assigned[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7);
spccbchp->configured[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7);
}
/* Set response code X'0010' in SPCCB header */
spccb->resp[0] = SPCCB_REAS_COMPLETE;
spccb->resp[1] = SPCCB_RESP_COMPLETE;
break;
default:
PTT(PTT_CL_ERR,"*DIAG080",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L);
/* Set response code X'06F0' for invalid MSSF command */
spccb->resp[0] = SPCCB_REAS_UNASSIGNED;
spccb->resp[1] = SPCCB_RESP_UNASSIGNED;
break;
} /* end switch(mssf_command) */
/* Mark page changed */
STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_CHANGE;
/* Set service signal external interrupt pending */
sysblk.servparm &= ~SERVSIG_ADDR;
sysblk.servparm |= spccb_absolute_addr;
ON_IC_SERVSIG;
/* Release the interrupt lock */
RELEASE_INTLOCK(regs);
/* Return condition code 0: Command initiated */
return 0;
} /* end function mssf_call */
#endif /* FEATURE_MSSF_CALL */
/*-------------------------------------------------------------------*/
/* Process LPAR DIAG 204 call */
/*-------------------------------------------------------------------*/
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 < MAX_CPU; 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 < MAX_CPU; 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) + (MAX_CPU * 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;
partxinfo->realcpu = hostinfo.num_procs;
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 < MAX_CPU; 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;
partxinfo->realcpu = hostinfo.num_procs;
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 < MAX_CPU; 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 */
/*-------------------------------------------------------------------*/
/* Process LPAR DIAG 224 call */
/*-------------------------------------------------------------------*/
void ARCH_DEP(diag224_call) (int r1, int r2, REGS *regs)
{
RADR abs; /* abs addr of data area */
BYTE *p; /* pointer to the data area */
unsigned int i; /* loop index */
//FIXME : this is probably incomplete.
// see linux/arch/s390/hypfs/hypfs_diag.c
UNREFERENCED(r1);
abs = APPLY_PREFIXING (regs->GR_L(r2), regs->PX);
/* Program check if data area is not on a page boundary */
if ( (abs & PAGEFRAME_BYTEMASK) != 0x000)
ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION);
/* Program check if data area is outside main storage */
if ( abs > regs->mainlim )
ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION);
/* Point to DIAG 224 data area */
p = regs->mainstor + abs;
/* Mark page referenced */
STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE;
/* First byte contains the number of entries - 1 */
*p = 5;
/* Clear the next 15 bytes */
memset (p + 1, 0, 15);
/* Set the 6 possible entries */
p += 16;
memcpy(p,diag224_cputable,sizeof(diag224_cputable)-1);
/* Convert to EBCDIC */
for (i = 0; i < sizeof(diag224_cputable); i++)
p[i] = host_to_guest(p[i]);
} /* end function diag224_call */
#if !defined(_GEN_ARCH)
#if defined(_ARCHMODE2)
#define _GEN_ARCH _ARCHMODE2
#include "diagmssf.c"
#endif
#if defined(_ARCHMODE3)
#undef _GEN_ARCH
#define _GEN_ARCH _ARCHMODE3
#include "diagmssf.c"
#endif
#endif /*!defined(_GEN_ARCH)*/
|