1 #pragma once 2 3 #include "host_interface.hpp" 4 5 #include <libpldm/instance-id.h> 6 #include <libpldm/pldm.h> 7 #include <libpldm/transport.h> 8 #include <libpldm/transport/mctp-demux.h> 9 10 #include <sdeventplus/clock.hpp> 11 #include <sdeventplus/source/io.hpp> 12 #include <sdeventplus/utility/timer.hpp> 13 14 #include <chrono> 15 #include <memory> 16 17 namespace openpower::pels 18 { 19 20 /** 21 * @class PLDMInterface 22 * 23 * This class handles sending the 'new file available' PLDM 24 * command to the host to notify it of a new PEL's ID and size. 25 * 26 * The command response is asynchronous. 27 */ 28 class PLDMInterface : public HostInterface 29 { 30 public: 31 PLDMInterface() = delete; 32 PLDMInterface(const PLDMInterface&) = default; 33 PLDMInterface& operator=(const PLDMInterface&) = default; 34 PLDMInterface(PLDMInterface&&) = default; 35 PLDMInterface& operator=(PLDMInterface&&) = default; 36 37 /** 38 * @brief Constructor 39 * 40 * @param[in] event - The sd_event object pointer 41 * @param[in] dataIface - The DataInterface object 42 */ 43 PLDMInterface(sd_event* event, DataInterfaceBase& dataIface) : 44 HostInterface(event, dataIface), 45 _receiveTimer( 46 event, 47 std::bind(std::mem_fn(&PLDMInterface::receiveTimerExpired), this)) 48 { 49 pldm_instance_db_init_default(&_pldm_idb); 50 51 readEID(); 52 } 53 54 /** 55 * @brief Destructor 56 */ 57 ~PLDMInterface(); 58 59 /** 60 * @brief Kicks off the send of the 'new file available' command 61 * to send up the ID and size of the new PEL. 62 * 63 * It starts by issuing the async D-Bus method call to read the 64 * instance ID. 65 * 66 * @param[in] id - The PEL ID 67 * @param[in] size - The PEL size in bytes 68 * 69 * @return CmdStatus - the success/fail status of the send 70 */ 71 CmdStatus sendNewLogCmd(uint32_t id, uint32_t size) override; 72 73 /** 74 * @brief Cancels waiting for a command response 75 * 76 * This will clear the instance ID so the next command 77 * will request a new one. 78 */ 79 void cancelCmd() override; 80 81 /** 82 * @brief Cleans up so that a new command is ready to be sent. 83 * 84 * Does not clear the instance ID. 85 */ 86 void cleanupCmd(); 87 88 private: 89 /** 90 * @brief The asynchronous callback for getting the response 91 * of the 'new file available' command. 92 * 93 * Calls the response callback that is registered. 94 * 95 * @param[in] io - The event source object 96 * @param[in] fd - The FD used 97 * @param[in] revents - The event bits 98 * @param[in] transport - The transport data pointer 99 */ 100 void receive(sdeventplus::source::IO& io, int fd, uint32_t revents, 101 pldm_transport* transport) override; 102 103 /** 104 * @brief Function called when the receive timer expires. 105 * 106 * This is considered a failure and so will invoke the 107 * registered response callback function with a failure 108 * indication. 109 */ 110 void receiveTimerExpired(); 111 112 /** 113 * @brief Configures the sdeventplus::source::IO object to 114 * call receive() on EPOLLIN activity on the PLDM FD 115 * which is used for command responses. 116 */ 117 void registerReceiveCallback(); 118 119 /** 120 * @brief Reads the MCTP endpoint ID out of a file 121 */ 122 void readEID(); 123 124 /** 125 * @brief Opens the PLDM file descriptor 126 */ 127 void open(); 128 129 /** @brief Opens the MCTP socket for sending and receiving messages. 130 * 131 */ 132 int openMctpDemuxTransport(); 133 134 /** 135 * @brief Encodes and sends the PLDM 'new file available' cmd 136 */ 137 void doSend(); 138 139 /** 140 * @brief Closes the PLDM file descriptor 141 */ 142 void closeFD(); 143 144 /** 145 * @brief Kicks off the send of the 'new file available' command 146 * to send the ID and size of a PEL after the instance ID 147 * has been retrieved. 148 */ 149 void startCommand(); 150 151 /** 152 * @brief Allocates the instance id. 153 */ 154 void allocIID(); 155 156 /** 157 * @brief Frees the instance id. 158 */ 159 void freeIID(); 160 161 /** 162 * @brief The MCTP endpoint ID 163 */ 164 mctp_eid_t _eid; 165 166 /** 167 * @brief The PLDM instance ID of the current command 168 * 169 * A new ID will be used for every command. 170 * 171 * If there are command failures, the same instance ID can be 172 * used on retries only if the host didn't respond. 173 */ 174 std::optional<pldm_instance_id_t> _instanceID; 175 176 /** 177 * @brief The PLDM command file descriptor for the current command 178 */ 179 int _fd = -1; 180 181 /** 182 * @brief The event object for handling callbacks on the PLDM FD 183 */ 184 std::unique_ptr<sdeventplus::source::IO> _source; 185 186 /** 187 * @brief A timer to only allow a certain amount of time for the 188 * async PLDM receive before it is considered a failure. 189 */ 190 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _receiveTimer; 191 192 /** 193 * @brief The command timeout value 194 */ 195 const std::chrono::milliseconds _receiveTimeout{45000}; 196 197 /** 198 * @brief The libpldm instance ID database. 199 */ 200 pldm_instance_db* _pldm_idb = nullptr; 201 202 /** 203 * @brief The ID of the PEL to notify the host of. 204 */ 205 uint32_t _pelID = 0; 206 207 /** 208 * @brief The size of the PEL to notify the host of. 209 */ 210 uint32_t _pelSize = 0; 211 212 /** 213 * @brief pldm transport instance. 214 */ 215 pldm_transport* pldmTransport = nullptr; 216 217 pldm_transport_mctp_demux* mctpDemux = nullptr; 218 }; 219 220 } // namespace openpower::pels 221