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/file_io.h> 24 #include <libpldm/platform.h> 25 #include <unistd.h> 26 27 #include <fstream> 28 #include <phosphor-logging/elog-errors.hpp> 29 #include <phosphor-logging/log.hpp> 30 #include <sdbusplus/bus.hpp> 31 32 namespace phosphor 33 { 34 namespace dump 35 { 36 namespace host 37 { 38 /** 39 * @brief Initiate offload of the dump with provided id 40 * 41 * @param[in] id - The Dump Source ID. 42 * 43 */ 44 void requestOffload(uint32_t id) 45 { 46 pldm::requestOffload(id); 47 } 48 49 void requestDelete(uint32_t id, uint32_t dumpType) 50 { 51 pldm::requestDelete(id, dumpType); 52 } 53 } // namespace host 54 55 namespace pldm 56 { 57 58 using namespace phosphor::logging; 59 60 constexpr auto eidPath = "/usr/share/pldm/host_eid"; 61 constexpr mctp_eid_t defaultEIDValue = 9; 62 63 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 64 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 65 66 mctp_eid_t readEID() 67 { 68 mctp_eid_t eid = defaultEIDValue; 69 70 std::ifstream eidFile{eidPath}; 71 if (!eidFile.good()) 72 { 73 log<level::ERR>("Could not open host EID file"); 74 elog<NotAllowed>(Reason("Required host dump action via pldm is not " 75 "allowed due to mctp end point read failed")); 76 } 77 else 78 { 79 std::string eid; 80 eidFile >> eid; 81 if (!eid.empty()) 82 { 83 eid = strtol(eid.c_str(), nullptr, 10); 84 } 85 else 86 { 87 log<level::ERR>("EID file was empty"); 88 elog<NotAllowed>( 89 Reason("Required host dump action via pldm is not " 90 "allowed due to mctp end point read failed")); 91 } 92 } 93 94 return eid; 95 } 96 97 void requestOffload(uint32_t id) 98 { 99 uint16_t effecterId = 0x05; // TODO PhyP temporary Hardcoded value. 100 101 std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(id) + 102 sizeof(uint8_t)> 103 requestMsg{}; 104 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 105 106 std::array<uint8_t, sizeof(id)> effecterValue{}; 107 108 memcpy(effecterValue.data(), &id, sizeof(id)); 109 110 mctp_eid_t eid = readEID(); 111 112 auto instanceID = getPLDMInstanceID(eid); 113 114 auto rc = encode_set_numeric_effecter_value_req( 115 instanceID, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32, 116 effecterValue.data(), request, 117 requestMsg.size() - sizeof(pldm_msg_hdr)); 118 119 if (rc != PLDM_SUCCESS) 120 { 121 log<level::ERR>("Message encode failure. ", entry("RC=%d", rc)); 122 elog<NotAllowed>(Reason("Host dump offload via pldm is not " 123 "allowed due to encode failed")); 124 } 125 126 uint8_t* responseMsg = nullptr; 127 size_t responseMsgSize{}; 128 129 CustomFd fd(openPLDM()); 130 131 rc = pldm_send_recv(eid, fd(), requestMsg.data(), requestMsg.size(), 132 &responseMsg, &responseMsgSize); 133 if (rc < 0) 134 { 135 auto e = errno; 136 log<level::ERR>("pldm_send failed", entry("RC=%d", rc), 137 entry("ERRNO=%d", e)); 138 elog<NotAllowed>(Reason("Host dump offload via pldm is not " 139 "allowed due to fileack send failed")); 140 } 141 pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg); 142 log<level::INFO>( 143 "Done. PLDM message", 144 entry("RC=%d", static_cast<uint16_t>(response->payload[0]))); 145 } 146 147 void requestDelete(uint32_t dumpId, uint32_t dumpType) 148 { 149 pldm_fileio_file_type pldmDumpType; 150 switch (dumpType) 151 { 152 case PLDM_FILE_TYPE_DUMP: 153 pldmDumpType = PLDM_FILE_TYPE_DUMP; 154 break; 155 case PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS: 156 pldmDumpType = PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS; 157 break; 158 default: 159 throw std::runtime_error("Unknown pldm dump file-io type to delete " 160 "host dump"); 161 } 162 const size_t pldmMsgHdrSize = sizeof(pldm_msg_hdr); 163 std::array<uint8_t, pldmMsgHdrSize + PLDM_FILE_ACK_REQ_BYTES> fileAckReqMsg; 164 165 mctp_eid_t mctpEndPointId = readEID(); 166 167 auto pldmInstanceId = getPLDMInstanceID(mctpEndPointId); 168 169 // - PLDM_SUCCESS - To indicate dump was readed (offloaded) or user decided, 170 // no longer host dump is not required so, initiate deletion from 171 // host memory 172 int retCode = 173 encode_file_ack_req(pldmInstanceId, pldmDumpType, dumpId, PLDM_SUCCESS, 174 reinterpret_cast<pldm_msg*>(fileAckReqMsg.data())); 175 176 if (retCode != PLDM_SUCCESS) 177 { 178 log<level::ERR>("Failed to encode pldm FileAck to delete host dump", 179 entry("SRC_DUMP_ID=%d", dumpId), 180 entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType), 181 entry("PLDM_RETURN_CODE=%d", retCode)); 182 elog<NotAllowed>(Reason("Host dump deletion via pldm is not " 183 "allowed due to encode fileack failed")); 184 } 185 186 uint8_t* pldmRespMsg = nullptr; 187 size_t pldmRespMsgSize; 188 189 CustomFd pldmFd(openPLDM()); 190 191 retCode = 192 pldm_send_recv(mctpEndPointId, pldmFd(), fileAckReqMsg.data(), 193 fileAckReqMsg.size(), &pldmRespMsg, &pldmRespMsgSize); 194 195 std::unique_ptr<uint8_t, decltype(std::free)*> pldmRespMsgPtr{pldmRespMsg, 196 std::free}; 197 if (retCode != PLDM_REQUESTER_SUCCESS) 198 { 199 auto errorNumber = errno; 200 log<level::ERR>("Failed to send pldm FileAck to delete host dump", 201 entry("SRC_DUMP_ID=%d", dumpId), 202 entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType), 203 entry("PLDM_RETURN_CODE=%d", retCode), 204 entry("ERRNO=%d", errorNumber), 205 entry("ERRMSG=%s", strerror(errorNumber))); 206 elog<NotAllowed>(Reason("Host dump deletion via pldm is not " 207 "allowed due to fileack send failed")); 208 } 209 210 uint8_t completionCode; 211 212 retCode = 213 decode_file_ack_resp(reinterpret_cast<pldm_msg*>(pldmRespMsgPtr.get()), 214 pldmRespMsgSize - pldmMsgHdrSize, &completionCode); 215 216 if (retCode || completionCode) 217 { 218 log<level::ERR>("Failed to delete host dump", 219 entry("SRC_DUMP_ID=%d", dumpId), 220 entry("PLDM_FILE_IO_TYPE=%d", pldmDumpType), 221 entry("PLDM_RETURN_CODE=%d", retCode), 222 entry("PLDM_COMPLETION_CODE=%d", completionCode)); 223 elog<NotAllowed>(Reason("Host dump deletion via pldm is " 224 "failed")); 225 } 226 227 log<level::INFO>("Deleted host dump", entry("SRC_DUMP_ID=%d", dumpId)); 228 } 229 } // namespace pldm 230 } // namespace dump 231 } // namespace phosphor 232