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 "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 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
65 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
66 
readEID()67 mctp_eid_t readEID()
68 {
69     mctp_eid_t eid = defaultEIDValue;
70 
71     std::ifstream eidFile{eidPath};
72     if (!eidFile.good())
73     {
74         lg2::error("Could not open host EID file");
75         elog<NotAllowed>(Reason("Required host dump action via pldm is not "
76                                 "allowed due to mctp end point read failed"));
77     }
78     else
79     {
80         std::string eid;
81         eidFile >> eid;
82         if (!eid.empty())
83         {
84             eid = strtol(eid.c_str(), nullptr, 10);
85         }
86         else
87         {
88             lg2::error("EID file was empty");
89             elog<NotAllowed>(
90                 Reason("Required host dump action via pldm is not "
91                        "allowed due to mctp end point read failed"));
92         }
93     }
94 
95     return eid;
96 }
97 
requestOffload(uint32_t id)98 void requestOffload(uint32_t id)
99 {
100     uint16_t effecterId = 0x05; // TODO PhyP temporary Hardcoded value.
101 
102     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(id) +
103                             sizeof(uint8_t)>
104         requestMsg{};
105     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
106 
107     std::array<uint8_t, sizeof(id)> effecterValue{};
108 
109     memcpy(effecterValue.data(), &id, sizeof(id));
110 
111     mctp_eid_t eid = readEID();
112 
113     auto instanceID = getPLDMInstanceID(eid);
114 
115     auto rc = encode_set_numeric_effecter_value_req(
116         instanceID, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
117         effecterValue.data(), request,
118         requestMsg.size() - sizeof(pldm_msg_hdr));
119 
120     if (rc != PLDM_SUCCESS)
121     {
122         lg2::error("Message encode failure. RC: {RC}", "RC", rc);
123         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
124                                 "allowed due to encode failed"));
125     }
126 
127     CustomFd fd(openPLDM());
128 
129     lg2::info("Sending request to offload dump id: {ID}, eid: {EID}", "ID", id,
130               "EID", eid);
131 
132     rc = pldm_send(eid, fd(), requestMsg.data(), requestMsg.size());
133     if (rc < 0)
134     {
135         auto e = errno;
136         lg2::error("pldm_send failed, RC: {RC}, errno: {ERRNO}", "RC", rc,
137                    "ERRNO", e);
138         elog<NotAllowed>(Reason("Host dump offload via pldm is not "
139                                 "allowed due to fileack send failed"));
140     }
141     lg2::info("Done. PLDM message, id: {ID}, RC: {RC}", "ID", id, "RC", rc);
142 }
143 
requestDelete(uint32_t dumpId,uint32_t dumpType)144 void requestDelete(uint32_t dumpId, uint32_t dumpType)
145 {
146     pldm_fileio_file_type pldmDumpType;
147     switch (dumpType)
148     {
149         case PLDM_FILE_TYPE_DUMP:
150             pldmDumpType = PLDM_FILE_TYPE_DUMP;
151             break;
152         case PLDM_FILE_TYPE_RESOURCE_DUMP:
153             pldmDumpType = PLDM_FILE_TYPE_RESOURCE_DUMP;
154             break;
155         default:
156             throw std::runtime_error("Unknown pldm dump file-io type to delete "
157                                      "host dump");
158     }
159     const size_t pldmMsgHdrSize = sizeof(pldm_msg_hdr);
160     std::array<uint8_t, pldmMsgHdrSize + PLDM_FILE_ACK_REQ_BYTES> fileAckReqMsg;
161 
162     mctp_eid_t mctpEndPointId = readEID();
163 
164     auto pldmInstanceId = getPLDMInstanceID(mctpEndPointId);
165 
166     // - PLDM_SUCCESS - To indicate dump was readed (offloaded) or user decided,
167     //   no longer host dump is not required so, initiate deletion from
168     //   host memory
169     int retCode =
170         encode_file_ack_req(pldmInstanceId, pldmDumpType, dumpId, PLDM_SUCCESS,
171                             reinterpret_cast<pldm_msg*>(fileAckReqMsg.data()));
172 
173     if (retCode != PLDM_SUCCESS)
174     {
175         lg2::error(
176             "Failed to encode pldm FileAck to delete host dump, "
177             "SRC_DUMP_ID: {SRC_DUMP_ID}, PLDM_FILE_IO_TYPE: {PLDM_DUMP_TYPE}, "
178             "PLDM_RETURN_CODE: {RET_CODE}",
179             "SRC_DUMP_ID", dumpId, "PLDM_DUMP_TYPE", pldmDumpType, "RET_CODE",
180             retCode);
181         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
182                                 "allowed due to encode fileack failed"));
183     }
184 
185     CustomFd pldmFd(openPLDM());
186 
187     retCode = pldm_send(mctpEndPointId, pldmFd(), fileAckReqMsg.data(),
188                         fileAckReqMsg.size());
189     if (retCode != PLDM_REQUESTER_SUCCESS)
190     {
191         auto errorNumber = errno;
192         lg2::error(
193             "Failed to send 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}, ERRNO: {ERRNO}, ERRMSG: {ERRMSG}",
196             "SRC_DUMP_ID", dumpId, "PLDM_DUMP_TYPE",
197             static_cast<std::underlying_type<pldm_fileio_file_type>::type>(
198                 pldmDumpType),
199             "RET_CODE", retCode, "ERRNO", errorNumber, "ERRMSG",
200             strerror(errorNumber));
201         elog<NotAllowed>(Reason("Host dump deletion via pldm is not "
202                                 "allowed due to fileack send failed"));
203     }
204 
205     lg2::info(
206         "Sent request to host to delete the dump, SRC_DUMP_ID: {SRC_DUMP_ID}",
207         "SRC_DUMP_ID", dumpId);
208 }
209 } // namespace pldm
210 } // namespace dump
211 } // namespace phosphor
212