summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Silver <bsilver@us.ibm.com>2014-09-30 08:22:11 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2014-10-23 04:51:02 -0500
commita9010ccc1130b81e45d1151bb5de9453d31c08a5 (patch)
treeecc60da4bd3623cc97851dfa75e98293f9c77bdd /src
parenta6b67089037c83373f548749a463dfd769938b77 (diff)
downloadtalos-hostboot-a9010ccc1130b81e45d1151bb5de9453d31c08a5.tar.gz
talos-hostboot-a9010ccc1130b81e45d1151bb5de9453d31c08a5.zip
IPMI Block Transfer implementation
Change-Id: I8f6a590b29d9171389d10abc5b6e68f91ac94d16 RTC: 114907 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/13721 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/build/tools/listdeps.pl3
-rw-r--r--src/include/usr/devicefw/userif.H5
-rw-r--r--src/include/usr/hbotcompid.H8
-rw-r--r--src/include/usr/ipmi/ipmi_reasoncodes.H46
-rw-r--r--src/include/usr/ipmi/ipmiif.H119
-rw-r--r--src/makefile1
-rw-r--r--src/sys/vfs/vfs_main.C3
-rw-r--r--src/usr/errl/test/errluserdetailtest.H14
-rw-r--r--src/usr/initservice/extinitsvc/extinitsvctasks.H14
-rw-r--r--src/usr/ipmi/HBconfig10
-rw-r--r--src/usr/ipmi/ipmibt.C246
-rw-r--r--src/usr/ipmi/ipmibt.H140
-rw-r--r--src/usr/ipmi/ipmidd.C495
-rw-r--r--src/usr/ipmi/ipmidd.H124
-rw-r--r--src/usr/ipmi/ipmimsg.C104
-rw-r--r--src/usr/ipmi/ipmimsg.H127
-rw-r--r--src/usr/ipmi/ipmirp.C445
-rw-r--r--src/usr/ipmi/ipmirp.H158
-rw-r--r--src/usr/ipmi/makefile35
-rw-r--r--src/usr/makefile1
20 files changed, 2089 insertions, 9 deletions
diff --git a/src/build/tools/listdeps.pl b/src/build/tools/listdeps.pl
index 4c45186ee..2b59a3a29 100755
--- a/src/build/tools/listdeps.pl
+++ b/src/build/tools/listdeps.pl
@@ -212,6 +212,7 @@ my %resident_modules = (
"liblpc.so" => '1',
"libconsole.so" => '1',
"liberrldisplay.so" => '1',
+ "libipmi.so" => '1',
);
# has with library to istep list file were the DepMod array is kept
@@ -406,5 +407,3 @@ sub usage
exit 0;
}
-
-
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H
index 69d334634..05c7cb214 100644
--- a/src/include/usr/devicefw/userif.H
+++ b/src/include/usr/devicefw/userif.H
@@ -60,6 +60,7 @@ namespace DeviceFW
EEPROM,
GPIO,
LPC,
+ IPMIBT, // As opposed to other phy's
LAST_ACCESS_TYPE,
};
@@ -166,10 +167,10 @@ namespace DeviceFW
/**
* Construct the device addressing parameters for the SCAN device ops.
- * @param[in] i_ring - The ring address to scan
+ * @param[in] i_ring - The ring address to scan
* @param[in] i_ringlen - The length of the ring to scan in bits
* NOTE: This value is the scanring length must
- * match the scandef file value.
+ * match the scandef file value.
* @param[in] i_flag - Specific requests on the scan such as
* check the header, or set pulse option.
* Flag options are located in: src/include/usr/scan/scanif.H
diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H
index e3ade8fbb..a96bec9d6 100644
--- a/src/include/usr/hbotcompid.H
+++ b/src/include/usr/hbotcompid.H
@@ -340,6 +340,14 @@ const compId_t LPC_COMP_ID = 0x2400;
const char LPC_COMP_NAME[] = "lpc";
//@}
+/** @name IPMI
+ * IPMI
+ */
+//@{
+const compId_t IPMI_COMP_ID = 0x2500;
+const char IPMI_COMP_NAME[] = "ipmi";
+//@}
+
/** @name RESERVED
* Reserved component ID. x3100 is the component ID
diff --git a/src/include/usr/ipmi/ipmi_reasoncodes.H b/src/include/usr/ipmi/ipmi_reasoncodes.H
new file mode 100644
index 000000000..12a9391bc
--- /dev/null
+++ b/src/include/usr/ipmi/ipmi_reasoncodes.H
@@ -0,0 +1,46 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/usr/ipmi/ipmi_reasoncodes.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_REASONCODES_H
+#define __IPMI_REASONCODES_H
+
+#include <hbotcompid.H>
+
+namespace IPMI
+{
+ enum IPMIModuleId
+ {
+ MOD_IPMISRV_SEND = 0x01, // IPMI::send/IPMI::sendrecv
+ MOD_IPMISRV_REPLY = 0x02, // IPMI::respond
+ };
+
+ enum IPMIReasonCode
+ {
+ RC_INVALID_QRESPONSE = IPMI_COMP_ID | 0x01,
+ RC_INVALID_SENDRECV = IPMI_COMP_ID | 0x02,
+ RC_INVALID_SEND = IPMI_COMP_ID | 0x03,
+ };
+};
+
+#endif
diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H
new file mode 100644
index 000000000..431b006ef
--- /dev/null
+++ b/src/include/usr/ipmi/ipmiif.H
@@ -0,0 +1,119 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/usr/ipmi/ipmiif.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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_IPMIIF_H
+#define __IPMI_IPMIIF_H
+
+#include <sys/msg.h>
+#include <errl/errlentry.H>
+
+namespace IPMI
+{
+ // Message types which travel on the IPMI message queues
+ enum msg_type
+ {
+ // Sent when the interface goes idle *and* we had write which
+ // was told the interface was busy. We won't get notified of
+ // the general idle state.
+ MSG_STATE_IDLE,
+
+ // Ready to read a response
+ MSG_STATE_RESP,
+
+ // Ready to read an event/sms
+ MSG_STATE_EVNT,
+
+ // A message which needs to be sent
+ MSG_STATE_SEND,
+
+ MSG_STATE_SHUTDOWN,
+
+ // Used to check range. Leave as last.
+ MSG_LAST_TYPE = MSG_STATE_SHUTDOWN,
+ };
+
+ // IPMI network functions
+ enum network_function
+ {
+ // These are the command network functions, the response
+ // network functions are the function + 1. So to determine
+ // the proper network function which issued the command
+ // associated with a response, subtract 1.
+ // Note: these are also shifted left to make room for the LUN.
+ NETFUN_CHASSIS = (0x00 << 2),
+ NETFUN_BRIDGE = (0x02 << 2),
+ NETFUN_SENSOR = (0x04 << 2),
+ NETFUN_APP = (0x06 << 2),
+ NETFUN_FIRMWARE = (0x08 << 2),
+ NETFUN_STORAGE = (0x0a << 2),
+ NETFUN_TRANPORT = (0x0c << 2),
+
+ // Overload the OEM netfun for a "none" netfun. We use this as a
+ // default for objects which will have their netfun filled in
+ NETFUN_NONE = (0x30 << 2),
+ };
+
+ /**
+ * Send message asynchronously
+ * @param[in] i_netfun, the network function
+ * @param[in] i_cmd, the command
+ * @param[in] i_len, the length of the buffer
+ * @param[in] i_data, the buffer - must be new'd
+ * @example uint8_t* data = new uint8_t[length];
+ * @warning do *not* delete data, the resource provider will do that.
+ *
+ * @return errlHndl_t, NULL on success
+ */
+ errlHndl_t send(const network_function i_netfun,
+ const uint8_t i_cmd, const size_t i_len,
+ uint8_t* i_data);
+
+ /**
+ * Send message synchronously
+ * @param[in] i_netfun, the network function
+ * @param[in] i_cmd, the command
+ * @param[out] o_completion_code, the completion code
+ * @param[in,out] io_len, the length of the buffer
+ * @param[in] i_data, the buffer - must be new'd
+ * @example uint8_t* data = new uint8_t[length];
+ * @example delete[] data;
+ *
+ * @return errlHndl_t, NULL on success
+ */
+ errlHndl_t sendrecv(const network_function i_netfun,
+ const uint8_t i_cmd, uint8_t& o_completion_code,
+ size_t& io_len, uint8_t*& io_data);
+
+ /**
+ * Get the max buffer size
+ * @param void
+ *
+ * @return the maximum space allowed for data, per message
+ * (max message for the transport - the header size)
+ */
+ inline size_t max_buffer(void);
+
+}; // end namespace IPMI
+
+#endif
diff --git a/src/makefile b/src/makefile
index f33622541..554c24691 100644
--- a/src/makefile
+++ b/src/makefile
@@ -164,6 +164,7 @@ EXTENDED_MODULES += $(if $(CONFIG_GPIODD),gpio,)
EXTENDED_MODULES += $(if $(CONFIG_CONSOLE),console)
EXTENDED_MODULES += $(if $(CONFIG_CONSOLE_OUTPUT_ERRORDISPLAY),errldisplay)
EXTENDED_MODULES += $(if $(CONFIG_SET_NOMINAL_PSTATE),pstates)
+EXTENDED_MODULES += $(if $(CONFIG_BMC_IPMI),ipmi)
TESTCASE_MODULES += cxxtest
TESTCASE_MODULES += testtrace
diff --git a/src/sys/vfs/vfs_main.C b/src/sys/vfs/vfs_main.C
index bf31df680..db6388cb7 100644
--- a/src/sys/vfs/vfs_main.C
+++ b/src/sys/vfs/vfs_main.C
@@ -201,6 +201,3 @@ void* vfs_start_entrypoint(VfsSystemModule * i_module)
}
return ptr;
}
-
-
-
diff --git a/src/usr/errl/test/errluserdetailtest.H b/src/usr/errl/test/errluserdetailtest.H
index 714f7f0d9..17b9e454e 100644
--- a/src/usr/errl/test/errluserdetailtest.H
+++ b/src/usr/errl/test/errluserdetailtest.H
@@ -32,6 +32,7 @@
*
*/
+#include <stdio.h>
#include <cxxtest/TestSuite.H>
#include <errl/errlentry.H>
#include <errl/errluserdetails.H>
@@ -93,6 +94,18 @@ public:
ErrlUserDetailsString stringUD("String test - string 3");
stringUD.addToLog(errl);
+ // Add a little test for making strings on the fly
+ {
+ const int test_data = 0xfeedface;
+ const char* format = "msg_respond() i/o error (transmit) 0x%x";
+ const size_t output_size = strlen(format) + (sizeof(int) * 2) + 1;
+ char output[output_size];
+ snprintf(output, output_size, format, test_data);
+
+ // Add msg_respond rc
+ ERRORLOG::ErrlUserDetailsString(output).addToLog(errl);
+ }
+
// shove a lot of traces here, so that we test the truncate in the
// write to PNOR
errl->collectTrace("TARG", 1024);
@@ -469,4 +482,3 @@ public:
};
#endif
-
diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H
index 9996bc994..47297f0ec 100644
--- a/src/usr/initservice/extinitsvc/extinitsvctasks.H
+++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H
@@ -150,8 +150,20 @@ const TaskInfo g_exttaskinfolist[] = {
}
},
+ /**
+ * @brief IPMI resource provider
+ */
+#ifdef CONFIG_BMC_IPMI
+ {
+ "libipmi.so", // taskname
+ NULL, // no ptr to fnct
+ {
-
+ START_TASK, // task type
+ EXT_IMAGE, // Extended Module
+ }
+ },
+#endif
/**
* @brief FSI SCOM Device Driver
*/
diff --git a/src/usr/ipmi/HBconfig b/src/usr/ipmi/HBconfig
new file mode 100644
index 000000000..0980a3eb2
--- /dev/null
+++ b/src/usr/ipmi/HBconfig
@@ -0,0 +1,10 @@
+config BMC_IPMI
+ default y if BMC_BT_LPC_IPMI
+ help
+ Determines if Hostboot communicates to the BMC using IPMI
+
+config BMC_BT_LPC_IPMI
+ default n
+ depends on BMC_IPMI
+ help
+ Determines if the BMC uses the LPC bus for block-transfer IPMI traffic
diff --git a/src/usr/ipmi/ipmibt.C b/src/usr/ipmi/ipmibt.C
new file mode 100644
index 000000000..d1be32bbe
--- /dev/null
+++ b/src/usr/ipmi/ipmibt.C
@@ -0,0 +1,246 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmibt.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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 ipmibt.C
+ * @brief code for the IPMI BT message class
+ */
+
+#include <devicefw/driverif.H>
+#include <devicefw/userif.H>
+#include <ipmi/ipmi_reasoncodes.H>
+#include <errl/errlmanager.H>
+
+#include <util/lockfree/counter.H>
+
+#include "ipmibt.H"
+#include "ipmirp.H"
+#include <errno.h>
+#include <config.h>
+
+// Defined in ipmidd.C
+extern trace_desc_t * g_trac_ipmi;
+#define IPMI_TRAC(printf_string,args...) \
+ TRACFCOMP(g_trac_ipmi,"bt: "printf_string,##args)
+
+namespace IPMI
+{
+ ///
+ /// @brief msg ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTMessage::BTMessage(const network_function i_netfun,
+ const uint8_t i_cmd, const uint8_t i_len,
+ uint8_t* i_data):
+ Message(i_netfun, i_cmd, i_len, i_data)
+ {
+ // Sometimes we need to get back to this IPMI msg from the msg_t,
+ // and sometimes we need to get the msg_t from the IPMI msg. So they
+ // know about each other.
+ iv_msg->extra_data = static_cast<void*>(this);
+ iv_msg->type = MSG_STATE_SEND;
+ }
+
+ ///
+ /// @brief Transimit - send the data out the device interface
+ ///
+ errlHndl_t BTMessage::xmit(void)
+ {
+ // When a uint8_t is constructed, it's initialied to 0. So,
+ // this initializes the sequence counter to 0.
+ static Util::Lockfree::Counter<uint8_t> seq;
+
+ // Assign a "unique" sequence number. Note that we don't
+ // leverage the network function to create a sequence
+ // number, we just keep an 8 bit counter. This *should*
+ // be ok - it means we will get back the response to any
+ // particular message before we send another 254 messages.
+ // This seems safe.
+ iv_seq = seq.next();
+
+ // Initialize the error state of the message
+ iv_state = 0;
+
+ size_t unused_size;
+ errlHndl_t err = deviceOp(DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ static_cast<void*>(this),
+ unused_size,
+ DeviceFW::IPMIBT);
+
+ // If we're not going to remain on the i_sendq, we need to
+ // delete the data.
+ if ((err) || (iv_state != EAGAIN))
+ {
+ delete[] iv_data;
+ }
+
+ return err;
+ }
+
+ ///
+ /// @brief Receive - get bits off the block-transfer interface
+ ///
+ errlHndl_t BTMessage::recv(void)
+ {
+ // Check to make sure we are in the right state (coding error)
+ assert(iv_data == NULL);
+
+ // Go down to the device and read. Note the driver is BT specific
+ // and we're BT specific so we can send down a BTMessage object.
+ size_t unused_length;
+ errlHndl_t err = deviceOp(DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ static_cast<void*>(this),
+ unused_length,
+ DeviceFW::IPMIBT);
+ if (err)
+ {
+ delete[] iv_data;
+
+ // If the reading the reponse fails, the caller may still call
+ // delete[] on the pointer we return to them. This makes sure that
+ // for this case, they're just deleting NULL.
+ iv_data = NULL;
+ iv_len = 0;
+ }
+
+ // For BT messages, the sequence number is the key - for other xports
+ // it might be different. Note the sequence number is a reference to
+ // our base's iv_key, so we're done.
+ return err;
+ }
+
+ ///
+ /// @brief BTSyncMessage ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTSyncMessage::BTSyncMessage(const network_function i_netfun,
+ const uint8_t i_cmd, const uint8_t i_len,
+ uint8_t* i_data):
+ BTMessage(i_netfun, i_cmd, i_len, i_data)
+ {
+ }
+
+ ///
+ /// @brief BTSyncMessage ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTAsyncMessage::BTAsyncMessage(const network_function i_netfun,
+ const uint8_t i_cmd, const uint8_t i_len,
+ uint8_t* i_data):
+ BTMessage(i_netfun, i_cmd, i_len, i_data)
+ {
+ }
+
+ ///
+ /// @brief sync msg transmit
+ ///
+ bool BTSyncMessage::xmit(respond_q_t& i_respondq)
+ {
+ errlHndl_t err = BTMessage::xmit();
+
+ if (err)
+ {
+ // Something went wrong, so we need to respond back with the error
+ iv_errl = err;
+
+ msg_q_t mq = Singleton<IpmiRP>::instance().msgQueue();
+ int rc = msg_respond(mq, iv_msg);
+ if (rc)
+ {
+ // Yuk. We can't respond back to our caller with that error. So,
+ // we'll commit it. I don't see much sense in creating another
+ // error log, so we'll just trace the msg_respond() failure.
+ IPMI_TRAC(ERR_MRK "msg_respond() i/o error (transmit) %d", rc);
+ err->collectTrace(IPMI_COMP_NAME);
+ errlCommit(err, IPMI_COMP_ID);
+ iv_errl = NULL;
+ }
+ }
+
+ // Otherwise, we either were transmitted ok or we were told EAGAIN.
+ // We can tell this by iv_state - if it's not EAGAIN, we need to go hang
+ // out on the response queue.
+ else if (iv_state != EAGAIN)
+ {
+ i_respondq[iv_seq] = iv_msg;
+ }
+ else {
+ IPMI_TRAC(INFO_MRK "busy, queue head %x:%x", iv_netfun, iv_cmd);
+ }
+
+ // If we had an i/o error we want the idle loop to stop
+ // If we got EAGAIN we want the idle loop to stop as we just
+ // put a message on the queue which couldn't be sent.
+ return (iv_state != 0);
+ }
+
+ ///
+ /// @brief async msg transmit
+ ///
+ bool BTAsyncMessage::xmit(respond_q_t&)
+ {
+ errlHndl_t err = BTMessage::xmit();
+ bool io_error = (iv_state != 0);
+
+ if (err)
+ {
+ // Not much we're going to do here, so just commit the error.
+ err->collectTrace(IPMI_COMP_NAME);
+ errlCommit(err, IPMI_COMP_ID);
+ }
+
+ // If we didn't have an error but we got back an EAGAIN
+ // we've been queued up for a retry. Otherwise, we're free
+ // to commit suicide.
+ else if (iv_state != EAGAIN)
+ {
+ // Yes, this is OK - there is no further reference to this object.
+ delete this;
+ }
+ else {
+ IPMI_TRAC(INFO_MRK "busy, queue head %x:%x", iv_netfun, iv_cmd);
+ }
+
+ // If we had an i/o error we want the idle loop to stop.
+ // If we got EAGAIN we want the idle loop to stop as we just
+ // put a message on the queue which couldn't be sent. Note
+ // we need to use this mechanism rather than letting the caller
+ // check iv_state as we may have just deleted ourselves.
+ return io_error;
+ }
+};
diff --git a/src/usr/ipmi/ipmibt.H b/src/usr/ipmi/ipmibt.H
new file mode 100644
index 000000000..6414e59b8
--- /dev/null
+++ b/src/usr/ipmi/ipmibt.H
@@ -0,0 +1,140 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmibt.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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_IPMIBT_H
+#define __IPMI_IPMIBT_H
+
+#include "ipmimsg.H"
+
+// How many bytes are in the IPMI BT message header
+#define IPMI_BT_HEADER_SIZE 3
+
+// Per BMC Firmware Specification v3.6 James, et al the ASPEED
+// is limited to a 64 byte IPMI message buffer.
+#define IPMI_BT_MAX_MESSAGE_SIZE 64
+
+#define IPMI_BT_MAX_DATA (IPMI_BT_MAX_MESSAGE_SIZE - IPMI_BT_HEADER_SIZE)
+
+namespace IPMI
+{
+ // IPMI block-transfer message base class
+ class BTMessage : public Message
+ {
+ public:
+ ///
+ /// @brief msg ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTMessage(const network_function i_netfun = NETFUN_NONE,
+ const uint8_t i_cmd = 0,
+ const uint8_t i_len = 0,
+ uint8_t* i_data = NULL);
+
+ ///
+ /// @brief transmit a message.
+ /// @return Error from operation
+ ///
+ errlHndl_t xmit(void);
+
+ ///
+ /// @brief transmit a message.
+ /// @param[in] i_respondq, a map sequence->msg_t
+ /// @return true iff there was no transmission error
+ ///
+ /// @note we're not pure abstract as we want to be able to
+ /// instantiate an object of BTMessage for reading.
+ ///
+ virtual bool xmit(respond_q_t& i_respondq)
+ {return true;};
+
+ ///
+ /// @brief receive a message.
+ ///
+ errlHndl_t recv(void);
+
+ ///
+ /// @brief the maximum buffer size of the underlying transport
+ /// @param void
+ /// @return size_t, the max buffer size
+ ///
+ size_t max_buffer(void)
+ { return IPMI_BT_MAX_DATA; }
+
+ };
+
+ // IPMI BT synchronous message
+ class BTSyncMessage : public BTMessage
+ {
+ public:
+ ///
+ /// @brief BTSyncMessage ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTSyncMessage(const network_function i_netfun, const uint8_t i_cmd,
+ const uint8_t i_len, uint8_t* i_data);
+
+ ///
+ /// @brief transmit a message.
+ /// @param[in] i_respondq, a map sequence->msg_t
+ ///
+ /// @return true iff there was no transmission error
+ ///
+ bool xmit(respond_q_t& i_respondq);
+ };
+
+ // IPMI BT asynchronous message
+ class BTAsyncMessage : public BTMessage
+ {
+ public:
+ ///
+ /// @brief BTSyncMessage ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ BTAsyncMessage(const network_function i_netfun, const uint8_t i_cmd,
+ const uint8_t i_len, uint8_t* i_data);
+
+ ///
+ /// @brief transmit a message.
+ /// @param[in] respond_q_t unused
+ ///
+ /// @return true iff there was no transmission error
+ ///
+ bool xmit(respond_q_t&);
+ };
+
+}; // end namespace IPMI
+
+#endif
diff --git a/src/usr/ipmi/ipmidd.C b/src/usr/ipmi/ipmidd.C
new file mode 100644
index 000000000..3456cac19
--- /dev/null
+++ b/src/usr/ipmi/ipmidd.C
@@ -0,0 +1,495 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmidd.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,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 ipmidd.C
+ *
+ * @brief Implementation of the IPMI Device Driver
+ */
+
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludlogregister.H>
+#include <errl/errludstring.H>
+#include "ipmidd.H"
+#include "ipmirp.H"
+#include <ipmi/ipmiif.H>
+#include <initservice/initserviceif.H>
+#include <util/align.H>
+#include <lpc/lpcif.H>
+#include <config.h>
+
+#include <sys/msg.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/task.h>
+
+/*****************************************************************************/
+// D e f i n e s
+/*****************************************************************************/
+
+trace_desc_t* g_trac_ipmi;
+TRAC_INIT(&g_trac_ipmi, IPMI_COMP_NAME, 6*KILOBYTE, TRACE::BUFFER_SLOW);
+
+#define IPMI_TRAC(printf_string,args...) \
+ TRACFCOMP(g_trac_ipmi,"dd: "printf_string,##args)
+
+// Registers. These are fixed for LPC/BT so we can hard-wire them
+#define REG_CONTROL 0xE4
+#define REG_HOSTBMC 0xE5
+#define REG_INTMASK 0xE6
+
+// Control register bits. The control register is interesting in that writing
+// 0's never does anything; all registers are either set to 1 when written
+// with a 1 or toggled (1/0) when written with a one. So, we don't ever need
+// to read-modify-write, we can just write an or'd mask of bits.
+#define CTRL_B_BUSY (1 << 7)
+#define CTRL_H_BUSY (1 << 6)
+#define CTRL_OEM0 (1 << 5)
+#define CTRL_SMS_ATN (1 << 4)
+#define CTRL_B2H_ATN (1 << 3)
+#define CTRL_H2B_ATN (1 << 2)
+#define CTRL_CLR_RD_PTR (1 << 1)
+#define CTRL_CLR_WR_PTR (1 << 0)
+
+#define IDLE_STATE (CTRL_B_BUSY | CTRL_B2H_ATN | CTRL_SMS_ATN | CTRL_H2B_ATN)
+
+// Bit in the INMASK register which signals to the BMC
+// to reset it's end of things.
+#define INT_BMC_HWRST (1 << 7)
+
+// How long to sychronously wait for the device to change state (in ns)
+#define WAIT_TIME 100000000
+
+/**
+ * @brief Performs an IPMI Message Read Operation
+ * This function performs a IPMI Message Read operation. It follows a
+ * pre-defined prototype functions in order to be registered with the
+ * device-driver framework.
+ *
+ * @param[in] i_opType Operation type READ
+ * @param[in] i_target IPMI target, ignored use the master sentinel
+ * @param[out] o_buffer Pointer to a BT message we're going to fill in.
+ * @param[out] o_buflen Always sizeof(uint8_t)
+ * @param[in] i_accessType DeviceFW::IPMIBT
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, it is unused
+ * @return errlHndl_t
+ */
+errlHndl_t ddRead(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* o_buffer,
+ size_t& o_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ // If someone passed in the wrong target, we have a coding error
+ assert(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target,
+ "ipmi read expects master processor target");
+
+ // We are the BT driver, so it's safe to assume they sent us a BTMessage.
+ return Singleton<IpmiDD>::instance().receive(
+ static_cast<IPMI::BTMessage*>(o_buffer));
+}
+
+/**
+ * @brief Performs an IPMI Message Write Operation
+ * This function performs a IPMI Message Write operation. It follows a
+ * pre-defined prototype functions in order to be registered with the
+ * device-driver framework.
+ *
+ * @param[in] i_opType Operation type WRITE
+ * @param[in] i_target IPMI target, ignored use the master sentinel
+ * @param[in] i_buffer Pointer to a BT message we're going to transmit
+ * @param[in] i_buflen Always sizeof(uint8_t)
+ * @param[in] i_accessType DeviceFW::IPMIBT
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, it is unused
+ * @return errlHndl_t
+ */
+errlHndl_t ddWrite(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* i_buffer,
+ size_t& i_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ // If someone passed in the wrong target, we have a coding error
+ assert(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target,
+ "ipmi write expects master processor target");
+
+ // We are the BT driver, so it's safe to assume they sent us a BTMessage
+ return Singleton<IpmiDD>::instance().send(
+ static_cast<IPMI::BTMessage*>(i_buffer));
+}
+
+// Register IPMIDD access functions to DD framework
+DEVICE_REGISTER_ROUTE(DeviceFW::READ,
+ DeviceFW::IPMIBT,
+ TARGETING::TYPE_PROC,
+ ddRead);
+
+DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
+ DeviceFW::IPMIBT,
+ TARGETING::TYPE_PROC,
+ ddWrite);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief Read an address from LPC space
+ */
+errlHndl_t IpmiDD::readLPC(const uint32_t i_addr, uint8_t& o_data)
+{
+ static size_t size = sizeof(uint8_t);
+ errlHndl_t err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ static_cast<void*>(&o_data),
+ size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr) );
+ return err;
+}
+
+/**
+ * @brief Write an address from LPC space
+ */
+errlHndl_t IpmiDD::writeLPC(const uint32_t i_addr,
+ uint8_t i_data)
+{
+ static size_t size = sizeof(uint8_t);
+ errlHndl_t err = deviceOp(DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ static_cast<void*>(&i_data),
+ size,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr) );
+ return err;
+}
+
+/**
+ * @brief Static function wrapper to pass into task_create
+ */
+static void* poll_control_register( void* /* unused */ )
+{
+ IPMI_TRAC(ENTER_MRK "poll_control_register" );
+ Singleton<IpmiDD>::instance().pollCtrl();
+ return NULL;
+}
+
+/**
+ * @brief Poll the control register
+ */
+void IpmiDD::pollCtrl(void)
+{
+ // Mark as an independent daemon so if it crashes we terminate.
+ task_detach();
+
+ // We send a message to this message queue when the ipmi state changes.
+ // Don't free these messages - these messages are sent async so the
+ // consumer will free the message.
+ static msg_q_t mq = Singleton<IpmiRP>::instance().msgQueue();
+ msg_t* msg = NULL;
+
+ uint8_t ctrl = 0;
+
+ while(1)
+ {
+ mutex_lock(&iv_mutex);
+ errlHndl_t err = readLPC(REG_CONTROL, ctrl);
+
+ // Not sure there's much we can do here but commit the log
+ // and let this thread fail.
+ if (err)
+ {
+ IPMI_TRAC(ERR_MRK "polling loop encountered an error, exiting");
+ errlCommit(err, IPMI_COMP_ID);
+ break;
+ }
+
+ else
+ {
+ // If we're idle, tell the resoure provider to check for any
+ // pending messages which were delayed due to contention. But don't
+ // send a message everytime we see idle, only if there we suspect
+ // we sent EAGAINs.
+ if (((ctrl & IDLE_STATE) == 0) && iv_eagains)
+ {
+ msg = msg_allocate();
+ msg->type = IPMI::MSG_STATE_IDLE;
+ msg_send(mq, msg);
+ iv_eagains = false;
+ }
+
+ // If we see the B2H_ATN, there's a response waiting
+ else if (ctrl & CTRL_B2H_ATN)
+ {
+ msg = msg_allocate();
+ msg->type = IPMI::MSG_STATE_RESP;
+ msg_send(mq, msg);
+ }
+
+ // If we see the SMS_ATN, there's an event waiting
+ else if (ctrl & CTRL_SMS_ATN)
+ {
+ IPMI_TRAC(ERR_MRK "sending state sms/event, unexpected");
+ msg = msg_allocate();
+ msg->type = IPMI::MSG_STATE_EVNT;
+ msg_send(mq, msg);
+ }
+ }
+ mutex_unlock(&iv_mutex);
+ nanosleep(0, WAIT_TIME);
+ }
+}
+
+/**
+ * @brief Performs a reset of the BT hardware
+ */
+inline errlHndl_t IpmiDD::reset(void)
+{
+ // Reset the BT interface, and flush messages. We eat messages off of
+ // the interface until it goes idle. We assume, since we're resetting,
+ // that there is nothing on the interface we're interested in.
+ mutex_lock(&iv_mutex);
+ IPMI_TRAC(ENTER_MRK "resetting the IPMI BT interface");
+
+ uint8_t ctrl = 0;
+ IPMI::BTMessage msg;
+
+ errlHndl_t err = readLPC(REG_CONTROL, ctrl);
+ while ((ctrl & (CTRL_B2H_ATN | CTRL_SMS_ATN)) && (err == NULL))
+ {
+ // There should only be one, if any - but we'll log each one we find.
+ IPMI_TRAC(INFO_MRK "found a waiting message during reset");
+ err = receive(&msg);
+ delete[] msg.iv_data;
+
+ if (err) {break;}
+
+ err = readLPC(REG_CONTROL, ctrl);
+ }
+
+ // Commit this log. We're about to reset the PHY anyway, so maybe
+ // that'll clear this error. If not, we'll report that error.
+ if (err)
+ {
+ errlCommit(err, IPMI_COMP_ID);
+ }
+
+ mutex_unlock(&iv_mutex);
+
+ IPMI_TRAC(EXIT_MRK "resetting the IPMI BT interface");
+ return writeLPC(REG_INTMASK, INT_BMC_HWRST);
+}
+
+/**
+ * @brief Performs an IPMI Message Write Operation
+ */
+errlHndl_t IpmiDD::send(IPMI::BTMessage* i_msg)
+{
+ errlHndl_t err = NULL;
+ uint8_t ctrl = 0;
+
+ mutex_lock(&iv_mutex);
+ do
+ {
+ err = readLPC(REG_CONTROL, ctrl);
+ if (err) { break; }
+
+ // If the interface isn't idle, tell the caller to come back
+ if ((ctrl & IDLE_STATE) != 0)
+ {
+ i_msg->iv_state = EAGAIN;
+ iv_eagains = true;
+ continue;
+ }
+
+ // Tell the interface we're writing. Per p. 135 of the
+ // spec we *do not* set H_BUSY.
+ err = writeLPC(REG_CONTROL, CTRL_CLR_WR_PTR);
+ if (err) { break; }
+
+ // Add the header size on as req_len is only the length of the data
+ err = writeLPC(REG_HOSTBMC, i_msg->iv_len + IPMI_BT_HEADER_SIZE);
+ if (err) { break; }
+
+ err = writeLPC(REG_HOSTBMC, i_msg->iv_netfun);
+ if (err) { break; }
+
+ err = writeLPC(REG_HOSTBMC, i_msg->iv_seq);
+ if (err) { break; }
+
+ err = writeLPC(REG_HOSTBMC, i_msg->iv_cmd);
+ if (err) { break; }
+
+ for( size_t i = 0; (i < i_msg->iv_len) && (err == NULL); ++i)
+ {
+ err = writeLPC(REG_HOSTBMC, i_msg->iv_data[i]);
+ }
+ if (err) { break; }
+
+ // If all is well, alert the host we sent bits.
+ err = writeLPC(REG_CONTROL, CTRL_H2B_ATN);
+ if (err) {break;}
+
+ } while(false);
+
+ mutex_unlock(&iv_mutex);
+
+ // If we have an error, try to reset the interface.
+ if (err)
+ {
+ reset();
+ }
+
+ // Don't bother reporting a write if we returned EAGAIN, the
+ // upper layers will report the re-queue or whatever.
+ if (i_msg->iv_state != EAGAIN)
+ {
+ IPMI_TRAC(INFO_MRK "write %s %x:%x seq %x len %x",
+ err ? "err" : "ok",
+ i_msg->iv_netfun, i_msg->iv_cmd, i_msg->iv_seq,
+ i_msg->iv_len);
+ }
+
+ return err;
+}
+
+/**
+ * @brief Read a response to an issued command, or an sms
+ */
+errlHndl_t IpmiDD::receive(IPMI::BTMessage* o_msg)
+{
+ errlHndl_t err = NULL;
+ uint8_t ctrl = 0;
+ bool marked_busy = false;
+
+ mutex_lock(&iv_mutex);
+
+ do
+ {
+ err = readLPC(REG_CONTROL, ctrl);
+ if (err) { break; }
+
+ // Tell the interface we're busy.
+ err = writeLPC(REG_CONTROL, CTRL_H_BUSY);
+ if (err) {break;}
+
+ marked_busy = true;
+
+ // Clear the pending state from the control register.
+ // Note the spec distinctly says "after setting H_BUSY,
+ // the host should clear this bit" - not at the same time.
+ // This is the hand-shake; H_BUSY gates the BMC which allows
+ // us to clear the ATN bits. Don't get fancy.
+ err = writeLPC(REG_CONTROL,
+ (ctrl & CTRL_B2H_ATN) ? CTRL_B2H_ATN : CTRL_SMS_ATN);
+ if (err) {break;}
+
+ // Tell the interface we're reading
+ err = writeLPC(REG_CONTROL, CTRL_CLR_RD_PTR);
+ if (err) {break;}
+
+ // The first byte is the length, grab it so we can allocate a buffer.
+ err = readLPC(REG_HOSTBMC, o_msg->iv_len);
+ if (err) { break; }
+
+ // I don't think SMS messages have a completion code.
+ o_msg->iv_len -= (ctrl & CTRL_B2H_ATN) ?
+ IPMI_BT_HEADER_SIZE + 1 : IPMI_BT_HEADER_SIZE;
+
+ err = readLPC(REG_HOSTBMC, o_msg->iv_netfun);
+ if (err) { break; }
+
+ err = readLPC(REG_HOSTBMC, o_msg->iv_seq);
+ if (err) { break; }
+
+ err = readLPC(REG_HOSTBMC, o_msg->iv_cmd);
+ if (err) { break; }
+
+ // I don't think SMS messages have a completion code.
+ if (CTRL_B2H_ATN)
+ {
+ err = readLPC(REG_HOSTBMC, o_msg->iv_cc);
+ if (err) { continue; }
+ }
+
+ o_msg->iv_data = new uint8_t[o_msg->iv_len];
+
+ for( size_t i = 0; (i < o_msg->iv_len) && (err == NULL); ++i)
+ {
+ err = readLPC(REG_HOSTBMC, o_msg->iv_data[i]);
+ }
+ if (err) { break; }
+
+ } while(0);
+
+ if (marked_busy)
+ {
+ // Clear the busy state (write 1 to toggle). Note if we get
+ // an error from the writeLPC, we toss it and return the first
+ // error as it likely has better information in it.
+ delete writeLPC(REG_CONTROL, CTRL_H_BUSY);
+ }
+
+ mutex_unlock(&iv_mutex);
+
+ IPMI_TRAC(INFO_MRK "read %s %s %x:%x seq %x len %x cc %x",
+ (ctrl & CTRL_B2H_ATN) ? "b2h" : "sms",
+ err ? "err" : "ok",
+ o_msg->iv_netfun, o_msg->iv_cmd, o_msg->iv_seq,
+ o_msg->iv_len, o_msg->iv_cc);
+
+ return err;
+}
+
+/**
+ * @brief Constructor
+ */
+IpmiDD::IpmiDD(void):
+ iv_eagains(false)
+{
+ mutex_init(&iv_mutex);
+
+ // reset the BT interface - no idea what state the BMC thinks things are in
+ errlHndl_t err = reset();
+ if (err)
+ {
+ IPMI_TRAC(ERR_MRK "error resetting the BT interface");
+ err->collectTrace(IPMI_COMP_NAME);
+ errlCommit(err, IPMI_COMP_ID);
+ }
+
+ // Start task to poll the control register
+ // This is a singleton so this will only be called once, right?
+ task_create( poll_control_register, NULL );
+
+ return;
+}
diff --git a/src/usr/ipmi/ipmidd.H b/src/usr/ipmi/ipmidd.H
new file mode 100644
index 000000000..d20dd6132
--- /dev/null
+++ b/src/usr/ipmi/ipmidd.H
@@ -0,0 +1,124 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmidd.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,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_IPMIDD_H
+#define __IPMI_IMPIDD_H
+
+#include <sys/msg.h>
+#include <ipmi/ipmiif.H>
+#include "ipmibt.H"
+
+/** @file ipmidd.H
+ * @brief Provides the interfaces to the IPMI Device Driver
+ */
+
+/**
+ * @brief IPMI Device Driver Class
+ * Provides read/write message capabilities.
+ */
+class IpmiDD
+{
+ public:
+ /**
+ * @brief Poll the control register
+ *
+ * @parm void
+ */
+ void pollCtrl(void);
+
+ /**
+ * @brief Performs an IPMI message read operation
+ *
+ * @param[out] o_msg - Destination buffer for data
+ *
+ * @return errlHndl_t NULL on success
+ */
+
+ errlHndl_t receive(IPMI::BTMessage* o_msg);
+
+ /**
+ * @brief Performs an IPMI message write operation
+ *
+ * @param[in] i_msg - Location of data to be written
+ *
+ * @return errlHndl_t NULL on success
+ */
+ errlHndl_t send(IPMI::BTMessage* i_msg);
+
+ /**
+ * @brief Performs a reset of the BT hardware
+ *
+ * @param void
+ *
+ * @return errlHndl_t NULL on success
+ */
+ errlHndl_t reset(void);
+
+ /**
+ * @brief Constructor
+ *
+ * @parm void
+ */
+ IpmiDD(void);
+
+ private:
+ /**
+ * @brief Read an address from LPC space
+ *
+ * @parm i_addr Absolute LPC Address
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readLPC(const uint32_t i_addr, uint8_t& o_data);
+
+ /**
+ * @brief Write an address from LPC space
+ *
+ * @parm i_addr Absolute LPC Address
+ * @parm i_data Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeLPC(const uint32_t i_addr, uint8_t i_data);
+
+ private: // Variables
+
+ /**
+ * @brief Mutex used to protect internal state
+ */
+ mutex_t iv_mutex;
+
+ /**
+ * @brief True if we told the RP to try a write again
+ */
+ bool iv_eagains;
+
+ // Disallow copying this class.
+ IpmiDD& operator=(const IpmiDD&);
+ IpmiDD(const IpmiDD&);
+};
+
+
+#endif
diff --git a/src/usr/ipmi/ipmimsg.C b/src/usr/ipmi/ipmimsg.C
new file mode 100644
index 000000000..09aa61b77
--- /dev/null
+++ b/src/usr/ipmi/ipmimsg.C
@@ -0,0 +1,104 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmimsg.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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 ipmi.C
+ * @brief code for the IPMI message class
+ */
+
+#include <errl/errlmanager.H>
+
+#include "ipmimsg.H"
+
+// This is because the factory lives in here.
+#include "ipmibt.H"
+
+#include <kernel/console.H>
+#include <config.h>
+
+// Defined in ipmidd.C
+extern trace_desc_t * g_trac_ipmi;
+#define IPMI_TRAC(printf_string,args...) \
+ TRACFCOMP(g_trac_ipmi,"msg: "printf_string,##args)
+
+namespace IPMI
+{
+ ///
+ /// @brief msg ctor
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (new'd space)
+ ///
+ Message::Message(const network_function i_netfun,
+ const uint8_t i_cmd, const uint8_t i_len,
+ uint8_t* i_data):
+ iv_msg(msg_allocate()),
+ iv_key(0),
+ iv_len(i_len),
+ iv_netfun(i_netfun),
+ iv_seq(iv_key),
+ iv_cmd(i_cmd),
+ iv_cc(0),
+ iv_state(0),
+ iv_errl(NULL),
+ iv_data(i_data)
+ {
+ }
+
+ ///
+ /// @brief static factory
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (allocated space)
+ /// @param[in] i_type, synchronous or async
+ ///
+ Message* Message::factory(const network_function i_netfun,
+ const uint8_t i_cmd, const uint8_t i_len,
+ uint8_t* i_data, const message_type i_type)
+ {
+ Message* new_message = NULL;
+
+ // CHECK: Put an ifdef here for the config'd transport type.
+ switch(i_type)
+ {
+ case TYPE_SYNC:
+ new_message = new BTSyncMessage(i_netfun, i_cmd, i_len, i_data);
+ break;
+ case TYPE_ASYNC:
+ new_message = new BTAsyncMessage(i_netfun, i_cmd, i_len, i_data);
+ break;
+ default:
+ // We have ourselves a bug
+ assert(false, "ipmi message factory: unk type %d\n", i_type);
+ break;
+ }
+
+ return new_message;
+ }
+
+};
diff --git a/src/usr/ipmi/ipmimsg.H b/src/usr/ipmi/ipmimsg.H
new file mode 100644
index 000000000..71a504017
--- /dev/null
+++ b/src/usr/ipmi/ipmimsg.H
@@ -0,0 +1,127 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmimsg.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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_IPMIMSG_H
+#define __IPMI_IPMIMSG_H
+
+#include <map>
+#include <list>
+#include <sys/msg.h>
+#include <errl/errlentry.H>
+#include <ipmi/ipmiif.H>
+
+namespace IPMI
+{
+ // Used in the factory for creating the proper subclass.
+ enum message_type
+ {
+ TYPE_SYNC = 0,
+ TYPE_ASYNC = 1,
+ };
+
+ typedef std::list<msg_t*> send_q_t;
+ typedef std::map<uint8_t,msg_t*> respond_q_t;
+
+ // IPMI message base class. A thing which expects to be sent down a
+ // msg_q (so has a msg_t) and defines operations performed by a generic
+ // IPMI resource manager. Details are left to the subclasses.
+ class Message
+ {
+ public:
+ ///
+ /// @brief static factory
+ /// @param[in] i_netfun, the network function
+ /// @param[in] i_cmd, the network command
+ /// @param[in] i_data, the data for the command
+ /// @param[in] i_len, the length of the data
+ /// @param[in] i_data, the data (allocated space)
+ /// @param[in] i_type, synchronous or async
+ ///
+ static Message* factory(const network_function i_netfun = NETFUN_NONE,
+ const uint8_t i_cmd = 0,
+ const uint8_t i_len = 0,
+ uint8_t* i_data = NULL,
+ const message_type i_type = TYPE_SYNC);
+
+ ///
+ /// @brief Message ctor
+ ///
+ Message(const network_function i_netfun = NETFUN_NONE,
+ const uint8_t i_cmd = 0,
+ const uint8_t i_len = 0,
+ uint8_t* i_data = NULL);
+
+ ///
+ /// @brief Message dtor
+ ///
+ virtual ~Message(void)
+ {
+ msg_free(iv_msg);
+ }
+
+ ///
+ /// @brief the maximum buffer size of the underlying transport
+ /// @param void
+ /// @return size_t, the max buffer size
+ ///
+ virtual size_t max_buffer(void) = 0;
+
+ ///
+ /// @brief transmit a message.
+ /// @param[in] i_respondq, a map: iv_key->msg_t
+ /// @return true iff there was no transmission error
+ ///
+ virtual bool xmit(respond_q_t& i_respondq) = 0;
+
+ ///
+ /// @brief receive a message.
+ /// @return Error from operation
+ /// @note fills our iv_key with the proper information
+ ///
+ virtual errlHndl_t recv(void) = 0;
+
+ msg_t* iv_msg; // Pointer back to our msg_q msg_t
+ uint8_t iv_key; // key used by the respond queue
+
+ // Note: Some of these might turn out to be transport specific
+ // if so, we'll just move them down in to the subclasses
+ uint8_t iv_len; // Length
+ uint8_t iv_netfun; // Network Function
+ uint8_t& iv_seq; // Sequence number, reference to iv_key
+ uint8_t iv_cmd; // Command
+ uint8_t iv_cc; // Completion Code
+ uint8_t iv_state; // Driver things, like EAGAIN
+ errlHndl_t iv_errl; // Pointer to the errlHandl_t if needed
+ uint8_t* iv_data; // Pointer to the message data
+
+ private:
+ // Disallow copying this class. Should suffice for disabling copy for
+ // all subclasses too.
+ Message& operator=(const Message&);
+ Message(const Message&);
+ };
+
+}; // end namespace IPMI
+
+#endif
diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C
new file mode 100644
index 000000000..008b66f8c
--- /dev/null
+++ b/src/usr/ipmi/ipmirp.C
@@ -0,0 +1,445 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmirp.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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 ipmirp.C
+ * @brief IPMI resource provider definition
+ */
+
+#include "ipmirp.H"
+#include <ipmi/ipmi_reasoncodes.H>
+#include <devicefw/driverif.H>
+#include <devicefw/userif.H>
+
+#include <config.h>
+#include <sys/task.h>
+#include <initservice/taskargs.H>
+#include <initservice/initserviceif.H>
+#include <sys/vfs.h>
+
+#include <targeting/common/commontargeting.H>
+#include <kernel/ipc.H>
+#include <arch/ppc.H>
+#include <errl/errlmanager.H>
+#include <sys/time.h>
+#include <sys/misc.h>
+#include <errno.h>
+
+// Defined in ipmidd.C
+extern trace_desc_t * g_trac_ipmi;
+#define IPMI_TRAC(printf_string,args...) \
+ TRACFCOMP(g_trac_ipmi,"rp: "printf_string,##args)
+
+/**
+ * setup _start and handle barrier
+ */
+TASK_ENTRY_MACRO( IpmiRP::daemonProcess );
+
+/**
+ * @brief Constructor
+ */
+IpmiRP::IpmiRP(void):
+ iv_msgQ(msg_q_create()),
+ iv_sendq(),
+ iv_respondq()
+{
+}
+
+/**
+ * @brief Destructor
+ */
+IpmiRP::~IpmiRP(void)
+{
+ msg_q_destroy(iv_msgQ);
+}
+
+void* IpmiRP::start(void* unused)
+{
+ Singleton<IpmiRP>::instance().execute();
+ return NULL;
+}
+
+void IpmiRP::daemonProcess(errlHndl_t& o_errl)
+{
+ task_create(&IpmiRP::start, NULL);
+}
+
+/**
+ * @brief Return the maximum data size to allocate
+ */
+inline size_t IpmiRP::maxBuffer(void)
+{
+ // shared_ptrs would be handy here, fwiw.
+ IPMI::Message* msg = IPMI::Message::factory();
+ size_t mbs = msg->max_buffer();
+ delete msg;
+ return mbs;
+}
+
+/**
+ * @brief Entry point of the resource provider
+ */
+void IpmiRP::execute(void)
+{
+ // Mark as an independent daemon so if it crashes we terminate.
+ task_detach();
+
+ IPMI_TRAC(ENTER_MRK "message loop");
+
+ // TODO: RTC 116300 Mark the daemon as started in the interface.
+ // TODO: RTC 116300 Query the BMC for timeouts, other config
+ // TODO: RTC 116300 Hold off transmitters until the BMC is ready?
+
+ // Register shutdown events with init service.
+ // Done at the "end" of shutdown processesing.
+ // This will flush out any IPMI messages which were sent as
+ // part of the shutdown processing. We chose MBOX priority
+ // as we don't want to accidentally get this message after
+ // interrupt processing has stopped in case we need intr to
+ // finish flushing the pipe.
+ INITSERVICE::registerShutdownEvent(iv_msgQ, IPMI::MSG_STATE_SHUTDOWN,
+ INITSERVICE::MBOX_PRIORITY);
+ do {
+
+ while (true)
+ {
+ msg_t* msg = msg_wait(iv_msgQ);
+
+ const IPMI::msg_type msg_type =
+ static_cast<IPMI::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 <= IPMI::MSG_LAST_TYPE,
+ "msg_type %d not handled", msg_type);
+
+ switch(msg_type)
+ {
+ // Messages we're told to send. If we get a transmission
+ // error (EAGAIN counts) then the interface is likely
+ // not idle, and so we don't want to bother with idle below
+ case IPMI::MSG_STATE_SEND:
+ // Push the message on the queue, and the idle() at the
+ // bottom of this loop will start the transmit process.
+ // Be sure to push_back to ensure ordering of transmission.
+ iv_sendq.push_back(msg);
+ break;
+
+ // State changes from the IPMI hardware. These are async
+ // messages so we get rid of them here.
+ case IPMI::MSG_STATE_IDLE:
+ msg_free(msg);
+ // No-op - we do it at the bottom of the loop.
+ break;
+
+ case IPMI::MSG_STATE_RESP:
+ msg_free(msg);
+ response();
+ break;
+ case IPMI::MSG_STATE_EVNT:
+ IPMI_TRAC(ERR_MRK "msg loop: unexpected ipmi sms");
+ msg_free(msg);
+ // TODO: RTC 116300 Handle SMS messages
+ break;
+
+ // Accept no more messages. Anything in the sendq is doomed.
+ // This should be OK - either they were async messages in which
+ // case they'd appear to never have been sent or they're sync
+ // in which case the higher layers should have handled this case
+ // in their shutdown processing.
+ case IPMI::MSG_STATE_SHUTDOWN:
+ IPMI_TRAC(INFO_MRK "ipmi shuting down");
+ // TODO: RTC 116887 Hold off transmitters, drain queues.
+ // Patrick suggests handling this like mailboxes.
+ msg_respond(iv_msgQ, msg);
+ break;
+ };
+
+ // There's a good chance the interface will be idle right after
+ // the operation we just performed. Since we need to poll for the
+ // idle state, calling idle after processing a message may decrease
+ // the latency of waiting for idle. The worst case is that we find
+ // the interface busy and go back to waiting. Note: there's no need
+ // to keep calling idle if there are old elements on the sendq;
+ // we'll need to wait for the interface to indicate we're idle.
+ if ((IPMI::MSG_STATE_SEND != msg_type) || (iv_sendq.size() == 1))
+ {
+ idle();
+ }
+ }
+
+ } while (false);
+
+ return;
+}
+
+///
+/// @brief Go in to the idle state
+///
+void IpmiRP::idle(void)
+{
+ // If the interface is idle, we can write anything we need to write.
+ for (IPMI::send_q_t::iterator i = iv_sendq.begin(); i != iv_sendq.end();)
+ {
+ // If we have a problem transmitting a message, then we just stop
+ // here and wait for the next time the interface transitions to idle.
+ // Note that there are two failure cases: the first is that there is
+ // a problem transmitting. In this case we told the other end of the
+ // message queue, and so the life of this message is over. The other
+ // case is that the interface turned out to be busy in which case
+ // this message can sit on the queue and it'll be next.
+
+ IPMI::Message* msg = static_cast<IPMI::Message*>((*i)->extra_data);
+
+ // If there was an i/o error, we do nothing - leave this message on
+ // the queue. Don't touch msg after xmit returns. If the message was
+ // sent, and it was async, msg has been destroyed.
+ if (msg->xmit(iv_respondq))
+ {
+ break;
+ }
+ i = iv_sendq.erase(i);
+ }
+ return;
+}
+
+///
+/// @brief Handle a response to a message we sent
+///
+void IpmiRP::response(void)
+{
+ IPMI::Message* rcv_buf = IPMI::Message::factory();
+
+ do
+ {
+ // Go down to the device and read. Fills in iv_key.
+ errlHndl_t err = rcv_buf->recv();
+
+ if (err)
+ {
+ // Not much we're going to do here, so lets commit the error and
+ // the original request will timeout.
+ err->collectTrace(IPMI_COMP_NAME);
+ errlCommit(err, IPMI_COMP_ID);
+ break;
+ }
+
+ // Look for a message with this seq number waiting for a
+ // repsonse. If there isn't a message looking for this response,
+ // log that fact and drop this on the floor.
+ // TO THINK ABOUT: Could there be a command which generated
+ // more than one response packet from the BMC? If this happens,
+ // these messages should be handled like SMS messages - sent to
+ // the appropriate queue for a waiter to take care of. So if a
+ // message can generate more than one packet of response, something
+ // needs to register for the overflow. So far we have not seen
+ // any such beast ...
+ IPMI::respond_q_t::iterator itr = iv_respondq.find(rcv_buf->iv_key);
+ if (itr == iv_respondq.end())
+ {
+ // Every async message goes through this path. The semantics
+ // somewhat contrary to IPMI semantics in that we have the ability
+ // to generate "async" messages when the IPMI spec says there's no
+ // such thing. We decided to just drop the response on the floor.
+ // This is good for "fire and forget" situations where we don't
+ // really care if the BMC gets the message or processes it
+ // correctly. However, the BMC doesn't know we don't care about the
+ // response and sends it. This code path does the dropping of the
+ // response.
+ delete[] rcv_buf->iv_data;
+ break;
+ }
+
+ msg_t* original_msg = itr->second;
+ iv_respondq.erase(itr);
+
+ // Hand the allocated buffer over to the original message's
+ // ipmi_msg_t It will be responsible for de-allocating it
+ // when it's dtor is called.
+ IPMI::Message* ipmi_msg =
+ static_cast<IPMI::Message*>(original_msg->extra_data);
+
+ // Hand ownership of the data to the original requestor
+ ipmi_msg->iv_data = rcv_buf->iv_data;
+ ipmi_msg->iv_len = rcv_buf->iv_len;
+
+ // Send the response to the original caller of sendrecv()
+ int rc = msg_respond(iv_msgQ, original_msg);
+ if (rc)
+ {
+ // Not much we're going to do here, so lets commit an error and
+ // the original request will timeout.
+
+ /* @errorlog tag
+ * @errortype ERRL_SEV_UNRECOVERABLE
+ * @moduleid IPMI::MOD_IPMISRV_REPLY
+ * @reasoncode IPMI::RC_INVALID_QRESPONSE
+ * @userdata1 rc from msg_respond()
+ * @devdesc msg_respond() failed
+ */
+ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ IPMI::MOD_IPMISRV_REPLY,
+ IPMI::RC_INVALID_QRESPONSE,
+ rc,
+ 0,
+ true);
+ err->collectTrace(IPMI_COMP_NAME);
+
+ IPMI_TRAC(ERR_MRK "msg_respond() i/o error (response) %d", rc);
+ errlCommit(err, IPMI_COMP_ID);
+
+ // Remove the response data.
+ delete[] ipmi_msg->iv_data;
+
+ break;
+ }
+
+ } while(false);
+
+ delete rcv_buf;
+ return;
+}
+
+
+
+namespace IPMI
+{
+ ///
+ /// @brief Synchronus message send
+ ///
+ errlHndl_t sendrecv(const IPMI::network_function i_netfun,
+ const uint8_t i_cmd, uint8_t& o_completion_code,
+ size_t& io_len, uint8_t*& io_data)
+ {
+ errlHndl_t err;
+ static msg_q_t mq = Singleton<IpmiRP>::instance().msgQueue();
+
+ IPMI::Message* ipmi_msg = IPMI::Message::factory(i_netfun, i_cmd,
+ io_len, io_data,
+ IPMI::TYPE_SYNC);
+
+ // I think if the buffer is too large this is a programming error.
+ assert(io_len <= max_buffer());
+
+ IPMI_TRAC("queuing sync %x:%x", i_netfun, i_cmd);
+ int rc = msg_sendrecv(mq, ipmi_msg->iv_msg);
+
+ // If the kernel didn't give a hassle about he message, check to see if
+ // there was an error reported back from the other end of the queue. If
+ // this message made it to the other end of the queue, then our memory
+ // (io_data) is in the proper state.
+ if (rc == 0) {
+ err = ipmi_msg->iv_errl;
+ }
+
+ // Otherwise, lets make an errl out of our return code
+ else
+ {
+ /* @errorlog tag
+ * @errortype ERRL_SEV_UNRECOVERABLE
+ * @moduleid IPMI::MOD_IPMISRV_SEND
+ * @reasoncode IPMI::RC_INVALID_SENDRECV
+ * @userdata1 rc from msq_sendrecv()
+ * @devdesc msg_sendrecv() failed
+ */
+ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ IPMI::MOD_IPMISRV_SEND,
+ IPMI::RC_INVALID_SENDRECV,
+ rc,
+ 0,
+ true);
+ err->collectTrace(IPMI_COMP_NAME);
+
+ // ... and clean up the memory for the caller
+ delete[] io_data;
+ }
+
+ // The length and the data are the response, if there was one. All of
+ // there are pretty much invalid if there was an error.
+ io_len = ipmi_msg->iv_len;
+ io_data = ipmi_msg->iv_data;
+ o_completion_code = ipmi_msg->iv_cc;
+ delete ipmi_msg;
+
+ return err;
+ }
+
+ ///
+ /// @brief Asynchronus message send
+ ///
+ errlHndl_t send(const IPMI::network_function i_netfun,
+ const uint8_t i_cmd,
+ const size_t i_len, uint8_t* i_data)
+ {
+ static msg_q_t mq = Singleton<IpmiRP>::instance().msgQueue();
+ errlHndl_t err = NULL;
+
+ // We don't delete this message, the message will self destruct
+ // after it's been transmitted. Note it could be placed on the send
+ // queue and we are none the wiser - so we can't delete it.
+ IPMI::Message* ipmi_msg = IPMI::Message::factory(i_netfun, i_cmd,
+ i_len, i_data,
+ IPMI::TYPE_ASYNC);
+
+ // I think if the buffer is too large this is a programming error.
+ assert(i_len <= max_buffer());
+
+ IPMI_TRAC("queuing async %x:%x", i_netfun, i_cmd);
+ int rc = msg_send(mq, ipmi_msg->iv_msg);
+
+ if (rc)
+ {
+ /* @errorlog tag
+ * @errortype ERRL_SEV_UNRECOVERABLE
+ * @moduleid IPMI::MOD_IPMISRV_SEND
+ * @reasoncode IPMI::RC_INVALID_SEND
+ * @userdata1 rc from msq_send()
+ * @devdesc msg_send() failed
+ */
+ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ IPMI::MOD_IPMISRV_SEND,
+ IPMI::RC_INVALID_SEND,
+ rc,
+ 0,
+ true);
+ err->collectTrace(IPMI_COMP_NAME);
+
+ // ... and clean up the memory for the caller
+ delete[] i_data;
+ }
+
+ return err;
+ }
+
+ ///
+ /// @brief Maximum buffer for data (max xport - header)
+ ///
+ inline size_t max_buffer(void)
+ {
+ static const size_t mbs = Singleton<IpmiRP>::instance().maxBuffer();
+ return mbs;
+ }
+
+};
diff --git a/src/usr/ipmi/ipmirp.H b/src/usr/ipmi/ipmirp.H
new file mode 100644
index 000000000..7e535fe67
--- /dev/null
+++ b/src/usr/ipmi/ipmirp.H
@@ -0,0 +1,158 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/ipmi/ipmirp.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,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_IPMIRP_H
+#define __IPMI_IMPIRP_H
+
+/**
+ * @file ipmirp.H
+ * @brief IPMI service provider declariation
+ */
+
+#include <stdint.h>
+#include <builtins.h>
+#include <ipmi/ipmiif.H>
+#include "ipmibt.H"
+#include <errl/errlentry.H>
+#include <sys/msg.h>
+#include <sys/sync.h>
+#include <list>
+#include <map>
+#include <util/locked/list.H>
+#include <intr/interrupt.H>
+#include <limits.h>
+
+namespace TARGETING
+{
+ class Target;
+};
+
+class IpmiRP
+{
+ public:
+
+ /**
+ * Initialize the IPMI service
+ * @param[in] o_errl, NULL if OK
+ */
+ static void daemonProcess(errlHndl_t& o_errl);
+
+ /**
+ * Thread start routine for the resource provider
+ * @param[in] void*, unused
+ */
+ static void* start(void* unused);
+
+ /**
+ * Default constructor
+ */
+ IpmiRP(void);
+
+ /**
+ * Destructor
+ */
+ ~IpmiRP(void);
+
+ /**
+ * The mailbox service provider task
+ */
+ void msgHandler(void);
+
+ /**
+ * Return the max data buffer to allocate for the underlying transport.
+ */
+ inline size_t maxBuffer(void);
+
+ /**
+ * @brief Get the message queue associated with this RP
+ * @param[in] void
+ * @return, a msg_q_t which is the message queue
+ */
+ msg_q_t msgQueue(void)
+ { return iv_msgQ; }
+
+ private:
+
+ /**
+ * Entry point for the resource provider
+ */
+ void execute(void);
+
+ /**
+ * @brief Transmit a message over the IPMI interface
+ * @param[in] i_msg, ptr to the message_q message
+ * @note i_msg is not const because it contains a return code
+ */
+ int xmit(msg_t* i_msg);
+
+ /**
+ * @brief Transmit a synchronous message over the IPMI interface
+ * @param[in] i_msg, ptr to the message_q message
+ * @note this is a message used internally to send a message
+ * over the IPMI interface and wait for a response from the BMC
+ * @note i_msg is not const because it contains a return code
+ */
+ void xmit_sync(msg_t* i_msg);
+
+ /**
+ * @brief Transmit an asynchronous message over the IPMI interface
+ * @param[in] i_msg, ptr to the message_q message
+ * @note this is a message used internally to send a message
+ * over the IPMI interface and not wait for a response from the BMC
+ * @note i_msg is not const because it contains a return code
+ */
+ void xmit_async(msg_t* i_msg);
+
+ /**
+ * @brief Handle a message from the interface indicating the
+ * interface has gone idle (and can be written to.)
+ * @param[in] void
+ */
+ void idle(void);
+
+ /**
+ * @brief Handle an indication from the interface indicating the
+ * BMC interface has a response message ready to read
+ * @param[in] void
+ */
+ void response(void);
+
+ /**
+ * @brief Handle an indication from the interface indicating the
+ * BMC interface has an event/sms message ready to read
+ * @param[in] void
+ */
+ void event(void);
+
+ msg_q_t iv_msgQ; //!< ipmi mesage queue
+ IPMI::send_q_t iv_sendq; //!< msg to send queue
+ IPMI::respond_q_t iv_respondq; //!< msg respond pending list
+
+ // Disallow copying this class.
+ IpmiRP& operator=(const IpmiRP&);
+ IpmiRP(const IpmiRP&);
+};
+
+#endif
diff --git a/src/usr/ipmi/makefile b/src/usr/ipmi/makefile
new file mode 100644
index 000000000..fb2a19473
--- /dev/null
+++ b/src/usr/ipmi/makefile
@@ -0,0 +1,35 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/ipmi/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2011,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
+ROOTPATH = ../../..
+MODULE = ipmi
+
+OBJS += ipmimsg.o
+OBJS += $(if $(CONFIG_BMC_BT_LPC_IPMI),ipmibt.o)
+OBJS += ipmirp.o
+OBJS += $(if $(CONFIG_BMC_BT_LPC_IPMI),ipmidd.o)
+
+#SUBDIRS += test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/makefile b/src/usr/makefile
index 02f622520..ec0f713f0 100644
--- a/src/usr/makefile
+++ b/src/usr/makefile
@@ -63,5 +63,6 @@ SUBDIRS += gpio.d
SUBDIRS += lpc.d
SUBDIRS += console.d
SUBDIRS += errldisplay.d
+SUBDIRS += ipmi.d
include ${ROOTPATH}/config.mk
OpenPOWER on IntegriCloud