summaryrefslogtreecommitdiffstats
path: root/src/usr/ipmi
diff options
context:
space:
mode:
authorBrian Horton <brianh@linux.ibm.com>2014-10-31 16:18:55 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2014-12-13 10:28:12 -0600
commitbdf9a8c834ee8c608f4462e146a2f957c08919c2 (patch)
tree687845f32fe66fd288905649424dfe0f47b24275 /src/usr/ipmi
parent6442105c625774bfac33a57fe6b76c18bcb5665b (diff)
downloadtalos-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.C236
-rw-r--r--src/usr/ipmi/ipmifru.H108
-rw-r--r--src/usr/ipmi/ipmirp.C5
-rw-r--r--src/usr/ipmi/makefile1
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
OpenPOWER on IntegriCloud