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