diff options
| author | Brian Silver <bsilver@us.ibm.com> | 2014-09-30 08:22:11 -0500 |
|---|---|---|
| committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2014-10-23 04:51:02 -0500 |
| commit | a9010ccc1130b81e45d1151bb5de9453d31c08a5 (patch) | |
| tree | ecc60da4bd3623cc97851dfa75e98293f9c77bdd /src/usr/ipmi/ipmibt.C | |
| parent | a6b67089037c83373f548749a463dfd769938b77 (diff) | |
| download | talos-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/usr/ipmi/ipmibt.C')
| -rw-r--r-- | src/usr/ipmi/ipmibt.C | 246 |
1 files changed, 246 insertions, 0 deletions
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; + } +}; |

