static int ARCH_DEP(chsc_get_conf_info) (CHSC_REQ *chsc_req, CHSC_RSP *chsc_rsp) { U16 req_len, rsp_len; CHSC_REQ12 *chsc_req12 = (CHSC_REQ12 *)(chsc_req); CHSC_RSP12 *chsc_rsp12 = (CHSC_RSP12 *)(chsc_rsp+1); /* Fetch length of request field */ FETCH_HW(req_len, chsc_req12->length); rsp_len = sizeof(CHSC_RSP) + sizeof(CHSC_RSP12); memset(chsc_rsp12, 0, sizeof(CHSC_RSP12) ); STORE_HW(chsc_rsp12->len1,80); STORE_FW(chsc_rsp12->info1,0x10); STORE_FW(chsc_rsp12->info2,0x10); STORE_FW(chsc_rsp12->info3,0xFF); STORE_FW(chsc_rsp12->test,0xE3C5E2E3); /* Store response length */ STORE_HW(chsc_rsp->length,rsp_len); /* Store request OK */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_OK); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; }
int ARCH_DEP(chsc_get_sch_desc) (CHSC_REQ *chsc_req, CHSC_RSP *chsc_rsp) { U16 req_len, sch, f_sch, l_sch, rsp_len; CHSC_REQ4 *chsc_req4 = (CHSC_REQ4 *)(chsc_req); CHSC_RSP4 *chsc_rsp4 = (CHSC_RSP4 *)(chsc_rsp); #if 0 { U16 resv1, resv2, resv3; FETCH_HW(resv1,chsc_req4->resv1); FETCH_HW(resv2,chsc_req4->resv2); FETCH_HW(resv3,chsc_req4->resv3); logmsg(D_("chsc_get_sch_desc: resv1=%4.4X resv2=%4.4X resv3=%4.4X\n"),resv1,resv2,resv3); } #endif FETCH_HW(f_sch,chsc_req4->f_sch); FETCH_HW(l_sch,chsc_req4->l_sch); /* Fetch length of request field */ FETCH_HW(req_len, chsc_req4->length); rsp_len = sizeof(CHSC_RSP) + ((1 + l_sch - f_sch) * sizeof(CHSC_RSP4)); if(l_sch < f_sch || rsp_len > (0x1000 - req_len)) { /* Set response field length */ STORE_HW(chsc_rsp->length,sizeof(CHSC_RSP)); /* Store request error */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_ERRREQ); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } for(sch = f_sch; sch <= l_sch; sch++, chsc_rsp4++) { DEVBLK *dev; memset(chsc_rsp4, 0x00, sizeof(CHSC_RSP4) ); // ZZ FIXME: Dunno how to put the proper lcss id in here... if((dev = find_device_by_subchan(0x00010000|sch))) { chsc_rsp4->sch_val = 1; if(dev->pmcw.flag5 & PMCW5_V) chsc_rsp4->dev_val = 1; chsc_rsp4->st = (dev->pmcw.flag25 & PMCW25_TYPE) >> 5; chsc_rsp4->unit_addr = dev->devnum & 0xff; STORE_HW(chsc_rsp4->devno,dev->devnum); chsc_rsp4->path_mask = dev->pmcw.pim; STORE_HW(chsc_rsp4->sch, sch); memcpy(chsc_rsp4->chpid, dev->pmcw.chpid, 8); } }
static int ARCH_DEP(chsc_get_sch_desc) (CHSC_REQ *chsc_req, CHSC_RSP *chsc_rsp) { U16 req_len, sch, f_sch, l_sch, rsp_len, lcss; CHSC_REQ4 *chsc_req4 = (CHSC_REQ4 *)(chsc_req); CHSC_RSP4 *chsc_rsp4 = (CHSC_RSP4 *)(chsc_rsp+1); FETCH_HW(f_sch,chsc_req4->f_sch); FETCH_HW(l_sch,chsc_req4->l_sch); FETCH_HW(lcss,chsc_req4->ssidfmt); lcss &= CHSC_REQ4_SSID; lcss >>= 4; /* Fetch length of request field */ FETCH_HW(req_len, chsc_req4->length); rsp_len = sizeof(CHSC_RSP) + ((1 + l_sch - f_sch) * sizeof(CHSC_RSP4)); if(l_sch < f_sch || rsp_len > (0x1000 - req_len)) { /* Set response field length */ STORE_HW(chsc_rsp->length,sizeof(CHSC_RSP)); /* Store request error */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_ERRREQ); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } for(sch = f_sch; sch <= l_sch; sch++, chsc_rsp4++) { DEVBLK *dev; memset(chsc_rsp4, 0, sizeof(CHSC_RSP4) ); if((dev = find_device_by_subchan((LCSS_TO_SSID(lcss) << 16)|sch))) { int n; chsc_rsp4->sch_val = 1; if(dev->pmcw.flag5 & PMCW5_V) chsc_rsp4->dev_val = 1; chsc_rsp4->st = (dev->pmcw.flag25 & PMCW25_TYPE) >> 5; chsc_rsp4->unit_addr = dev->devnum & 0xff; STORE_HW(chsc_rsp4->devno,dev->devnum); chsc_rsp4->path_mask = dev->pmcw.pim; STORE_HW(chsc_rsp4->sch, sch); memcpy(chsc_rsp4->chpid, dev->pmcw.chpid, 8); if(dev->fla[0]) chsc_rsp4->fla_valid_mask = dev->pmcw.pim; for(n = 0; n < 7; n++) if(dev->pmcw.pim & (0x80 >> n)) STORE_HW(chsc_rsp4->fla[n], dev->fla[n]); } }
/*-------------------------------------------------------------------*/ void get_mpfactors(BYTE *dest) { /*-------------------------------------------------------------------*/ /* The new z10 machine will use a denominator of 65535 for better */ /* granularity. But this will mess up old software. We will stick */ /* to the old value of 100. Bernard Feb 26, 2010. */ /*-------------------------------------------------------------------*/ #define MPFACTOR_DENOMINATOR 100 #define MPFACTOR_PERCENT 95 static U16 mpfactors[MAX_CPU_ENGINES-1] = {0}; static BYTE didthis = 0; if (!didthis) { /* First time: initialize array... */ U32 mpfactor = MPFACTOR_DENOMINATOR; size_t i; for (i=0; i < arraysize( mpfactors ); i++) { /* Calculate the value of each subsequent entry as percentage of the previous entry's value. */ mpfactor = (mpfactor * MPFACTOR_PERCENT) / 100; STORE_HW( &mpfactors[i], (U16) mpfactor ); } didthis = 1; } /* Return the requested information... */ memcpy( dest, &mpfactors[0], (MAX_CPU-1) * sizeof(U16) ); }
/*-------------------------------------------------------------------*/ void get_mpfactors(BYTE *dest) { /*-------------------------------------------------------------------*/ /* The new z10 machine will use a denominator of 65535 for better */ /* granularity. But this will mess up old software. We will stick */ /* to the old value of 100. Bernard Feb 26, 2010. */ /* */ /* Calculations will be done in a higher precision to prevent early */ /* truncation and degradation of the factors. To achieve this, the */ /* factors are calculated * 256. When storing the values, the */ /* individual values are rounded up by 128 and then divided by 256 */ /* for the store operation. */ /* */ /* Once the number of host logical CPUs is reached, subsequent MP */ /* factors are no longer adjusted. */ /* */ /* MPFACTOR_DENOMINATOR must be 100, 255, or 65535. */ /* */ /* It is recommended that MPFACTOR_PERCENT remain at 95 (95%). */ /*-------------------------------------------------------------------*/ #define MPFACTOR_DENOMINATOR 100 #define MPFACTOR_PERCENT 95 static U16 mpfactors[MAX_CPU_ENGINES-1] = {0}; static BYTE didthis = 0; if (!didthis) { /* First time: initialize array... */ size_t limit = get_RealCPCount(); size_t i; U32 mpfactor = MPFACTOR_DENOMINATOR << 8; U16 result = 0; U16 resmin = 1; switch (MPFACTOR_DENOMINATOR) { default: /* resmin = 1; break; */ case 100: resmin = 1; break; case 255: resmin = 101; break; case 65535: resmin = 256; break; } for (i=0; i < arraysize(mpfactors); i++) { /* Calculate the value of each subsequent entry as a * percentage of the previous entry's value for the real * defined CPU entries. */ if (i < limit) { mpfactor = (mpfactor * MPFACTOR_PERCENT) / 100; result = (mpfactor + 128) >> 8; result = MAX(result, resmin); } STORE_HW( &mpfactors[i], result ); }
/*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_br) (int amode, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; #if defined(FEATURE_ESAME) if(amode && ia > 0xFFFFFFFFULL) { TRACE_F3_BR *tte; size = sizeof(TRACE_F3_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_BR_FMT; tte->fmt2 = TRACE_F3_BR_FM2; STORE_HW(tte->resv,0); STORE_DW(tte->newia64,ia); } else #endif /*defined(FEATURE_ESAME)*/ if(amode) { TRACE_F2_BR *tte; size = sizeof(TRACE_F2_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia31,ia | 0x80000000); } else { TRACE_F1_BR *tte; size = sizeof(TRACE_F1_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia24,ia & 0x00FFFFFF); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_br) */
/*-------------------------------------------------------------------*/ void ARCH_DEP(sclp_scedio_event) (SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb + 1); U16 sccb_len; U16 evd_len; if( ARCH_DEP(scedio_request)(SCLP_READ_EVENT_DATA, evd_hdr) ) { /* Update SCCB length field if variable request */ if (sccb->type & SCCB_TYPE_VARIABLE) { FETCH_HW(evd_len, evd_hdr->totlen); sccb_len = evd_len + sizeof(SCCB_HEADER); STORE_HW(sccb->length, sccb_len); sccb->type &= ~SCCB_TYPE_VARIABLE; } /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } }
static void CTCT_Read( DEVBLK* pDEVBLK, U32 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U32* pResidual, BYTE* pMore ) { PCTCIHDR pFrame = NULL; // -> Frame header PCTCISEG pSegment = NULL; // -> Segment in buffer fd_set rfds; // Read FD_SET int iRetVal; // Return code from 'select' int iLength = 0; static struct timeval tv; // Timeout time for 'select' // Limit how long we should wait for data to come in FD_ZERO( &rfds ); FD_SET( pDEVBLK->fd, &rfds ); tv.tv_sec = CTC_READ_TIMEOUT_SECS; tv.tv_usec = 0; iRetVal = select( pDEVBLK->fd + 1, &rfds, NULL, NULL, &tv ); switch( iRetVal ) { case 0: *pUnitStat = CSW_CE | CSW_DE | CSW_UC | CSW_SM; pDEVBLK->sense[0] = 0; return; case -1: if( HSO_errno == HSO_EINTR ) return; WRMSG(HHC00973, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; default: break; } // Read an IP packet from the TUN device iLength = read_socket( pDEVBLK->fd, pDEVBLK->buf, pDEVBLK->bufsize ); // Check for other error condition if( iLength < 0 ) { WRMSG(HHC00973, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Trace the packet received from the TUN device if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { WRMSG(HHC00913, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, iLength, "TUN" ); packet_trace( pDEVBLK->buf, iLength, '<' ); } // Fix-up Frame pointer pFrame = (PCTCIHDR)pIOBuf; // Fix-up Segment pointer pSegment = (PCTCISEG)( pIOBuf + sizeof( CTCIHDR ) ); // Initialize segment memset( pSegment, 0, iLength + sizeof( CTCISEG ) ); // Update next frame offset STORE_HW( pFrame->hwOffset, (U16)(iLength + sizeof( CTCIHDR ) + sizeof( CTCISEG )) ); // Store segment length STORE_HW( pSegment->hwLength, (U16)(iLength + sizeof( CTCISEG )) ); // Store Frame type STORE_HW( pSegment->hwType, ETH_TYPE_IP ); // Copy data memcpy( pSegment->bData, pDEVBLK->buf, iLength ); // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pIOBuf + sizeof( CTCIHDR ) + sizeof( CTCISEG ) + iLength ); STORE_HW( pFrame->hwOffset, 0x0000 ); // Calculate #of bytes returned including two slack bytes iLength += sizeof( CTCIHDR ) + sizeof( CTCISEG ) + 2; if( sCount < (U32)iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } // Set unit status *pUnitStat = CSW_CE | CSW_DE; }
/*-------------------------------------------------------------------*/ static void convert_ckd_file (IFD ifd, char *ifname, int itrklen, BYTE *itrkbuf, int repl, int quiet, char *ofname, int fseqn, U16 devtype, U32 heads, U32 trksize, BYTE *obuf, U32 start, U32 end, U32 volcyls, BYTE *volser) { int rc; /* Return code */ int ofd; /* Output file descriptor */ CKDDASD_DEVHDR devhdr; /* Output device header */ CKDDASD_TRKHDR *trkhdr; /* -> Output track header */ CKDDASD_RECHDR *rechdr; /* -> Output record header */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ int fileseq; /* CKD header sequence number*/ int highcyl; /* CKD header high cyl number*/ BYTE *opos; /* -> Byte in output buffer */ BYTE klen; /* Key length */ U16 dlen; /* Data length */ BYTE rec; /* Record number */ BYTE *iptr; /* -> Byte in input buffer */ BYTE *kptr; /* -> Key in input buffer */ BYTE *dptr; /* -> Data in input buffer */ int ilen; /* Bytes left in input buffer*/ H30CKD_TRKHDR *ith; /* -> Input track header */ U32 ihc, ihh; /* Input trk header cyl,head */ U32 offset; /* Current input file offset */ char pathname[MAX_PATH]; /* file path in host format */ UNREFERENCED(volser); /* Set file sequence number to zero if this is the only file */ if (fseqn == 1 && end + 1 == volcyls) fileseq = 0; else fileseq = fseqn; /* Set high cylinder number to zero if this is the last file */ if (end + 1 == volcyls) highcyl = 0; else highcyl = end; /* Create the AWSCKD image file */ hostpath(pathname, (char *)ofname, sizeof(pathname)); ofd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY | (repl ? 0 : O_EXCL), S_IRUSR | S_IWUSR | S_IRGRP); if (ofd < 0) { fprintf (stderr, "%s open error: %s\n", ofname, strerror(errno)); EXIT(8); } /* Create the device header */ memset(&devhdr, 0, CKDDASD_DEVHDR_SIZE); memcpy(devhdr.devid, "CKD_P370", 8); devhdr.heads[3] = (heads >> 24) & 0xFF; devhdr.heads[2] = (heads >> 16) & 0xFF; devhdr.heads[1] = (heads >> 8) & 0xFF; devhdr.heads[0] = heads & 0xFF; devhdr.trksize[3] = (trksize >> 24) & 0xFF; devhdr.trksize[2] = (trksize >> 16) & 0xFF; devhdr.trksize[1] = (trksize >> 8) & 0xFF; devhdr.trksize[0] = trksize & 0xFF; devhdr.devtype = devtype & 0xFF; devhdr.fileseq = fileseq; devhdr.highcyl[1] = (highcyl >> 8) & 0xFF; devhdr.highcyl[0] = highcyl & 0xFF; /* Write the device header */ rc = write (ofd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < CKDDASD_DEVHDR_SIZE) { fprintf (stderr, "%s device header write error: %s\n", ofname, errno ? strerror(errno) : "incomplete"); EXIT(1); } /* Write each cylinder */ for (cyl = start; cyl <= end; cyl++) { /* Display progress message every 10 cylinders */ if ((cyl % 10) == 0) { #ifdef EXTERNALGUI if (extgui) fprintf (stderr, "CYL=%u\n", cyl); else #endif /*EXTERNALGUI*/ if (quiet == 0) fprintf (stderr, "Writing cylinder %u\r", cyl); } for (head = 0; head < heads; head++) { /* Calculate the current offset in the file */ offset = ((cyl*heads)+head)*itrklen; /* Read the input track image (except cyl 0 head 0 already read by the open_input_image procedure) */ if (cyl > 0 || head > 0) { read_input_data (ifd, ifname, itrkbuf, itrklen, offset); } /* end if(cyl>0||head>0) */ /* Validate the track header */ ith = (H30CKD_TRKHDR*)itrkbuf; FETCH_HW (ihc, ith->cyl); FETCH_HW (ihh, ith->head); if (ihc != cyl || ihh != head) { fprintf (stderr, "Invalid track header found at offset %8.8X\n" "in input file %s\n" "Expected cyl=%4.4X head=%4.4X\n" " Found cyl=%4.4X head=%4.4X\n", offset, ifname, cyl, head, ihc, ihh); EXIT(8); } /* Clear the output track image to zeroes */ memset (obuf, 0, trksize); /* Build the output track header */ trkhdr = (CKDDASD_TRKHDR*)obuf; trkhdr->bin = 0; STORE_HW (trkhdr->cyl, cyl); STORE_HW (trkhdr->head, head); opos = obuf + CKDDASD_TRKHDR_SIZE; /* Copy each record from the input buffer */ iptr = itrkbuf + H30CKD_TRKHDR_SIZE; ilen = itrklen - H30CKD_TRKHDR_SIZE; while (1) { /* Locate the next input record */ rc = find_input_record (itrkbuf, &iptr, &ilen, &klen, &kptr, &dlen, &dptr, &ihc, &ihh, &rec); /* Exit at end of track */ if (rc == 1) break; /* Error if invalid record header detected */ if (rc > 1) { fprintf (stderr, "Invalid record header (reason %d)\n" "at offset %4.4X" " in track at cyl %4.4X head %4.4X\n" "at offset %8.8X in input file %s\n", rc, (unsigned int)(iptr-itrkbuf), cyl, head, offset, ifname); EXIT(9); } /* Build AWSCKD record header in output buffer */ rechdr = (CKDDASD_RECHDR*)opos; opos += CKDDASD_RECHDR_SIZE; STORE_HW (rechdr->cyl, ihc); STORE_HW (rechdr->head, ihh); rechdr->rec = rec; rechdr->klen = klen; STORE_HW (rechdr->dlen, dlen); /* Copy key and data to output buffer */ if (klen != 0) { memcpy (opos, kptr, klen); opos += klen; } if (dlen != 0) { memcpy (opos, dptr, dlen); opos += dlen; } } /* end while */ /* Build the end of track marker */ memcpy (opos, eighthexFF, 8); /* Write the track to the file */ rc = write (ofd, obuf, trksize); if (rc < 0 || (U32)rc < trksize) { fprintf (stderr, "%s cylinder %u head %u write error: %s\n", ofname, cyl, head, errno ? strerror(errno) : "incomplete"); EXIT(1); } } /* end for(head) */ } /* end for(cyl) */ /* Close the AWSCKD image file */ rc = close (ofd); if (rc < 0) { fprintf (stderr, "%s close error: %s\n", ofname, strerror(errno)); EXIT(10); } /* Display completion message */ fprintf (stderr, "%u cylinders successfully written to file %s\n", cyl - start, ofname); } /* end function convert_ckd_file */
/*-------------------------------------------------------------------*/ 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 */
/*-------------------------------------------------------------------*/ 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 */
/*-------------------------------------------------------------------*/ static int ARCH_DEP(scedio_request)(U32 sclp_command, SCCB_EVD_HDR *evd_hdr) { SCCB_SCEDIO_BK *scedio_bk = (SCCB_SCEDIO_BK*)(evd_hdr + 1); SCCB_SCEDIOV_BK *scediov_bk; SCCB_SCEDIOR_BK *scedior_bk; int rc; static struct { SCCB_SCEDIO_BK scedio_bk; union { SCCB_SCEDIOV_BK v; SCCB_SCEDIOR_BK r; } io; } static_scedio_bk ; static int scedio_pending; if(sclp_command == SCLP_READ_EVENT_DATA) { int pending_req = scedio_pending; U16 evd_len; /* Return no data if the scedio thread is still active */ if(scedio_tid) return 0; /* Update the scedio_bk copy in the SCCB */ if(scedio_pending) { /* Zero all fields */ memset (evd_hdr, 0, sizeof(SCCB_EVD_HDR)); /* Set type in event header */ evd_hdr->type = SCCB_EVD_TYPE_SCEDIO; /* Store scedio header */ *scedio_bk = static_scedio_bk.scedio_bk; /* Calculate event response length */ evd_len = sizeof(SCCB_EVD_HDR) + sizeof(SCCB_SCEDIO_BK); switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOR: scedior_bk = (SCCB_SCEDIOR_BK*)(scedio_bk + 1); *scedior_bk = static_scedio_bk.io.r; evd_len += sizeof(SCCB_SCEDIOR_BK); break; case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); *scediov_bk = static_scedio_bk.io.v ; evd_len += sizeof(SCCB_SCEDIOV_BK); break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)evd_hdr->type,(U32)scedio_bk->flag1,scedio_bk->flag3); } /* Set length in event header */ STORE_HW(evd_hdr->totlen, evd_len); } /* Reset the pending flag */ scedio_pending = 0; /* Return true if a request was pending */ return pending_req; } else { #if !defined(NO_SIGABEND_HANDLER) switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); switch(scediov_bk->type) { case SCCB_SCEDIOV_TYPE_INIT: /* Kill the scedio thread if it is active */ if( scedio_tid ) { OBTAIN_INTLOCK(NULL); signal_thread(scedio_tid, SIGKILL); scedio_tid = 0; scedio_pending = 0; RELEASE_INTLOCK(NULL); } break; } break; } #endif /* Take a copy of the scedio_bk in the SCCB */ static_scedio_bk.scedio_bk = *scedio_bk; switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOR: scedior_bk = (SCCB_SCEDIOR_BK*)(scedio_bk + 1); static_scedio_bk.io.r = *scedior_bk; break; case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); static_scedio_bk.io.v = *scediov_bk; break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)evd_hdr->type,(U32)scedio_bk->flag1,scedio_bk->flag3); } /* Create the scedio thread */ rc = create_thread(&scedio_tid, &sysblk.detattr, ARCH_DEP(scedio_thread), &static_scedio_bk, "scedio_thread"); if (rc) { WRMSG(HHC00102, "E", strerror(rc)); return -1; } scedio_pending = 1; } return 0; }
void CTCI_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame = NULL; size_t iLength = 0; int rc = 0; for ( ; ; ) { obtain_lock( &pCTCBLK->Lock ); if( !pCTCBLK->fDataPending ) { struct timespec waittime; struct timeval now; release_lock( &pCTCBLK->Lock ); gettimeofday( &now, NULL ); waittime.tv_sec = now.tv_sec + CTC_READ_TIMEOUT_SECS; waittime.tv_nsec = now.tv_usec * 1000; obtain_lock( &pCTCBLK->EventLock ); rc = timed_wait_condition( &pCTCBLK->Event, &pCTCBLK->EventLock, &waittime ); release_lock( &pCTCBLK->EventLock ); if( rc == ETIMEDOUT || rc == EINTR ) { // check for halt condition if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT || pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT040I %4.4X: Halt or Clear Recognized\n"), pDEVBLK->devnum ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = sCount; return; } continue; } obtain_lock( &pCTCBLK->Lock ); } // Sanity check if( pCTCBLK->iFrameOffset == 0 ) { release_lock( &pCTCBLK->Lock ); continue; } // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pCTCBLK->bFrameBuffer + sizeof( CTCIHDR ) + pCTCBLK->iFrameOffset ); STORE_HW( pFrame->hwOffset, 0x0000 ); // (fix for day-1 bug offered by Vince Weaver [[email protected]]) // iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ) + 2; iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ); if( sCount < iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } *pUnitStat = CSW_CE | CSW_DE; memcpy( pIOBuf, pCTCBLK->bFrameBuffer, iLength ); if( pCTCBLK->fDebug ) { logmsg( _("HHCCT041I %4.4X: CTC Received Frame (%d bytes):\n"), pDEVBLK->devnum, iLength ); packet_trace( pCTCBLK->bFrameBuffer, iLength ); } // Reset frame buffer pCTCBLK->iFrameOffset = 0; pCTCBLK->fDataPending = 0; release_lock( &pCTCBLK->Lock ); return; } }
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear) { REGS *regs; /* -> Regs */ DEVBLK *dev; /* -> Device control block */ int i; /* Array subscript */ BYTE unitstat; /* IPL device unit status */ BYTE chanstat; /* IPL device channel status */ int rc; /* Get started */ if ((rc = ARCH_DEP(common_load_begin) (cpu, clear)) ) return rc; /* Ensure CPU is online */ if (!IS_CPU_ONLINE(cpu)) { char buf[80]; MSGBUF(buf, "CP%02.2X Offline", devnum); WRMSG (HHC00810, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buf); return -1; } /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ /* Point to the device block for the IPL device */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { char buf[80]; MSGBUF(buf, "device %4.4X not found", devnum); WRMSG (HHC00810, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buf); HDC1(debug_cpu_state, regs); return -1; } if(sysblk.haveiplparm) { for(i=0;i<16;i++) { regs->GR_L(i)=fetch_fw(&sysblk.iplparmstring[i*4]); } sysblk.haveiplparm=0; } /* Set Main Storage Reference and Update bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); sysblk.main_clear = sysblk.xpnd_clear = 0; /* Build the IPL CCW at location 0 */ regs->psa->iplpsw[0] = 0x02; /* CCW command = Read */ regs->psa->iplpsw[1] = 0; /* Data address = zero */ regs->psa->iplpsw[2] = 0; regs->psa->iplpsw[3] = 0; regs->psa->iplpsw[4] = CCW_FLAGS_CC | CCW_FLAGS_SLI; /* CCW flags */ regs->psa->iplpsw[5] = 0; /* Reserved byte */ regs->psa->iplpsw[6] = 0; /* Byte count = 24 */ regs->psa->iplpsw[7] = 24; /* Enable the subchannel for the IPL device */ dev->pmcw.flag5 |= PMCW5_E; /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ dev->busy = 1; RELEASE_INTLOCK(NULL); /* Execute the IPL channel program */ ARCH_DEP(execute_ccw_chain) (dev); OBTAIN_INTLOCK(NULL); /* Clear the interrupt pending and device busy conditions */ obtain_lock (&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; /* Check that load completed normally */ unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { char buf[80]; char buf2[16]; memset(buf,0,sizeof(buf)); for (i=0; i < (int)dev->numsense; i++) { MSGBUF(buf2, "%2.2X", dev->sense[i]); strlcat(buf, buf2, sizeof(buf) ); if ((i & 3) == 3) strlcat(buf, " ", sizeof(buf)); } { char buffer[256]; MSGBUF(buffer, "architecture mode %s, csw status %2.2X%2.2X, sense %s", get_arch_mode_string((REGS *)0), unitstat, chanstat, buf); WRMSG (HHC00828, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, buffer); } HDC1(debug_cpu_state, regs); return -1; } #ifdef FEATURE_S370_CHANNEL /* Test the EC mode bit in the IPL PSW */ if (regs->psa->iplpsw[1] & 0x08) { /* In EC mode, store device address at locations 184-187 */ STORE_FW(regs->psa->ioid, dev->devnum); } else { /* In BC mode, store device address at locations 2-3 */ STORE_HW(regs->psa->iplpsw + 2, dev->devnum); } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set LPUM */ dev->pmcw.lpum = 0x80; STORE_FW(regs->psa->ioid, (dev->ssid<<16)|dev->subchan); /* Store zeroes at locations 188-191 */ memset (regs->psa->ioparm, 0, 4); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Save IPL device number, cpu number and lcss */ sysblk.ipldev = devnum; sysblk.iplcpu = regs->cpuad; sysblk.ipllcss = lcss; sysblk.ipled = TRUE; /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_ipl */
/*-------------------------------------------------------------------*/ 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 */ #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ RADR abs; /* abs addr of data area */ int i; /* loop counter */ struct rusage usage; /* RMF type data */ ETOD ETOD; /* Extended TOD clock */ U64 uCPU[MAX_CPU_ENGINES]; /* User CPU time (us) */ U64 tCPU[MAX_CPU_ENGINES]; /* Total CPU time (us) */ #if defined(FEATURE_PHYSICAL_DIAG204) static BYTE physical[8] = {0xD7,0xC8,0xE8,0xE2,0xC9,0xC3,0xC1,0xD3}; /* PHYSICAL */ #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ #if defined(FEATURE_EXTENDED_DIAG204) U64 oCPU[MAX_CPU_ENGINES]; /* Online CPU time (us) */ U64 wCPU[MAX_CPU_ENGINES]; /* Wait CPU time (us) */ #endif /*defined(FEATURE_EXTENDED_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; /* Retrieve the TOD clock value */ etod_clock(regs, &ETOD, ETOD_extended); /* Get processor time(s) and leave out non-CPU processes and * threads */ for(i = 0; i < sysblk.maxcpu; ++i) { if (IS_CPU_ONLINE(i)) { /* Get CPU times in microseconds */ getrusage((int)sysblk.cputid[i], &usage); uCPU[i] = timeval2us(&usage.ru_utime); tCPU[i] = uCPU[i] + timeval2us(&usage.ru_stime); } } 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,ETOD2tod(ETOD)); /* hercules partition */ partinfo = (DIAG204_PART*)(hdrinfo + 1); memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = sysblk.lparnum; /* Hercules partition */ partinfo->virtcpu = sysblk.cpus; get_lparname(partinfo->partname); /* hercules cpu's */ 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); STORE_DW(cpuinfo->totdispatch,tCPU[i]); STORE_DW(cpuinfo->effdispatch, uCPU[i]); cpuinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* LPAR management */ /* FIXME: This section should report on the real CPUs, appearing * and transformed for reporting purposes. This should * also be properly reflected in STSI information. */ 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 */ 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); STORE_DW(cpuinfo->totdispatch, tCPU[i]); STORE_DW(cpuinfo->effdispatch, uCPU[i]); 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); /* Retrieve the TOD clock value */ etod_clock(regs, &ETOD, ETOD_extended); /* Get processor time(s) and leave out non-CPU processes and * threads */ for(i = 0; i < sysblk.maxcpu; ++i) { if (IS_CPU_ONLINE(i)) { /* Get CPU times in microseconds */ getrusage((int)sysblk.cputid[i], &usage); oCPU[i] = etod2us(ETOD.high - regs->tod_epoch - sysblk.cpucreateTOD[i]); uCPU[i] = timeval2us(&usage.ru_utime); tCPU[i] = uCPU[i] + timeval2us(&usage.ru_stime); wCPU[i] = tCPU[i] - uCPU[i]; } } 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,ETOD.high); STORE_DW(hdrxinfo->diagstck2,ETOD.low); /* hercules partition */ partxinfo = (DIAG204_X_PART*)(hdrxinfo + 1); memset(partxinfo, 0, sizeof(DIAG204_PART)); partxinfo->partnum = sysblk.lparnum; /* 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 */ 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); STORE_DW(cpuxinfo->totdispatch, tCPU[i]); STORE_DW(cpuxinfo->effdispatch, uCPU[i]); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, oCPU[i]); STORE_DW(cpuxinfo->waittime, wCPU[i]); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* LPAR management */ /* FIXME: This section should report on the real CPUs, appearing * and transformed for reporting purposes. This should * also be properly reflected in STSI information. */ 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 */ 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); STORE_DW(cpuxinfo->totdispatch, tCPU[i]); STORE_DW(cpuxinfo->effdispatch, uCPU[i]); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, oCPU[i]); STORE_DW(cpuxinfo->waittime, wCPU[i]); 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_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 */
/*-------------------------------------------------------------------*/ int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear) { REGS *regs; /* -> Regs */ DEVBLK *dev; /* -> Device control block */ int i; /* Array subscript */ BYTE unitstat; /* IPL device unit status */ BYTE chanstat; /* IPL device channel status */ /* Get started */ if (ARCH_DEP(common_load_begin) (cpu, clear) != 0) return -1; /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ /* Point to the device block for the IPL device */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { logmsg (_("HHCCP027E Device %4.4X not in configuration%s\n"), devnum, (sysblk.arch_mode == ARCH_370 ? " or not conneceted to channelset" : "")); HDC1(debug_cpu_state, regs); return -1; } #if defined(OPTION_IPLPARM) if(sysblk.haveiplparm) { for(i=0;i<16;i++) { regs->GR_L(i)=fetch_fw(&sysblk.iplparmstring[i*4]); } sysblk.haveiplparm=0; } #endif /* Set Main Storage Reference and Update bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); sysblk.main_clear = sysblk.xpnd_clear = 0; /* Build the IPL CCW at location 0 */ regs->psa->iplpsw[0] = 0x02; /* CCW command = Read */ regs->psa->iplpsw[1] = 0; /* Data address = zero */ regs->psa->iplpsw[2] = 0; regs->psa->iplpsw[3] = 0; regs->psa->iplpsw[4] = CCW_FLAGS_CC | CCW_FLAGS_SLI; /* CCW flags */ regs->psa->iplpsw[5] = 0; /* Reserved byte */ regs->psa->iplpsw[6] = 0; /* Byte count = 24 */ regs->psa->iplpsw[7] = 24; /* Enable the subchannel for the IPL device */ dev->pmcw.flag5 |= PMCW5_E; /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ dev->busy = 1; RELEASE_INTLOCK(NULL); /* Execute the IPL channel program */ ARCH_DEP(execute_ccw_chain) (dev); OBTAIN_INTLOCK(NULL); /* Clear the interrupt pending and device busy conditions */ obtain_lock (&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; /* Check that load completed normally */ #ifdef FEATURE_S370_CHANNEL unitstat = dev->csw[4]; chanstat = dev->csw[5]; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { logmsg (_("HHCCP029E %s mode IPL failed: CSW status=%2.2X%2.2X\n" " Sense="), get_arch_mode_string(regs), unitstat, chanstat); for (i=0; i < (int)dev->numsense; i++) { logmsg ("%2.2X", dev->sense[i]); if ((i & 3) == 3) logmsg(" "); } logmsg ("\n"); HDC1(debug_cpu_state, regs); return -1; } #ifdef FEATURE_S370_CHANNEL /* Test the EC mode bit in the IPL PSW */ if (regs->psa->iplpsw[1] & 0x08) { /* In EC mode, store device address at locations 184-187 */ STORE_FW(regs->psa->ioid, dev->devnum); } else { /* In BC mode, store device address at locations 2-3 */ STORE_HW(regs->psa->iplpsw + 2, dev->devnum); } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set LPUM */ dev->pmcw.lpum = 0x80; STORE_FW(regs->psa->ioid, (dev->ssid<<16)|dev->subchan); /* Store zeroes at locations 188-191 */ memset (regs->psa->ioparm, 0, 4); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Save IPL device number, cpu number and lcss */ sysblk.ipldev = devnum; sysblk.iplcpu = regs->cpuad; sysblk.ipllcss = lcss; /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_ipl */
/*-------------------------------------------------------------------*/ static void ARCH_DEP(external_interrupt) (int code, REGS *regs) { RADR pfx; PSA *psa; int rc; PTT(PTT_CL_SIG,"*EXTINT",code,regs->cpuad,regs->psw.IA_L); #if defined(_FEATURE_SIE) /* Set the main storage reference and change bits */ if(SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Point to SIE copy of PSA in state descriptor */ psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_IP_PSA_OFFSET); STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); } else #endif /*defined(_FEATURE_SIE)*/ { /* Point to PSA in main storage */ pfx = regs->PX; #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) SIE_TRANSLATE(&pfx, ACCTYPE_SIE, regs); #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ psa = (void*)(regs->mainstor + pfx); STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* Store the interrupt code in the PSW */ regs->psw.intcode = code; /* Zero extcpuad field unless extcall or ems signal or blockio */ if(code != EXT_EXTERNAL_CALL_INTERRUPT #if defined(FEATURE_VM_BLOCKIO) && code != EXT_BLOCKIO_INTERRUPT #endif /* defined(FEATURE_VM_BLOCKIO) */ && code != EXT_EMERGENCY_SIGNAL_INTERRUPT) STORE_HW(psa->extcpad,0); #if defined(FEATURE_BCMODE) /* For ECMODE, store external interrupt code at PSA+X'86' */ if ( ECMODE(®s->psw) ) #endif /*defined(FEATURE_BCMODE)*/ STORE_HW(psa->extint,code); if ( !SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) || SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) || SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Store current PSW at PSA+X'18' */ ARCH_DEP(store_psw) (regs, psa->extold); /* Load new PSW from PSA+X'58' */ rc = ARCH_DEP(load_psw) (regs, psa->extnew); if ( rc ) { RELEASE_INTLOCK(regs); ARCH_DEP(program_interrupt)(regs, rc); } } #if defined(FEATURE_INTERVAL_TIMER) /* Ensure the interval timer is uptodate */ ARCH_DEP(store_int_timer_nolock) (regs); #endif RELEASE_INTLOCK(regs); if ( SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) longjmp (regs->progjmp, SIE_INTERCEPT_EXT); else longjmp (regs->progjmp, SIE_NO_INTERCEPT); } /* end function external_interrupt */
/*-------------------------------------------------------------------*/ 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,sysblk.maxcpu); 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 += (U16)(sizeof(SPCCB_CPU_INFO) * sysblk.maxcpu); 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 < sysblk.maxcpu; 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) { for (i = 0; i < 8; i++) { if( ((0x80 >> i) & dev->pmcw.pim) ) { BYTE chpid; chpid = dev->pmcw.chpid[i]; spccbchp->installed[chpid / 8] |= 0x80 >> (chpid % 8); spccbchp->assigned[chpid / 8] |= 0x80 >> (chpid % 8); spccbchp->configured[chpid / 8] |= 0x80 >> (chpid % 8); } } } /* 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 */
// -------------------------------------------------------------------- // CTCI_EnqueueIPFrame // -------------------------------------------------------------------- // // Places the provided IP frame in the next available frame slot in // the adapter buffer. For details regarding the actual buffer layout // please refer to the comments preceding the CTCI_ReadThread function. // // Returns: // // 0 == Success // -1 == Failure; errno = ENOBUFS: No buffer space available // EMSGSIZE: Message too long // static int CTCI_EnqueueIPFrame( DEVBLK* pDEVBLK, BYTE* pData, size_t iSize ) { PCTCIHDR pFrame; PCTCISEG pSegment; PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; // Will frame NEVER fit into buffer?? if( iSize > MAX_CTCI_FRAME_SIZE( pCTCBLK ) ) { errno = EMSGSIZE; // Message too long return -1; // (-1==failure) } obtain_lock( &pCTCBLK->Lock ); // Ensure we dont overflow the buffer if( ( pCTCBLK->iFrameOffset + // Current buffer Offset sizeof( CTCIHDR ) + // Size of Block Header sizeof( CTCISEG ) + // Size of Segment Header iSize + // Size of Ethernet packet sizeof(pFrame->hwOffset) ) // Size of Block terminator > pCTCBLK->iMaxFrameBufferSize ) // Size of Frame buffer { release_lock( &pCTCBLK->Lock ); errno = ENOBUFS; // No buffer space available return -1; // (-1==failure) } // Fix-up Frame pointer pFrame = (PCTCIHDR)pCTCBLK->bFrameBuffer; // Fix-up Segment pointer pSegment = (PCTCISEG)( pCTCBLK->bFrameBuffer + sizeof( CTCIHDR ) + pCTCBLK->iFrameOffset ); // Initialize segment memset( pSegment, 0, iSize + sizeof( CTCISEG ) ); // Increment offset pCTCBLK->iFrameOffset += sizeof( CTCISEG ) + iSize; // Update next frame offset STORE_HW( pFrame->hwOffset, pCTCBLK->iFrameOffset + sizeof( CTCIHDR ) ); // Store segment length STORE_HW( pSegment->hwLength, sizeof( CTCISEG ) + iSize ); // Store Frame type STORE_HW( pSegment->hwType, ETH_TYPE_IP ); // Copy data memcpy( pSegment->bData, pData, iSize ); // Mark data pending pCTCBLK->fDataPending = 1; release_lock( &pCTCBLK->Lock ); obtain_lock( &pCTCBLK->EventLock ); signal_condition( &pCTCBLK->Event ); release_lock( &pCTCBLK->EventLock ); return 0; // (0==success) }