#include #include #include #include #include #include #include #include #include /* change this to be callback mchWriteRead, move to drvMch.c * * Call ipmiMsgWriteRead. * If error, increment error count. Else, set error count back to zero. * If MCH is alive, but there is no response or error count reaches 10, * start a new session and return error. * Check message sequence, session sequence, completion code. * * RETURNS: 0 if error-free response * non-zero if error, no response, or failed to start new session * * Arguments: * mchSess - Pointer to session data structure * ipmiSess - Pointer to IPMI data structure * message - Pointer to outgoing message array * messageSize - Size of outgoing message * response - Pointer to response array * responseSize - Response size; if 0, allow for max response length * cmd - IPMI command code * netfn - IPMI network function * codeOffs - Additional offset used to read completion code * outSess - 1 if outside a session; 0 if in a session */ int mchMsgWriteReadHelper(MchSess mchSess, IpmiSess ipmiSess, uint8_t *message, size_t messageSize, uint8_t *response, size_t *responseSize, uint8_t cmd, uint8_t netfn, int codeOffs, int outSess) { int i, status, inst = mchSess->instance; uint8_t ipmiSeq = 0, code; int ipmiSeqOffs = IPMI_RPLY_SEQLUN_OFFSET; uint8_t seq[4]; uint32_t seqInt; uint32_t seqRplyInt; size_t responseLen; /* seems we check this twice for sensor reads */ if ( !MCH_ONLN( mchStat[inst] ) ) return -1; status = ipmiMsgWriteRead( mchSess->name, message, messageSize, response, responseSize, mchSess->timeout, &responseLen ); /* printf("%s Message status %i, received %i, expected %i, raw data:\n", mchSess->name, status, (int)responseLen, *(int *)responseSize ); for ( i = 0; i < responseLen; i++ ) printf("%02x ", response[i]); printf("\n"); */ if ( MCH_DBG( mchStat[inst] ) >= MCH_DBG_MED ) { if ( MCH_DBG( mchStat[inst] ) >= MCH_DBG_HIGH ) { printf("%s Message status %i, received %i, expected %i, raw data:\n", mchSess->name, status, (int)responseLen, *(int *)responseSize ); for ( i = 0; i < responseLen; i++ ) printf("%02x ", response[i]); printf("\n"); } else if ( status ) printf("%s Message status %i, received %i, expected %i\n", mchSess->name, status, (int)responseLen, *(int *)responseSize); } *responseSize = responseLen; /* Pass actual response length back to caller */ if ( outSess ) { if ( (code = response[IPMI_RPLY_COMPLETION_CODE_OFFSET]) && MCH_DBG( mchStat[inst] ) ) ipmiCompletionCode( mchSess->name, code, cmd, netfn ); return code; } if ( /*(responseLen == 0) ||*/ (mchSess->err > 9) ) { if ( MCH_DBG( mchStat[inst] ) ) printf("%s start new session; err count is %i\n", mchSess->name, mchSess->err); /* Reset error count to 0 */ mchSess->err = 0; /* Close current session, start new one, and return error */ mchMsgCloseSess( mchSess, ipmiSess, response ); mchNewSession( mchSess, ipmiSess ); return -1; } if ( responseLen == 0 ) { mchSess->err++; return -1; } /* Verify IPMI message sequence number. If incorrect, increment error count and return error */ ipmiSeq = (response[ipmiSeqOffs] & 0xFC) >> 2; if ( ipmiSeq != ipmiSess->seq ) { if ( MCH_DBG( mchStat[inst] ) ) printf("%s Incorrect IPMI sequence; got %i but expected %i\n", mchSess->name, ipmiSeq, ipmiSess->seq ); mchSess->err++; return -1; } /* Extract session sequence number from reply */ for ( i = 0; i < IPMI_RPLY_SEQ_LENGTH ; i++) seq[i] = response[IPMI_RPLY_SEQ_OFFSET + i]; /* bridged offset ? */ seqInt = arrayToUint32( seq ); seqRplyInt = arrayToUint32( ipmiSess->seqRply ); /* Check session sequence number. If it is not increasing or more than * 7 counts higher than last time, increment our stored seq number and set error. * Else store sequence number. * * If seq number error or completion code non-zero, increment error count and return error. * Else reset error count to 0 and return success. */ if ( (seqInt <= seqRplyInt) || (seqInt - seqRplyInt > 7) ) { if ( MCH_DBG( mchStat[inst] ) >= MCH_DBG_MED ) printf("%s sequence number %i, previous %i\n", mchSess->name, seqInt, seqRplyInt); incr4Uint8Array( ipmiSess->seqRply, 1 ); mchSess->err++; return -1; } else { for ( i = 0; i < IPMI_RPLY_SEQ_LENGTH ; i++) ipmiSess->seqRply[i] = seq[i]; if ( (code = response[IPMI_RPLY_COMPLETION_CODE_OFFSET + codeOffs]) ) { if ( MCH_DBG( mchStat[inst] ) ) ipmiCompletionCode( mchSess->name, code, cmd, netfn ); //mchSess->err++; // only increment error count for some errors ? --not parameter out of range, for example return code; } } mchSess->err = 0; return 0; } static void mchSetSizeOffs(int type, int *offs, size_t *responseSize, int *bridged, uint8_t *rsAddr, uint8_t *rqAddr) { switch ( type ) { default: *offs = 0; *responseSize = HEADER_LENGTH +3; *bridged = 0; *rsAddr = 0; *rqAddr = 0; break; /* case MCH_TYPE_NAT: *offs = IPMI_RPLY_BRIDGED_1REPLY_OFFSET; *responseSize += *offs; *bridged = 1; *rsAddr = IPMI_MSG_ADDR_CM; *rqAddr = IPMI_MSG_ADDR_BMC; */ break; case MCH_TYPE_VT: // note that we used to only check comp code of send msg reply (not payload reply) which is different than other devices; may need to revert to that *offs = IPMI_RPLY_BRIDGED_2REPLY_OFFSET; *responseSize = HEADER_LENGTH + 3 + *offs; *bridged = 1; *rsAddr = IPMI_MSG_ADDR_CM; *rqAddr = IPMI_MSG_ADDR_BMC; break; } } int mchMsgCheckSizes(size_t destSize, int offset, size_t srcSize) { if ( 0 >= srcSize ) { printf("mchMsgCheckSizes: message size %i less than zero\n", srcSize); return -1; } else if ( (offset + srcSize) > destSize ) { printf("mchMsgCheckSizes: copy size %i larger than destination %i \n", offset+srcSize, destSize); return -1; } return 0; } /* Temporary workaround for using different usernames across different devices */ int mchMsgGetSess(MchSess mchSess, IpmiSess ipmiSess, uint8_t *response) { size_t size = sizeof( GET_SESS_MSG ); uint8_t msg[size]; uint8_t code; uint8_t user1[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t user2[16] = { 'i', 'p', 'm', 'i', 'u', 's', 'e', 'r', 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t user3[16] = { 'A', 'D', 'M', 'I', 'N', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; memcpy( msg, GET_SESS_MSG, size ); memcpy( msg + 4, user1, sizeof( user1 ) ); code = ipmiMsgGetSess( mchSess, ipmiSess, response, msg ); if ( (code == IPMI_COMP_CODE_GET_SESS_INVALID_USER) || (code == IPMI_COMP_CODE_GET_SESS_NULL_USER) ) { memcpy( msg + 4, user2, sizeof( user2 ) ); return ipmiMsgGetSess( mchSess, ipmiSess, response, msg ); } else if ( code == IPMI_COMP_CODE_INVALID_FIELD ) { memcpy( msg + 4, user3, sizeof( user3 ) ); return ipmiMsgGetSess( mchSess, ipmiSess, response, msg ); } return code; } /* Close Session - test for NAT and determine reply offset*/ int mchMsgCloseSess(MchSess mchSess, IpmiSess ipmiSess, uint8_t *data) { size_t responseSize = MCH_IS_NAT( mchSess->type ) ? IPMI_RPLY_CLOSE_SESSION_LENGTH_NAT : IPMI_RPLY_CLOSE_SESSION_LENGTH_VT; return ipmiMsgCloseSess( mchSess, ipmiSess, data, &responseSize ); } /* Chassis Control * * RETURNS: status from ipmiMsgChassisControl * 0 on success * non-zero for error */ int mchMsgChassisControl(MchData mchData, uint8_t *data, uint8_t parm) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_CHAS_CTRL_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgChassisControl( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, parm, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgChassisControl size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get FRU Inventory Info * * RETURNS: status from ipmiMsgGetFruInfo * 0 on success * non-zero for error */ int mchMsgGetFruInvInfo(MchData mchData, uint8_t *data, uint8_t id) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_FRU_INV_INFO_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgGetFruInvInfo( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, id, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetFruInvInfo size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Read FRU data * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgReadFru(MchData mchData, uint8_t *data, uint8_t id, uint8_t *readOffset, uint8_t readSize) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_READ_FRU_DATA_LENGTH_HDR + readSize; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgReadFru( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, id, readOffset, readSize, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgReadFru size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get SDR (Sensor Data Record) Repository Info * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetSdrRepInfo(MchData mchData, uint8_t *data) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_SDRREP_INFO_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgGetSdrRepInfo( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetSdrRepInfo size error roffs %i payloadSize %i responseSize %i\n", roffs, payloadSize, responseSize); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Reserve SDR (Sensor Data Record) Repository * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgReserveSdrRep(MchData mchData, uint8_t *data) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_RESERVE_SDRREP_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; //printf("expected response size %i\n", responseSize); if ( (rval = ipmiMsgReserveSdrRep( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, &responseSize, offs )) ) goto bail; /* printf("\nmchmsgreservesdrrep roffs %i payloadSize %i\n", roffs, payloadSize); int z; for ( z = 0; z < MSG_MAX_LENGTH; z++ ) printf("0x%02x ", response[z]); printf("\n\n"); */ if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgReserveSdrRep size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* * Get SDR (Sensor Data Record) * * Offset and reservation ID are 0 unless doing partial read that begins at an * offset into the SDR other than 0. * * Used for both Get SDR (parm = 0) and Get Device SDR (parm = 1). * Only differences in the message are the network function and command code. * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetSdr(MchData mchData, uint8_t *data, uint8_t *id, uint8_t *res, uint8_t offset, uint8_t readSize, uint8_t parm, uint8_t recordSize) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; uint8_t sdrDataSize = ( readSize == 0xFF ) ? SDR_MAX_LENGTH : readSize; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_SDR_LENGTH_HDR + sdrDataSize; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgGetSdr( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, id, res, offset, readSize, parm, recordSize, &responseSize, offs )) ) goto bail; /* printf("\nmchmsggetsdr\n"); int z; for ( z = 0; z < MSG_MAX_LENGTH; z++ ) printf("0x%02x ", response[z]); printf("\n\n"); */ if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetSdr size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get Device Sensor Data Record (SDR) Info * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetDevSdrInfo(MchData mchData, uint8_t *data, uint8_t parm) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_DEV_SDR_INFO_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgGetDevSdrInfo( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, parm, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetDevSdrInfo size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get Sensor Reading. Caller specifies expected message response length. * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgReadSensor(MchData mchData, uint8_t *data, uint8_t sens, uint8_t lun, size_t *sensReadMsgSize) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr ); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += *sensReadMsgSize + FOOTER_LENGTH; if ( (rval = ipmiMsgReadSensor( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, sens, lun, &responseSize, offs )) ) goto bail; payloadSize = *sensReadMsgSize = responseSize - roffs - FOOTER_LENGTH; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgReadSensor size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } int mchMsgGetSensorThresholds(MchData mchData, uint8_t *data, uint8_t sens, uint8_t lun) { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_SENSOR_THRESH_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; if ( (rval = ipmiMsgGetSensorThresholds( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, sens, lun, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetSensorThresholds size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Set FRU Activation using Vadatech MCH - not used at this time * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFruActVt(MchData mchData, uint8_t *data, uint8_t fru, uint8_t parm) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SET_FRU_ACT_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; size_t messageSize; size_t responseSize = IPMI_RPLY_SET_FRU_POLICY_LENGTH_VT; uint8_t cmd = IPMI_MSG_CMD_SET_FRU_ACT; uint8_t netfn = IPMI_MSG_NETFN_PICMG; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); memcpy( b1msg2, SET_FRU_ACT_MSG, b1msg2Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; b1msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; b1msg2[IPMI_MSG2_SET_FRU_ACT_CMD_OFFSET] = parm; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, 0, 0, 0 ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, 0, 0 ); } /* Set FRU Activation - For NAT MCH, used to deactivate/activate FRU * * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFruActNat(MchData mchData, uint8_t *data, uint8_t fru, uint8_t parm) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SET_FRU_ACT_MSG ); uint8_t imsg2[imsg2Size]; size_t messageSize; size_t responseSize = 0;/*IPMI_RPLY_SET_FRU_ACT_LENGTH_NAT; - determine length */ uint8_t cmd = IPMI_MSG_CMD_SET_FRU_ACT; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int offs = 0; /* determine needed offset */ memcpy( imsg2, SET_FRU_ACT_MSG, imsg2Size ); imsg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_SW; imsg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; imsg2[IPMI_MSG2_SET_FRU_ACT_CMD_OFFSET] = parm; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, netfn, imsg2, imsg2Size, 0, 0, 0, 0, 0, 0 ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, offs, 0 ); } /* Set FRU Activation Policy - For Vadatech MCH, used to deactivate/activate FRU * * (See ATCA spec 3.2.4.2.2) * * Activate version causes FRU to transition from "Inactive" to "Activation Request" * Deactivate version causes FRU to transition from "Active" to "Deactivation Request" * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFruActPolicyVt(MchData mchData, uint8_t *data, uint8_t fru, uint8_t mask, uint8_t bits) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SET_FRU_POLICY_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; size_t messageSize; size_t responseSize = IPMI_RPLY_SET_FRU_POLICY_LENGTH_VT; uint8_t cmd = IPMI_MSG_CMD_SET_FRU_POLICY; uint8_t netfn = IPMI_MSG_NETFN_PICMG; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); memcpy( b1msg2, SET_FRU_POLICY_MSG, b1msg2Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; b1msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; b1msg2[IPMI_MSG2_SET_FRU_POLICY_MASK_OFFSET] = mask; b1msg2[IPMI_MSG2_SET_FRU_POLICY_BITS_OFFSET] = bits; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, 0, 0, 0 ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, 0, 0 ); } /* Set FRU Activation Policy using NAT MCH - not yet tested; may be single message like SetFruActNat * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFruActPolicyNat(MchData mchData, uint8_t *data, uint8_t fru, uint8_t mask, uint8_t bits) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SEND_MSG_MSG ); size_t b2msg1Size = sizeof( IPMI_MSG1 ); size_t b2msg2Size = sizeof( SET_FRU_POLICY_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; uint8_t b2msg1[b2msg1Size]; uint8_t b2msg2[b2msg2Size]; size_t messageSize; size_t responseSize = IPMI_RPLY_SET_FRU_POLICY_LENGTH_NAT; uint8_t cmd = IPMI_MSG_CMD_SET_FRU_POLICY; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int offs = IPMI_RPLY_2ND_BRIDGED_OFFSET_NAT; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; memcpy( b1msg2, SEND_MSG_MSG , b1msg2Size ); memcpy( b2msg1, IPMI_MSG1 , b2msg1Size ); memcpy( b2msg2, SET_FRU_POLICY_MSG, b2msg2Size ); b1msg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_BMC; b2msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMBL + IPMI_MSG_TRACKING; b2msg1[IPMI_MSG1_RSADDR_OFFSET] = FRU_I2C_ADDR[fru]; b2msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = 0; /* 0 for front; 0x80 for rear */ b2msg2[IPMI_MSG2_SET_FRU_POLICY_MASK_OFFSET] = mask; b2msg2[IPMI_MSG2_SET_FRU_POLICY_BITS_OFFSET] = bits; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, b2msg1, b2msg2, b2msg2Size ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, offs, 0 ); } /* * Based on parm (0 for Deactivate, 1 for Activate), * set appropriate mask and bits and call: * ipmiMsgSetFruActPolicyVt for Vadatech MCH or * ipmiMsgSetFruActNat for NAT MCH * * RETURNS: * -1 if illegal parm value * or retrun value of ipmiMsgSetFruActPolicy (0 on success) */ int mchMsgSetFruActHelper(MchData mchData, uint8_t *data, uint8_t fru, int parm) { uint8_t mask; uint8_t bits; mchMsgGetFruActPolicyHelper( mchData, data, fru ); if ( parm == 0 ) { mask = 1 << 1; /* make this #define */ bits = 0; } else if ( parm == 1 ){ mask = 1; bits = 0; } else return -1; if ( MCH_IS_NAT( mchData->mchSess->type ) ) return mchMsgSetFruActNat( mchData, data, fru, parm ); else return mchMsgSetFruActPolicyVt( mchData, data, fru, mask, bits ); } /* Get FRU Activation Policy using Vadatech MCH; message contains 1 bridged message * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetFruActPolicyVt(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( GET_FAN_PROP_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; size_t messageSize; size_t responseSize = IPMI_RPLY_GET_FRU_POLICY_LENGTH_VT; uint8_t cmd = IPMI_MSG_CMD_GET_FRU_POLICY; uint8_t netfn = IPMI_MSG_NETFN_PICMG; memcpy( imsg2, SEND_MSG_MSG, imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); memcpy( b1msg2, GET_FRU_POLICY_MSG, b1msg2Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; b1msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, 0, 0, 0 ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, 0, 0 ); } /* Get FRU Activation Policy using NAT MCH - not yet tested; may be single message like SetFruActNat * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetFruActPolicyNat(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SEND_MSG_MSG ); size_t b2msg1Size = sizeof( IPMI_MSG1 ); size_t b2msg2Size = sizeof( GET_FRU_POLICY_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; uint8_t b2msg1[b2msg1Size]; uint8_t b2msg2[b2msg2Size]; size_t messageSize; size_t responseSize = IPMI_RPLY_GET_FRU_POLICY_LENGTH_NAT; uint8_t cmd = IPMI_MSG_CMD_GET_FRU_POLICY; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int offs = IPMI_RPLY_2ND_BRIDGED_OFFSET_NAT; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; memcpy( b1msg2, SEND_MSG_MSG , b1msg2Size ); memcpy( b2msg1, IPMI_MSG1 , b2msg1Size ); memcpy( b2msg2, GET_FRU_POLICY_MSG , b2msg2Size ); b1msg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_BMC; b2msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMBL + IPMI_MSG_TRACKING; b2msg1[IPMI_MSG1_RSADDR_OFFSET] = FRU_I2C_ADDR[fru]; b2msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = 0; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, b2msg1, b2msg2, b2msg2Size ); return mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, data, &responseSize, cmd, netfn, offs, 0); } int mchMsgGetFruActPolicyHelper(MchData mchData, uint8_t *data, uint8_t fru) { if ( !( MCH_IS_NAT( mchData->mchSess->type )) ) return mchMsgGetFruActPolicyVt( mchData, data, fru ); else return mchMsgGetFruActPolicyNat( mchData, data, fru ); } /* Get Device ID -- this is called before we know device type -- need to update this * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetDeviceId(MchData mchData, uint8_t *data, int bridged, uint8_t rsAddr) // change this to either never be bridged or to implement device checking and offsets; handle rqAddr too { uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t responseSize = IPMI_RPLY_GET_DEVICE_ID_LENGTH + HEADER_LENGTH; int rval, offs = 0, rqAddr = 0; if ( (rval = ipmiMsgGetDeviceId( mchData->mchSess, mchData->ipmiSess, response, bridged, rsAddr, rqAddr, &responseSize, offs )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), HEADER_LENGTH, IPMI_RPLY_GET_DEVICE_ID_LENGTH )) ) { printf("mchMsgGetDeviceId size error\n"); goto bail; } memcpy( data, response + HEADER_LENGTH, IPMI_RPLY_GET_DEVICE_ID_LENGTH ); bail: return rval; } /* Get Fan Speed Properties using Vadatech MCH; message contains 1 bridged message * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetFanPropVt(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t imsg2Size = sizeof( GET_FAN_PROP_MSG ); uint8_t imsg2[imsg2Size]; size_t messageSize; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_FAN_PROP_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; uint8_t cmd = IPMI_MSG_CMD_GET_FAN_PROP; uint8_t netfn = IPMI_MSG_NETFN_PICMG; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; memcpy( imsg2, GET_FAN_PROP_MSG, imsg2Size ); imsg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; if ( bridged ) // may need to distinguish between once and twice-bridged messages ipmiBuildSendMsg( mchData->ipmiSess, message, &messageSize, cmd, netfn, rsAddr, rqAddr, imsg2, imsg2Size, 0 ); else messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, netfn, imsg2, imsg2Size, 0, 0, 0, 0, 0, 0 ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) { printf("mchmsggetfanpropvt rval %i\n", rval); goto bail; } if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetFanPropVt size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get Fan Speed Properties using NAT MCH; message contains 2 bridged messages * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetFanPropNat(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SEND_MSG_MSG ); size_t b2msg1Size = sizeof( IPMI_MSG1 ); size_t b2msg2Size = sizeof( GET_FAN_PROP_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; uint8_t b2msg1[b2msg1Size]; uint8_t b2msg2[b2msg2Size]; size_t messageSize; size_t offs = IPMI_RPLY_2ND_BRIDGED_OFFSET_NAT; size_t roffs = HEADER_LENGTH + 3 + offs; size_t payloadSize = IPMI_RPLY_GET_FAN_PROP_LENGTH; size_t responseSize = roffs + payloadSize + FOOTER_LENGTH; uint8_t cmd = IPMI_MSG_CMD_GET_FAN_PROP; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int rval; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; memcpy( b1msg2, SEND_MSG_MSG , b1msg2Size ); memcpy( b2msg1, IPMI_MSG1 , b2msg1Size ); memcpy( b2msg2, GET_FAN_PROP_MSG , b2msg2Size ); b1msg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_BMC; b2msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMBL + IPMI_MSG_TRACKING; b2msg1[IPMI_MSG1_RSADDR_OFFSET] = FRU_I2C_ADDR[fru]; b2msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = 0; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, b2msg1, b2msg2, b2msg2Size ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetFanPropNat size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } int mchMsgGetFanPropHelper(MchData mchData, uint8_t *data, uint8_t fru) { if ( MCH_IS_NAT( mchData->mchSess->type ) ) return mchMsgGetFanPropNat( mchData, data, fru ); else return mchMsgGetFanPropVt( mchData, data, fru ); } int mchMsgGetFanLevelVt(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t imsg2Size = sizeof( GET_FAN_LEVEL_MSG ); uint8_t imsg2[imsg2Size]; size_t messageSize; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_FAN_LEVEL_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; uint8_t cmd = IPMI_MSG_CMD_GET_FAN_LEVEL; uint8_t netfn = IPMI_MSG_NETFN_PICMG; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; memcpy( imsg2, GET_FAN_LEVEL_MSG, imsg2Size ); imsg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; if ( bridged ) // may need to distinguish between once and twice-bridged messages ipmiBuildSendMsg( mchData->ipmiSess, message, &messageSize, cmd, netfn, rsAddr, rqAddr, imsg2, imsg2Size, 0 ); else messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, netfn, imsg2, imsg2Size, 0, 0, 0, 0, 0, 0 ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetFanLevelVt size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Get Fan Level using NAT MCH; message contains 2 bridged messages * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgGetFanLevelNat(MchData mchData, uint8_t *data, uint8_t fru) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SEND_MSG_MSG ); size_t b2msg1Size = sizeof( IPMI_MSG1 ); size_t b2msg2Size = sizeof( GET_FAN_LEVEL_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; uint8_t b2msg1[b2msg1Size]; uint8_t b2msg2[b2msg2Size]; size_t messageSize; size_t offs = IPMI_RPLY_2ND_BRIDGED_OFFSET_NAT; size_t roffs = HEADER_LENGTH + 3 + offs; size_t payloadSize = IPMI_RPLY_GET_FAN_LEVEL_LENGTH; size_t responseSize = roffs + payloadSize + FOOTER_LENGTH; uint8_t cmd = IPMI_MSG_CMD_GET_FAN_LEVEL; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int rval; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; memcpy( b1msg2, SEND_MSG_MSG , b1msg2Size ); memcpy( b2msg1, IPMI_MSG1 , b2msg1Size ); memcpy( b2msg2, GET_FAN_LEVEL_MSG , b2msg2Size ); b1msg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_BMC; b2msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMBL + IPMI_MSG_TRACKING; b2msg1[IPMI_MSG1_RSADDR_OFFSET] = FRU_I2C_ADDR[fru]; b2msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = 0; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, b2msg1, b2msg2, b2msg2Size ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetFanLevelNat size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } int mchMsgGetFanLevelHelper(MchData mchData, uint8_t *data, uint8_t fru) { if ( MCH_IS_NAT( mchData->mchSess->type ) ) return mchMsgGetFanLevelNat( mchData, data, fru ); else return mchMsgGetFanLevelVt( mchData, data, fru ); } /* Set Fan Level using Vadatech MCH; message contains 1 bridged message * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFanLevelVt(MchData mchData, uint8_t *data, uint8_t fru, uint8_t level) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t imsg2Size = sizeof( SET_FAN_LEVEL_MSG ); uint8_t imsg2[imsg2Size]; size_t messageSize; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_SET_FAN_LEVEL_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; uint8_t cmd = IPMI_MSG_CMD_SET_FAN_LEVEL; uint8_t netfn = IPMI_MSG_NETFN_PICMG; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; memcpy( imsg2, SET_FAN_LEVEL_MSG, imsg2Size ); imsg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; imsg2[IPMI_MSG2_SET_FAN_LEVEL_OFFSET] = level; if ( bridged ) // may need to distinguish between once and twice-bridged messages ipmiBuildSendMsg( mchData->ipmiSess, message, &messageSize, cmd, netfn, rsAddr, rqAddr, imsg2, imsg2Size, 0 ); else messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, netfn, imsg2, imsg2Size, 0, 0, 0, 0, 0, 0 ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgSetFanLevelVt size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } /* Set Fan Level using NAT MCH; message contains 2 bridged messages * * RETURNS: status from mchMsgWriteReadHelper * 0 on success * non-zero for error */ int mchMsgSetFanLevelNat(MchData mchData, uint8_t *data, uint8_t fru, uint8_t level) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t imsg2Size = sizeof( SEND_MSG_MSG ); size_t b1msg1Size = sizeof( IPMI_MSG1 ); size_t b1msg2Size = sizeof( SEND_MSG_MSG ); size_t b2msg1Size = sizeof( IPMI_MSG1 ); size_t b2msg2Size = sizeof( GET_FAN_LEVEL_MSG ); uint8_t imsg2[imsg2Size]; uint8_t b1msg1[b1msg1Size]; uint8_t b1msg2[b1msg2Size]; uint8_t b2msg1[b2msg1Size]; uint8_t b2msg2[b2msg2Size]; size_t messageSize; size_t offs = IPMI_RPLY_2ND_BRIDGED_OFFSET_NAT; size_t roffs = HEADER_LENGTH + 3 + offs; size_t payloadSize = IPMI_RPLY_SET_FAN_LEVEL_LENGTH; size_t responseSize = roffs + payloadSize + FOOTER_LENGTH; uint8_t cmd = IPMI_MSG_CMD_SET_FAN_LEVEL; uint8_t netfn = IPMI_MSG_NETFN_PICMG; int rval; memcpy( imsg2, SEND_MSG_MSG , imsg2Size ); memcpy( b1msg1, IPMI_MSG1 , b1msg1Size ); imsg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMB0 + IPMI_MSG_TRACKING; b1msg1[IPMI_MSG1_RSADDR_OFFSET] = IPMI_MSG_ADDR_CM; memcpy( b1msg2, SEND_MSG_MSG , b1msg2Size ); memcpy( b2msg1, IPMI_MSG1 , b2msg1Size ); memcpy( b2msg2, SET_FAN_LEVEL_MSG , b2msg2Size ); b1msg2[IPMI_MSG2_RQADDR_OFFSET] = IPMI_MSG_ADDR_BMC; b2msg1[IPMI_MSG1_NETFNLUN_OFFSET] = netfn << 2; b1msg2[IPMI_MSG2_CHAN_OFFSET] = IPMI_MSG_CHAN_IPMBL + IPMI_MSG_TRACKING; b2msg1[IPMI_MSG1_RSADDR_OFFSET] = FRU_I2C_ADDR[fru]; b2msg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = 0; b2msg2[IPMI_MSG2_SET_FAN_LEVEL_OFFSET] = level; messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, IPMI_MSG_NETFN_APP_REQUEST, imsg2, imsg2Size, b1msg1, b1msg2, b1msg2Size, b2msg1, b2msg2, b2msg2Size ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgSetFanLevelNat size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; } int mchMsgSetFanLevelHelper(MchData mchData, uint8_t *data, uint8_t fru, uint8_t level) { if ( MCH_IS_NAT( mchData->mchSess->type ) ) return mchMsgSetFanLevelNat( mchData, data, fru, level ); else return mchMsgSetFanLevelVt( mchData, data, fru, level ); } int mchMsgGetPowerLevelVt(MchData mchData, uint8_t *data, uint8_t fru, uint8_t parm) { uint8_t message[MSG_MAX_LENGTH] = { 0 }; uint8_t imsg2Size = sizeof( GET_POWER_LEVEL_MSG ); uint8_t imsg2[imsg2Size]; size_t messageSize; uint8_t response[MSG_MAX_LENGTH] = { 0 }; size_t roffs, responseSize, payloadSize = IPMI_RPLY_GET_POWER_LEVEL_LENGTH; int rval, offs, bridged; uint8_t rsAddr, rqAddr; uint8_t cmd = IPMI_MSG_CMD_GET_POWER_LEVEL; uint8_t netfn = IPMI_MSG_NETFN_PICMG; mchSetSizeOffs( mchData->mchSess->type, &offs, &responseSize, &bridged, &rsAddr, &rqAddr); roffs = responseSize; /* Offset into packet our section of interest */ responseSize += payloadSize + FOOTER_LENGTH; memcpy( imsg2, GET_POWER_LEVEL_MSG, imsg2Size ); imsg2[IPMI_MSG2_SET_FRU_ACT_FRU_OFFSET] = fru; imsg2[IPMI_MSG2_GET_POWER_LEVEL_TYPE_OFFSET] = parm; if ( bridged ) // may need to distinguish between once and twice-bridged messages ipmiBuildSendMsg( mchData->ipmiSess, message, &messageSize, cmd, netfn, rsAddr, rqAddr, imsg2, imsg2Size, 0 ); else messageSize = ipmiMsgBuild( mchData->ipmiSess, message, cmd, netfn, imsg2, imsg2Size, 0, 0, 0, 0, 0, 0 ); if ( (rval = mchMsgWriteReadHelper( mchData->mchSess, mchData->ipmiSess, message, messageSize, response, &responseSize, cmd, netfn, offs, 0 )) ) goto bail; if ( (rval = mchMsgCheckSizes( sizeof( response ), roffs, payloadSize )) ) { printf("mchMsgGetPowerLevelVt size error\n"); goto bail; } memcpy( data, response + roffs, payloadSize ); bail: return rval; }