1 #pragma once 2 3 #include "config.h" 4 5 #include "handler.hpp" 6 #include "libpldmresponder/pdr.hpp" 7 #include "utils.hpp" 8 9 #include <stdint.h> 10 11 #include <map> 12 13 #include "libpldm/platform.h" 14 #include "libpldm/states.h" 15 16 namespace pldm 17 { 18 namespace responder 19 { 20 namespace platform 21 { 22 23 class Handler : public CmdHandler 24 { 25 public: 26 Handler() 27 { 28 handlers.emplace(PLDM_GET_PDR, 29 [this](const pldm_msg* request, size_t payloadLength) { 30 return this->getPDR(request, payloadLength); 31 }); 32 handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES, 33 [this](const pldm_msg* request, size_t payloadLength) { 34 return this->setStateEffecterStates(request, 35 payloadLength); 36 }); 37 } 38 39 /** @brief Handler for GetPDR 40 * 41 * @param[in] request - Request message payload 42 * @param[in] payloadLength - Request payload length 43 * @param[out] Response - Response message written here 44 */ 45 Response getPDR(const pldm_msg* request, size_t payloadLength); 46 47 /** @brief Handler for setStateEffecterStates 48 * 49 * @param[in] request - Request message 50 * @param[in] payloadLength - Request payload length 51 * @return Response - PLDM Response message 52 */ 53 Response setStateEffecterStates(const pldm_msg* request, 54 size_t payloadLength); 55 56 /** @brief Function to set the effecter requested by pldm requester 57 * @param[in] dBusIntf - The interface object 58 * @param[in] effecterId - Effecter ID sent by the requester to act on 59 * @param[in] stateField - The state field data for each of the states, 60 * equal to composite effecter count in number 61 * @return - Success or failure in setting the states. Returns failure in 62 * terms of PLDM completion codes if atleast one state fails to be set 63 */ 64 template <class DBusInterface> 65 int setStateEffecterStatesHandler( 66 const DBusInterface& dBusIntf, effecter::Id effecterId, 67 const std::vector<set_effecter_state_field>& stateField) 68 { 69 using namespace std::string_literals; 70 using DBusProperty = std::variant<std::string, bool>; 71 using StateSetId = uint16_t; 72 using StateSetNum = uint8_t; 73 using PropertyMap = 74 std::map<StateSetId, std::map<StateSetNum, DBusProperty>>; 75 static const PropertyMap stateNumToDbusProp = { 76 {PLDM_BOOT_PROGRESS_STATE, 77 {{PLDM_BOOT_NOT_ACTIVE, 78 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus." 79 "Standby"s}, 80 {PLDM_BOOT_COMPLETED, 81 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus." 82 "BootComplete"s}}}, 83 {PLDM_SYSTEM_POWER_STATE, 84 {{PLDM_OFF_SOFT_GRACEFUL, 85 "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}}; 86 using namespace pldm::responder::pdr; 87 using namespace pldm::responder::effecter::dbus_mapping; 88 89 state_effecter_possible_states* states = nullptr; 90 pldm_state_effecter_pdr* pdr = nullptr; 91 uint8_t compEffecterCnt = stateField.size(); 92 uint32_t recordHndl{}; 93 Repo& pdrRepo = get(PDR_JSONS_DIR); 94 pdr::Entry pdrEntry{}; 95 96 while (!pdr) 97 { 98 pdrEntry = pdrRepo.at(recordHndl); 99 pldm_pdr_hdr* header = 100 reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data()); 101 if (header->type != PLDM_STATE_EFFECTER_PDR) 102 { 103 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 104 if (recordHndl) 105 { 106 continue; 107 } 108 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 109 } 110 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data()); 111 recordHndl = pdr->hdr.record_handle; 112 if (pdr->effecter_id == effecterId) 113 { 114 states = reinterpret_cast<state_effecter_possible_states*>( 115 pdr->possible_states); 116 if (compEffecterCnt > pdr->composite_effecter_count) 117 { 118 std::cerr 119 << "The requester sent wrong composite effecter" 120 << " count for the effecter, EFFECTER_ID=" << effecterId 121 << "COMP_EFF_CNT=" << compEffecterCnt << "\n"; 122 return PLDM_ERROR_INVALID_DATA; 123 } 124 break; 125 } 126 recordHndl = pdrRepo.getNextRecordHandle(recordHndl); 127 if (!recordHndl) 128 { 129 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 130 } 131 pdr = nullptr; 132 } 133 134 std::map<StateSetId, std::function<int(const std::string& objPath, 135 const uint8_t currState)>> 136 effecterToDbusEntries = { 137 {PLDM_BOOT_PROGRESS_STATE, 138 [&](const std::string& objPath, const uint8_t currState) { 139 auto stateSet = 140 stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE); 141 if (stateSet == stateNumToDbusProp.end()) 142 { 143 std::cerr << "Couldn't find D-Bus mapping for " 144 << "PLDM_BOOT_PROGRESS_STATE, EFFECTER_ID=" 145 << effecterId << "\n"; 146 return PLDM_ERROR; 147 } 148 auto iter = stateSet->second.find( 149 stateField[currState].effecter_state); 150 if (iter == stateSet->second.end()) 151 { 152 std::cerr << "Invalid state field passed or field not " 153 << "found for PLDM_BOOT_PROGRESS_STATE, " 154 "EFFECTER_ID=" 155 << effecterId << " FIELD=" 156 << stateField[currState].effecter_state 157 << " OBJECT_PATH=" << objPath.c_str() 158 << "\n"; 159 return PLDM_ERROR_INVALID_DATA; 160 } 161 auto dbusProp = "OperatingSystemState"; 162 std::variant<std::string> value{ 163 std::get<std::string>(iter->second)}; 164 auto dbusInterface = 165 "xyz.openbmc_project.State.OperatingSystem.Status"; 166 try 167 { 168 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp, 169 dbusInterface, value); 170 } 171 catch (const std::exception& e) 172 { 173 std::cerr 174 << "Error setting property, ERROR=" << e.what() 175 << " PROPERTY=" << dbusProp 176 << " INTERFACE=" << dbusInterface 177 << " PATH=" << objPath.c_str() << "\n"; 178 return PLDM_ERROR; 179 } 180 return PLDM_SUCCESS; 181 }}, 182 {PLDM_SYSTEM_POWER_STATE, 183 [&](const std::string& objPath, const uint8_t currState) { 184 auto stateSet = 185 stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE); 186 if (stateSet == stateNumToDbusProp.end()) 187 { 188 std::cerr << "Couldn't find D-Bus mapping for " 189 << "PLDM_SYSTEM_POWER_STATE, EFFECTER_ID=" 190 << effecterId << "\n"; 191 return PLDM_ERROR; 192 } 193 auto iter = stateSet->second.find( 194 stateField[currState].effecter_state); 195 if (iter == stateSet->second.end()) 196 { 197 std::cerr << "Invalid state field passed or field not " 198 << "found for PLDM_SYSTEM_POWER_STATE, " 199 "EFFECTER_ID=" 200 << effecterId << " FIELD=" 201 << stateField[currState].effecter_state 202 << " OBJECT_PATH=" << objPath.c_str() 203 << "\n"; 204 return PLDM_ERROR_INVALID_DATA; 205 } 206 auto dbusProp = "RequestedPowerTransition"; 207 std::variant<std::string> value{ 208 std::get<std::string>(iter->second)}; 209 auto dbusInterface = "xyz.openbmc_project.State.Chassis"; 210 try 211 { 212 dBusIntf.setDbusProperty(objPath.c_str(), dbusProp, 213 dbusInterface, value); 214 } 215 catch (const std::exception& e) 216 { 217 std::cerr 218 << "Error setting property, ERROR=" << e.what() 219 << " PROPERTY=" << dbusProp 220 << " INTERFACE=" << dbusInterface 221 << " PATH=" << objPath.c_str() << "\n"; 222 return PLDM_ERROR; 223 } 224 return PLDM_SUCCESS; 225 }}}; 226 227 int rc = PLDM_SUCCESS; 228 auto paths = get(effecterId); 229 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState) 230 { 231 std::vector<StateSetNum> allowed{}; 232 // computation is based on table 79 from DSP0248 v1.1.1 233 uint8_t bitfieldIndex = stateField[currState].effecter_state / 8; 234 uint8_t bit = 235 stateField[currState].effecter_state - (8 * bitfieldIndex); 236 if (states->possible_states_size < bitfieldIndex || 237 !(states->states[bitfieldIndex].byte & (1 << bit))) 238 { 239 std::cerr << "Invalid state set value, EFFECTER_ID=" 240 << effecterId 241 << " VALUE=" << stateField[currState].effecter_state 242 << " COMPOSITE_EFFECTER_ID=" << currState 243 << " DBUS_PATH=" << paths[currState].c_str() << "\n"; 244 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 245 break; 246 } 247 auto iter = effecterToDbusEntries.find(states->state_set_id); 248 if (iter == effecterToDbusEntries.end()) 249 { 250 uint16_t setId = states->state_set_id; 251 std::cerr << "Did not find the state set for the" 252 << " state effecter pdr, STATE=" << setId 253 << " EFFECTER_ID=" << effecterId << "\n"; 254 rc = PLDM_PLATFORM_INVALID_STATE_VALUE; 255 break; 256 } 257 if (stateField[currState].set_request == PLDM_REQUEST_SET) 258 { 259 rc = iter->second(paths[currState], currState); 260 if (rc != PLDM_SUCCESS) 261 { 262 break; 263 } 264 } 265 uint8_t* nextState = 266 reinterpret_cast<uint8_t*>(states) + 267 sizeof(state_effecter_possible_states) - 268 sizeof(states->states) + 269 (states->possible_states_size * sizeof(states->states)); 270 states = 271 reinterpret_cast<state_effecter_possible_states*>(nextState); 272 } 273 return rc; 274 } 275 }; 276 277 } // namespace platform 278 } // namespace responder 279 } // namespace pldm 280