xref: /openbmc/phosphor-debug-collector/host-transport-extensions/pldm/oem/ibm/pldm_oem_cmds.cpp (revision ecdd36d8d3c783e03588f0b7a9007f3abd3edc9b)
1 /**
2  * Copyright © 2019 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "pldm_oem_cmds.hpp"
17 
18 #include "dump_utils.hpp"
19 #include "host-transport-extensions/pldm/common/pldm_utils.hpp"
20 #include "xyz/openbmc_project/Common/error.hpp"
21 
22 #include <libpldm/base.h>
23 #include <libpldm/oem/ibm/file_io.h>
24 #include <libpldm/platform.h>
25 #include <unistd.h>
26 
27 #include <phosphor-logging/elog-errors.hpp>
28 #include <phosphor-logging/lg2.hpp>
29 #include <sdbusplus/bus.hpp>
30 
31 #include <fstream>
32 
33 namespace phosphor
34 {
35 namespace dump
36 {
37 namespace host
38 {
39 /**
40  * @brief Initiate offload of the dump with provided id
41  *
42  * @param[in] id - The Dump Source ID.
43  *
44  */
requestOffload(uint32_t id)45 void requestOffload(uint32_t id)
46 {
47     pldm::requestOffload(id);
48 }
49 
requestDelete(uint32_t id,uint32_t dumpType)50 void requestDelete(uint32_t id, uint32_t dumpType)
51 {
52     pldm::requestDelete(id, dumpType);
53 }
54 } // namespace host
55 
56 namespace pldm
57 {
58 
59 using namespace phosphor::logging;
60 
61 constexpr auto eidPath = "/usr/share/pldm/host_eid";
62 constexpr mctp_eid_t defaultEIDValue = 9;
63 
64 PLDMInstanceManager instanceManager;
65 
66 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
67 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
68 
readEID()69 mctp_eid_t readEID()
70 {
71     mctp_eid_t eid = defaultEIDValue;
72 
73     std::ifstream eidFile{eidPath};
74     if (!eidFile.good())
75     {
76         lg2::error("Could not open host EID file");
77         elog<NotAllowed>(Reason("Required host dump action via pldm is not "
78                                 "allowed due to mctp end point read failed"));
79     }
80     else
81     {
82         std::string eidStr;
83         eidFile >> eidStr;
84         if (!eidStr.empty())
85         {
86             eid = strtol(eidStr.c_str(), nullptr, 10);
87         }
88         else
89         {
90             lg2::error("EID file was empty");
91             elog<NotAllowed>(Reason(
92                 "Required host dump action via pldm is not "
93                 "allowed due to mctp end point read failed"));
94         }
95     }
96 
97     return eid;
98 }
99 
requestOffload(uint32_t id)100 void requestOffload(uint32_t id)
101 {
102     uint16_t effecterId = 0x05; // TODO PhyP temporary Hardcoded value.
103 
104     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(id) +
105                             sizeof(uint8_t)>
106         requestMsg{};
107     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
108 
109     std::array<uint8_t, sizeof(id)> effecterValue{};
110 
111     memcpy(effecterValue.data(), &id, sizeof(id));
112 
113     mctp_eid_t eid = readEID();
114 
115     auto instanceID = getPLDMInstanceID(eid);
116 
117     auto rc = encode_set_numeric_effecter_value_req(
118         instanceID, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
119         effecterValue.data(), request,
120         requestMsg.size() - sizeof(pldm_msg_hdr));
121 
122     if (rc != PLDM_SUCCESS)
123     {
124         freePLDMInstanceID(instanceID, eid);
125         lg2::error("Message encode failure. RC: {RC}", "RC", rc);
126         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
127                                 "allowed due to encode failed"));
128     }
129 
130     rc = openPLDM(eid);
131     if (rc < 0)
132     {
133         freePLDMInstanceID(instanceID, eid);
134         lg2::error(" openPLDMfailure. RC: {RC}", "RC", rc);
135         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
136                                 "allowed due to openPLDM failed"));
137     }
138 
139     lg2::info("Sending request to offload dump id: {ID}, eid: {EID}", "ID", id,
140               "EID", eid);
141 
142     pldm_tid_t pldmTID = static_cast<pldm_tid_t>(eid);
143     rc = pldm_transport_send_msg(pldmTransport, pldmTID, requestMsg.data(),
144                                  requestMsg.size());
145     if (rc < 0)
146     {
147         freePLDMInstanceID(instanceID, eid);
148         pldmClose();
149         auto e = errno;
150         lg2::error("pldm_transport_send_msg failed, RC: {RC}, errno: {ERRNO}",
151                    "RC", rc, "ERRNO", e);
152         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
153                                 "allowed due to fileack send failed"));
154     }
155     freePLDMInstanceID(instanceID, eid);
156     pldmClose();
157     lg2::info("Done. PLDM message, id: {ID}, RC: {RC}", "ID", id, "RC", rc);
158 }
159 
requestDelete(uint32_t dumpId,uint32_t dumpType)160 void requestDelete(uint32_t dumpId, uint32_t dumpType)
161 {
162     pldm_fileio_file_type pldmDumpType;
163     switch (dumpType)
164     {
165         case PLDM_FILE_TYPE_DUMP:
166             pldmDumpType = PLDM_FILE_TYPE_DUMP;
167             break;
168         case PLDM_FILE_TYPE_RESOURCE_DUMP:
169             pldmDumpType = PLDM_FILE_TYPE_RESOURCE_DUMP;
170             break;
171         default:
172             throw std::runtime_error("Unknown pldm dump file-io type to delete "
173                                      "host dump");
174     }
175     const size_t pldmMsgHdrSize = sizeof(pldm_msg_hdr);
176     std::array<uint8_t, pldmMsgHdrSize + PLDM_FILE_ACK_REQ_BYTES> fileAckReqMsg;
177 
178     mctp_eid_t mctpEndPointId = readEID();
179 
180     auto pldmInstanceId = getPLDMInstanceID(mctpEndPointId);
181 
182     // - PLDM_SUCCESS - To indicate dump was readed (offloaded) or user decided,
183     //   no longer host dump is not required so, initiate deletion from
184     //   host memory
185     int retCode =
186         encode_file_ack_req(pldmInstanceId, pldmDumpType, dumpId, PLDM_SUCCESS,
187                             reinterpret_cast<pldm_msg*>(fileAckReqMsg.data()));
188 
189     if (retCode != PLDM_SUCCESS)
190     {
191         freePLDMInstanceID(pldmInstanceId, mctpEndPointId);
192         lg2::error(
193             "Failed to encode pldm FileAck to delete host dump, "
194             "SRC_DUMP_ID: {SRC_DUMP_ID}, PLDM_FILE_IO_TYPE: {PLDM_DUMP_TYPE}, "
195             "PLDM_RETURN_CODE: {RET_CODE}",
196             "SRC_DUMP_ID", dumpId, "PLDM_DUMP_TYPE", pldmDumpType, "RET_CODE",
197             retCode);
198         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
199                                 "allowed due to encode fileack failed"));
200     }
201 
202     retCode = openPLDM(mctpEndPointId);
203     if (retCode < 0)
204     {
205         freePLDMInstanceID(pldmInstanceId, mctpEndPointId);
206         lg2::error(
207             "Failed to openPLDM to delete host dump, "
208             "SRC_DUMP_ID: {SRC_DUMP_ID}, PLDM_FILE_IO_TYPE: {PLDM_DUMP_TYPE}, "
209             "PLDM_RETURN_CODE: {RET_CODE}",
210             "SRC_DUMP_ID", dumpId, "PLDM_DUMP_TYPE", pldmDumpType, "RET_CODE",
211             retCode);
212         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
213                                 "allowed due to openPLDM failed"));
214     }
215 
216     pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEndPointId);
217     retCode = pldm_transport_send_msg(
218         pldmTransport, pldmTID, fileAckReqMsg.data(), fileAckReqMsg.size());
219     if (retCode != PLDM_REQUESTER_SUCCESS)
220     {
221         auto errorNumber = errno;
222         freePLDMInstanceID(pldmInstanceId, mctpEndPointId);
223         pldmClose();
224         lg2::error(
225             "Failed to send pldm FileAck to delete host dump, "
226             "SRC_DUMP_ID: {SRC_DUMP_ID}, PLDM_FILE_IO_TYPE: {PLDM_DUMP_TYPE}, "
227             "PLDM_RETURN_CODE: {RET_CODE}, ERRNO: {ERRNO}, ERRMSG: {ERRMSG}",
228             "SRC_DUMP_ID", dumpId, "PLDM_DUMP_TYPE",
229             static_cast<std::underlying_type<pldm_fileio_file_type>::type>(
230                 pldmDumpType),
231             "RET_CODE", retCode, "ERRNO", errorNumber, "ERRMSG",
232             strerror(errorNumber));
233         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
234                                 "allowed due to fileack send failed"));
235     }
236 
237     freePLDMInstanceID(pldmInstanceId, mctpEndPointId);
238     pldmClose();
239     lg2::info(
240         "Sent request to host to delete the dump, SRC_DUMP_ID: {SRC_DUMP_ID}",
241         "SRC_DUMP_ID", dumpId);
242 }
243 } // namespace pldm
244 } // namespace dump
245 } // namespace phosphor
246