xref: /openbmc/phosphor-logging/extensions/openpower-pels/pldm_interface.cpp (revision a44efe48bb03c369d02f2c5e93506d2718d04d18)
15c350fdfSMatt Spinler /**
25c350fdfSMatt Spinler  * Copyright © 2019 IBM Corporation
35c350fdfSMatt Spinler  *
45c350fdfSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
55c350fdfSMatt Spinler  * you may not use this file except in compliance with the License.
65c350fdfSMatt Spinler  * You may obtain a copy of the License at
75c350fdfSMatt Spinler  *
85c350fdfSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
95c350fdfSMatt Spinler  *
105c350fdfSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
115c350fdfSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
125c350fdfSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c350fdfSMatt Spinler  * See the License for the specific language governing permissions and
145c350fdfSMatt Spinler  * limitations under the License.
155c350fdfSMatt Spinler  */
165c350fdfSMatt Spinler #include "pldm_interface.hpp"
175c350fdfSMatt Spinler 
185c350fdfSMatt Spinler #include <libpldm/base.h>
195c350fdfSMatt Spinler #include <libpldm/file_io.h>
205c350fdfSMatt Spinler #include <unistd.h>
215c350fdfSMatt Spinler 
225c350fdfSMatt Spinler #include <fstream>
235c350fdfSMatt Spinler #include <phosphor-logging/log.hpp>
245c350fdfSMatt Spinler 
255c350fdfSMatt Spinler namespace openpower::pels
265c350fdfSMatt Spinler {
275c350fdfSMatt Spinler 
285c350fdfSMatt Spinler using namespace phosphor::logging;
295c350fdfSMatt Spinler using namespace sdeventplus;
305c350fdfSMatt Spinler using namespace sdeventplus::source;
315c350fdfSMatt Spinler 
325c350fdfSMatt Spinler constexpr auto eidPath = "/usr/share/pldm/host_eid";
335c350fdfSMatt Spinler constexpr mctp_eid_t defaultEIDValue = 9;
345c350fdfSMatt Spinler 
355c350fdfSMatt Spinler constexpr uint16_t pelFileType = 0;
365c350fdfSMatt Spinler 
375c350fdfSMatt Spinler PLDMInterface::~PLDMInterface()
385c350fdfSMatt Spinler {
395c350fdfSMatt Spinler     closeFD();
405c350fdfSMatt Spinler }
415c350fdfSMatt Spinler 
425c350fdfSMatt Spinler void PLDMInterface::closeFD()
435c350fdfSMatt Spinler {
445c350fdfSMatt Spinler     if (_fd >= 0)
455c350fdfSMatt Spinler     {
465c350fdfSMatt Spinler         close(_fd);
475c350fdfSMatt Spinler         _fd = -1;
485c350fdfSMatt Spinler     }
495c350fdfSMatt Spinler }
505c350fdfSMatt Spinler 
515c350fdfSMatt Spinler void PLDMInterface::readEID()
525c350fdfSMatt Spinler {
535c350fdfSMatt Spinler     _eid = defaultEIDValue;
545c350fdfSMatt Spinler 
555c350fdfSMatt Spinler     std::ifstream eidFile{eidPath};
565c350fdfSMatt Spinler     if (!eidFile.good())
575c350fdfSMatt Spinler     {
585c350fdfSMatt Spinler         log<level::ERR>("Could not open host EID file");
595c350fdfSMatt Spinler     }
605c350fdfSMatt Spinler     else
615c350fdfSMatt Spinler     {
625c350fdfSMatt Spinler         std::string eid;
635c350fdfSMatt Spinler         eidFile >> eid;
645c350fdfSMatt Spinler         if (!eid.empty())
655c350fdfSMatt Spinler         {
665c350fdfSMatt Spinler             _eid = atoi(eid.c_str());
675c350fdfSMatt Spinler         }
685c350fdfSMatt Spinler         else
695c350fdfSMatt Spinler         {
705c350fdfSMatt Spinler             log<level::ERR>("EID file was empty");
715c350fdfSMatt Spinler         }
725c350fdfSMatt Spinler     }
735c350fdfSMatt Spinler }
745c350fdfSMatt Spinler 
755c350fdfSMatt Spinler void PLDMInterface::open()
765c350fdfSMatt Spinler {
775c350fdfSMatt Spinler     _fd = pldm_open();
785c350fdfSMatt Spinler     if (_fd < 0)
795c350fdfSMatt Spinler     {
805c350fdfSMatt Spinler         auto e = errno;
815c350fdfSMatt Spinler         log<level::ERR>("pldm_open failed", entry("ERRNO=%d", e),
825c350fdfSMatt Spinler                         entry("RC=%d\n", _fd));
835c350fdfSMatt Spinler         throw std::exception{};
845c350fdfSMatt Spinler     }
855c350fdfSMatt Spinler }
865c350fdfSMatt Spinler 
875c350fdfSMatt Spinler CmdStatus PLDMInterface::sendNewLogCmd(uint32_t id, uint32_t size)
885c350fdfSMatt Spinler {
895c350fdfSMatt Spinler     try
905c350fdfSMatt Spinler     {
915c350fdfSMatt Spinler         closeFD();
925c350fdfSMatt Spinler 
935c350fdfSMatt Spinler         open();
945c350fdfSMatt Spinler 
955c350fdfSMatt Spinler         readInstanceID();
965c350fdfSMatt Spinler 
975c350fdfSMatt Spinler         registerReceiveCallback();
985c350fdfSMatt Spinler 
995c350fdfSMatt Spinler         doSend(id, size);
1005c350fdfSMatt Spinler     }
1015c350fdfSMatt Spinler     catch (const std::exception& e)
1025c350fdfSMatt Spinler     {
1035c350fdfSMatt Spinler         closeFD();
1045c350fdfSMatt Spinler 
1055c350fdfSMatt Spinler         _inProgress = false;
1065c350fdfSMatt Spinler         _source.reset();
1075c350fdfSMatt Spinler         return CmdStatus::failure;
1085c350fdfSMatt Spinler     }
1095c350fdfSMatt Spinler 
1105c350fdfSMatt Spinler     _inProgress = true;
1115c350fdfSMatt Spinler     _receiveTimer.restartOnce(_receiveTimeout);
1125c350fdfSMatt Spinler     return CmdStatus::success;
1135c350fdfSMatt Spinler }
1145c350fdfSMatt Spinler 
1155c350fdfSMatt Spinler void PLDMInterface::registerReceiveCallback()
1165c350fdfSMatt Spinler {
1175c350fdfSMatt Spinler     _source = std::make_unique<IO>(
1185c350fdfSMatt Spinler         _event, _fd, EPOLLIN,
1195c350fdfSMatt Spinler         std::bind(std::mem_fn(&PLDMInterface::receive), this,
1205c350fdfSMatt Spinler                   std::placeholders::_1, std::placeholders::_2,
1215c350fdfSMatt Spinler                   std::placeholders::_3));
1225c350fdfSMatt Spinler }
1235c350fdfSMatt Spinler 
1245c350fdfSMatt Spinler void PLDMInterface::readInstanceID()
1255c350fdfSMatt Spinler {
1265c350fdfSMatt Spinler     try
1275c350fdfSMatt Spinler     {
1285c350fdfSMatt Spinler         _instanceID = _dataIface.getPLDMInstanceID(_eid);
1295c350fdfSMatt Spinler     }
1305c350fdfSMatt Spinler     catch (const std::exception& e)
1315c350fdfSMatt Spinler     {
1325c350fdfSMatt Spinler         log<level::ERR>(
1335c350fdfSMatt Spinler             "Failed to get instance ID from PLDM Requester D-Bus daemon",
1345c350fdfSMatt Spinler             entry("ERROR=%s", e.what()));
1355c350fdfSMatt Spinler         throw;
1365c350fdfSMatt Spinler     }
1375c350fdfSMatt Spinler }
1385c350fdfSMatt Spinler 
1395c350fdfSMatt Spinler void PLDMInterface::doSend(uint32_t id, uint32_t size)
1405c350fdfSMatt Spinler {
1415c350fdfSMatt Spinler     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(pelFileType) +
1429694ba62SDeepak Kodihalli                             sizeof(id) + sizeof(uint64_t)>
1435c350fdfSMatt Spinler         requestMsg;
1445c350fdfSMatt Spinler 
1455c350fdfSMatt Spinler     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
1465c350fdfSMatt Spinler 
1475c350fdfSMatt Spinler     auto rc = encode_new_file_req(_instanceID, pelFileType, id, size, request);
1485c350fdfSMatt Spinler     if (rc != PLDM_SUCCESS)
1495c350fdfSMatt Spinler     {
1505c350fdfSMatt Spinler         log<level::ERR>("encode_new_file_req failed", entry("RC=%d", rc));
1515c350fdfSMatt Spinler         throw std::exception{};
1525c350fdfSMatt Spinler     }
1535c350fdfSMatt Spinler 
1545c350fdfSMatt Spinler     rc = pldm_send(_eid, _fd, requestMsg.data(), requestMsg.size());
1555c350fdfSMatt Spinler     if (rc < 0)
1565c350fdfSMatt Spinler     {
1575c350fdfSMatt Spinler         auto e = errno;
1585c350fdfSMatt Spinler         log<level::ERR>("pldm_send failed", entry("RC=%d", rc),
1595c350fdfSMatt Spinler                         entry("ERRNO=%d", e));
1605c350fdfSMatt Spinler 
1615c350fdfSMatt Spinler         throw std::exception{};
1625c350fdfSMatt Spinler     }
1635c350fdfSMatt Spinler }
1645c350fdfSMatt Spinler 
1655c350fdfSMatt Spinler void PLDMInterface::receive(IO& io, int fd, uint32_t revents)
1665c350fdfSMatt Spinler {
1675c350fdfSMatt Spinler     if (!(revents & EPOLLIN))
1685c350fdfSMatt Spinler     {
1695c350fdfSMatt Spinler         return;
1705c350fdfSMatt Spinler     }
1715c350fdfSMatt Spinler 
1725c350fdfSMatt Spinler     uint8_t* responseMsg = nullptr;
1735c350fdfSMatt Spinler     size_t responseSize = 0;
1745c350fdfSMatt Spinler     ResponseStatus status = ResponseStatus::success;
1755c350fdfSMatt Spinler 
1765c350fdfSMatt Spinler     auto rc = pldm_recv(_eid, fd, _instanceID, &responseMsg, &responseSize);
1775c350fdfSMatt Spinler     if (rc < 0)
1785c350fdfSMatt Spinler     {
1795c350fdfSMatt Spinler         if (rc == PLDM_REQUESTER_INSTANCE_ID_MISMATCH)
1805c350fdfSMatt Spinler         {
1815c350fdfSMatt Spinler             // We got a response to someone else's message. Ignore it.
1825c350fdfSMatt Spinler             return;
1835c350fdfSMatt Spinler         }
1845c350fdfSMatt Spinler         else if (rc == PLDM_REQUESTER_NOT_RESP_MSG)
1855c350fdfSMatt Spinler         {
1865c350fdfSMatt Spinler             // Due to the MCTP loopback, we may get notified of the message
1875c350fdfSMatt Spinler             // we just sent.
1885c350fdfSMatt Spinler             return;
1895c350fdfSMatt Spinler         }
1905c350fdfSMatt Spinler 
1915c350fdfSMatt Spinler         auto e = errno;
1925c350fdfSMatt Spinler         log<level::ERR>("pldm_recv failed", entry("RC=%d", rc),
1935c350fdfSMatt Spinler                         entry("ERRNO=%d", e));
1945c350fdfSMatt Spinler         status = ResponseStatus::failure;
1955c350fdfSMatt Spinler 
1965c350fdfSMatt Spinler         responseMsg = nullptr;
1975c350fdfSMatt Spinler     }
1985c350fdfSMatt Spinler 
1995c350fdfSMatt Spinler     _inProgress = false;
2005c350fdfSMatt Spinler     _receiveTimer.setEnabled(false);
2015c350fdfSMatt Spinler     closeFD();
2025c350fdfSMatt Spinler     _source.reset();
2035c350fdfSMatt Spinler 
2045c350fdfSMatt Spinler     if (status == ResponseStatus::success)
2055c350fdfSMatt Spinler     {
2065c350fdfSMatt Spinler         uint8_t completionCode = 0;
2075c350fdfSMatt Spinler         auto response = reinterpret_cast<pldm_msg*>(responseMsg);
2085c350fdfSMatt Spinler 
2095c350fdfSMatt Spinler         auto decodeRC = decode_new_file_resp(response, PLDM_NEW_FILE_RESP_BYTES,
2105c350fdfSMatt Spinler                                              &completionCode);
2115c350fdfSMatt Spinler         if (decodeRC < 0)
2125c350fdfSMatt Spinler         {
2135c350fdfSMatt Spinler             log<level::ERR>("decode_new_file_resp failed",
2145c350fdfSMatt Spinler                             entry("RC=%d", decodeRC));
2155c350fdfSMatt Spinler             status = ResponseStatus::failure;
2165c350fdfSMatt Spinler         }
2175c350fdfSMatt Spinler         else
2185c350fdfSMatt Spinler         {
2195c350fdfSMatt Spinler             if (completionCode != PLDM_SUCCESS)
2205c350fdfSMatt Spinler             {
2215c350fdfSMatt Spinler                 log<level::ERR>("Bad PLDM completion code",
2225c350fdfSMatt Spinler                                 entry("COMPLETION_CODE=%d", completionCode));
2235c350fdfSMatt Spinler                 status = ResponseStatus::failure;
2245c350fdfSMatt Spinler             }
2255c350fdfSMatt Spinler         }
2265c350fdfSMatt Spinler     }
2275c350fdfSMatt Spinler 
228*a44efe48SMatt Spinler     callResponseFunc(status);
2295c350fdfSMatt Spinler 
2305c350fdfSMatt Spinler     if (responseMsg)
2315c350fdfSMatt Spinler     {
2325c350fdfSMatt Spinler         free(responseMsg);
2335c350fdfSMatt Spinler     }
2345c350fdfSMatt Spinler }
2355c350fdfSMatt Spinler 
2365c350fdfSMatt Spinler void PLDMInterface::receiveTimerExpired()
2375c350fdfSMatt Spinler {
2385c350fdfSMatt Spinler     log<level::ERR>("Timed out waiting for PLDM response");
2395c350fdfSMatt Spinler     cancelCmd();
2405c350fdfSMatt Spinler 
241*a44efe48SMatt Spinler     callResponseFunc(ResponseStatus::failure);
2425c350fdfSMatt Spinler }
2435c350fdfSMatt Spinler 
2445c350fdfSMatt Spinler void PLDMInterface::cancelCmd()
2455c350fdfSMatt Spinler {
2465c350fdfSMatt Spinler     _inProgress = false;
2475c350fdfSMatt Spinler     _source.reset();
2485c350fdfSMatt Spinler 
2495c350fdfSMatt Spinler     if (_receiveTimer.isEnabled())
2505c350fdfSMatt Spinler     {
2515c350fdfSMatt Spinler         _receiveTimer.setEnabled(false);
2525c350fdfSMatt Spinler     }
2535c350fdfSMatt Spinler 
2545c350fdfSMatt Spinler     closeFD();
2555c350fdfSMatt Spinler }
2565c350fdfSMatt Spinler 
2575c350fdfSMatt Spinler } // namespace openpower::pels
258