diff options
Diffstat (limited to 'src/usr/ipmi')
-rw-r--r-- | src/usr/ipmi/ipmidd.C | 42 | ||||
-rw-r--r-- | src/usr/ipmi/ipmidd.H | 10 | ||||
-rw-r--r-- | src/usr/ipmi/ipmirp.C | 78 | ||||
-rw-r--r-- | src/usr/ipmi/ipmirp.H | 9 |
4 files changed, 122 insertions, 17 deletions
diff --git a/src/usr/ipmi/ipmidd.C b/src/usr/ipmi/ipmidd.C index 4484daca5..7e5e3722c 100644 --- a/src/usr/ipmi/ipmidd.C +++ b/src/usr/ipmi/ipmidd.C @@ -208,6 +208,8 @@ static void* poll_control_register( void* /* unused */ ) */ void IpmiDD::pollCtrl(void) { + IPMI_TRAC(ENTER_MRK "poll_control_register" ); + // Mark as an independent daemon so if it crashes we terminate. task_detach(); @@ -222,12 +224,14 @@ void IpmiDD::pollCtrl(void) 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) { + mutex_unlock(&iv_mutex); IPMI_TRAC(ERR_MRK "polling loop encountered an error, exiting"); errlCommit(err, IPMI_COMP_ID); break; @@ -238,14 +242,22 @@ void IpmiDD::pollCtrl(void) // 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) + if ((ctrl & IDLE_STATE) == 0) { - msg = msg_allocate(); - msg->type = IPMI::MSG_STATE_IDLE; - msg_send(mq, msg); - iv_eagains = false; + if (iv_eagains) + { + msg = msg_allocate(); + msg->type = IPMI::MSG_STATE_IDLE; + msg_send(mq, msg); + iv_eagains = false; + } + // Check on shutdown if idle + else if (iv_shutdown_now) + { + mutex_unlock(&iv_mutex); + break; // exit loop and terminate task + } } - // If we see the B2H_ATN, there's a response waiting else if (ctrl & CTRL_B2H_ATN) { @@ -264,8 +276,10 @@ void IpmiDD::pollCtrl(void) } } mutex_unlock(&iv_mutex); + nanosleep(0, WAIT_TIME); } + IPMI_TRAC(EXIT_MRK "poll_control_register" ); } /** @@ -473,9 +487,25 @@ errlHndl_t IpmiDD::receive(IPMI::BTMessage* o_msg) } /** + * @brief shutdown the device driver + */ +void IpmiDD::handleShutdown(void) +{ + IPMI_TRAC(ENTER_MRK "handle Shutdown" ); + mutex_lock(&iv_mutex); + iv_shutdown_now = true; // signal poll controller to terminate + + // TODO: RTC 116600 mask interrupts + + mutex_unlock(&iv_mutex); + IPMI_TRAC(EXIT_MRK "handle Shutdown" ); +} + +/** * @brief Constructor */ IpmiDD::IpmiDD(void): + iv_shutdown_now(false), iv_eagains(false) { mutex_init(&iv_mutex); diff --git a/src/usr/ipmi/ipmidd.H b/src/usr/ipmi/ipmidd.H index d20dd6132..2faed9b3b 100644 --- a/src/usr/ipmi/ipmidd.H +++ b/src/usr/ipmi/ipmidd.H @@ -76,6 +76,11 @@ class IpmiDD errlHndl_t reset(void); /** + * @brief shutdown the device driver + */ + void handleShutdown(void); + + /** * @brief Constructor * * @parm void @@ -111,6 +116,11 @@ class IpmiDD mutex_t iv_mutex; /** + * @brief Shut down resources + */ + bool iv_shutdown_now; + + /** * @brief True if we told the RP to try a write again */ bool iv_eagains; diff --git a/src/usr/ipmi/ipmirp.C b/src/usr/ipmi/ipmirp.C index 12b5015a2..9265e06b7 100644 --- a/src/usr/ipmi/ipmirp.C +++ b/src/usr/ipmi/ipmirp.C @@ -29,6 +29,7 @@ #include "ipmirp.H" #include "ipmiconfig.H" +#include "ipmidd.H" #include <ipmi/ipmi_reasoncodes.H> #include <devicefw/driverif.H> #include <devicefw/userif.H> @@ -69,7 +70,9 @@ IpmiRP::IpmiRP(void): iv_outstanding_req(IPMI::g_outstanding_req), iv_xmit_buffer_size(IPMI::g_xmit_buffer_size), iv_recv_buffer_size(IPMI::g_recv_buffer_size), - iv_retries(IPMI::g_retries) + iv_retries(IPMI::g_retries), + iv_shutdown_msg(NULL), + iv_shutdown_now(false) { mutex_init(&iv_mutex); sync_cond_init(&iv_cv); @@ -152,6 +155,8 @@ void IpmiRP::timeoutThread(void) // Mark as an independent daemon so if it crashes we terminate. task_detach(); + IPMI_TRAC(ENTER_MRK "time out thread"); + // If there's something on the queue we want to grab it's timeout time // and wait. Note the response queue is "sorted" as we send messages in // order. So, the first message on the queue is the one who's timeout @@ -159,11 +164,17 @@ void IpmiRP::timeoutThread(void) while (true) { mutex_lock(&iv_mutex); - while (iv_timeoutq.size() == 0) + while ((iv_timeoutq.size() == 0) && !iv_shutdown_now) { sync_cond_wait(&iv_cv, &iv_mutex); } + // shutting down... + if (iv_shutdown_now) + { + break; // return and terminate thread + } + msg_t*& msq_msg = iv_timeoutq.front(); IPMI::Message* msg = static_cast<IPMI::Message*>(msq_msg->extra_data); @@ -186,6 +197,12 @@ void IpmiRP::timeoutThread(void) // Get him off the responseq, and reply back to the waiter that // there was a timeout response(msg, IPMI::CC_TIMEOUT); + + // Tell the resource provider to check for any pending messages + msg_t* msg_idleMsg = msg_allocate(); + msg_idleMsg->type = IPMI::MSG_STATE_IDLE; + msg_send(iv_msgQ, msg_idleMsg); + mutex_unlock(&iv_mutex); } else @@ -194,6 +211,7 @@ void IpmiRP::timeoutThread(void) nanosleep( 0, timeout - now ); } } + IPMI_TRAC(EXIT_MRK "time out thread"); return; } @@ -266,7 +284,7 @@ void IpmiRP::getInterfaceCapabilities(void) */ void IpmiRP::execute(void) { - bool shutdown_pending = false; + bool l_shutdown_pending = false; // Mark as an independent daemon so if it crashes we terminate. task_detach(); @@ -307,7 +325,19 @@ void IpmiRP::execute(void) // bottom of this loop will start the transmit process. // Be sure to push_back to ensure ordering of transmission. case IPMI::MSG_STATE_SEND: - iv_sendq.push_back(msg); + if (!l_shutdown_pending) + { + iv_sendq.push_back(msg); + } + // shutting down, do not accept new messages + else + { + IPMI_TRAC(WARN_MRK "IPMI shutdown pending. Message dropped"); + IPMI::Message* ipmi_msg = + static_cast<IPMI::Message*>(msg->extra_data); + response(ipmi_msg, IPMI::CC_BADSTATE); + msg_free(msg); + } break; // State changes from the IPMI hardware. These are async @@ -333,8 +363,9 @@ 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 shutting down"); - shutdown_pending = true; + IPMI_TRAC(INFO_MRK "ipmi begin shutdown"); + l_shutdown_pending = true; // Stop incoming new messages + iv_shutdown_msg = msg; // Reply to this message break; }; @@ -350,12 +381,11 @@ void IpmiRP::execute(void) idle(); } - // TODO: RTC 106887 Hold off transmitters, drain queues. - // Patrick suggests handling this like mailboxes. - if (shutdown_pending && iv_respondq.empty() && iv_sendq.empty()) + // Once quiesced, shutdown and reply to shutdown msg + if (l_shutdown_pending && iv_respondq.empty() && iv_sendq.empty()) { - msg_respond(iv_msgQ, msg); - break; + shutdownNow(); + break; // exit loop and terminate task } } @@ -559,6 +589,32 @@ void IpmiRP::queueForResponse(IPMI::Message& i_msg) return; } +/// +/// @brief handle shutdown. +/// Queued messages to send have been sent and all responses complete. +/// Now that we are quiesced, deallocate resources and respond to the +/// shutdown message +/// +void IpmiRP::shutdownNow(void) +{ + IPMI_TRAC(INFO_MRK "ipmi shut down now"); + + mutex_lock(&iv_mutex); + iv_shutdown_now = true; // Shutdown underway + + // Wake up Time out thread to terminate. + sync_cond_signal(&iv_cv); + mutex_unlock(&iv_mutex); + + // TODO: RTC 116600 unRegisterMsgQ for interrupts + + // Shut down device driver + Singleton<IpmiDD>::instance().handleShutdown(); + + // reply back to shutdown requester that we are shutdown + msg_respond(iv_msgQ, iv_shutdown_msg); +} + namespace IPMI { diff --git a/src/usr/ipmi/ipmirp.H b/src/usr/ipmi/ipmirp.H index 2edf24e9a..d1ebaad7d 100644 --- a/src/usr/ipmi/ipmirp.H +++ b/src/usr/ipmi/ipmirp.H @@ -193,6 +193,12 @@ class IpmiRP */ void getInterfaceCapabilities(void); + /** + * @brief Clean up resources and reply to shutdown msg + * @param[in] void + */ + void shutdownNow(void); + msg_q_t iv_msgQ; //!< ipmi mesage queue IPMI::send_q_t iv_sendq; //!< msg to send queue IPMI::timeout_q_t iv_timeoutq; //!< msgs waiting for a timeout @@ -218,6 +224,9 @@ class IpmiRP // Recomended number of retries uint8_t iv_retries; + // Shutdown + msg_t * iv_shutdown_msg; //!< shutdown msg to respond to + bool iv_shutdown_now; //!< shutdown now // Disallow copying this class. IpmiRP& operator=(const IpmiRP&); |