1 #include "file_io_type_pcie.hpp"
2 
3 #include "libpldm/base.h"
4 #include "libpldm/file_io.h"
5 
6 #include <stdint.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 
10 PHOSPHOR_LOG2_USING;
11 
12 namespace pldm
13 {
14 namespace responder
15 {
16 
17 static constexpr auto pciePath = "/var/lib/pldm/pcie-topology/";
18 constexpr auto topologyFile = "topology";
19 constexpr auto cableInfoFile = "cableinfo";
20 
21 namespace fs = std::filesystem;
22 std::unordered_map<uint16_t, bool> PCIeInfoHandler::receivedFiles;
23 
24 PCIeInfoHandler::PCIeInfoHandler(uint32_t fileHandle, uint16_t fileType) :
25     FileHandler(fileHandle), infoType(fileType)
26 {
27     receivedFiles.emplace(infoType, false);
28 }
29 
30 int PCIeInfoHandler::writeFromMemory(
31     uint32_t offset, uint32_t length, uint64_t address,
32     oem_platform::Handler* /*oemPlatformHandler*/)
33 {
34     if (!fs::exists(pciePath))
35     {
36         fs::create_directories(pciePath);
37         fs::permissions(pciePath,
38                         fs::perms::others_read | fs::perms::owner_write);
39     }
40 
41     fs::path infoFile(fs::path(pciePath) / topologyFile);
42     if (infoType == PLDM_FILE_TYPE_CABLE_INFO)
43     {
44         infoFile = (fs::path(pciePath) / cableInfoFile);
45     }
46 
47     try
48     {
49         std::ofstream pcieData(infoFile, std::ios::out | std::ios::binary);
50         auto rc = transferFileData(infoFile, false, offset, length, address);
51         if (rc != PLDM_SUCCESS)
52         {
53             error("TransferFileData failed in PCIeTopology with error {ERROR}",
54                   "ERROR", rc);
55             return rc;
56         }
57         return PLDM_SUCCESS;
58     }
59     catch (const std::exception& e)
60     {
61         error("Create/Write data to the File type {TYPE}, failed {ERROR}",
62               "TYPE", infoType, "ERROR", e);
63         return PLDM_ERROR;
64     }
65 }
66 
67 int PCIeInfoHandler::write(const char* buffer, uint32_t, uint32_t& length,
68                            oem_platform::Handler* /*oemPlatformHandler*/)
69 {
70     fs::path infoFile(fs::path(pciePath) / topologyFile);
71     if (infoType == PLDM_FILE_TYPE_CABLE_INFO)
72     {
73         infoFile = (fs::path(pciePath) / cableInfoFile);
74     }
75 
76     try
77     {
78         std::ofstream pcieData(infoFile, std::ios::out | std::ios::binary |
79                                              std::ios::app);
80 
81         if (!buffer)
82         {
83             pcieData.write(buffer, length);
84         }
85         pcieData.close();
86     }
87     catch (const std::exception& e)
88     {
89         error("Create/Write data to the File type {TYPE}, failed {ERROR}",
90               "TYPE", infoType, "ERROR", e);
91         return PLDM_ERROR;
92     }
93 
94     return PLDM_SUCCESS;
95 }
96 
97 int PCIeInfoHandler::fileAck(uint8_t /*fileStatus*/)
98 {
99     receivedFiles[infoType] = true;
100     try
101     {
102         if (receivedFiles.at(PLDM_FILE_TYPE_CABLE_INFO) &&
103             receivedFiles.at(PLDM_FILE_TYPE_PCIE_TOPOLOGY))
104         {
105             receivedFiles.clear();
106         }
107     }
108     catch (const std::out_of_range& e)
109     {
110         info("Received only one of the topology file");
111     }
112     return PLDM_SUCCESS;
113 }
114 
115 } // namespace responder
116 } // namespace pldm
117