diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/runtime/interface.h | 98 | ||||
| -rw-r--r-- | src/include/usr/ipmi/ipmi_reasoncodes.H | 1 | ||||
| -rw-r--r-- | src/include/usr/ipmi/ipmisel.H | 35 | ||||
| -rw-r--r-- | src/makefile | 2 | ||||
| -rw-r--r-- | src/usr/ipmi/ipmirp.C | 2 | ||||
| -rw-r--r-- | src/usr/ipmi/ipmisel.C | 277 | ||||
| -rw-r--r-- | src/usr/ipmi/makefile | 1 | ||||
| -rw-r--r-- | src/usr/ipmi/runtime/makefile | 37 | ||||
| -rw-r--r-- | src/usr/ipmi/runtime/rt_ipmirp.C | 142 | ||||
| -rw-r--r-- | src/usr/ipmi/runtime/test/makefile | 31 | ||||
| -rw-r--r-- | src/usr/ipmi/runtime/test/rt_ipmitest.H | 102 | ||||
| -rw-r--r-- | src/usr/testcore/rtloader/loader.H | 29 |
12 files changed, 606 insertions, 151 deletions
diff --git a/src/include/runtime/interface.h b/src/include/runtime/interface.h index 9ade9a07d..5279cb892 100644 --- a/src/include/runtime/interface.h +++ b/src/include/runtime/interface.h @@ -42,8 +42,29 @@ #include <stdint.h> #include <time.h> +/** Memory error types defined for memory_error() interface. */ +enum MemoryError_t +{ + /** Hardware has reported a solid memory CE that is correctable, but + * continues to report errors on subsequent reads. A second CE on that + * cache line will result in memory UE. Therefore, it is advised to migrate + * off of the address range as soon as possible. */ + MEMORY_ERROR_CE, + + /** Hardware has reported an uncorrectable error in memory (memory UE, + * channel failure, etc). The hypervisor should migrate any partitions off + * this address range as soon as possible. Note that these kind of errors + * will most likely result in partition failures. It is advised that the + * hypervisor waits some time for PRD to handle hardware attentions so that + * the hypervisor will know all areas of memory that are impacted by the + * failure. */ + MEMORY_ERROR_UE, +}; + + + /** - * i2c master description: chip, engine and port packed into + * I2C Master Description: chip, engine and port packed into * a single 64-bit argument * * --------------------------------------------------- @@ -51,12 +72,12 @@ * | (32) | (16) | (8) | (8) | * --------------------------------------------------- */ -#define HBRT_I2C_MASTER_CHIP_SHIFT 32 -#define HBRT_I2C_MASTER_CHIP_MASK (0xfffffffful << 32) -#define HBRT_I2C_MASTER_ENGINE_SHIFT 8 -#define HBRT_I2C_MASTER_ENGINE_MASK (0xfful << 8) -#define HBRT_I2C_MASTER_PORT_SHIFT 0 -#define HBRT_I2C_MASTER_PORT_MASK (0xfful) +#define HBRT_I2C_MASTER_CHIP_SHIFT 32 +#define HBRT_I2C_MASTER_CHIP_MASK (0xfffffffful << 32) +#define HBRT_I2C_MASTER_ENGINE_SHIFT 8 +#define HBRT_I2C_MASTER_ENGINE_MASK (0xfful << 8) +#define HBRT_I2C_MASTER_PORT_SHIFT 0 +#define HBRT_I2C_MASTER_PORT_MASK (0xfful) /** @typedef hostInterfaces_t @@ -154,9 +175,10 @@ typedef struct hostInterfaces void (*nanosleep)(uint64_t i_seconds, uint64_t i_nano_seconds); /** - * @brief Report an error to the host + * @brief Report an OCC error to the host * @param[in] Failing status that identifies the nature of the fail * @param[in] Identifier that specifies the failing part + * @platform FSP */ void (*report_failure)( uint64_t i_status, uint64_t i_partId ); @@ -197,15 +219,21 @@ typedef struct hostInterfaces int (*pnor_write) (uint32_t i_proc, const char* i_partitionName, uint64_t i_offset, void* i_data, size_t i_sizeBytes); + /** * @brief Read data from an i2c device - * @param[in] i_master - Chip/engine/port of i2c bus + * @param[in] i_master - chip, engine and port packed into + * a single 64-bit argument + * --------------------------------------------------- + * | chip | reserved | eng | port | + * | (32) | (16) | (8) | (8) | + * --------------------------------------------------- * @param[in] i_devAddr - I2C address of device * @param[in] i_offsetSize - Length of offset (in bytes) * @param[in] i_offset - Offset within device to read * @param[in] i_length - Number of bytes to read * @param[out] o_data - Data that was read - * @return 0 on success else return code + * @return 0 on success else return code * @platform OpenPOWER */ int (*i2c_read)( uint64_t i_master, uint16_t i_devAddr, @@ -214,7 +242,12 @@ typedef struct hostInterfaces /** * @brief Write data to an i2c device - * @param[in] i_master - Chip/engine/port of i2c bus + * @param[in] i_master - chip, engine and port packed into + * a single 64-bit argument + * --------------------------------------------------- + * | chip | reserved | eng | port | + * | (32) | (16) | (8) | (8) | + * --------------------------------------------------- * @param[in] i_devAddr - I2C address of device * @param[in] i_offsetSize - Length of offset (in bytes) * @param[in] i_offset - Offset within device to write @@ -227,7 +260,50 @@ typedef struct hostInterfaces uint32_t i_offsetSize, uint32_t i_offset, uint32_t i_length, void* i_data ); + /** + * @brief Perform an IPMI transaction + * @param[in] netfn The IPMI netfn byte + * @param[in] cmd The IPMI cmd byte + * @param[in] tx_buf The IPMI packet to send to the host + * @param[in] tx_size The number of bytes to send + * @param[in] rx_buf A buffer to be populated with the IPMI + * response. First bytes will be the + * IPMI completion code. + * @param[inout] rx_size The allocated size of the rx buffer on input + * updated to the size of the response on output. + * @retval rc - non-zero on error + * @platform OpenPower + */ + int (*ipmi_msg)(uint8_t netfn, uint8_t cmd, + void *tx_buf, size_t tx_size, + void *rx_buf, size_t *rx_size); + + + /** + * @brief Hardware has reported a memory error. This function requests the + * hypervisor to remove the all addresses within the address range given + * (including endpoints) from the available memory space. + * + * It is understood that the hypervisor may not be able to immediately + * deallocate the memory because it may be in use by a partition. Therefore, the + * hypervisor should cache all requests and deallocate the memory once it has + * been freed. + * + * @param i_startAddr The beginning address of the range. + * @param i_endAddr The end address of the range. + * @param i_errorType See enum MemoryError_t. + * + * @return 0 if the request is successfully received. Any value other than 0 on + * failure. The hypervisor should cache the request and return + * immediately. It should not wait for the request to be applied. See + * note above. + */ + int32_t memory_error( uint64_t i_startAddr, uint64_t i_endAddr, + MemoryError_t i_errorType ); + + // Reserve some space for future growth. + // do NOT ever change this number, even if you add functions. void (*reserved[32])(void); } hostInterfaces_t; diff --git a/src/include/usr/ipmi/ipmi_reasoncodes.H b/src/include/usr/ipmi/ipmi_reasoncodes.H index 6244b2d00..8040f934b 100644 --- a/src/include/usr/ipmi/ipmi_reasoncodes.H +++ b/src/include/usr/ipmi/ipmi_reasoncodes.H @@ -35,6 +35,7 @@ namespace IPMI MOD_IPMISRV_REPLY = 0x02, // IPMI::respond MOD_IPMISENSOR = 0x03, // IPMI::sensor MOD_IPMIDCMI = 0x04, // IPMI::sensor + MOD_IPMIRT = 0x05, // rt IPMI::send/IPMI::sendrecv }; enum IPMIReasonCode diff --git a/src/include/usr/ipmi/ipmisel.H b/src/include/usr/ipmi/ipmisel.H index 82d86bf6f..de2dd3218 100644 --- a/src/include/usr/ipmi/ipmisel.H +++ b/src/include/usr/ipmi/ipmisel.H @@ -202,8 +202,26 @@ namespace IPMISEL delete eSelExtra; } }; + + /** + * @brief parse the msg and call send_esel to send the esel (handles if + * the SEL reservation is lost) + * @param[in] i_msg + */ + void process_esel(msg_t *i_msg); + + /** + * @brief do the actual ipmi calls to send the esel data to the bmc + * @param[in] i_data esel data + * @param[in] o_err any error generated during the send + * @param[in] o_cc ipmi completion code from last sendrecv + */ + void send_esel(IPMISEL::eselInitData * i_data, + errlHndl_t &o_err, IPMI::completion_code &o_cc); + } // namespace IPMISEL +#ifndef __HOSTBOOT_RUNTIME class IpmiSEL { public: @@ -238,27 +256,12 @@ class IpmiSEL */ void execute(void); - /** - * @brief parse the msg and call send_esel to send the esel (handles if - * the SEL reservation is lost) - * @param[in] i_msg - */ - void process_esel(msg_t *i_msg) const; - - /** - * @brief do the actual ipmi calls to send the esel data to the bmc - * @param[in] i_data esel data - * @param[in] o_err any error generated during the send - * @param[in] o_cc ipmi completion code from last sendrecv - */ - void send_esel(IPMISEL::eselInitData * i_data, - errlHndl_t &o_err, IPMI::completion_code &o_cc) const; - msg_q_t iv_msgQ; //!< ipmi message queue //Disallow copying of this class. IpmiSEL& operator=(const IpmiSEL&); IpmiSEL(const IpmiSEL&); }; +#endif #endif diff --git a/src/makefile b/src/makefile index 97dbc3e39..6fdb8c6e6 100644 --- a/src/makefile +++ b/src/makefile @@ -236,6 +236,7 @@ RUNTIME_MODULES += $(if $(CONFIG_HTMGT),htmgt_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),bus_training_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),attn_rt) RUNTIME_MODULES += $(if $(CONFIG_HBRT_PRD),prdf_rt) +RUNTIME_MODULES += $(if $(CONFIG_BMC_IPMI),ipmi_rt) RUNTIME_MODULES += pnor_rt RUNTIME_DATA_MODULES += @@ -251,6 +252,7 @@ RUNTIME_TESTCASE_MODULES += testvpd_rt RUNTIME_TESTCASE_MODULES += testhwpf_rt RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_HBRT_PRD),testprdf_rt) RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_HBRT_PRD),testattn_rt) +RUNTIME_TESTCASE_MODULES += $(if $(CONFIG_BMC_IPMI),testipmi_rt) RUNTIME_TESTCASE_MODULES += testpnor_rt RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C index 51b943ab0..50f8ef2b5 100644 --- a/src/usr/ipmi/ipmirp.C +++ b/src/usr/ipmi/ipmirp.C @@ -865,7 +865,7 @@ namespace IPMI IPMI_TRAC("queuing sync %x:%x", ipmi_msg->iv_netfun, ipmi_msg->iv_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 + // If the kernel didn't give a hassle about the 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. diff --git a/src/usr/ipmi/ipmisel.C b/src/usr/ipmi/ipmisel.C index df746f011..92a70faa5 100644 --- a/src/usr/ipmi/ipmisel.C +++ b/src/usr/ipmi/ipmisel.C @@ -44,125 +44,7 @@ extern trace_desc_t * g_trac_ipmi; #define IPMI_TRAC(printf_string,args...) \ TRACFCOMP(g_trac_ipmi,"sel: "printf_string,##args) -namespace IPMISEL -{ - void sendESEL(uint8_t* i_eselData, uint32_t i_dataSize, - uint32_t i_eid, uint8_t i_eventDirType, - uint8_t i_sensorType, uint8_t i_sensorNumber) - { - IPMI_TRAC(ENTER_MRK "sendESEL()"); - - // one message queue to the SEL thread - static msg_q_t mq = Singleton<IpmiSEL>::instance().msgQueue(); - - msg_t *msg = msg_allocate(); - msg->type = MSG_SEND_ESEL; - msg->data[0] = i_eid; - - // create the sel record of information - IPMISEL::selRecord l_sel; - l_sel.record_type = IPMISEL::record_type_ami_esel; - l_sel.generator_id = IPMISEL::generator_id_ami; - l_sel.evm_format_version = IPMISEL::format_ipmi_version_2_0; - l_sel.sensor_type = i_sensorType; - l_sel.sensor_number = i_sensorNumber; - l_sel.event_dir_type = i_eventDirType; - l_sel.event_data1 = IPMISEL::event_data1_ami; - - eselInitData *eselData = - new eselInitData(&l_sel, i_eselData, i_dataSize); - - msg->extra_data = eselData; - - //Send the msg to the sel thread - int rc = msg_send(mq,msg); - if(rc) - { - IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message",rc); - delete eselData; - } - IPMI_TRAC(EXIT_MRK "sendESEL"); - return; - } // sendESEL -} // IPMISEL - - -/** - * @brief Constructor - */ -IpmiSEL::IpmiSEL(void): - iv_msgQ(msg_q_create()) -{ - IPMI_TRAC(ENTER_MRK "IpmiSEL ctor"); - task_create(&IpmiSEL::start,NULL); -} - -/** - * @brief Destructor - */ -IpmiSEL::~IpmiSEL(void) -{ - msg_q_destroy(iv_msgQ); -} - -void* IpmiSEL::start(void* unused) -{ - Singleton<IpmiSEL>::instance().execute(); - return NULL; -} - -/** - * @brief Entry point of the sel ipmi thread - */ -//@todo: RTC 119832 -void IpmiSEL::execute(void) -{ - //Mark as an independent daemon so if it crashes we terminate. - task_detach(); - - // 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, IPMISEL::MSG_STATE_SHUTDOWN, - INITSERVICE::MBOX_PRIORITY); - - while(true) - { - msg_t* msg = msg_wait(iv_msgQ); - - const IPMISEL::msg_type msg_type = - static_cast<IPMISEL::msg_type>(msg->type); - - // Invert the "default" by checking here. This allows the compiler - // to warn us if the enum has an unhadled case but still catch - // runtime errors where msg_type is set out of bounds. - assert(msg_type <= IPMISEL::MSG_LAST_TYPE, - "msg_type %d not handled", msg_type); - - switch(msg_type) - { - case IPMISEL::MSG_SEND_ESEL: - process_esel(msg); - //done with msg - msg_free(msg); - break; - - case IPMISEL::MSG_STATE_SHUTDOWN: - IPMI_TRAC(INFO_MRK "ipmisel shutdown event"); - - //Respond that we are done shutting down. - msg_respond(iv_msgQ, msg); - break; - } - } // while(1) - IPMI_TRAC(EXIT_MRK "message loop"); - return; -} // execute - +// local functions /* * @brief Store either Record/Reserve ID from given data */ @@ -196,10 +78,63 @@ enum esel_retry SLEEP_BASE = 2 * NS_PER_MSEC, }; + +namespace IPMISEL +{ +void sendESEL(uint8_t* i_eselData, uint32_t i_dataSize, + uint32_t i_eid, uint8_t i_eventDirType, + uint8_t i_sensorType, uint8_t i_sensorNumber) +{ + IPMI_TRAC(ENTER_MRK "sendESEL()"); + +#ifdef __HOSTBOOT_RUNTIME + // HBRT doesn't send a msg, but use the msg structure to pass the data + msg_t l_msg; + msg_t *msg = &l_msg; + memset(msg, 0, sizeof(msg_t)); +#else + msg_t *msg = msg_allocate(); +#endif + msg->type = MSG_SEND_ESEL; + msg->data[0] = i_eid; + + // create the sel record of information + IPMISEL::selRecord l_sel; + l_sel.record_type = IPMISEL::record_type_ami_esel; + l_sel.generator_id = IPMISEL::generator_id_ami; + l_sel.evm_format_version = IPMISEL::format_ipmi_version_2_0; + l_sel.sensor_type = i_sensorType; + l_sel.sensor_number = i_sensorNumber; + l_sel.event_dir_type = i_eventDirType; + l_sel.event_data1 = IPMISEL::event_data1_ami; + + eselInitData *eselData = + new eselInitData(&l_sel, i_eselData, i_dataSize); + + msg->extra_data = eselData; + +#ifdef __HOSTBOOT_RUNTIME + process_esel(msg); +#else + // one message queue to the SEL thread + static msg_q_t mq = Singleton<IpmiSEL>::instance().msgQueue(); + + //Send the msg to the sel thread + int rc = msg_send(mq,msg); + if(rc) + { + IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message",rc); + delete eselData; + } +#endif + IPMI_TRAC(EXIT_MRK "sendESEL"); + return; +} // sendESEL + /* * @brief process esel msg */ -void IpmiSEL::process_esel(msg_t *i_msg) const +void process_esel(msg_t *i_msg) { errlHndl_t l_err = NULL; IPMI::completion_code l_cc = IPMI::CC_UNKBAD; @@ -212,7 +147,7 @@ void IpmiSEL::process_esel(msg_t *i_msg) const while (l_send_count > 0) { // try to send the eles to the bmc - send_esel(l_data, l_err, l_cc); + IPMISEL::send_esel(l_data, l_err, l_cc); // if no error but last completion code was: if ((l_err == NULL) && @@ -240,15 +175,31 @@ void IpmiSEL::process_esel(msg_t *i_msg) const if(l_err) { +#ifdef __HOSTBOOT_RUNTIME + // HBRT can't commit an error, since this could already be in the + // errlCommit path since HBRT is single threaded + IPMI_TRAC(ERR_MRK "DELETING l_err 0x%.8X", l_err->eid()); + delete l_err; + l_err = NULL; + + // TODO RTC: 123419 investigate adding a 'iv_isIpmiEnabled' flag and setting + // that to false somehow, so that we can commit error logs in this path + // and future calls wont try to send them down. +#else l_err->collectTrace(IPMI_COMP_NAME); errlCommit(l_err, IPMI_COMP_ID); +#endif } else if((l_cc == IPMI::CC_OK) && // no error (l_eid != 0)) // and it's an errorlog { +#ifdef __HOSTBOOT_RUNTIME + // TODO RTC: 123419 story to add storing errlog to PNOR in HBRT if IPMI +#else // eSEL successfully sent to the BMC - send an ack to the errlmanager IPMI_TRAC(INFO_MRK "Sending ack for eid 0x%.8X", l_eid); ERRORLOG::ErrlManager::errlAckErrorlog(l_eid); +#endif } delete l_data; @@ -260,8 +211,8 @@ void IpmiSEL::process_esel(msg_t *i_msg) const /* * @brief Send esel data to bmc */ -void IpmiSEL::send_esel(IPMISEL::eselInitData * i_data, - errlHndl_t &o_err, IPMI::completion_code &o_cc) const +void send_esel(IPMISEL::eselInitData * i_data, + errlHndl_t &o_err, IPMI::completion_code &o_cc) { IPMI_TRAC(ENTER_MRK "send_esel"); uint8_t* data = NULL; @@ -402,3 +353,83 @@ void IpmiSEL::send_esel(IPMISEL::eselInitData * i_data, return; } // send_esel +} // IPMISEL + +#ifndef __HOSTBOOT_RUNTIME +/** + * @brief Constructor + */ +IpmiSEL::IpmiSEL(void) + :iv_msgQ(msg_q_create()) +{ + IPMI_TRAC(ENTER_MRK "IpmiSEL ctor"); + task_create(&IpmiSEL::start,NULL); +} + +/** + * @brief Destructor + */ +IpmiSEL::~IpmiSEL(void) +{ + msg_q_destroy(iv_msgQ); +} + +void* IpmiSEL::start(void* unused) +{ + Singleton<IpmiSEL>::instance().execute(); + return NULL; +} + +/** + * @brief Entry point of the sel ipmi thread + */ +//@todo: RTC 119832 +void IpmiSEL::execute(void) +{ + //Mark as an independent daemon so if it crashes we terminate. + task_detach(); + + // 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, IPMISEL::MSG_STATE_SHUTDOWN, + INITSERVICE::MBOX_PRIORITY); + + while(true) + { + msg_t* msg = msg_wait(iv_msgQ); + + const IPMISEL::msg_type msg_type = + static_cast<IPMISEL::msg_type>(msg->type); + + // Invert the "default" by checking here. This allows the compiler + // to warn us if the enum has an unhadled case but still catch + // runtime errors where msg_type is set out of bounds. + assert(msg_type <= IPMISEL::MSG_LAST_TYPE, + "msg_type %d not handled", msg_type); + + switch(msg_type) + { + case IPMISEL::MSG_SEND_ESEL: + IPMISEL::process_esel(msg); + //done with msg + msg_free(msg); + break; + + case IPMISEL::MSG_STATE_SHUTDOWN: + IPMI_TRAC(INFO_MRK "ipmisel shutdown event"); + + //Respond that we are done shutting down. + msg_respond(iv_msgQ, msg); + break; + } + } // while(1) + IPMI_TRAC(EXIT_MRK "message loop"); + return; +} // execute +#endif + diff --git a/src/usr/ipmi/makefile b/src/usr/ipmi/makefile index 8dad57f3e..fb6a249a4 100644 --- a/src/usr/ipmi/makefile +++ b/src/usr/ipmi/makefile @@ -39,6 +39,7 @@ OBJS += ipmipowerstate.o OBJS += ipmiselrecord.o OBJS += ipmidcmi.o +SUBDIRS += runtime.d #SUBDIRS += test.d include ${ROOTPATH}/config.mk diff --git a/src/usr/ipmi/runtime/makefile b/src/usr/ipmi/runtime/makefile new file mode 100644 index 000000000..21ab138ff --- /dev/null +++ b/src/usr/ipmi/runtime/makefile @@ -0,0 +1,37 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/ipmi/runtime/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015 +# [+] 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 +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../.. +MODULE = ipmi_rt + +OBJS += ipmisel.o +OBJS += ipmisensor.o +OBJS += rt_ipmirp.o + +SUBDIRS += test.d + +VPATH += .. +include $(ROOTPATH)/config.mk + diff --git a/src/usr/ipmi/runtime/rt_ipmirp.C b/src/usr/ipmi/runtime/rt_ipmirp.C new file mode 100644 index 000000000..7184c85f7 --- /dev/null +++ b/src/usr/ipmi/runtime/rt_ipmirp.C @@ -0,0 +1,142 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/runtime/rt_ipmirp.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 rt_ipmirp.C + * @brief IPMI resource provider definition for runtime + */ + +#include "../ipmirp.H" +#include "../ipmiconfig.H" +#include "../ipmidd.H" +#include <ipmi/ipmi_reasoncodes.H> +#include <ipmi/ipmiif.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> +#include <runtime/interface.h> + +trace_desc_t * g_trac_ipmi; +#define IPMI_TRAC(printf_string,args...) \ + TRACFCOMP(g_trac_ipmi,"rt: "printf_string,##args) + +namespace IPMI +{ + // TODO RTC: 124099 move to a _hb attribute + // ATTR_IPMI_MAX_BUFFER_SEND_SIZE + static const size_t g_max_buffer = 61; + size_t max_buffer(void) + { + return g_max_buffer; + } + + /// + /// @brief Synchronus message send + /// + errlHndl_t sendrecv(const IPMI::command_t& i_cmd, + IPMI::completion_code& o_completion_code, + size_t& io_len, uint8_t*& io_data) + { + errlHndl_t err = NULL; + int rc = 0; + + // if the buffer is too large this is a programming error. + assert(io_len <= g_max_buffer); + + IPMI_TRAC("calling sync %x:%x len=%d", + i_cmd.first, i_cmd.second, io_len); + + if(g_hostInterfaces && g_hostInterfaces->ipmi_msg) + { + size_t l_len = g_max_buffer; // max size the BMC can return + uint8_t *l_data = new uint8_t[l_len]; + + rc = g_hostInterfaces->ipmi_msg( + i_cmd.first, i_cmd.second, + io_data, io_len, + l_data, &l_len); + + if(rc) + { + IPMI_TRAC(ERR_MRK + "Failed sending ipmi msg (%x:%x) to bmc rc: %d. ", + i_cmd.first, i_cmd.second, rc); + + /* @errorlog tag + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid IPMI::MOD_IPMIRT + * @reasoncode IPMI::RC_INVALID_SENDRECV + * @userdata1[0:31] rc from ipmi_msg() + * @userdata1[32:46] netfn of failing msg + * @userdata1[47:63] cmd of failing msg + * @userdata2 length of failing msg + * @devdesc ipmi_msg() failed + * @custdesc Firmware error + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + IPMI::MOD_IPMIRT, + IPMI::RC_INVALID_SENDRECV, + TWO_UINT32_TO_UINT64(rc, + TWO_UINT16_TO_UINT32(i_cmd.first, i_cmd.second)), + io_len, + true); + err->collectTrace(IPMI_COMP_NAME); + delete[] io_data; + io_data = NULL; + io_len = 0; + } + else + { + // clean up the memory for the caller + o_completion_code = static_cast<IPMI::completion_code>(io_data[0]); + + // now need to create the buffer to return + io_len = l_len - 1; // get rid of the completion_code + delete[] io_data; + io_data = new uint8_t[io_len]; + memcpy(io_data, &l_data[1], io_len); // data after CC + } + delete[] l_data; + } + else + { + IPMI_TRAC(ERR_MRK + "Host interfaces not initialized; ipmi msg not sent. "); + } + + return err; + } // sendrecv +}; diff --git a/src/usr/ipmi/runtime/test/makefile b/src/usr/ipmi/runtime/test/makefile new file mode 100644 index 000000000..a12933112 --- /dev/null +++ b/src/usr/ipmi/runtime/test/makefile @@ -0,0 +1,31 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/ipmi/runtime/test/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015 +# [+] 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 +HOSTBOOT_RUNTIME = 1 +ROOTPATH = ../../../../.. + +MODULE = testipmi_rt +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/usr/ipmi/runtime/test/rt_ipmitest.H b/src/usr/ipmi/runtime/test/rt_ipmitest.H new file mode 100644 index 000000000..b3a252e31 --- /dev/null +++ b/src/usr/ipmi/runtime/test/rt_ipmitest.H @@ -0,0 +1,102 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/runtime/test/rt_ipmitest.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] 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 __RT_IPMITEST_H +#define __RT_IPMITEST_H + +/** + * @file ipmitest.H + * + * @brief Test case for IPMI messages +*/ + +#include <cxxtest/TestSuite.H> + +#include "../../../trace/entry.H" + +#include <ipmi/ipmiif.H> +#include <ipmi/ipmisensor.H> + + +class RT_IpmiTest: public CxxTest::TestSuite +{ +public: + + + /** + * @brief call sendrecv directly + */ + void testIpmi1(void) + { + do + { + IPMI::completion_code cc = IPMI::CC_UNKBAD; + size_t len = 0; + uint8_t* data = NULL; + errlHndl_t err = IPMI::sendrecv(IPMI::get_capabilities(), cc, len, data); + + TS_WARN("testIpmi1: cc x%x, len %d", cc, len); + + if ( err != NULL ) + { + TS_FAIL("testIpmi1: get_capabilities() failed"); + break; + } + if (cc != IPMI::CC_OK) + { + TS_FAIL("testIpmi1: get_capabilities() failed with cc 0x%x", cc); + break; + } + if (len != 5) + { + TS_FAIL("testIpmi1: get_capabilities() returned len %d instead of 5", + len); + break; + } + + TS_WARN("testIpmi1: get_capabilities x%x, x%x x%x x%x x%x", + data[0], data[1], data[2], data[3], data[4]); + + } + while(0); + } + + /** + * @brief call IPMI::sensor function + */ + void testIpmi2(void) + { + do + { + uint8_t l_sensorNumber = SENSOR::getFaultSensorNumber( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + + TS_WARN("testIpmi2: getFaultSensorNumber x%x", + l_sensorNumber); + } + while(0); + } +}; + +#endif diff --git a/src/usr/testcore/rtloader/loader.H b/src/usr/testcore/rtloader/loader.H index 041337118..9ac9c5ebc 100644 --- a/src/usr/testcore/rtloader/loader.H +++ b/src/usr/testcore/rtloader/loader.H @@ -41,6 +41,7 @@ #include <string.h> #include <devicefw/userif.H> #include <pnor/ecc.H> +#include <ipmi/ipmiif.H> trace_desc_t* g_trac_hbrt = NULL; TRAC_INIT(&g_trac_hbrt, "HBRT_TEST", 2*KILOBYTE); @@ -122,6 +123,7 @@ class RuntimeLoaderTest : public CxxTest::TestSuite intf->get_reserved_mem = rt_get_reserved_mem; intf->pnor_read = rt_pnor_read; intf->pnor_write= rt_pnor_write; + intf->ipmi_msg= rt_ipmi_msg; // Call init. runtimeInterfaces_t* rtInterface = @@ -518,6 +520,33 @@ class RuntimeLoaderTest : public CxxTest::TestSuite return cv_targ_addr; } + static int rt_ipmi_msg(uint8_t netfn, uint8_t cmd, + void *tx_buf, size_t tx_size, + void *rx_buf, size_t *rx_size) + { + TRACFCOMP(g_trac_hbrt, ENTER_MRK + "rt_ipmi_msg: tx_buf:%x/%x, size:%d, rx_buf:%p, size:%d", + netfn, cmd, tx_size, + rx_buf, *rx_size); + + errlHndl_t l_err = NULL; + do { + ((uint8_t*)rx_buf)[0] = IPMI::CC_OK; + rx_size = 0; + } while (0); + + //commit the error + uint32_t l_plid = 0; + if (l_err) + { + l_plid = l_err->plid(); + errlCommit (l_err, CXXTEST_COMP_ID); + } + TRACFCOMP(g_trac_hbrt, EXIT_MRK"rt_ipmi_msg"); + return l_plid; + } + + static uint64_t cv_vpd_addr; static uint64_t cv_vpd_phys_addr; static uint64_t cv_targ_addr; |

