summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard J. Knight <rjknight@us.ibm.com>2015-02-07 18:24:43 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-02-19 21:59:52 -0600
commit27809d56544caa11f43b21321a519c5bd9014054 (patch)
treed3b003a6beea36d070b34bd4b72d1682bd017409
parent74b5d9951f657e62da93975e71f0c671e9791df5 (diff)
downloadtalos-hostboot-27809d56544caa11f43b21321a519c5bd9014054.tar.gz
talos-hostboot-27809d56544caa11f43b21321a519c5bd9014054.zip
Add support for soft power off command from BMC
Change-Id: I065a281700dc7a878e1502b29b06a70aba5896f9 RTC:108830 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/15747 Reviewed-by: Brian H. Horton <brianh@linux.ibm.com> Tested-by: Jenkins Server Reviewed-by: Brian Silver <bsilver@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
-rw-r--r--src/include/usr/initservice/initserviceif.H11
-rw-r--r--src/include/usr/ipmi/ipmiif.H12
-rw-r--r--src/usr/initservice/baseinitsvc/initservice.C31
-rw-r--r--src/usr/ipmi/ipmirp.C103
-rw-r--r--src/usr/ipmi/ipmirp.H3
5 files changed, 120 insertions, 40 deletions
diff --git a/src/include/usr/initservice/initserviceif.H b/src/include/usr/initservice/initserviceif.H
index 6bc977978..e475dadb5 100644
--- a/src/include/usr/initservice/initserviceif.H
+++ b/src/include/usr/initservice/initserviceif.H
@@ -5,9 +5,9 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2014 */
-/* [+] International Business Machines Corp. */
+/* Contributors Listed Below - COPYRIGHT 2011,2015 */
/* [+] Google Inc. */
+/* [+] International Business Machines Corp. */
/* */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
@@ -43,16 +43,17 @@ namespace INITSERVICE
*/
enum EventPriority_t
{
- LOWEST_PRIORITY = 0, //!<< Notifiy last, LIFO order
+ LOWEST_PRIORITY = 0, //!<< Notify last, LIFO order
CONSOLE_PRIORITY = LOWEST_PRIORITY, //!<< Shutdown Console
INTR_PRIORITY = 1, //!<< Shutdown INTR
MBOX_PRIORITY = 2, //!<< Shutdown MBOX
NO_PRIORITY = 16, //!<< No dependency / dont' care, LIFO order
- HIGHEST_PRIORITY = 127, //!<< Nofity first, LIFO order
+ HIGHEST_PRIORITY = 127, //!<< Notify first, LIFO order
+ POST_MEM_FLUSH_START_PRIORITY = 128, //!<< Post Mem Flush callbacks
};
/**
- * @brief Register a block/range of vitual memory to be handled during a
+ * @brief Register a block/range of virtual memory to be handled during a
* shutdown.
*
* @param[in] i_vaddr - Base virtual address
diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H
index 5856717ec..56e3c532b 100644
--- a/src/include/usr/ipmi/ipmiif.H
+++ b/src/include/usr/ipmi/ipmiif.H
@@ -50,8 +50,10 @@ namespace IPMI
MSG_STATE_SHUTDOWN,
+ MSG_STATE_GRACEFUL_SHUTDOWN,
+
// Used to check range. Leave as last.
- MSG_LAST_TYPE = MSG_STATE_SHUTDOWN,
+ MSG_LAST_TYPE = MSG_STATE_GRACEFUL_SHUTDOWN,
};
// Used in the factory for creating the proper subclass.
@@ -199,6 +201,11 @@ namespace IPMI
{ return std::make_pair(NETFUN_APP, 0x36); }
+ // Chassis messages
+ inline const command_t chassis_power_off(void)
+ { return std::make_pair(NETFUN_CHASSIS, 0x02); }
+
+
// Storage messages
inline const command_t set_sel_time(void)
{ return std::make_pair(NETFUN_STORAGE, 0x49); }
@@ -206,8 +213,6 @@ namespace IPMI
inline const command_t write_fru_data(void)
{ return std::make_pair(NETFUN_STORAGE, 0x12); }
-
- // Sensor messages
inline const command_t get_sel_info(void)
{ return std::make_pair(NETFUN_STORAGE, 0x40); }
@@ -225,6 +230,7 @@ namespace IPMI
inline const command_t platform_event(void)
{ return std::make_pair(NETFUN_SENSOR, 0x02); }
+ // Sensor messages
inline const command_t set_sensor_reading(void)
{ return std::make_pair(NETFUN_SENSOR, 0x30); }
diff --git a/src/usr/initservice/baseinitsvc/initservice.C b/src/usr/initservice/baseinitsvc/initservice.C
index 0826781c2..fed5a70e5 100644
--- a/src/usr/initservice/baseinitsvc/initservice.C
+++ b/src/usr/initservice/baseinitsvc/initservice.C
@@ -5,7 +5,9 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2014 */
+/* Contributors Listed Below - COPYRIGHT 2011,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. */
@@ -756,13 +758,13 @@ void InitService::doShutdown(uint64_t i_status,
TRACFCOMP(g_trac_initsvc, "doShutdown> status=%.16X",worst_status);
- // Call registered services and notify of shutdown
- msg_t * l_msg = msg_allocate();
- l_msg->data[1] = 0;
- l_msg->extra_data = 0;
+ msg_t * l_msg = msg_allocate(); // filled with zeros on creation
+ // Call registered services and notify of shutdown
+ // except those who asked for post memory flush callbacks
for(EventRegistry_t::iterator i = iv_regMsgQ.begin();
- i != iv_regMsgQ.end();
+ ( (i != iv_regMsgQ.end()) &&
+ (i->msgPriority <= HIGHEST_PRIORITY));
++i)
{
l_msg->type = i->msgType;
@@ -770,8 +772,6 @@ void InitService::doShutdown(uint64_t i_status,
msg_sendrecv(i->msgQ,l_msg);
}
- msg_free(l_msg);
-
std::vector<regBlock_t*>::iterator l_rb_iter = iv_regBlock.begin();
//FLUSH each registered block in order
while (l_rb_iter!=iv_regBlock.end())
@@ -804,6 +804,20 @@ void InitService::doShutdown(uint64_t i_status,
l_rb_iter++;
}
+ // send message to registered services who asked for a
+ // post memory flush callback
+ for(EventRegistry_t::iterator i = iv_regMsgQ.begin();
+ i != iv_regMsgQ.end(); ++i)
+ {
+ if( i->msgPriority >= POST_MEM_FLUSH_START_PRIORITY)
+ {
+ l_msg->type = i->msgType;
+ l_msg->data[0] = worst_status;
+ msg_sendrecv(i->msgQ,l_msg);
+ }
+ }
+ msg_free(l_msg);
+
// Wait a little bit to give other tasks a chance to call shutdown
// before moving on in case we want to modify the status we are
// failing with. This is after shutting down all daemons and flushing
@@ -811,6 +825,7 @@ void InitService::doShutdown(uint64_t i_status,
// a chance to log a better RC (e.g. pnor errors).
task_yield();
nanosleep(0,TEN_CTX_SWITCHES_NS);
+
TRACFCOMP(g_trac_initsvc, "doShutdown> Final status=%.16X",worst_status);
shutdown(worst_status,
diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C
index e3a53512d..51b943ab0 100644
--- a/src/usr/ipmi/ipmirp.C
+++ b/src/usr/ipmi/ipmirp.C
@@ -75,7 +75,8 @@ IpmiRP::IpmiRP(void):
iv_recv_buffer_size(IPMI::g_recv_buffer_size),
iv_retries(IPMI::g_retries),
iv_shutdown_msg(NULL),
- iv_shutdown_now(false)
+ iv_shutdown_now(false),
+ iv_graceful_shutdown_pending(false)
{
mutex_init(&iv_mutex);
sync_cond_init(&iv_cv);
@@ -188,7 +189,7 @@ void IpmiRP::timeoutThread(void)
msg_t*& msq_msg = iv_timeoutq.front();
IPMI::Message* msg = static_cast<IPMI::Message*>(msq_msg->extra_data);
- // The diffence between the timeout of the first message in the
+ // The difference between the timeout of the first message in the
// queue and the current time is the time we wait for a timeout
timespec_t tmp_time;
clock_gettime(CLOCK_MONOTONIC, &tmp_time);
@@ -234,7 +235,7 @@ void IpmiRP::getInterfaceCapabilities(void)
// Mark as an independent daemon so if it crashes we terminate.
task_detach();
- // Queue up a get-capabilties message. Anything that queues up behind us
+ // Queue up a get-capabilities message. Anything that queues up behind us
// (I guess it could queue up in front of us too ...) will use the defaults.
IPMI::completion_code cc = IPMI::CC_UNKBAD;
@@ -246,7 +247,7 @@ void IpmiRP::getInterfaceCapabilities(void)
// If we have a problem, we can't "turn on" the IPMI stack.
if (err)
{
- IPMI_TRAC("get_capabilties returned an error, using defaults");
+ IPMI_TRAC("get_capabilities returned an error, using defaults");
err->collectTrace(IPMI_COMP_NAME);
errlCommit(err, IPMI_COMP_ID);
break;
@@ -388,15 +389,11 @@ void IpmiRP::lastChanceEventHandler(void)
// Mark as an independent daemon so if it crashes we terminate.
task_detach();
- // TODO: RTC: 108830, copy the code below to make a handler for power-off
- //
// To create a event handler, all you need to do is create a message
- // queue (or use one you have) and register for events. I left this
- // code here as an example.
- //
- // Create a message queue and register with the resource provider
- // msg_q_t queue = msg_q_create();
- // registerForEvent(IPMI::power_off(), queue);
+ // queue (or use one you have) and register for events.
+
+ // register with the resource provider, use the existing queue
+ registerForEvent(IPMI::power_off(), iv_last_chanceq);
// We'll handle the pnor request in this context as we just send
@@ -415,6 +412,23 @@ void IpmiRP::lastChanceEventHandler(void)
// an async message which says "no."
rejectPnorRequest();
}
+ else if ( event->iv_cmd[0] == IPMI::power_off().second )
+ {
+ // handle the graceful shutdown message
+ IPMI_TRAC("Graceful shutdown request recieved");
+
+ // register for the post memory flush callback
+ INITSERVICE::registerShutdownEvent(iv_msgQ,
+ IPMI::MSG_STATE_GRACEFUL_SHUTDOWN,
+ INITSERVICE::POST_MEM_FLUSH_START_PRIORITY);
+
+ iv_graceful_shutdown_pending = true;
+ lwsync();
+
+ // initiate the shutdown processing in the background
+ INITSERVICE::doShutdown(SHUTDOWN_STATUS_GOOD,true);
+
+ }
else {
// TODO: RTC: 120128
// The last-chance handler should do more than this - it needs to
@@ -447,7 +461,7 @@ void IpmiRP::execute(void)
task_detach();
// Register shutdown events with init service.
- // Done at the "end" of shutdown processesing.
+ // Done at the "end" of shutdown processing.
// 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
@@ -476,7 +490,7 @@ void IpmiRP::execute(void)
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
+ // to warn us if the enum has an un-handled 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);
@@ -497,7 +511,7 @@ void IpmiRP::execute(void)
{
IPMI_TRAC(WARN_MRK "IPMI shutdown pending. Message dropped");
IPMI::Message* ipmi_msg =
- static_cast<IPMI::Message*>(msg->extra_data);
+ static_cast<IPMI::Message*>(msg->extra_data);
response(ipmi_msg, IPMI::CC_BADSTATE);
msg_free(msg);
}
@@ -537,10 +551,37 @@ void IpmiRP::execute(void)
// Accept no more messages. Anything in the sendq is sent and
// we wait for the reply from the BMC.
case IPMI::MSG_STATE_SHUTDOWN:
- IPMI_TRAC(INFO_MRK "ipmi begin shutdown");
- l_shutdown_pending = true; // Stop incoming new messages
- iv_shutdown_msg = msg; // Reply to this message
+ {
+ IPMI_TRAC(INFO_MRK "MSG_STATE_SHUTDOWN: ipmi begin shutdown");
+ l_shutdown_pending = true; // Stop incoming new messages
+ iv_shutdown_msg = msg; // Reply to this message
+
+ break;
+ }
+
+ case IPMI::MSG_STATE_GRACEFUL_SHUTDOWN:
+ {
+ IPMI_TRAC(INFO_MRK "MSG_STATE_GRACEFUL_SHUTDOWN: send power"
+ " off command to BMC");
+ // clear the graceful shutdown flag so we will exit after
+ // sending the power off cmd
+ iv_graceful_shutdown_pending = false;
+ size_t len = 1;
+ uint8_t* data = new uint8_t[len];
+
+ // send the force shutdown option.
+ data[0] = 0;
+
+ IPMI::Message* ipmi_msg = IPMI::Message::factory(
+ IPMI::chassis_power_off(), len, data, IPMI::TYPE_ASYNC);
+
+ // queue up the power off message
+ iv_sendq.push_back(ipmi_msg->iv_msg);
+
+ iv_shutdown_msg = msg; // Reply to this message
+ }
break;
+
};
// There's a good chance the interface will be idle right after
@@ -555,11 +596,25 @@ void IpmiRP::execute(void)
idle();
}
- // Once quiesced, shutdown and reply to shutdown msg
+ // Once quiesced, reply to shutdown msg and exit.
+ // For IPMI based systems if we received the soft power off (graceful
+ // shutdown) request then we have more processing to do, so respond
+ // to the first shutdown message and instead of exiting we go back
+ // and wait for the post memory flush shutdown message then send a
+ // power off command to the BMC
if (l_shutdown_pending && iv_respondq.empty() && iv_sendq.empty())
{
- shutdownNow();
- break; // exit loop and terminate task
+ if(iv_graceful_shutdown_pending)
+ {
+
+ IPMI_TRAC(INFO_MRK "reply to the MSG_STATE_SHUTDOWN message");
+ msg_respond(iv_msgQ, iv_shutdown_msg);
+ }
+ else
+ {
+ shutdownNow();
+ break; // exit loop and terminate task
+ }
}
}
@@ -664,7 +719,7 @@ void IpmiRP::response(IPMI::Message* i_msg)
do {
// Look for a message with this seq number waiting for a
- // repsonse. If there isn't a message looking for this response,
+ // response. If there isn't a message looking for this response,
// that's an error. Async messages should also be on this queue,
// even though the caller has long gone on to other things.
IPMI::respond_q_t::iterator itr = iv_respondq.find(i_msg->iv_key);
@@ -709,7 +764,7 @@ void IpmiRP::response(IPMI::Message* i_msg)
IPMI::Message* ipmi_msg =
static_cast<IPMI::Message*>(original_msg->extra_data);
- // Hand ownership of the data to the original requestor
+ // Hand ownership of the data to the original requester
ipmi_msg->iv_data = i_msg->iv_data;
ipmi_msg->iv_len = i_msg->iv_len;
ipmi_msg->iv_cc = i_msg->iv_cc;
@@ -771,7 +826,7 @@ void IpmiRP::queueForResponse(IPMI::Message& i_msg)
///
void IpmiRP::shutdownNow(void)
{
- IPMI_TRAC(INFO_MRK "ipmi shut down now");
+ IPMI_TRAC(INFO_MRK "IpmiRP::shutdownNow() ");
mutex_lock(&iv_mutex);
iv_shutdown_now = true; // Shutdown underway
diff --git a/src/usr/ipmi/ipmirp.H b/src/usr/ipmi/ipmirp.H
index 5f06be3da..3cfeedb6b 100644
--- a/src/usr/ipmi/ipmirp.H
+++ b/src/usr/ipmi/ipmirp.H
@@ -250,6 +250,9 @@ class IpmiRP
msg_t * iv_shutdown_msg; //!< shutdown msg to respond to
bool iv_shutdown_now; //!< shutdown now
+ //!< handle ipmi soft power off request
+ bool iv_graceful_shutdown_pending;
+
// Disallow copying this class.
IpmiRP& operator=(const IpmiRP&);
IpmiRP(const IpmiRP&);
OpenPOWER on IntegriCloud