blob: b907af4847b744c988783f79c30fe903af122b31 [file] [log] [blame]
#pragma once
#include "host_interface.hpp"
#include <libpldm/instance-id.h>
#include <libpldm/pldm.h>
#include <libpldm/transport.h>
#include <libpldm/transport/mctp-demux.h>
#include <sdeventplus/clock.hpp>
#include <sdeventplus/source/io.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <chrono>
#include <memory>
namespace openpower::pels
{
/**
* @class PLDMInterface
*
* This class handles sending the 'new file available' PLDM
* command to the host to notify it of a new PEL's ID and size.
*
* The command response is asynchronous.
*/
class PLDMInterface : public HostInterface
{
public:
PLDMInterface() = delete;
PLDMInterface(const PLDMInterface&) = default;
PLDMInterface& operator=(const PLDMInterface&) = default;
PLDMInterface(PLDMInterface&&) = default;
PLDMInterface& operator=(PLDMInterface&&) = default;
/**
* @brief Constructor
*
* @param[in] event - The sd_event object pointer
* @param[in] dataIface - The DataInterface object
*/
PLDMInterface(sd_event* event, DataInterfaceBase& dataIface) :
HostInterface(event, dataIface),
_receiveTimer(
event,
std::bind(std::mem_fn(&PLDMInterface::receiveTimerExpired), this))
{
pldm_instance_db_init_default(&_pldm_idb);
readEID();
}
/**
* @brief Destructor
*/
~PLDMInterface();
/**
* @brief Kicks off the send of the 'new file available' command
* to send up the ID and size of the new PEL.
*
* It starts by issuing the async D-Bus method call to read the
* instance ID.
*
* @param[in] id - The PEL ID
* @param[in] size - The PEL size in bytes
*
* @return CmdStatus - the success/fail status of the send
*/
CmdStatus sendNewLogCmd(uint32_t id, uint32_t size) override;
/**
* @brief Cancels waiting for a command response
*
* This will clear the instance ID so the next command
* will request a new one.
*/
void cancelCmd() override;
/**
* @brief Cleans up so that a new command is ready to be sent.
*
* Does not clear the instance ID.
*/
void cleanupCmd();
private:
/**
* @brief The asynchronous callback for getting the response
* of the 'new file available' command.
*
* Calls the response callback that is registered.
*
* @param[in] io - The event source object
* @param[in] fd - The FD used
* @param[in] revents - The event bits
* @param[in] transport - The transport data pointer
*/
void receive(sdeventplus::source::IO& io, int fd, uint32_t revents,
pldm_transport* transport) override;
/**
* @brief Function called when the receive timer expires.
*
* This is considered a failure and so will invoke the
* registered response callback function with a failure
* indication.
*/
void receiveTimerExpired();
/**
* @brief Configures the sdeventplus::source::IO object to
* call receive() on EPOLLIN activity on the PLDM FD
* which is used for command responses.
*/
void registerReceiveCallback();
/**
* @brief Reads the MCTP endpoint ID out of a file
*/
void readEID();
/**
* @brief Opens the PLDM file descriptor
*/
void open();
/** @brief Opens the MCTP socket for sending and receiving messages.
*
*/
int openMctpDemuxTransport();
/**
* @brief Encodes and sends the PLDM 'new file available' cmd
*/
void doSend();
/**
* @brief Closes the PLDM file descriptor
*/
void closeFD();
/**
* @brief Kicks off the send of the 'new file available' command
* to send the ID and size of a PEL after the instance ID
* has been retrieved.
*/
void startCommand();
/**
* @brief Allocates the instance id.
*/
void allocIID();
/**
* @brief Frees the instance id.
*/
void freeIID();
/**
* @brief The MCTP endpoint ID
*/
mctp_eid_t _eid;
/**
* @brief The PLDM instance ID of the current command
*
* A new ID will be used for every command.
*
* If there are command failures, the same instance ID can be
* used on retries only if the host didn't respond.
*/
std::optional<pldm_instance_id_t> _instanceID;
/**
* @brief The PLDM command file descriptor for the current command
*/
int _fd = -1;
/**
* @brief The event object for handling callbacks on the PLDM FD
*/
std::unique_ptr<sdeventplus::source::IO> _source;
/**
* @brief A timer to only allow a certain amount of time for the
* async PLDM receive before it is considered a failure.
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _receiveTimer;
/**
* @brief The command timeout value
*/
const std::chrono::milliseconds _receiveTimeout{10000};
/**
* @brief The libpldm instance ID database.
*/
pldm_instance_db* _pldm_idb = nullptr;
/**
* @brief The ID of the PEL to notify the host of.
*/
uint32_t _pelID = 0;
/**
* @brief The size of the PEL to notify the host of.
*/
uint32_t _pelSize = 0;
/**
* @brief pldm transport instance.
*/
pldm_transport* pldmTransport = nullptr;
pldm_transport_mctp_demux* mctpDemux = nullptr;
};
} // namespace openpower::pels