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]); } }
/*--------------------------------------------------------------------*/ DLL_EXPORT void mpc_display_rrh_and_pdu( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH, BYTE bDir, int iLimit ) { MPC_PH* pMPC_PH; U16 uNumPH; U16 uOffPH; int iForPH; int iDone; U32 uLenData; U32 uOffData; BYTE* pData; /* Display the MPC_RRH.*/ FETCH_HW( uOffPH, pMPC_RRH->offph ); mpc_display_stuff( pDEVBLK, "RRH", (BYTE*)pMPC_RRH, uOffPH, bDir ); /* Display the MPC_PH(s). */ FETCH_HW( uNumPH, pMPC_RRH->numph ); pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); for( iForPH = 1; iForPH <= uNumPH; iForPH++ ) { mpc_display_stuff( pDEVBLK, "PH", (BYTE*)pMPC_PH, SIZE_PH, bDir ); pMPC_PH = (MPC_PH*)((BYTE*)pMPC_PH + SIZE_PH); } /* Display the data referenced by the MPC_PH(s). */ /* if limit is negative or a silly number, don't display the */ /* data. If limit is zero, display all of the data, otherwise */ /* limit the length of the data displayed. */ iDone = 0; if( iLimit >= 0 && iLimit <= 65535 ) { pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); for( iForPH = 1; iForPH <= uNumPH; iForPH++ ) { FETCH_F3( uLenData, pMPC_PH->lendata ); FETCH_FW( uOffData, pMPC_PH->offdata ); pData = (BYTE*)pMPC_TH + uOffData; if( iLimit > 0 ) { if( iDone >= iLimit ) break; if( (int)uLenData > ( iLimit - iDone ) ) uLenData = ( iLimit - iDone ); iDone =+ uLenData; } mpc_display_stuff( pDEVBLK, "PDU", pData, uLenData, bDir ); pMPC_PH = (MPC_PH*)((BYTE*)pMPC_PH + SIZE_PH); } } return; } /* End function mpc_display_rrh_and_pdu() */
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; }
/* the first MPC_PUS of the required type will ever be returned. */ DLL_EXPORT MPC_PUS* mpc_point_pus( DEVBLK* pDEVBLK, MPC_PUK* pMPC_PUK, BYTE bType ) { MPC_PUS* pMPC_PUS; int iTotLenPUS; U16 uTotLenPUS; U16 uLenPUS; U16 uLenPUK; UNREFERENCED( pDEVBLK ); /* Get the length of the MPC_PUK, the total length of the */ /* following MPC_PUSs, then point to the first MPC_PUS. */ FETCH_HW( uLenPUK, pMPC_PUK->length ); FETCH_HW( uTotLenPUS, pMPC_PUK->lenpus ); iTotLenPUS = uTotLenPUS; pMPC_PUS = (MPC_PUS*)((BYTE*)pMPC_PUK + uLenPUK); /* Find the required MPC_PUS. */ while( iTotLenPUS > 0 ) { /* Ensure there are at least the first 4-bytes of an MPC_PUS. */ if( iTotLenPUS < 4 ) return NULL; /* Get the length of the MPC_PUS. */ FETCH_HW( uLenPUS, pMPC_PUS->length ); if( uLenPUS == 0 ) /* Better safe than sorry */ return NULL; /* Ensure there is the whole of the MPC_PUS. */ if( iTotLenPUS < uLenPUS ) return NULL; /* Check for the required MPC_PUS. */ if( pMPC_PUS->type == bType ) return pMPC_PUS; /* Point to the next MPC_PUS. */ pMPC_PUS = (MPC_PUS*)((BYTE*)pMPC_PUS + uLenPUS); iTotLenPUS -= uLenPUS; } return NULL; } /* End function mpc_point_pus() */
/*--------------------------------------------------------------------*/ DLL_EXPORT void mpc_display_rrh( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH, BYTE bDir ) { U16 uOffPH; // Display the MPC_RRH. FETCH_HW( uOffPH, pMPC_RRH->offph ); mpc_display_stuff( pDEVBLK, "RRH", (BYTE*)pMPC_RRH, uOffPH, bDir ); return; } /* End function mpc_display_rrh() */
/*--------------------------------------------------------------------*/ DLL_EXPORT void mpc_display_ptp_th_etc( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, BYTE bDir, int iLimit ) { MPC_RRH* pMPC_RRH; int iForRRH; U32 uOffRRH; U16 uNumRRH; /* Display MPC_TH. */ mpc_display_th( pDEVBLK, pMPC_TH, bDir ); /* Get the number of MPC_RRHs and the displacement from */ /* the start of the MPC_TH to the first (or only) MPC_RRH. */ FETCH_HW( uNumRRH, pMPC_TH->numrrh ); FETCH_FW( uOffRRH, pMPC_TH->offrrh ); /* Process each of the MPC_RRHs. */ for( iForRRH = 1; iForRRH <= uNumRRH; iForRRH++ ) { /* Point to the first or subsequent MPC_RRH. */ pMPC_RRH = (MPC_RRH*)((BYTE*)pMPC_TH + uOffRRH); /* Display the MPC_RRH etc. */ if( pMPC_RRH->proto == PROTOCOL_LAYER2 && pMPC_RRH->type == RRH_TYPE_CM ) { /* Display MPC_RRH and following packet data. */ mpc_display_rrh_and_pkt( pDEVBLK, pMPC_TH, pMPC_RRH, bDir, iLimit ); } else if( pMPC_RRH->proto == PROTOCOL_LAYER2 && pMPC_RRH->type == RRH_TYPE_IPA ) { /* Display MPC_RRH and following MPC_PIX etc. */ mpc_display_rrh_and_pix( pDEVBLK, pMPC_TH, pMPC_RRH, bDir ); } else if( pMPC_RRH->proto == PROTOCOL_UNKNOWN ) { /* Display MPC_RRH and following MPC_PUK etc. */ mpc_display_rrh_and_puk( pDEVBLK, pMPC_TH, pMPC_RRH, bDir ); } else { /* Display MPC_RRH */ mpc_display_rrh( pDEVBLK, pMPC_RRH, bDir ); } /* Get the displacement from the start of the MPC_TH to the */ /* next MPC_RRH. pMPC_RRH->offrrh will contain zero if this */ /* is the last MPC_RRH. */ FETCH_FW( uOffRRH, pMPC_RRH->offrrh ); } return; } /* End function mpc_display_ptp_th_etc() */
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); } }
/*--------------------------------------------------------------------*/ DLL_EXPORT void mpc_display_rrh_and_ipa( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH, BYTE bDir ) { MPC_PH* pMPC_PH; MPC_IPA* pMPC_IPA; BYTE* pMPC_IPA_CMD; U32 uOffData; U32 uLenData; U16 uOffPH; int iLenIPA; int iLenCmd; // Display the MPC_RRH. FETCH_HW( uOffPH, pMPC_RRH->offph ); mpc_display_stuff( pDEVBLK, "RRH", (BYTE*)pMPC_RRH, uOffPH, bDir ); // Point to and display the MPC_PH. pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); mpc_display_stuff( pDEVBLK, "PH", (BYTE*)pMPC_PH, SIZE_PH, bDir ); /* Point to and display the MPC_IPA (and commands, if any). */ FETCH_F3( uLenData, pMPC_PH->lendata ); FETCH_FW( uOffData, pMPC_PH->offdata ); if( uLenData > sizeof(MPC_IPA) ) { iLenIPA = sizeof(MPC_IPA); iLenCmd = uLenData - sizeof(MPC_IPA); } else { iLenIPA = uLenData; iLenCmd = 0; } pMPC_IPA = (MPC_IPA*)((BYTE*)pMPC_TH + uOffData); mpc_display_stuff( pDEVBLK, "IPA", (BYTE*)pMPC_IPA, iLenIPA, bDir ); if( iLenCmd ) { pMPC_IPA_CMD = (BYTE*)pMPC_IPA + iLenIPA; mpc_display_stuff( pDEVBLK, "Cmd", (BYTE*)pMPC_IPA_CMD, iLenCmd, bDir ); } return; } /* End function mpc_display_rrh_and_ipa() */
/*--------------------------------------------------------------------*/ DLL_EXPORT MPC_PUK* mpc_point_puk( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH ) { MPC_PH* pMPC_PH; MPC_PUK* pMPC_PUK; U32 uOffData; U16 uOffPH; UNREFERENCED( pDEVBLK ); // Point to the MPC_PH. FETCH_HW( uOffPH, pMPC_RRH->offph ); pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); // Get the length of and point to the data referenced by the // MPC_PH. The data contain a MPC_PUK and one or more MPC_PUSs. FETCH_FW( uOffData, pMPC_PH->offdata ); pMPC_PUK = (MPC_PUK*)((BYTE*)pMPC_TH + uOffData); return pMPC_PUK; } /* End function mpc_point_puk() */
/*-------------------------------------------------------------------*/ 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; } }
/* followed by a single MPC_PIX. */ DLL_EXPORT void mpc_display_rrh_and_pix( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH, BYTE bDir ) { MPC_PH* pMPC_PH; MPC_PIX* pMPC_PIX; U32 uOffData; U32 uLenData; U16 uOffPH; // Display the MPC_RRH. FETCH_HW( uOffPH, pMPC_RRH->offph ); mpc_display_stuff( pDEVBLK, "RRH", (BYTE*)pMPC_RRH, uOffPH, bDir ); // Point to and display the MPC_PH. pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); mpc_display_stuff( pDEVBLK, "PH", (BYTE*)pMPC_PH, SIZE_PH, bDir ); // Point to and display the MPC_PIX. FETCH_F3( uLenData, pMPC_PH->lendata ); FETCH_FW( uOffData, pMPC_PH->offdata ); pMPC_PIX = (MPC_PIX*)((BYTE*)pMPC_TH + uOffData); mpc_display_stuff( pDEVBLK, "PIX", (BYTE*)pMPC_PIX, uLenData, bDir ); return; } /* End function mpc_display_rrh_and_pix() */
/* is followed by up to four MPC_PUSs. */ DLL_EXPORT void mpc_display_rrh_and_puk( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH, BYTE bDir ) { MPC_PH* pMPC_PH; MPC_PUK* pMPC_PUK; MPC_PUS* pMPC_PUS; int iTotLenPUS; U32 uOffData; U16 uTotLenPUS; U16 uLenPUS; U16 uLenPUK; U16 uOffPH; // Display the MPC_RRH. FETCH_HW( uOffPH, pMPC_RRH->offph ); mpc_display_stuff( pDEVBLK, "RRH", (BYTE*)pMPC_RRH, uOffPH, bDir ); // Point to and display the MPC_PH. pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH); mpc_display_stuff( pDEVBLK, "PH", (BYTE*)pMPC_PH, SIZE_PH, bDir ); // Get the length of and point to the data referenced by the // MPC_PH. The data contain a MPC_PUK and one or more MPC_PUSs. FETCH_FW( uOffData, pMPC_PH->offdata ); pMPC_PUK = (MPC_PUK*)((BYTE*)pMPC_TH + uOffData); // Display the MPC_PUK. FETCH_HW( uLenPUK, pMPC_PUK->length ); mpc_display_stuff( pDEVBLK, "PUK", (BYTE*)pMPC_PUK, uLenPUK, bDir ); // Get the total length of the following MPC_PUSs, then point to // the first MPC_PUS. FETCH_HW( uTotLenPUS, pMPC_PUK->lenpus ); iTotLenPUS = uTotLenPUS; pMPC_PUS = (MPC_PUS*)((BYTE*)pMPC_PUK + uLenPUK); // Display all of the MPC_PUSs. while( iTotLenPUS > 0 ) { // Ensure there are at least the first 4-bytes of the MPC_PUS. if( iTotLenPUS < 4 ) { mpc_display_stuff( pDEVBLK, "???", (BYTE*)pMPC_PUS, iTotLenPUS, bDir ); break; } // Get the length of the MPC_PUS. FETCH_HW( uLenPUS, pMPC_PUS->length ); if( uLenPUS == 0 ) /* Better safe than sorry */ { mpc_display_stuff( pDEVBLK, "???", (BYTE*)pMPC_PUS, iTotLenPUS, bDir ); break; } // Ensure there is the whole of the MPC_PUS. if( iTotLenPUS < uLenPUS ) { mpc_display_stuff( pDEVBLK, "???", (BYTE*)pMPC_PUS, iTotLenPUS, bDir ); break; } // Display the MPC_PUS. mpc_display_stuff( pDEVBLK, "PUS", (BYTE*)pMPC_PUS, uLenPUS, bDir ); // Point to the next MPC_PUS pMPC_PUS = (MPC_PUS*)((BYTE*)pMPC_PUS + uLenPUS); iTotLenPUS -= uLenPUS; } return; } /* End function mpc_display_rrh_and_puk() */
/*-------------------------------------------------------------------*/ static int find_input_record (BYTE *buf, BYTE **ppbuf, int *plen, BYTE *pkl, BYTE **pkp, U16 *pdl, BYTE **pdp, U32 *pcc, U32 *phh, BYTE *prn) { H30CKD_RECHDR *hrec; /* Input record header */ U16 dlen; /* Data length */ BYTE klen; /* Key length */ int n; /* Integer work area */ UNREFERENCED(buf); /* End of track if not enough bytes remain in buffer */ if (*plen < H30CKD_RECHDR_SIZE) return 1; /* Point to record header */ hrec = (H30CKD_RECHDR*)(*ppbuf); /* End of track if record header is all zero */ if (memcmp(*ppbuf, twelvehex00, 12) == 0) return 1; /* Extract the key length and data length */ klen = hrec->klen; FETCH_HW (dlen, hrec->dlen); /* Check that the reserved bytes are all zero */ if (memcmp(hrec->resv00, twelvehex00, sizeof(hrec->resv00)) != 0) return 2; /* Check that the key and data do not overflow the buffer */ if (*plen < H30CKD_RECHDR_SIZE + klen + dlen) return 3; /* Return the cylinder, head, and record number */ FETCH_HW (*pcc, hrec->cyl); FETCH_HW (*phh, hrec->head); *prn = hrec->rec; /* Point past the record header to the key */ *plen -= H30CKD_RECHDR_SIZE; *ppbuf += H30CKD_RECHDR_SIZE; /* Return the key length and key pointer */ *pkl = klen; *pkp = *ppbuf; /* Point past the key to the data */ *plen -= klen; *ppbuf += klen; /* Return the data length and data pointer */ *pdl = dlen; *pdp = *ppbuf; /* Point past the data to the next record header */ *plen -= dlen; *ppbuf += dlen; /* Ensure next header starts on a fullword boundary */ if ((klen + dlen) & 3) { n = 4 - ((klen + dlen) % 4); *plen -= n; *ppbuf += n; } /* Issue progress message */ #if 0 fprintf (stderr, "+%4.4X cyl=%4.4X head=%4.4X rec=%2.2X" " kl=%2.2X dl=%4.4X trkbal=%d\n", (BYTE*)hrec-buf, *pcc, *phh, *prn, klen, dlen, *plen); #endif return 0; } /* end function find_input_record */
/*-------------------------------------------------------------------*/ 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 */
int main( int argc, char *argv[] ) { U64 nxtpos; /* file position of next read */ U64 altpos; /* file position of alternate track */ U64 orgpos; /* alternate track's file position of original track */ U32 numbad = 0; /* Counts defective tracks */ U32 reclaimed = 0; /* Counts reclaimed tracks */ U32 remaining; /* Counts number of tracks to process */ U32 total; /* Total number of tracks to process */ int infile = -1; /* Input file descriptor integer */ int outfile = -1; /* output file descriptor integer */ int cyl; /* Cylinder number */ int head; /* Head number */ int track; /* Track number */ int rc; /* Return code */ U8 trackbuf[TRACKSIZE]; /* Primary track buffer */ U8 alttrack[TRACKSIZE]; /* Alternate track buffer */ U8 altmark[6] = { BAD_TRACK_SIG }; /* Defective track signature */ U8 reclaim = 0; /* false: map, true: reclaim */ /*----------------*/ /* Initialization */ /*----------------*/ if (argc < 3 || argc > 4) return error( EINVAL, "invalid number of arguments" ); if (1 && strcmp( argv[1], "MAP" ) != 0 && strcmp( argv[1], "map" ) != 0 && strcmp( argv[1], "RECLAIM" ) != 0 && strcmp( argv[1], "reclaim" ) != 0 ) return error( EINVAL, "invalid 'action'" ); reclaim = ((strcmp( argv[1], "RECLAIM" ) == 0) || (strcmp( argv[1], "reclaim" ) == 0)); if (reclaim && argc < 4) return error( EINVAL, "missing outfile argument" ); printf( "Run option = %s\n", argv[1] ); printf( "Opening input file \"%s\"...\n", argv[2] ); if ((infile = HOPEN( argv[2], O_RDONLY | O_BINARY )) < 0) return error( errno, "could not open input file" ); /*------------------------------*/ /* Read and inspect file header */ /*------------------------------*/ if ((rc = read(infile, trackbuf, FILEHDRSIZE)) <= 0 || rc != FILEHDRSIZE) return error( EIO, "I/O error reading header from input file" ); if (memcmp(trackbuf, "CKD_P370", 8) != 0) return error(EINTR, "input file is no CKD dasd image"); if (trackbuf[16] != 0x90) return error(EINTR, "input file is no 3390 dasd image"); FETCH_FW( head, &trackbuf[8] ); FETCH_FW( track, &trackbuf[12] ); FETCH_HW( cyl, &trackbuf[18] ); if (bswap_32(track) != TRACKSIZE) return error(EINTR, "input file uses an unsupported track size"); printf("3390 DASD image: %d heads, %d cylinders\n\n", bswap_32(head), bswap_16(cyl)); remaining = total = TRACKSPERCYL * bswap_16(cyl); /*-----------------------------------------------------------*/ /* Open output file and copy file header (only on "reclaim") */ /*-----------------------------------------------------------*/ if (reclaim) { printf( "Opening output file \"%s\"...\n", argv[3] ); if ((outfile = HOPEN( argv[3], O_CREAT | O_EXCL | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP )) < 0) return error( errno, "could not open output file" ); if ((rc = write( outfile, trackbuf, FILEHDRSIZE )) < 0 || rc != FILEHDRSIZE) return error( EIO, "I/O error writing output file" ); } c: /*---------------------------*/ /* Start of copy tracks loop */ /*---------------------------*/ track = total - remaining; cyl = CYLNUM ( track ); head = HEADNUM( track ); if (!head) printf( "Inspecting cylinder %d...\r", cyl ); /* Read next track */ if ((rc = read( infile, trackbuf, TRACKSIZE )) <= 0 || rc != TRACKSIZE) return error( errno, "I/O error reading input file" ); /*------------------*/ /* Defective track? */ /*------------------*/ if (memcmp( &trackbuf[TRACKSIZE-16], altmark, 6 ) == 0) { numbad++; /* Count defective tracks */ if (reclaim) printf( "Reclaiming track %6d = Cyl %4d (%4.4X), Head %2d (%2.2X)...\n", track, cyl, cyl, head, head ); else printf( "Track %6d = Cyl %4d (%4.4X), Head %2d (%2.2X) is flagged\nas being defective and has an alternate track assigned.\n", track, cyl, cyl, head, head ); FETCH_DW( altpos, &trackbuf[ TRACKSIZE-8 ] ); /* get alternate track position */ nxtpos= lseek( infile, 0, SEEK_CUR ); /* save current file position */ lseek( infile, altpos, SEEK_SET ); /* position to alternate */ read ( infile, alttrack, TRACKSIZE ); /* read alternate track */ lseek( infile, nxtpos, SEEK_SET ); /* restore original file position */ FETCH_DW( orgpos, &alttrack[ TRACKSIZE-8 ] ); /* get original track position */ /*----------------------------------------------*/ #if (DEBUGOPT & DEBUG_POSITIONS) { int alttrk = POS2TRACK( altpos ); int altcyl = CYLNUM ( alttrk ); int althead = HEADNUM( alttrk ); int orgtrk = POS2TRACK( orgpos ); int orgcyl = CYLNUM ( orgtrk ); int orghead = HEADNUM( orgtrk ); printf("\n"); printf( "\taltpos = %llx ==> track %6d = Cyl %4d (%4.4X), Head %2d (%2.2X)\n", altpos, alttrk, altcyl, altcyl, althead, althead ); printf( "\torgpos = %llx ==> track %6d = Cyl %4d (%4.4X), Head %2d (%2.2X)\n", orgpos, orgtrk, orgcyl, orgcyl, orghead, orghead ); } #endif #if (DEBUGOPT & DEBUG_TRACKDATA) { char *dump = NULL; printf("\n"); hexdumpe( "\tPRI: ", &dump, trackbuf, 0, TRACKSIZE, orgpos, 4, 4 ); if (dump) printf( "%s\n", dump ); hexdumpe( "\tALT: ", &dump, alttrack, 0, TRACKSIZE, altpos, 4, 4 ); if (dump) printf( "%s", dump ); if (dump) free( dump ); } #endif #if (DEBUGOPT & DEBUG_BOTH) /* if EITHER debug option */ printf("\n"); /* if EITHER debug option */ #endif /*----------------------------------------------*/ if (reclaim) { /* Reclaim the original track: the alternate tracks's position of the original defective track must match, and the track header containing the cylinder and track numbers must also match. */ if (orgpos == (nxtpos-TRACKSIZE) && memcmp( &alttrack[0], &trackbuf[0], 16 ) == 0) { /* copy alternate track data to original track */ memcpy( trackbuf, alttrack, TRACKSIZE ); /* indicate original track is no longer defective */ memset( &trackbuf[TRACKSIZE-16], 0, 16 ); reclaimed++; /* Count reclaimed tracks */ } else fprintf( stderr, "\t*** ERROR *** Reclaim failed!\n\n" ); } } /*----------------------------*/ /* Write track to output file */ /*----------------------------*/ if (reclaim) if ((rc = write( outfile, trackbuf, TRACKSIZE )) < 0 || rc != TRACKSIZE) return error( EIO, "I/O error writing output file" ); /*------------------------------*/ /* Loop until all tracks copied */ /*------------------------------*/ if (--remaining) goto c; /*-----------------------*/ /* Print totals and exit */ /*-----------------------*/ if (infile > 0) close( infile ); if (outfile > 0) close( outfile ); printf( "%d tracks (%d cylinders) read.\n", total, CYLNUM(total) ); if (reclaim) printf( "%d tracks (%d cylinders) written.\n", total, CYLNUM(total) ); if (!reclaim) printf( "Image currently has %d defective tracks assigned to an alternate.\n", numbad ); else { printf( "Image had %d defective tracks assigned to an alternate.\n", numbad ); printf( "A total of %d defective tracks were reclaimed from their assigned alternate.\n", reclaimed ); printf( "Reclaim %s.\n", reclaimed >= numbad ? "was successful" : "function FAILED" ); } PAUSEIFBEINGDEBUGGED(); return (0); }
/*-------------------------------------------------------------------*/ static IFD open_input_image (char *ifname, U16 *devt, U32 *vcyls, U32 *itrkl, BYTE **itrkb, BYTE *volser) { int rc; /* Return code */ H30CKD_TRKHDR h30trkhdr; /* Input track header */ IFD ifd; /* Input file descriptor */ int len; /* Length of input */ U16 code; /* Device type code */ U16 dt; /* Device type */ U32 cyls; /* Device size (pri+alt cyls)*/ U32 alts; /* Number of alternate cyls */ BYTE *itrkbuf; /* -> Input track buffer */ U32 itrklen; /* Input track length */ BYTE *pbuf; /* Current byte in input buf */ BYTE klen; /* Key length */ U16 dlen; /* Data length */ BYTE *kptr; /* -> Key in input buffer */ BYTE *dptr; /* -> Data in input buffer */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ BYTE rec; /* Record number */ char pathname[MAX_PATH]; /* file path in host format */ hostpath(pathname, (char *)ifname, sizeof(pathname)); /* Open the HDR-30 CKD image file */ #if defined(HAVE_LIBZ) if (strcmp(ifname, "-") == 0) ifd = gzdopen (STDIN_FILENO, "rb"); else ifd = gzopen (pathname, "rb"); if (ifd == NULL) { fprintf (stderr, "Cannot open %s: %s\n", ifname, errno == 0 ? "gzopen error" : strerror(errno)); EXIT(3); } #else /*!defined(HAVE_LIBZ)*/ if (strcmp(ifname, "-") == 0) ifd = STDIN_FILENO; else { ifd = hopen(pathname, O_RDONLY | O_BINARY); if (ifd < 0) { fprintf (stderr, "Cannot open %s: %s\n", ifname, strerror(errno)); EXIT(3); } } #endif /*!defined(HAVE_LIBZ)*/ /* Read the first track header */ read_input_data (ifd, ifname, (BYTE*)&h30trkhdr, H30CKD_TRKHDR_SIZE, 0); #if !defined(HAVE_LIBZ) /* Reject input if compressed and we lack gzip support */ if (memcmp(h30trkhdr.devcode, gz_magic_id, sizeof(gz_magic_id)) == 0) { fprintf (stderr, "Input file %s appears to be a .gz file\n" "but this program was compiled without compression support\n", ifname); EXIT(3); } #endif /*!defined(HAVE_LIBZ)*/ /* Reject input if it is already in CKD or CCKD format */ if (memcmp((BYTE*)&h30trkhdr, ckd_ident, sizeof(ckd_ident)) == 0) { fprintf (stderr, "Input file %s is already in CKD format, use dasdcopy\n", ifname); EXIT(3); } /* Extract the device type code from the track header */ FETCH_HW (code, h30trkhdr.devcode); /* Determine the input device type and size from the device code */ switch (code) { case 0x01: dt=0x3330; cyls=411; alts=7; break; /* 3330 */ case 0x02: dt=0x3330; cyls=815; alts=7; break; /* 3330-11 */ case 0x03: dt=0x3340; cyls=351; alts=1; break; /* 3340-35 */ case 0x04: dt=0x3340; cyls=701; alts=1; break; /* 3340-70 */ case 0x05: dt=0x3350; cyls=562; alts=7; break; /* 3350 */ case 0x06: dt=0x3375; cyls=962; alts=3; break; /* 3375 */ case 0x08: dt=0x3380; cyls=888; alts=3; break; /* 3380-A,D,J*/ case 0x09: dt=0x3380; cyls=1774; alts=4; break; /* 3380-E */ case 0x0A: dt=0x3380; cyls=2660; alts=5; break; /* 3380-K */ case 0x0B: dt=0x3390; cyls=1117; alts=4; break; /* 3390-1 */ case 0x0C: dt=0x3390; cyls=2230; alts=4; break; /* 3390-2 */ case 0x0D: dt=0x3390; cyls=3343; alts=4; break; /* 3390-3 */ case 0x12: dt=0x2314; cyls=203; alts=3; break; /* 2314 */ case 0x13: dt=0x3390; cyls=10038; alts=21; break; /* 3390-9 */ case 0x14: dt=0x9345; cyls=1454; alts=14; break; /* 9345-1 */ case 0x15: dt=0x9345; cyls=2170; alts=14; break; /* 9345-2 */ default: fprintf (stderr, "Unknown device code %4.4X" \ " at offset 00000000 in input file %s\n", code, ifname); EXIT(3); } /* end switch(code) */ /* Use the device type to determine the input image track size */ switch (dt) { case 0x2314: itrklen = 0x2000; break; case 0x3330: itrklen = 0x3400; break; case 0x3340: itrklen = 0x2400; break; case 0x3350: itrklen = 0x4C00; break; case 0x3375: itrklen = 0x9000; break; case 0x3380: itrklen = 0xBC00; break; case 0x3390: itrklen = 0xE400; break; case 0x9345: itrklen = 0xBC00; break; default: fprintf (stderr, "Unknown device type: %4.4X\n", dt); EXIT(3); } /* end switch(dt) */ /* Obtain the input track buffer */ itrkbuf = malloc (itrklen); if (itrkbuf == NULL) { fprintf (stderr, "Cannot obtain storage for input track buffer: %s\n", strerror(errno)); EXIT(3); } /* Copy the first track header to the input track buffer */ memcpy (itrkbuf, &h30trkhdr, H30CKD_TRKHDR_SIZE); /* Read the remainder of the first track into the buffer */ read_input_data (ifd, ifname, itrkbuf + H30CKD_TRKHDR_SIZE, itrklen - H30CKD_TRKHDR_SIZE, H30CKD_TRKHDR_SIZE); /* Initialize the volume serial number */ strcpy ((char *)volser, "(NONE)"); /* Search for volume label in record 3 of first track */ pbuf = itrkbuf + H30CKD_TRKHDR_SIZE; len = itrklen - H30CKD_TRKHDR_SIZE; while (1) { /* Find next input record */ rc = find_input_record (itrkbuf, &pbuf, &len, &klen, &kptr, &dlen, &dptr, &cyl, &head, &rec); /* Give up if error or end of track */ if (rc != 0) break; /* Process when record 3 is found */ if (cyl == 0 && head == 0 && rec == 3) { /* Extract volser if it is a volume label */ if (klen == 4 && memcmp(kptr, ebcdicvol1, 4) == 0 && dlen == 80 && memcmp(dptr, ebcdicvol1, 4) == 0) make_asciiz ((char *)volser, 7, dptr+4, 6); break; } } /* end while */ /* Set output variables and return the input file descriptor */ *devt = dt; *vcyls = cyls - alts; *itrkl = itrklen; *itrkb = itrkbuf; return ifd; } /* end function open_input_image */
/*-------------------------------------------------------------------*/ 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 */
static void CTCT_Write( DEVBLK* pDEVBLK, U32 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U32* pResidual ) { PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { WRMSG(HHC00906, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet WRMSG(HHC00907, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { WRMSG(HHC00908, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( (U32)iPos + sSegLen > sOffset ) || ( (U32)iPos + sSegLen > sCount ) ) { WRMSG(HHC00909, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { WRMSG(HHC00934, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename ); if( pDEVBLK->ccwtrace ) packet_trace( pSegment->bData, sDataLen, '>' ); } // Write the IP packet rc = write_socket( pDEVBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { WRMSG(HHC00936, "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; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( (U32)iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; }
void CTCI_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { logmsg( _("HHCCT042E %4.4X: Write CCW count %u is invalid\n"), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet logmsg( _("HHCCT043I %4.4X: Interface command: %s %8.8X\n"), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { logmsg( _("HHCCT044E %4.4X: Write buffer contains incomplete " "segment header at offset %4.4X\n"), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( iPos + sSegLen > sOffset ) || ( iPos + sSegLen > sCount ) ) { logmsg( _("HHCCT045E %4.4X: Write buffer contains invalid " "segment length %u at offset %4.4X\n"), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending to TUN device if( pCTCBLK->fDebug ) { logmsg( _("HHCCT046I %4.4X: Sending packet to %s:\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName ); packet_trace( pSegment->bData, sDataLen ); } // Write the IP packet to the TUN/TAP interface rc = TUNTAP_Write( pCTCBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { logmsg( _("HHCCT047E %4.4X: Error writing to %s: rc=%d errno=%d %s\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, rc, errno, strerror(errno)); } /* Kludge for Ubuntu 10.04 by Martin Truebner */ if (rc == -1 && errno == 22) rc = 0; if (rc < 0) { pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; }