| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (c)  2018 Intel Corporation. | 
|  | 3 | * Copyright (c)  2018-present Facebook. | 
|  | 4 | * | 
|  | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 6 | * you may not use this file except in compliance with the License. | 
|  | 7 | * You may obtain a copy of the License at | 
|  | 8 | * | 
|  | 9 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 10 | * | 
|  | 11 | * Unless required by applicable law or agreed to in writing, software | 
|  | 12 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 14 | * See the License for the specific language governing permissions and | 
|  | 15 | * limitations under the License. | 
|  | 16 | */ | 
|  | 17 |  | 
|  | 18 | #include <ipmid/api.h> | 
|  | 19 |  | 
|  | 20 | #include <boost/container/flat_map.hpp> | 
|  | 21 | #include <commandutils.hpp> | 
| Vijay Khemka | 1b6fae3 | 2019-03-25 17:43:01 -0700 | [diff] [blame] | 22 | #include <ipmid/utils.hpp> | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 23 | #include <phosphor-logging/log.hpp> | 
|  | 24 | #include <sdbusplus/message/types.hpp> | 
|  | 25 | #include <sdbusplus/timer.hpp> | 
|  | 26 | #include <sensorutils.hpp> | 
|  | 27 | #include <storagecommands.hpp> | 
|  | 28 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 29 | #include <iostream> | 
| Patrick Williams | 2405ae9 | 2023-05-10 07:50:09 -0500 | [diff] [blame] | 30 | #include <unordered_map> | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 31 |  | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 32 | namespace ipmi | 
|  | 33 | { | 
|  | 34 |  | 
|  | 35 | namespace storage | 
|  | 36 | { | 
|  | 37 | void registerStorageFunctions() __attribute__((constructor)); | 
|  | 38 |  | 
|  | 39 | constexpr static const size_t maxMessageSize = 64; | 
|  | 40 | constexpr static const size_t maxFruSdrNameSize = 16; | 
|  | 41 | static constexpr int sensorMapUpdatePeriod = 2; | 
|  | 42 | using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 43 |  | 
|  | 44 | using ManagedObjectSensor = | 
|  | 45 | std::map<sdbusplus::message::object_path, | 
|  | 46 | std::map<std::string, std::map<std::string, DbusVariant>>>; | 
|  | 47 |  | 
|  | 48 | static uint16_t sdrReservationID; | 
|  | 49 |  | 
|  | 50 | static boost::container::flat_map<std::string, ManagedObjectSensor> SensorCache; | 
|  | 51 | static SensorSubTree sensorTree; | 
|  | 52 |  | 
|  | 53 | void registerSensorFunctions() __attribute__((constructor)); | 
|  | 54 | using ManagedObjectType = boost::container::flat_map< | 
|  | 55 | sdbusplus::message::object_path, | 
|  | 56 | boost::container::flat_map< | 
|  | 57 | std::string, boost::container::flat_map<std::string, DbusVariant>>>; | 
|  | 58 | using ManagedEntry = std::pair< | 
|  | 59 | sdbusplus::message::object_path, | 
|  | 60 | boost::container::flat_map< | 
|  | 61 | std::string, boost::container::flat_map<std::string, DbusVariant>>>; | 
|  | 62 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 63 | constexpr static const char* fruDeviceServiceName = | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 64 | "xyz.openbmc_project.FruDevice"; | 
|  | 65 | constexpr static const size_t cacheTimeoutSeconds = 10; | 
|  | 66 |  | 
|  | 67 | static std::vector<uint8_t> fruCache; | 
| Potin Lai | 4de5876 | 2023-09-01 15:56:00 +0800 | [diff] [blame] | 68 | static uint16_t cacheBus = 0xFFFF; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 69 | static uint8_t cacheAddr = 0XFF; | 
|  | 70 |  | 
| Patrick Williams | d79f89e | 2023-12-05 12:45:03 -0600 | [diff] [blame] | 71 | std::unique_ptr<sdbusplus::Timer> cacheTimer = nullptr; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 72 |  | 
|  | 73 | // we unfortunately have to build a map of hashes in case there is a | 
|  | 74 | // collision to verify our dev-id | 
|  | 75 | boost::container::flat_map<uint8_t, std::pair<uint8_t, uint8_t>> deviceHashes; | 
|  | 76 |  | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 77 | static sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 78 |  | 
| Delphine CC Chiu | 2ca4aa0 | 2023-02-01 16:30:18 +0800 | [diff] [blame] | 79 | using InterfaceName = std::string; | 
|  | 80 | using PropertyName = std::string; | 
|  | 81 | using ThresholdStr = std::string; | 
|  | 82 |  | 
|  | 83 | enum class AlarmType | 
|  | 84 | { | 
|  | 85 | low, | 
|  | 86 | high | 
|  | 87 | }; | 
|  | 88 |  | 
|  | 89 | struct Property | 
|  | 90 | { | 
|  | 91 | PropertyName name; | 
|  | 92 | ThresholdStr threshold; | 
|  | 93 | }; | 
|  | 94 |  | 
|  | 95 | const std::vector<InterfaceName> thresholdCheckedOrder{ | 
|  | 96 | "xyz.openbmc_project.Sensor.Threshold.HardShutdown", | 
|  | 97 | "xyz.openbmc_project.Sensor.Threshold.SoftShutdown", | 
|  | 98 | "xyz.openbmc_project.Sensor.Threshold.Critical", | 
|  | 99 | "xyz.openbmc_project.Sensor.Threshold.Warning"}; | 
|  | 100 |  | 
|  | 101 | const std::unordered_map<std::string, std::map<AlarmType, Property>> | 
|  | 102 | alarmProperties{ | 
|  | 103 | {"xyz.openbmc_project.Sensor.Threshold.HardShutdown", | 
|  | 104 | {{AlarmType::low, Property{"HardShutdownAlarmLow", "LNR"}}, | 
|  | 105 | {AlarmType::high, Property{"HardShutdownAlarmHigh", "UNR"}}}}, | 
|  | 106 |  | 
|  | 107 | {"xyz.openbmc_project.Sensor.Threshold.SoftShutdown", | 
|  | 108 | {{AlarmType::low, Property{"SoftShutdownAlarmLow", "LNR"}}, | 
|  | 109 | {AlarmType::high, Property{"SoftShutdownAlarmHigh", "UNR"}}}}, | 
|  | 110 |  | 
|  | 111 | {"xyz.openbmc_project.Sensor.Threshold.Critical", | 
|  | 112 | {{AlarmType::low, Property{"CriticalAlarmLow", "LCR"}}, | 
|  | 113 | {AlarmType::high, Property{"CriticalAlarmHigh", "UCR"}}}}, | 
|  | 114 |  | 
|  | 115 | {"xyz.openbmc_project.Sensor.Threshold.Warning", | 
|  | 116 | {{AlarmType::low, Property{"WarningAlarmLow", "LNC"}}, | 
|  | 117 | {AlarmType::high, Property{"WarningAlarmHigh", "UNC"}}}}, | 
|  | 118 | }; | 
|  | 119 |  | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 120 | static bool getSensorMap(std::string sensorConnection, std::string sensorPath, | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 121 | SensorMap& sensorMap) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 122 | { | 
|  | 123 | static boost::container::flat_map< | 
|  | 124 | std::string, std::chrono::time_point<std::chrono::steady_clock>> | 
|  | 125 | updateTimeMap; | 
|  | 126 |  | 
|  | 127 | auto updateFind = updateTimeMap.find(sensorConnection); | 
|  | 128 | auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>(); | 
|  | 129 | if (updateFind != updateTimeMap.end()) | 
|  | 130 | { | 
|  | 131 | lastUpdate = updateFind->second; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | auto now = std::chrono::steady_clock::now(); | 
|  | 135 |  | 
|  | 136 | if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate) | 
|  | 137 | .count() > sensorMapUpdatePeriod) | 
|  | 138 | { | 
|  | 139 | updateTimeMap[sensorConnection] = now; | 
|  | 140 |  | 
|  | 141 | auto managedObj = dbus.new_method_call( | 
| Potin Lai | 8ee95d6 | 2022-12-21 11:11:59 +0800 | [diff] [blame] | 142 | sensorConnection.c_str(), "/xyz/openbmc_project/sensors", | 
|  | 143 | "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 144 |  | 
|  | 145 | ManagedObjectSensor managedObjects; | 
|  | 146 | try | 
|  | 147 | { | 
|  | 148 | auto reply = dbus.call(managedObj); | 
|  | 149 | reply.read(managedObjects); | 
|  | 150 | } | 
| Patrick Williams | 35d1254 | 2021-10-06 11:21:13 -0500 | [diff] [blame] | 151 | catch (const sdbusplus::exception_t&) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 152 | { | 
|  | 153 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 154 | "Error getting managed objects from connection", | 
|  | 155 | phosphor::logging::entry("CONNECTION=%s", | 
|  | 156 | sensorConnection.c_str())); | 
|  | 157 | return false; | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | SensorCache[sensorConnection] = managedObjects; | 
|  | 161 | } | 
|  | 162 | auto connection = SensorCache.find(sensorConnection); | 
|  | 163 | if (connection == SensorCache.end()) | 
|  | 164 | { | 
|  | 165 | return false; | 
|  | 166 | } | 
|  | 167 | auto path = connection->second.find(sensorPath); | 
|  | 168 | if (path == connection->second.end()) | 
|  | 169 | { | 
|  | 170 | return false; | 
|  | 171 | } | 
|  | 172 | sensorMap = path->second; | 
|  | 173 |  | 
|  | 174 | return true; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | bool writeFru() | 
|  | 178 | { | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 179 | sdbusplus::message_t writeFru = dbus.new_method_call( | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 180 | fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", | 
|  | 181 | "xyz.openbmc_project.FruDeviceManager", "WriteFru"); | 
|  | 182 | writeFru.append(cacheBus, cacheAddr, fruCache); | 
|  | 183 | try | 
|  | 184 | { | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 185 | sdbusplus::message_t writeFruResp = dbus.call(writeFru); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 186 | } | 
| Patrick Williams | 35d1254 | 2021-10-06 11:21:13 -0500 | [diff] [blame] | 187 | catch (const sdbusplus::exception_t&) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 188 | { | 
|  | 189 | // todo: log sel? | 
|  | 190 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 191 | "error writing fru"); | 
|  | 192 | return false; | 
|  | 193 | } | 
|  | 194 | return true; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | void createTimer() | 
|  | 198 | { | 
|  | 199 | if (cacheTimer == nullptr) | 
|  | 200 | { | 
| Patrick Williams | d79f89e | 2023-12-05 12:45:03 -0600 | [diff] [blame] | 201 | cacheTimer = std::make_unique<sdbusplus::Timer>(writeFru); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 202 | } | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | ipmi_ret_t replaceCacheFru(uint8_t devId) | 
|  | 206 | { | 
|  | 207 | static uint8_t lastDevId = 0xFF; | 
|  | 208 |  | 
|  | 209 | bool timerRunning = (cacheTimer != nullptr) && !cacheTimer->isExpired(); | 
|  | 210 | if (lastDevId == devId && timerRunning) | 
|  | 211 | { | 
|  | 212 | return IPMI_CC_OK; // cache already up to date | 
|  | 213 | } | 
|  | 214 | // if timer is running, stop it and writeFru manually | 
|  | 215 | else if (timerRunning) | 
|  | 216 | { | 
|  | 217 | cacheTimer->stop(); | 
|  | 218 | writeFru(); | 
|  | 219 | } | 
|  | 220 |  | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 221 | sdbusplus::message_t getObjects = dbus.new_method_call( | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 222 | fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", | 
|  | 223 | "GetManagedObjects"); | 
|  | 224 | ManagedObjectType frus; | 
|  | 225 | try | 
|  | 226 | { | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 227 | sdbusplus::message_t resp = dbus.call(getObjects); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 228 | resp.read(frus); | 
|  | 229 | } | 
| Patrick Williams | 35d1254 | 2021-10-06 11:21:13 -0500 | [diff] [blame] | 230 | catch (const sdbusplus::exception_t&) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 231 | { | 
|  | 232 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 233 | "replaceCacheFru: error getting managed objects"); | 
|  | 234 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 235 | } | 
|  | 236 |  | 
|  | 237 | deviceHashes.clear(); | 
|  | 238 |  | 
| cchoux | b2ae88b | 2023-09-13 00:35:36 +0800 | [diff] [blame] | 239 | uint8_t fruHash = 0; | 
|  | 240 | uint8_t mbFruBus = 0, mbFruAddr = 0; | 
|  | 241 |  | 
|  | 242 | auto device = getMbFruDevice(); | 
|  | 243 | if (device) | 
|  | 244 | { | 
|  | 245 | std::tie(mbFruBus, mbFruAddr) = *device; | 
|  | 246 | deviceHashes.emplace(0, std::make_pair(mbFruBus, mbFruAddr)); | 
|  | 247 | fruHash++; | 
|  | 248 | } | 
|  | 249 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 250 | for (const auto& fru : frus) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 251 | { | 
|  | 252 | auto fruIface = fru.second.find("xyz.openbmc_project.FruDevice"); | 
|  | 253 | if (fruIface == fru.second.end()) | 
|  | 254 | { | 
|  | 255 | continue; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | auto busFind = fruIface->second.find("BUS"); | 
|  | 259 | auto addrFind = fruIface->second.find("ADDRESS"); | 
|  | 260 | if (busFind == fruIface->second.end() || | 
|  | 261 | addrFind == fruIface->second.end()) | 
|  | 262 | { | 
|  | 263 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 264 | "fru device missing Bus or Address", | 
|  | 265 | phosphor::logging::entry("FRU=%s", fru.first.str.c_str())); | 
|  | 266 | continue; | 
|  | 267 | } | 
|  | 268 |  | 
| Patrick Williams | ef0efbc | 2020-05-13 11:26:51 -0500 | [diff] [blame] | 269 | uint8_t fruBus = std::get<uint32_t>(busFind->second); | 
|  | 270 | uint8_t fruAddr = std::get<uint32_t>(addrFind->second); | 
| cchoux | b2ae88b | 2023-09-13 00:35:36 +0800 | [diff] [blame] | 271 | if (fruBus != mbFruBus || fruAddr != mbFruAddr) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 272 | { | 
| cchoux | b2ae88b | 2023-09-13 00:35:36 +0800 | [diff] [blame] | 273 | deviceHashes.emplace(fruHash, std::make_pair(fruBus, fruAddr)); | 
|  | 274 | fruHash++; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 275 | } | 
|  | 276 | } | 
|  | 277 | auto deviceFind = deviceHashes.find(devId); | 
|  | 278 | if (deviceFind == deviceHashes.end()) | 
|  | 279 | { | 
|  | 280 | return IPMI_CC_SENSOR_INVALID; | 
|  | 281 | } | 
|  | 282 |  | 
|  | 283 | fruCache.clear(); | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 284 | sdbusplus::message_t getRawFru = dbus.new_method_call( | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 285 | fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", | 
|  | 286 | "xyz.openbmc_project.FruDeviceManager", "GetRawFru"); | 
|  | 287 | cacheBus = deviceFind->second.first; | 
|  | 288 | cacheAddr = deviceFind->second.second; | 
|  | 289 | getRawFru.append(cacheBus, cacheAddr); | 
|  | 290 | try | 
|  | 291 | { | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 292 | sdbusplus::message_t getRawResp = dbus.call(getRawFru); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 293 | getRawResp.read(fruCache); | 
|  | 294 | } | 
| Patrick Williams | 35d1254 | 2021-10-06 11:21:13 -0500 | [diff] [blame] | 295 | catch (const sdbusplus::exception_t&) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 296 | { | 
|  | 297 | lastDevId = 0xFF; | 
| Potin Lai | 4de5876 | 2023-09-01 15:56:00 +0800 | [diff] [blame] | 298 | cacheBus = 0xFFFF; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 299 | cacheAddr = 0xFF; | 
|  | 300 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 301 | } | 
|  | 302 |  | 
|  | 303 | lastDevId = devId; | 
|  | 304 | return IPMI_CC_OK; | 
|  | 305 | } | 
|  | 306 |  | 
| Patrick Williams | 010dee0 | 2024-08-16 15:19:44 -0400 | [diff] [blame] | 307 | ipmi_ret_t ipmiStorageReadFRUData( | 
|  | 308 | ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, | 
|  | 309 | ipmi_data_len_t dataLen, ipmi_context_t) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 310 | { | 
|  | 311 | if (*dataLen != 4) | 
|  | 312 | { | 
|  | 313 | *dataLen = 0; | 
|  | 314 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 315 | } | 
|  | 316 | *dataLen = 0; // default to 0 in case of an error | 
|  | 317 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 318 | auto req = static_cast<GetFRUAreaReq*>(request); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 319 |  | 
|  | 320 | if (req->countToRead > maxMessageSize - 1) | 
|  | 321 | { | 
|  | 322 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 323 | } | 
|  | 324 | ipmi_ret_t status = replaceCacheFru(req->fruDeviceID); | 
|  | 325 |  | 
|  | 326 | if (status != IPMI_CC_OK) | 
|  | 327 | { | 
|  | 328 | return status; | 
|  | 329 | } | 
|  | 330 |  | 
|  | 331 | size_t fromFRUByteLen = 0; | 
|  | 332 | if (req->countToRead + req->fruInventoryOffset < fruCache.size()) | 
|  | 333 | { | 
|  | 334 | fromFRUByteLen = req->countToRead; | 
|  | 335 | } | 
|  | 336 | else if (fruCache.size() > req->fruInventoryOffset) | 
|  | 337 | { | 
|  | 338 | fromFRUByteLen = fruCache.size() - req->fruInventoryOffset; | 
|  | 339 | } | 
|  | 340 | size_t padByteLen = req->countToRead - fromFRUByteLen; | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 341 | uint8_t* respPtr = static_cast<uint8_t*>(response); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 342 | *respPtr = req->countToRead; | 
|  | 343 | std::copy(fruCache.begin() + req->fruInventoryOffset, | 
|  | 344 | fruCache.begin() + req->fruInventoryOffset + fromFRUByteLen, | 
|  | 345 | ++respPtr); | 
|  | 346 | // if longer than the fru is requested, fill with 0xFF | 
|  | 347 | if (padByteLen) | 
|  | 348 | { | 
|  | 349 | respPtr += fromFRUByteLen; | 
|  | 350 | std::fill(respPtr, respPtr + padByteLen, 0xFF); | 
|  | 351 | } | 
|  | 352 | *dataLen = fromFRUByteLen + 1; | 
|  | 353 |  | 
|  | 354 | return IPMI_CC_OK; | 
|  | 355 | } | 
|  | 356 |  | 
| Patrick Williams | 010dee0 | 2024-08-16 15:19:44 -0400 | [diff] [blame] | 357 | ipmi_ret_t ipmiStorageWriteFRUData( | 
|  | 358 | ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, | 
|  | 359 | ipmi_data_len_t dataLen, ipmi_context_t) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 360 | { | 
|  | 361 | if (*dataLen < 4 || | 
|  | 362 | *dataLen >= | 
|  | 363 | 0xFF + 3) // count written return is one byte, so limit to one | 
|  | 364 | // byte of data after the three request data bytes | 
|  | 365 | { | 
|  | 366 | *dataLen = 0; | 
|  | 367 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 368 | } | 
|  | 369 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 370 | auto req = static_cast<WriteFRUDataReq*>(request); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 371 | size_t writeLen = *dataLen - 3; | 
|  | 372 | *dataLen = 0; // default to 0 in case of an error | 
|  | 373 |  | 
|  | 374 | ipmi_ret_t status = replaceCacheFru(req->fruDeviceID); | 
|  | 375 | if (status != IPMI_CC_OK) | 
|  | 376 | { | 
|  | 377 | return status; | 
|  | 378 | } | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 379 | size_t lastWriteAddr = req->fruInventoryOffset + writeLen; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 380 | if (fruCache.size() < lastWriteAddr) | 
|  | 381 | { | 
|  | 382 | fruCache.resize(req->fruInventoryOffset + writeLen); | 
|  | 383 | } | 
|  | 384 |  | 
|  | 385 | std::copy(req->data, req->data + writeLen, | 
|  | 386 | fruCache.begin() + req->fruInventoryOffset); | 
|  | 387 |  | 
|  | 388 | bool atEnd = false; | 
|  | 389 |  | 
|  | 390 | if (fruCache.size() >= sizeof(FRUHeader)) | 
|  | 391 | { | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 392 | FRUHeader* header = reinterpret_cast<FRUHeader*>(fruCache.data()); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 393 |  | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 394 | size_t lastRecordStart = std::max( | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 395 | header->internalOffset, | 
|  | 396 | std::max(header->chassisOffset, | 
|  | 397 | std::max(header->boardOffset, header->productOffset))); | 
|  | 398 | // TODO: Handle Multi-Record FRUs? | 
|  | 399 |  | 
|  | 400 | lastRecordStart *= 8; // header starts in are multiples of 8 bytes | 
|  | 401 |  | 
|  | 402 | // get the length of the area in multiples of 8 bytes | 
|  | 403 | if (lastWriteAddr > (lastRecordStart + 1)) | 
|  | 404 | { | 
|  | 405 | // second byte in record area is the length | 
|  | 406 | int areaLength(fruCache[lastRecordStart + 1]); | 
|  | 407 | areaLength *= 8; // it is in multiples of 8 bytes | 
|  | 408 |  | 
|  | 409 | if (lastWriteAddr >= (areaLength + lastRecordStart)) | 
|  | 410 | { | 
|  | 411 | atEnd = true; | 
|  | 412 | } | 
|  | 413 | } | 
|  | 414 | } | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 415 | uint8_t* respPtr = static_cast<uint8_t*>(response); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 416 | if (atEnd) | 
|  | 417 | { | 
|  | 418 | // cancel timer, we're at the end so might as well send it | 
|  | 419 | cacheTimer->stop(); | 
|  | 420 | if (!writeFru()) | 
|  | 421 | { | 
|  | 422 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 423 | } | 
|  | 424 | *respPtr = std::min(fruCache.size(), static_cast<size_t>(0xFF)); | 
|  | 425 | } | 
|  | 426 | else | 
|  | 427 | { | 
|  | 428 | // start a timer, if no further data is sent in cacheTimeoutSeconds | 
|  | 429 | // seconds, check to see if it is valid | 
|  | 430 | createTimer(); | 
|  | 431 | cacheTimer->start(std::chrono::duration_cast<std::chrono::microseconds>( | 
|  | 432 | std::chrono::seconds(cacheTimeoutSeconds))); | 
|  | 433 | *respPtr = 0; | 
|  | 434 | } | 
|  | 435 |  | 
|  | 436 | *dataLen = 1; | 
|  | 437 |  | 
|  | 438 | return IPMI_CC_OK; | 
|  | 439 | } | 
|  | 440 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 441 | ipmi_ret_t getFruSdrCount(size_t& count) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 442 | { | 
|  | 443 | ipmi_ret_t ret = replaceCacheFru(0); | 
|  | 444 | if (ret != IPMI_CC_OK) | 
|  | 445 | { | 
|  | 446 | return ret; | 
|  | 447 | } | 
|  | 448 | count = deviceHashes.size(); | 
|  | 449 | return IPMI_CC_OK; | 
|  | 450 | } | 
|  | 451 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 452 | ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 453 | { | 
|  | 454 | ipmi_ret_t ret = replaceCacheFru(0); // this will update the hash list | 
|  | 455 | if (ret != IPMI_CC_OK) | 
|  | 456 | { | 
|  | 457 | return ret; | 
|  | 458 | } | 
|  | 459 | if (deviceHashes.size() < index) | 
|  | 460 | { | 
|  | 461 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 462 | } | 
|  | 463 | auto device = deviceHashes.begin() + index; | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 464 | uint8_t& bus = device->second.first; | 
|  | 465 | uint8_t& address = device->second.second; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 466 |  | 
|  | 467 | ManagedObjectType frus; | 
|  | 468 |  | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 469 | sdbusplus::message_t getObjects = dbus.new_method_call( | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 470 | fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", | 
|  | 471 | "GetManagedObjects"); | 
|  | 472 | try | 
|  | 473 | { | 
| Patrick Williams | cd315e0 | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 474 | sdbusplus::message_t resp = dbus.call(getObjects); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 475 | resp.read(frus); | 
|  | 476 | } | 
| Patrick Williams | 35d1254 | 2021-10-06 11:21:13 -0500 | [diff] [blame] | 477 | catch (const sdbusplus::exception_t&) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 478 | { | 
|  | 479 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 480 | } | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 481 | boost::container::flat_map<std::string, DbusVariant>* fruData = nullptr; | 
| Patrick Williams | 010dee0 | 2024-08-16 15:19:44 -0400 | [diff] [blame] | 482 | auto fru = std::find_if( | 
|  | 483 | frus.begin(), frus.end(), | 
|  | 484 | [bus, address, &fruData](ManagedEntry& entry) { | 
|  | 485 | auto findFruDevice = | 
|  | 486 | entry.second.find("xyz.openbmc_project.FruDevice"); | 
|  | 487 | if (findFruDevice == entry.second.end()) | 
|  | 488 | { | 
|  | 489 | return false; | 
|  | 490 | } | 
|  | 491 | fruData = &(findFruDevice->second); | 
|  | 492 | auto findBus = findFruDevice->second.find("BUS"); | 
|  | 493 | auto findAddress = findFruDevice->second.find("ADDRESS"); | 
|  | 494 | if (findBus == findFruDevice->second.end() || | 
|  | 495 | findAddress == findFruDevice->second.end()) | 
|  | 496 | { | 
|  | 497 | return false; | 
|  | 498 | } | 
|  | 499 | if (std::get<uint32_t>(findBus->second) != bus) | 
|  | 500 | { | 
|  | 501 | return false; | 
|  | 502 | } | 
|  | 503 | if (std::get<uint32_t>(findAddress->second) != address) | 
|  | 504 | { | 
|  | 505 | return false; | 
|  | 506 | } | 
|  | 507 | return true; | 
|  | 508 | }); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 509 | if (fru == frus.end()) | 
|  | 510 | { | 
|  | 511 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 512 | } | 
|  | 513 | std::string name; | 
|  | 514 | auto findProductName = fruData->find("BOARD_PRODUCT_NAME"); | 
|  | 515 | auto findBoardName = fruData->find("PRODUCT_PRODUCT_NAME"); | 
|  | 516 | if (findProductName != fruData->end()) | 
|  | 517 | { | 
| Patrick Williams | ef0efbc | 2020-05-13 11:26:51 -0500 | [diff] [blame] | 518 | name = std::get<std::string>(findProductName->second); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 519 | } | 
|  | 520 | else if (findBoardName != fruData->end()) | 
|  | 521 | { | 
| Patrick Williams | ef0efbc | 2020-05-13 11:26:51 -0500 | [diff] [blame] | 522 | name = std::get<std::string>(findBoardName->second); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 523 | } | 
|  | 524 | else | 
|  | 525 | { | 
|  | 526 | name = "UNKNOWN"; | 
|  | 527 | } | 
|  | 528 | if (name.size() > maxFruSdrNameSize) | 
|  | 529 | { | 
|  | 530 | name = name.substr(0, maxFruSdrNameSize); | 
|  | 531 | } | 
|  | 532 | size_t sizeDiff = maxFruSdrNameSize - name.size(); | 
|  | 533 |  | 
|  | 534 | resp.header.record_id_lsb = 0x0; // calling code is to implement these | 
|  | 535 | resp.header.record_id_msb = 0x0; | 
|  | 536 | resp.header.sdr_version = ipmiSdrVersion; | 
|  | 537 | resp.header.record_type = 0x11; // FRU Device Locator | 
|  | 538 | resp.header.record_length = sizeof(resp.body) + sizeof(resp.key) - sizeDiff; | 
|  | 539 | resp.key.deviceAddress = 0x20; | 
|  | 540 | resp.key.fruID = device->first; | 
|  | 541 | resp.key.accessLun = 0x80; // logical / physical fru device | 
|  | 542 | resp.key.channelNumber = 0x0; | 
|  | 543 | resp.body.reserved = 0x0; | 
|  | 544 | resp.body.deviceType = 0x10; | 
|  | 545 | resp.body.entityID = 0x0; | 
|  | 546 | resp.body.entityInstance = 0x1; | 
|  | 547 | resp.body.oem = 0x0; | 
|  | 548 | resp.body.deviceIDLen = name.size(); | 
|  | 549 | name.copy(resp.body.deviceID, name.size()); | 
|  | 550 |  | 
|  | 551 | return IPMI_CC_OK; | 
|  | 552 | } | 
|  | 553 |  | 
|  | 554 | ipmi_ret_t ipmiStorageReserveSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 555 | ipmi_request_t, ipmi_response_t response, | 
|  | 556 | ipmi_data_len_t dataLen, ipmi_context_t) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 557 | { | 
|  | 558 | printCommand(+netfn, +cmd); | 
|  | 559 |  | 
|  | 560 | if (*dataLen) | 
|  | 561 | { | 
|  | 562 | *dataLen = 0; | 
|  | 563 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 564 | } | 
|  | 565 | *dataLen = 0; // default to 0 in case of an error | 
|  | 566 | sdrReservationID++; | 
|  | 567 | if (sdrReservationID == 0) | 
|  | 568 | { | 
|  | 569 | sdrReservationID++; | 
|  | 570 | } | 
|  | 571 | *dataLen = 2; | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 572 | auto resp = static_cast<uint8_t*>(response); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 573 | resp[0] = sdrReservationID & 0xFF; | 
|  | 574 | resp[1] = sdrReservationID >> 8; | 
|  | 575 |  | 
|  | 576 | return IPMI_CC_OK; | 
|  | 577 | } | 
|  | 578 |  | 
|  | 579 | ipmi_ret_t ipmiStorageGetSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
|  | 580 | ipmi_request_t request, ipmi_response_t response, | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 581 | ipmi_data_len_t dataLen, ipmi_context_t) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 582 | { | 
|  | 583 | printCommand(+netfn, +cmd); | 
|  | 584 |  | 
|  | 585 | if (*dataLen != 6) | 
|  | 586 | { | 
|  | 587 | *dataLen = 0; | 
|  | 588 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 589 | } | 
|  | 590 | auto requestedSize = *dataLen; | 
|  | 591 | *dataLen = 0; // default to 0 in case of an error | 
|  | 592 |  | 
|  | 593 | constexpr uint16_t lastRecordIndex = 0xFFFF; | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 594 | auto req = static_cast<GetSDRReq*>(request); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 595 |  | 
|  | 596 | // reservation required for partial reads with non zero offset into | 
|  | 597 | // record | 
|  | 598 | if ((sdrReservationID == 0 || req->reservationID != sdrReservationID) && | 
|  | 599 | req->offset) | 
|  | 600 | { | 
|  | 601 | return IPMI_CC_INVALID_RESERVATION_ID; | 
|  | 602 | } | 
|  | 603 |  | 
| Potin Lai | 5a7a04d | 2024-01-10 15:25:21 +0800 | [diff] [blame] | 604 | if (!getSensorSubtree(sensorTree) && sensorTree.empty()) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 605 | { | 
|  | 606 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | size_t fruCount = 0; | 
|  | 610 | ipmi_ret_t ret = ipmi::storage::getFruSdrCount(fruCount); | 
|  | 611 | if (ret != IPMI_CC_OK) | 
|  | 612 | { | 
|  | 613 | return ret; | 
|  | 614 | } | 
|  | 615 |  | 
|  | 616 | size_t lastRecord = sensorTree.size() + fruCount - 1; | 
|  | 617 | if (req->recordID == lastRecordIndex) | 
|  | 618 | { | 
|  | 619 | req->recordID = lastRecord; | 
|  | 620 | } | 
|  | 621 | if (req->recordID > lastRecord) | 
|  | 622 | { | 
|  | 623 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 624 | } | 
|  | 625 |  | 
| cchoux | 8713427 | 2023-10-06 15:20:23 +0800 | [diff] [blame] | 626 | uint16_t nextRecord = lastRecord >= static_cast<size_t>(req->recordID + 1) | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 627 | ? req->recordID + 1 | 
|  | 628 | : 0XFFFF; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 629 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 630 | auto responseClear = static_cast<uint8_t*>(response); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 631 | std::fill(responseClear, responseClear + requestedSize, 0); | 
|  | 632 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 633 | auto resp = static_cast<get_sdr::GetSdrResp*>(response); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 634 | resp->next_record_id_lsb = nextRecord & 0xFF; | 
|  | 635 | resp->next_record_id_msb = nextRecord >> 8; | 
|  | 636 |  | 
|  | 637 | if (req->recordID >= sensorTree.size()) | 
|  | 638 | { | 
|  | 639 | size_t fruIndex = req->recordID - sensorTree.size(); | 
|  | 640 | if (fruIndex >= fruCount) | 
|  | 641 | { | 
|  | 642 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 643 | } | 
|  | 644 | get_sdr::SensorDataFruRecord data; | 
|  | 645 | if (req->offset > sizeof(data)) | 
|  | 646 | { | 
|  | 647 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 648 | } | 
|  | 649 | ret = ipmi::storage::getFruSdrs(fruIndex, data); | 
|  | 650 | if (ret != IPMI_CC_OK) | 
|  | 651 | { | 
|  | 652 | return ret; | 
|  | 653 | } | 
|  | 654 | data.header.record_id_msb = req->recordID << 8; | 
|  | 655 | data.header.record_id_lsb = req->recordID & 0xFF; | 
|  | 656 | if (sizeof(data) < (req->offset + req->bytesToRead)) | 
|  | 657 | { | 
|  | 658 | req->bytesToRead = sizeof(data) - req->offset; | 
|  | 659 | } | 
|  | 660 | *dataLen = req->bytesToRead + 2; // next record | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 661 | std::memcpy(&resp->record_data, (char*)&data + req->offset, | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 662 | req->bytesToRead); | 
|  | 663 | return IPMI_CC_OK; | 
|  | 664 | } | 
|  | 665 |  | 
|  | 666 | std::string connection; | 
|  | 667 | std::string path; | 
|  | 668 | uint16_t sensorIndex = req->recordID; | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 669 | for (const auto& sensor : sensorTree) | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 670 | { | 
|  | 671 | if (sensorIndex-- == 0) | 
|  | 672 | { | 
|  | 673 | if (!sensor.second.size()) | 
|  | 674 | { | 
|  | 675 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 676 | } | 
|  | 677 | connection = sensor.second.begin()->first; | 
|  | 678 | path = sensor.first; | 
|  | 679 | break; | 
|  | 680 | } | 
|  | 681 | } | 
|  | 682 |  | 
|  | 683 | SensorMap sensorMap; | 
|  | 684 | if (!getSensorMap(connection, path, sensorMap)) | 
|  | 685 | { | 
|  | 686 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 687 | } | 
|  | 688 | uint8_t sensornumber = (req->recordID & 0xFF); | 
| Willy Tu | e39f939 | 2022-06-15 13:24:20 -0700 | [diff] [blame] | 689 | get_sdr::SensorDataFullRecord record = {}; | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 690 |  | 
|  | 691 | record.header.record_id_msb = req->recordID << 8; | 
|  | 692 | record.header.record_id_lsb = req->recordID & 0xFF; | 
|  | 693 | record.header.sdr_version = ipmiSdrVersion; | 
|  | 694 | record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD; | 
|  | 695 | record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) - | 
|  | 696 | sizeof(get_sdr::SensorDataRecordHeader); | 
|  | 697 | record.key.owner_id = 0x20; | 
|  | 698 | record.key.owner_lun = 0x0; | 
|  | 699 | record.key.sensor_number = sensornumber; | 
|  | 700 |  | 
|  | 701 | record.body.entity_id = 0x0; | 
|  | 702 | record.body.entity_instance = 0x01; | 
|  | 703 | record.body.sensor_capabilities = 0x60; // auto rearm - todo hysteresis | 
|  | 704 | record.body.sensor_type = getSensorTypeFromPath(path); | 
|  | 705 | std::string type = getSensorTypeStringFromPath(path); | 
|  | 706 | auto typeCstr = type.c_str(); | 
|  | 707 | auto findUnits = sensorUnits.find(typeCstr); | 
|  | 708 | if (findUnits != sensorUnits.end()) | 
|  | 709 | { | 
|  | 710 | record.body.sensor_units_2_base = | 
|  | 711 | static_cast<uint8_t>(findUnits->second); | 
|  | 712 | } // else default 0x0 unspecified | 
|  | 713 |  | 
|  | 714 | record.body.event_reading_type = getSensorEventTypeFromPath(path); | 
|  | 715 |  | 
|  | 716 | auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value"); | 
|  | 717 | if (sensorObject == sensorMap.end()) | 
|  | 718 | { | 
|  | 719 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 720 | } | 
|  | 721 |  | 
|  | 722 | auto maxObject = sensorObject->second.find("MaxValue"); | 
|  | 723 | auto minObject = sensorObject->second.find("MinValue"); | 
|  | 724 | double max = 128; | 
|  | 725 | double min = -127; | 
|  | 726 | if (maxObject != sensorObject->second.end()) | 
|  | 727 | { | 
| Patrick Williams | ef0efbc | 2020-05-13 11:26:51 -0500 | [diff] [blame] | 728 | max = std::visit(VariantToDoubleVisitor(), maxObject->second); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 729 | } | 
|  | 730 |  | 
|  | 731 | if (minObject != sensorObject->second.end()) | 
|  | 732 | { | 
| Patrick Williams | ef0efbc | 2020-05-13 11:26:51 -0500 | [diff] [blame] | 733 | min = std::visit(VariantToDoubleVisitor(), minObject->second); | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 734 | } | 
|  | 735 |  | 
|  | 736 | int16_t mValue; | 
|  | 737 | int8_t rExp; | 
|  | 738 | int16_t bValue; | 
|  | 739 | int8_t bExp; | 
|  | 740 | bool bSigned; | 
|  | 741 |  | 
|  | 742 | if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned)) | 
|  | 743 | { | 
|  | 744 | return IPMI_CC_RESPONSE_ERROR; | 
|  | 745 | } | 
|  | 746 |  | 
|  | 747 | // apply M, B, and exponents, M and B are 10 bit values, exponents are 4 | 
|  | 748 | record.body.m_lsb = mValue & 0xFF; | 
|  | 749 |  | 
|  | 750 | // move the smallest bit of the MSB into place (bit 9) | 
|  | 751 | // the MSbs are bits 7:8 in m_msb_and_tolerance | 
|  | 752 | uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0; | 
|  | 753 |  | 
|  | 754 | // assign the negative | 
|  | 755 | if (mValue < 0) | 
|  | 756 | { | 
|  | 757 | mMsb |= (1 << 7); | 
|  | 758 | } | 
|  | 759 | record.body.m_msb_and_tolerance = mMsb; | 
|  | 760 |  | 
|  | 761 | record.body.b_lsb = bValue & 0xFF; | 
|  | 762 |  | 
|  | 763 | // move the smallest bit of the MSB into place | 
|  | 764 | // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb | 
|  | 765 | uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0; | 
|  | 766 |  | 
|  | 767 | // assign the negative | 
|  | 768 | if (bValue < 0) | 
|  | 769 | { | 
|  | 770 | bMsb |= (1 << 7); | 
|  | 771 | } | 
|  | 772 | record.body.b_msb_and_accuracy_lsb = bMsb; | 
|  | 773 |  | 
|  | 774 | record.body.r_b_exponents = bExp & 0x7; | 
|  | 775 | if (bExp < 0) | 
|  | 776 | { | 
|  | 777 | record.body.r_b_exponents |= 1 << 3; | 
|  | 778 | } | 
|  | 779 | record.body.r_b_exponents = (rExp & 0x7) << 4; | 
|  | 780 | if (rExp < 0) | 
|  | 781 | { | 
|  | 782 | record.body.r_b_exponents |= 1 << 7; | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | // todo fill out rest of units | 
|  | 786 | if (bSigned) | 
|  | 787 | { | 
|  | 788 | record.body.sensor_units_1 = 1 << 7; | 
|  | 789 | } | 
|  | 790 |  | 
|  | 791 | // populate sensor name from path | 
|  | 792 | std::string name; | 
|  | 793 | size_t nameStart = path.rfind("/"); | 
|  | 794 | if (nameStart != std::string::npos) | 
|  | 795 | { | 
|  | 796 | name = path.substr(nameStart + 1, std::string::npos - nameStart); | 
|  | 797 | } | 
|  | 798 |  | 
|  | 799 | std::replace(name.begin(), name.end(), '_', ' '); | 
|  | 800 | if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH) | 
|  | 801 | { | 
|  | 802 | name.resize(FULL_RECORD_ID_STR_MAX_LENGTH); | 
|  | 803 | } | 
|  | 804 | record.body.id_string_info = name.size(); | 
|  | 805 | std::strncpy(record.body.id_string, name.c_str(), | 
|  | 806 | sizeof(record.body.id_string)); | 
|  | 807 |  | 
|  | 808 | if (sizeof(get_sdr::SensorDataFullRecord) < | 
|  | 809 | (req->offset + req->bytesToRead)) | 
|  | 810 | { | 
|  | 811 | req->bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - req->offset; | 
|  | 812 | } | 
|  | 813 |  | 
| Patrick Williams | 2405ae9 | 2023-05-10 07:50:09 -0500 | [diff] [blame] | 814 | *dataLen = 2 + | 
|  | 815 | req->bytesToRead; // bytesToRead + MSB and LSB of next record id | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 816 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 817 | std::memcpy(&resp->record_data, (char*)&record + req->offset, | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 818 | req->bytesToRead); | 
|  | 819 |  | 
|  | 820 | return IPMI_CC_OK; | 
|  | 821 | } | 
|  | 822 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 823 | static int getSensorConnectionByName(std::string& name, std::string& connection, | 
|  | 824 | std::string& path) | 
| Vijay Khemka | 427b276 | 2019-12-12 12:49:25 -0800 | [diff] [blame] | 825 | { | 
| Potin Lai | 5a7a04d | 2024-01-10 15:25:21 +0800 | [diff] [blame] | 826 | if (!getSensorSubtree(sensorTree) && sensorTree.empty()) | 
| Vijay Khemka | 427b276 | 2019-12-12 12:49:25 -0800 | [diff] [blame] | 827 | { | 
|  | 828 | return -1; | 
|  | 829 | } | 
|  | 830 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 831 | for (const auto& sensor : sensorTree) | 
| Vijay Khemka | 427b276 | 2019-12-12 12:49:25 -0800 | [diff] [blame] | 832 | { | 
|  | 833 | path = sensor.first; | 
|  | 834 | if (path.find(name) != std::string::npos) | 
|  | 835 | { | 
|  | 836 | connection = sensor.second.begin()->first; | 
|  | 837 | return 0; | 
|  | 838 | } | 
|  | 839 | } | 
|  | 840 | return -1; | 
|  | 841 | } | 
|  | 842 |  | 
| Delphine CC Chiu | 2ca4aa0 | 2023-02-01 16:30:18 +0800 | [diff] [blame] | 843 | int getSensorThreshold(std::string& name, std::string& thresholdStr) | 
|  | 844 | { | 
|  | 845 | std::string connection; | 
|  | 846 | std::string path; | 
|  | 847 | int ret = -1; | 
|  | 848 | thresholdStr = ""; | 
|  | 849 |  | 
|  | 850 | ret = getSensorConnectionByName(name, connection, path); | 
|  | 851 | if (ret < 0) | 
|  | 852 | { | 
|  | 853 | return ret; | 
|  | 854 | } | 
|  | 855 |  | 
|  | 856 | SensorMap sensorMap; | 
|  | 857 | if (!getSensorMap(connection, path, sensorMap)) | 
|  | 858 | { | 
|  | 859 | return ret; | 
|  | 860 | } | 
|  | 861 |  | 
|  | 862 | // Iterate threshold interfaces with priority order | 
|  | 863 | for (auto& interface : thresholdCheckedOrder) | 
|  | 864 | { | 
|  | 865 | auto interfaceProperty = alarmProperties.find(interface); | 
|  | 866 | if (interfaceProperty == alarmProperties.end()) | 
|  | 867 | { | 
|  | 868 | continue; | 
|  | 869 | } | 
|  | 870 |  | 
|  | 871 | auto propertyValue = interfaceProperty->second; | 
|  | 872 |  | 
|  | 873 | // Checks threshold properties value in sensorMap | 
|  | 874 | auto thresholdInterfaceSensorMap = sensorMap.find(interface); | 
|  | 875 |  | 
|  | 876 | // Ignore if interface not set | 
|  | 877 | if (thresholdInterfaceSensorMap == sensorMap.end()) | 
|  | 878 | { | 
|  | 879 | continue; | 
|  | 880 | } | 
|  | 881 |  | 
|  | 882 | auto& thresholdMap = thresholdInterfaceSensorMap->second; | 
|  | 883 |  | 
|  | 884 | auto& propertyAlarmHigh = propertyValue.at(AlarmType::high); | 
|  | 885 | auto alarmHigh = thresholdMap.find(propertyAlarmHigh.name); | 
|  | 886 | if (alarmHigh != thresholdMap.end()) | 
|  | 887 | { | 
|  | 888 | if (std::get<bool>(alarmHigh->second)) | 
|  | 889 | { | 
|  | 890 | thresholdStr = propertyAlarmHigh.threshold; | 
|  | 891 | break; | 
|  | 892 | } | 
|  | 893 | } | 
|  | 894 |  | 
|  | 895 | auto& propertyAlarmLow = propertyValue.at(AlarmType::low); | 
|  | 896 | auto alarmLow = thresholdMap.find(propertyAlarmLow.name); | 
|  | 897 | if (alarmLow != thresholdMap.end()) | 
|  | 898 | { | 
|  | 899 | if (std::get<bool>(alarmLow->second)) | 
|  | 900 | { | 
|  | 901 | thresholdStr = propertyAlarmLow.threshold; | 
|  | 902 | break; | 
|  | 903 | } | 
|  | 904 | } | 
|  | 905 | } | 
|  | 906 |  | 
|  | 907 | return 0; | 
|  | 908 | } | 
|  | 909 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 910 | int getSensorValue(std::string& name, double& val) | 
| Vijay Khemka | 427b276 | 2019-12-12 12:49:25 -0800 | [diff] [blame] | 911 | { | 
|  | 912 | std::string connection; | 
|  | 913 | std::string path; | 
|  | 914 | int ret = -1; | 
|  | 915 |  | 
|  | 916 | ret = getSensorConnectionByName(name, connection, path); | 
|  | 917 | if (ret < 0) | 
|  | 918 | { | 
|  | 919 | return ret; | 
|  | 920 | } | 
|  | 921 |  | 
|  | 922 | SensorMap sensorMap; | 
|  | 923 | if (!getSensorMap(connection, path, sensorMap)) | 
|  | 924 | { | 
|  | 925 | return ret; | 
|  | 926 | } | 
|  | 927 | auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value"); | 
|  | 928 |  | 
|  | 929 | if (sensorObject == sensorMap.end() || | 
|  | 930 | sensorObject->second.find("Value") == sensorObject->second.end()) | 
|  | 931 | { | 
|  | 932 | return ret; | 
|  | 933 | } | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 934 | auto& valueVariant = sensorObject->second["Value"]; | 
| Vijay Khemka | 427b276 | 2019-12-12 12:49:25 -0800 | [diff] [blame] | 935 | val = std::visit(VariantToDoubleVisitor(), valueVariant); | 
|  | 936 |  | 
|  | 937 | return 0; | 
|  | 938 | } | 
|  | 939 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 940 | const static boost::container::flat_map<const char*, std::string, CmpStr> | 
| Vijay Khemka | 58bd5d8 | 2019-12-13 11:05:56 -0800 | [diff] [blame] | 941 | sensorUnitStr{{{"temperature", "C"}, | 
|  | 942 | {"voltage", "V"}, | 
|  | 943 | {"current", "mA"}, | 
|  | 944 | {"fan_tach", "RPM"}, | 
|  | 945 | {"fan_pwm", "RPM"}, | 
|  | 946 | {"power", "W"}}}; | 
|  | 947 |  | 
| Vijay Khemka | 63c99be | 2020-05-27 19:14:35 -0700 | [diff] [blame] | 948 | int getSensorUnit(std::string& name, std::string& unit) | 
| Vijay Khemka | 58bd5d8 | 2019-12-13 11:05:56 -0800 | [diff] [blame] | 949 | { | 
|  | 950 | std::string connection; | 
|  | 951 | std::string path; | 
|  | 952 | int ret = -1; | 
|  | 953 |  | 
|  | 954 | ret = getSensorConnectionByName(name, connection, path); | 
|  | 955 | if (ret < 0) | 
|  | 956 | { | 
|  | 957 | return ret; | 
|  | 958 | } | 
|  | 959 |  | 
|  | 960 | std::string sensorTypeStr = getSensorTypeStringFromPath(path); | 
|  | 961 | auto findSensor = sensorUnitStr.find(sensorTypeStr.c_str()); | 
|  | 962 | if (findSensor != sensorUnitStr.end()) | 
|  | 963 | { | 
|  | 964 | unit = findSensor->second; | 
|  | 965 | return 0; | 
|  | 966 | } | 
|  | 967 | else | 
|  | 968 | return -1; | 
|  | 969 | } | 
|  | 970 |  | 
| Patrick Williams | 010dee0 | 2024-08-16 15:19:44 -0400 | [diff] [blame] | 971 | ipmi_ret_t ipmiStorageGetFRUInvAreaInfo( | 
|  | 972 | ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response, | 
|  | 973 | ipmi_data_len_t dataLen, ipmi_context_t) | 
| Vijay Khemka | 17cf134 | 2020-11-02 14:44:42 -0800 | [diff] [blame] | 974 | { | 
|  | 975 | if (*dataLen != 1) | 
|  | 976 | { | 
|  | 977 | *dataLen = 0; | 
|  | 978 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 979 | } | 
|  | 980 | *dataLen = 0; // default to 0 in case of an error | 
|  | 981 |  | 
|  | 982 | uint8_t reqDev = *(static_cast<uint8_t*>(request)); | 
|  | 983 | if (reqDev == 0xFF) | 
|  | 984 | { | 
|  | 985 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 986 | } | 
|  | 987 | ipmi_ret_t status = replaceCacheFru(reqDev); | 
|  | 988 |  | 
|  | 989 | if (status != IPMI_CC_OK) | 
|  | 990 | { | 
|  | 991 | return status; | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | GetFRUAreaResp* respPtr = static_cast<GetFRUAreaResp*>(response); | 
|  | 995 | respPtr->inventorySizeLSB = fruCache.size() & 0xFF; | 
|  | 996 | respPtr->inventorySizeMSB = fruCache.size() >> 8; | 
|  | 997 | respPtr->accessType = static_cast<uint8_t>(GetFRUAreaAccessType::byte); | 
|  | 998 |  | 
|  | 999 | *dataLen = sizeof(GetFRUAreaResp); | 
|  | 1000 | return IPMI_CC_OK; | 
|  | 1001 | } | 
|  | 1002 |  | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 1003 | void registerStorageFunctions() | 
|  | 1004 | { | 
| Vijay Khemka | 17cf134 | 2020-11-02 14:44:42 -0800 | [diff] [blame] | 1005 | // <Get FRU Inventory Area Info> | 
|  | 1006 | ipmiPrintAndRegister( | 
|  | 1007 | NETFUN_STORAGE, | 
|  | 1008 | static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetFRUInvAreaInfo), | 
|  | 1009 | NULL, ipmiStorageGetFRUInvAreaInfo, PRIVILEGE_OPERATOR); | 
|  | 1010 |  | 
| Vijay Khemka | e7d23d0 | 2019-03-08 13:13:40 -0800 | [diff] [blame] | 1011 | // <READ FRU Data> | 
|  | 1012 | ipmiPrintAndRegister( | 
|  | 1013 | NETFUN_STORAGE, | 
|  | 1014 | static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReadFRUData), NULL, | 
|  | 1015 | ipmiStorageReadFRUData, PRIVILEGE_OPERATOR); | 
|  | 1016 |  | 
|  | 1017 | // <WRITE FRU Data> | 
|  | 1018 | ipmiPrintAndRegister( | 
|  | 1019 | NETFUN_STORAGE, | 
|  | 1020 | static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdWriteFRUData), | 
|  | 1021 | NULL, ipmiStorageWriteFRUData, PRIVILEGE_OPERATOR); | 
|  | 1022 |  | 
|  | 1023 | // <Reserve SDR Repo> | 
|  | 1024 | ipmiPrintAndRegister( | 
|  | 1025 | NETFUN_STORAGE, | 
|  | 1026 | static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReserveSDR), | 
|  | 1027 | nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER); | 
|  | 1028 |  | 
|  | 1029 | // <Get Sdr> | 
|  | 1030 | ipmiPrintAndRegister( | 
|  | 1031 | NETFUN_STORAGE, | 
|  | 1032 | static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSDR), nullptr, | 
|  | 1033 | ipmiStorageGetSDR, PRIVILEGE_USER); | 
|  | 1034 | return; | 
|  | 1035 | } | 
|  | 1036 | } // namespace storage | 
|  | 1037 | } // namespace ipmi |