diff options
author | Brian Horton <brianh@linux.ibm.com> | 2014-10-31 16:18:55 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2014-12-13 10:28:12 -0600 |
commit | bdf9a8c834ee8c608f4462e146a2f957c08919c2 (patch) | |
tree | 687845f32fe66fd288905649424dfe0f47b24275 /src/usr/ipmi | |
parent | 6442105c625774bfac33a57fe6b76c18bcb5665b (diff) | |
download | talos-hostboot-bdf9a8c834ee8c608f4462e146a2f957c08919c2.tar.gz talos-hostboot-bdf9a8c834ee8c608f4462e146a2f957c08919c2.zip |
IPMI interface for fru write data command
Change-Id: I3c0c4c7c14521f1b64af37d62e57a5947602ed11
RTC: 116453
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14393
Reviewed-by: Brian Silver <bsilver@us.ibm.com>
Tested-by: Jenkins Server
Reviewed-by: WILLIAM G. HOFFA <wghoffa@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/ipmi')
-rw-r--r-- | src/usr/ipmi/ipmifru.C | 236 | ||||
-rw-r--r-- | src/usr/ipmi/ipmifru.H | 108 | ||||
-rw-r--r-- | src/usr/ipmi/ipmirp.C | 5 | ||||
-rw-r--r-- | src/usr/ipmi/makefile | 1 |
4 files changed, 348 insertions, 2 deletions
diff --git a/src/usr/ipmi/ipmifru.C b/src/usr/ipmi/ipmifru.C new file mode 100644 index 000000000..e365684f3 --- /dev/null +++ b/src/usr/ipmi/ipmifru.C @@ -0,0 +1,236 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/ipmifru.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file ipmifru.C + * @brief IPMI fru inventory definition + */ + +#include "ipmifru.H" +#include "ipmiconfig.H" +#include <devicefw/driverif.H> +#include <devicefw/userif.H> + +#include <sys/task.h> +#include <builtins.h> +#include <initservice/taskargs.H> +#include <initservice/initserviceif.H> + +#include <errl/errlmanager.H> +#include <errl/errlentry.H> + +// Defined in ipmidd.C +extern trace_desc_t * g_trac_ipmi; +#define IPMI_TRAC(printf_string,args...) \ + TRACFCOMP(g_trac_ipmi,"fru: "printf_string,##args) + +#ifdef CONFIG_BMC_IPMI + +const uint8_t writeDataHeader = 3; + +/** + * setup _start and handle barrier + */ + +/** + * @brief Constructor + */ +IpmiFRU::IpmiFRU(void): + iv_msgQ(msg_q_create()) +{ + task_create(&IpmiFRU::start, NULL); +} + +/** + * @brief Destructor + */ +IpmiFRU::~IpmiFRU(void) +{ + msg_q_destroy(iv_msgQ); +} + +void* IpmiFRU::start(void* unused) +{ + Singleton<IpmiFRU>::instance().execute(); + return NULL; +} + +/** + * @brief Entry point of the fru ipmi thread + */ +void IpmiFRU::execute(void) +{ + // Mark as an independent daemon so if it crashes we terminate. + task_detach(); + + IPMI_TRAC(ENTER_MRK "execute: fru message loop"); + do { + while (true) + { + msg_t* msg = msg_wait(iv_msgQ); + + const IPMIFRU::msg_type msg_type = + static_cast<IPMIFRU::msg_type>(msg->type); + + // Invert the "default" by checking here. This allows the compiler + // to warn us if the enum has an unhandled case but still catch + // runtime errors where msg_type is set out of bounds. + assert(msg_type <= IPMIFRU::MSG_LAST_TYPE, + "msg_type %d not handled", msg_type); + + switch(msg_type) + { + case IPMIFRU::MSG_WRITE_FRU_DATA: + sendWriteFruData(msg); + + // done with the msg + msg_free(msg); + break; + }; + } // while + } while (false); + + return; +} // execute + +/// +/// @brief Send write_fru_data msg to IpmiRP +/// called for msg->type MSG_WRITE_FRU_DATA +/// +void IpmiFRU::sendWriteFruData(msg_t *i_msg) +{ + errlHndl_t err = NULL; + const size_t l_maxBuffer = IPMI::max_buffer(); + + // pull out the data - deviceId and offset are in data[0] + const uint8_t &l_deviceId = (i_msg->data[0] >> 32); + uint16_t l_offset = (i_msg->data[0] & 0xFFFFFFFF); + uint16_t l_dataOffset = 0; // start at the l_data[0] + + size_t l_dataSize = i_msg->data[1]; // FRU data size + uint8_t *l_data = static_cast<uint8_t*>(i_msg->extra_data); + + IPMI_TRAC(ENTER_MRK "sendWriteFruData for dev 0x%x, size %d", + l_deviceId, l_dataSize); + + while ((l_dataSize > 0) && (err == NULL)) + { + size_t this_size = std::min(l_maxBuffer, l_dataSize + writeDataHeader); + uint8_t *this_data = new uint8_t[this_size]; + const uint16_t l_fruSize = this_size - writeDataHeader; + + // copy device ID, offset, fru data to new buffer + this_data[0] = l_deviceId; + this_data[1] = l_offset & 0xFF; + this_data[2] = l_offset >> 8; + memcpy(&this_data[writeDataHeader], l_data + l_dataOffset, l_fruSize); + + IPMI_TRAC(INFO_MRK "sending write_fru_data fru size %d offset %d", + l_fruSize, l_offset); + + // update the offsets for the next time around + l_offset += l_fruSize; + l_dataOffset += l_fruSize; + + IPMI::completion_code cc = IPMI::CC_UNKBAD; + err = IPMI::sendrecv(IPMI::write_fru_data(), cc, this_size, this_data); + if (err) + { + IPMI_TRAC(ERR_MRK "Failed to send write_fru_data dev 0x%x", + l_deviceId); + // err is set, so we'll break out of the while loop + } + else if (cc != IPMI::CC_OK) + { + IPMI_TRAC(ERR_MRK "Failed to send write_fru_data dev 0x%x CC 0x%x", + l_deviceId, cc); + // stop sending; breaks out of the while loop + l_dataSize = 0; + } + else + { + l_dataSize -= l_fruSize; + } + + // delete the buffer returned from sendrecv + delete [] this_data; + + } // while there is data to send and no error + + if (err) + { + err->collectTrace(IPMI_COMP_NAME); + errlCommit(err, IPMI_COMP_ID); + } + + // delete the space the caller allocated; we need to do this because + // we're async relative to the caller + delete [] l_data; + + return; +} // sendWriteFruData + +namespace IPMIFRU +{ + /// + /// @brief Function to send fru data to the IpmiFRU msg queue + /// + void writeData(uint8_t i_deviceId, uint8_t *i_data, + uint32_t i_dataSize, uint32_t i_offset) + { + IPMI_TRAC(ENTER_MRK "writeData(deviceId 0x%x size %d offset %d)", + i_deviceId, i_dataSize, i_offset); + + // one message queue to the FRU thread + static msg_q_t mq = Singleton<IpmiFRU>::instance().msgQueue(); + + // send data in msg to fru thread + msg_t *msg = msg_allocate(); + + msg->type = MSG_WRITE_FRU_DATA; + msg->data[0] = (static_cast<uint64_t>(i_deviceId) << 32) | i_offset; + msg->data[1] = i_dataSize; + + uint8_t* l_data = new uint8_t[i_dataSize]; + memcpy(l_data, i_data, i_dataSize); + msg->extra_data = l_data; + + //Send the msg (async) to the fru thread + int rc = msg_send(mq, msg); + + //Return code is non-zero when the message queue is invalid + //or the message type is invalid. + if ( rc ) + { + IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message for dev 0x%x.", + rc, i_deviceId); + delete [] l_data; // delete, since msg wasn't sent + } + + IPMI_TRAC(EXIT_MRK "writeData"); + return; + } // writeData + +}; // IPMIFRU namespace +#endif // CONFIG_BMC_IPMI diff --git a/src/usr/ipmi/ipmifru.H b/src/usr/ipmi/ipmifru.H new file mode 100644 index 000000000..47e0459da --- /dev/null +++ b/src/usr/ipmi/ipmifru.H @@ -0,0 +1,108 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/ipmifru.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __IPMI_IPMIFRU_H +#define __IPMI_IMPIFRU_H + +/** + * @file ipmifru.H + * @brief IPMI FRU inventory declariation + */ + +#include <stdint.h> +#include <ipmi/ipmiif.H> +#include "ipmibt.H" + +/** + * + * + */ +namespace IPMIFRU +{ + void writeData(uint8_t i_deviceId, uint8_t *i_data, + uint32_t i_dataSize, uint32_t i_offset = 0); + + enum msg_type + { + MSG_WRITE_FRU_DATA, // async message - no reply + + // Used to check range. Leave as last. + MSG_LAST_TYPE = MSG_WRITE_FRU_DATA, + }; +} + + +class IpmiFRU +{ + public: + + /** + * Thread start routine for the resource provider + * @param[in] void*, unused + */ + static void* start(void* unused); + + /** + * Default constructor + */ + IpmiFRU(void); + + /** + * Destructor + */ + ~IpmiFRU(void); + + /** + * @brief Get the message queue associated with this FRU + * @param[in] void + * @return, a msg_q_t which is the message queue + */ + inline msg_q_t msgQueue(void) const + { return iv_msgQ; } + + private: + + /** + * Entry point for the fru ipmi thread + */ + void execute(void); + + /** + * @brief Handle a message with fru inventory data; msg is async + * @param[in] i_msg + */ + void sendWriteFruData(msg_t *i_msg); + + /** + * ipmi fru msg queue + */ + msg_q_t iv_msgQ; + + // Disallow copying this class. + IpmiFRU& operator=(const IpmiFRU&); + IpmiFRU(const IpmiFRU&); +}; + +#endif diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C index 9265e06b7..747e552ec 100644 --- a/src/usr/ipmi/ipmirp.C +++ b/src/usr/ipmi/ipmirp.C @@ -140,7 +140,8 @@ inline size_t IpmiRP::maxBuffer(void) // iv_xmit_buffer_size can change - it'll be one thing for // the default when the RP is created, and possibly another // when the get-capabilities command returns. - size_t mbs = iv_xmit_buffer_size - xport_header_size; + // an additional 1 is subtracted based on issues seen with AMI + size_t mbs = iv_xmit_buffer_size - xport_header_size - 1; mutex_unlock(&iv_mutex); @@ -727,7 +728,7 @@ namespace IPMI /// /// @brief Maximum buffer for data (max xport - header) /// - inline size_t max_buffer(void) + size_t max_buffer(void) { return Singleton<IpmiRP>::instance().maxBuffer(); } diff --git a/src/usr/ipmi/makefile b/src/usr/ipmi/makefile index 730a340d5..52f3dadfd 100644 --- a/src/usr/ipmi/makefile +++ b/src/usr/ipmi/makefile @@ -29,6 +29,7 @@ OBJS += ipmimsg.o OBJS += $(if $(CONFIG_BMC_BT_LPC_IPMI),ipmibt.o) OBJS += ipmirp.o OBJS += $(if $(CONFIG_BMC_BT_LPC_IPMI),ipmidd.o) +OBJS += ipmifru.o OBJS += ipmiconfig.o OBJS += ipmisensor.o OBJS += ipmiwatchdog.o |