| Brandon Wyman | 24e422f | 2017-07-25 19:40:14 -0500 | [diff] [blame] | 1 | /** | 
 | 2 |  * Copyright © 2017 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 |  */ | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 16 | #include <phosphor-logging/log.hpp> | 
 | 17 | #include <phosphor-logging/elog.hpp> | 
| Brandon Wyman | e0eb45c | 2017-10-06 12:58:42 -0500 | [diff] [blame] | 18 | #include <org/open_power/Witherspoon/Fault/error.hpp> | 
| Matt Spinler | ceacf94 | 2017-10-05 13:55:02 -0500 | [diff] [blame] | 19 | #include <xyz/openbmc_project/Common/Device/error.hpp> | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 20 | #include <xyz/openbmc_project/Software/Version/server.hpp> | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 21 | #include "elog-errors.hpp" | 
| Matt Spinler | d734e65 | 2018-01-18 14:31:15 -0600 | [diff] [blame] | 22 | #include "gpio.hpp" | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 23 | #include "names_values.hpp" | 
| Brandon Wyman | 24e422f | 2017-07-25 19:40:14 -0500 | [diff] [blame] | 24 | #include "power_supply.hpp" | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 25 | #include "pmbus.hpp" | 
 | 26 | #include "utility.hpp" | 
 | 27 |  | 
| Brandon Wyman | 1db9a9e | 2017-07-26 18:50:22 -0500 | [diff] [blame] | 28 | namespace witherspoon | 
| Brandon Wyman | 24e422f | 2017-07-25 19:40:14 -0500 | [diff] [blame] | 29 | { | 
 | 30 | namespace power | 
 | 31 | { | 
 | 32 | namespace psu | 
 | 33 | { | 
 | 34 |  | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 35 | using namespace phosphor::logging; | 
 | 36 | using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error; | 
 | 37 | using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error; | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 38 | namespace version = sdbusplus::xyz::openbmc_project::Software::server; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 39 |  | 
 | 40 | constexpr auto ASSOCIATION_IFACE = "org.openbmc.Association"; | 
 | 41 | constexpr auto LOGGING_IFACE = "xyz.openbmc_project.Logging.Entry"; | 
 | 42 | constexpr auto INVENTORY_IFACE = "xyz.openbmc_project.Inventory.Item"; | 
 | 43 | constexpr auto POWER_IFACE = "org.openbmc.control.Power"; | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 44 | constexpr auto INVENTORY_MGR_IFACE = "xyz.openbmc_project.Inventory.Manager"; | 
 | 45 | constexpr auto ASSET_IFACE = "xyz.openbmc_project.Inventory.Decorator.Asset"; | 
 | 46 | constexpr auto VERSION_IFACE = "xyz.openbmc_project.Software.Version"; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 47 |  | 
 | 48 | constexpr auto ENDPOINTS_PROP = "endpoints"; | 
 | 49 | constexpr auto MESSAGE_PROP = "Message"; | 
 | 50 | constexpr auto RESOLVED_PROP = "Resolved"; | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 51 | constexpr auto PRESENT_PROP = "Present"; | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 52 | constexpr auto SN_PROP = "SerialNumber"; | 
 | 53 | constexpr auto PN_PROP = "PartNumber"; | 
 | 54 | constexpr auto MODEL_PROP = "Model"; | 
 | 55 | constexpr auto VERSION_PROP = "Version"; | 
 | 56 | constexpr auto VERSION_PURPOSE_PROP = "Purpose"; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 57 |  | 
 | 58 | constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory"; | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 59 | constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0"; | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 60 |  | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 61 | constexpr auto SERIAL_NUMBER = "serial_number"; | 
 | 62 | constexpr auto PART_NUMBER = "part_number"; | 
 | 63 | constexpr auto FW_VERSION = "fw_version"; | 
 | 64 | constexpr auto CCIN = "ccin"; | 
| Matt Spinler | eb169fd | 2018-01-18 14:19:08 -0600 | [diff] [blame] | 65 | constexpr auto INPUT_HISTORY = "input_history"; | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 66 |  | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 67 | PowerSupply::PowerSupply(const std::string& name, size_t inst, | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 68 |                          const std::string& objpath, | 
 | 69 |                          const std::string& invpath, | 
 | 70 |                          sdbusplus::bus::bus& bus, | 
 | 71 |                          event::Event& e, | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 72 |                          std::chrono::seconds& t, | 
 | 73 |                          std::chrono::seconds& p) | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 74 |     : Device(name, inst), monitorPath(objpath), pmbusIntf(objpath), | 
| Brandon Wyman | 50bb85d | 2017-11-01 18:36:00 -0500 | [diff] [blame] | 75 |       inventoryPath(INVENTORY_OBJ_PATH + invpath), bus(bus), event(e), | 
 | 76 |       presentInterval(p), | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 77 |       presentTimer(e, [this]() | 
 | 78 |                    { | 
| Brandon Wyman | 2877add | 2017-11-10 17:44:19 -0600 | [diff] [blame] | 79 |                        // The hwmon path may have changed. | 
 | 80 |                        pmbusIntf.findHwmonDir(); | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 81 |                        this->present = true; | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 82 |  | 
| Matt Spinler | d734e65 | 2018-01-18 14:31:15 -0600 | [diff] [blame] | 83 |                        // Sync the INPUT_HISTORY data for all PSs | 
 | 84 |                        syncHistory(); | 
 | 85 |  | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 86 |                        // Update the inventory for the new device | 
 | 87 |                        updateInventory(); | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 88 |                    }), | 
 | 89 |       powerOnInterval(t), | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 90 |       powerOnTimer(e, [this]() | 
 | 91 |                    { | 
 | 92 |                        this->powerOn = true; | 
 | 93 |                    }) | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 94 | { | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 95 |     using namespace sdbusplus::bus; | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 96 |     presentMatch = std::make_unique<match_t>(bus, | 
 | 97 |                                              match::rules::propertiesChanged( | 
| Brandon Wyman | 50bb85d | 2017-11-01 18:36:00 -0500 | [diff] [blame] | 98 |                                                      inventoryPath, | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 99 |                                                      INVENTORY_IFACE), | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 100 |                                              [this](auto& msg) | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 101 |                                              { | 
 | 102 |                                                  this->inventoryChanged(msg); | 
 | 103 |                                              }); | 
 | 104 |     // Get initial presence state. | 
| Brandon Wyman | 253dc9b | 2017-08-12 13:45:52 -0500 | [diff] [blame] | 105 |     updatePresence(); | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 106 |  | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 107 |     // Write the SN, PN, etc to the inventory | 
 | 108 |     updateInventory(); | 
 | 109 |  | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 110 |     // Subscribe to power state changes | 
 | 111 |     powerOnMatch = std::make_unique<match_t>(bus, | 
 | 112 |                                              match::rules::propertiesChanged( | 
 | 113 |                                                      POWER_OBJ_PATH, | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 114 |                                                      POWER_IFACE), | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 115 |                                              [this](auto& msg) | 
 | 116 |                                              { | 
 | 117 |                                                  this->powerStateChanged(msg); | 
 | 118 |                                              }); | 
 | 119 |     // Get initial power state. | 
 | 120 |     updatePowerState(); | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 121 | } | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 122 |  | 
| Brandon Wyman | a1e9634 | 2017-09-25 16:47:44 -0500 | [diff] [blame] | 123 | void PowerSupply::captureCmd(util::NamesValues& nv, const std::string& cmd, | 
 | 124 |                              witherspoon::pmbus::Type type) | 
 | 125 | { | 
 | 126 |     if (pmbusIntf.exists(cmd, type)) | 
 | 127 |     { | 
 | 128 |         try | 
 | 129 |         { | 
 | 130 |             auto val = pmbusIntf.read(cmd, type); | 
 | 131 |             nv.add(cmd, val); | 
 | 132 |         } | 
 | 133 |         catch (std::exception& e) | 
 | 134 |         { | 
 | 135 |             log<level::INFO>("Unable to capture metadata", entry("CMD=%s", | 
 | 136 |                                                                  cmd)); | 
 | 137 |         } | 
 | 138 |     } | 
 | 139 | } | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 140 |  | 
| Brandon Wyman | 1db9a9e | 2017-07-26 18:50:22 -0500 | [diff] [blame] | 141 | void PowerSupply::analyze() | 
 | 142 | { | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 143 |     using namespace witherspoon::pmbus; | 
 | 144 |  | 
 | 145 |     try | 
 | 146 |     { | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 147 |         if (present) | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 148 |         { | 
| Brandon Wyman | 764c797 | 2017-08-22 17:05:36 -0500 | [diff] [blame] | 149 |             std::uint16_t statusWord = 0; | 
| Brandon Wyman | 764c797 | 2017-08-22 17:05:36 -0500 | [diff] [blame] | 150 |  | 
 | 151 |             // Read the 2 byte STATUS_WORD value to check for faults. | 
 | 152 |             statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug); | 
| Brandon Wyman | e4af980 | 2017-11-13 15:58:33 -0600 | [diff] [blame] | 153 |             readFail = 0; | 
| Brandon Wyman | 764c797 | 2017-08-22 17:05:36 -0500 | [diff] [blame] | 154 |  | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 155 |             checkInputFault(statusWord); | 
| Brandon Wyman | 764c797 | 2017-08-22 17:05:36 -0500 | [diff] [blame] | 156 |  | 
| Brandon Wyman | 3343e82 | 2017-11-03 16:54:11 -0500 | [diff] [blame] | 157 |             if (powerOn && !faultFound) | 
| Brandon Wyman | 764c797 | 2017-08-22 17:05:36 -0500 | [diff] [blame] | 158 |             { | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 159 |                 checkFanFault(statusWord); | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 160 |                 checkTemperatureFault(statusWord); | 
| Brandon Wyman | cfa032b | 2017-09-25 17:37:50 -0500 | [diff] [blame] | 161 |                 checkOutputOvervoltageFault(statusWord); | 
 | 162 |                 checkCurrentOutOverCurrentFault(statusWord); | 
 | 163 |                 checkPGOrUnitOffFault(statusWord); | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 164 |             } | 
| Matt Spinler | eb169fd | 2018-01-18 14:19:08 -0600 | [diff] [blame] | 165 |  | 
 | 166 |             updateHistory(); | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 167 |         } | 
 | 168 |     } | 
 | 169 |     catch (ReadFailure& e) | 
 | 170 |     { | 
| Brandon Wyman | e4af980 | 2017-11-13 15:58:33 -0600 | [diff] [blame] | 171 |         if (readFail < FAULT_COUNT) | 
 | 172 |         { | 
 | 173 |             readFail++; | 
 | 174 |         } | 
 | 175 |  | 
 | 176 |         if (!readFailLogged && readFail >= FAULT_COUNT) | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 177 |         { | 
 | 178 |             commit<ReadFailure>(); | 
 | 179 |             readFailLogged = true; | 
| Brandon Wyman | 442035f | 2017-08-08 15:58:45 -0500 | [diff] [blame] | 180 |         } | 
 | 181 |     } | 
 | 182 |  | 
| Brandon Wyman | 1db9a9e | 2017-07-26 18:50:22 -0500 | [diff] [blame] | 183 |     return; | 
 | 184 | } | 
 | 185 |  | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 186 | void PowerSupply::inventoryChanged(sdbusplus::message::message& msg) | 
 | 187 | { | 
 | 188 |     std::string msgSensor; | 
 | 189 |     std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData; | 
 | 190 |     msg.read(msgSensor, msgData); | 
 | 191 |  | 
 | 192 |     // Check if it was the Present property that changed. | 
 | 193 |     auto valPropMap = msgData.find(PRESENT_PROP); | 
 | 194 |     if (valPropMap != msgData.end()) | 
 | 195 |     { | 
| Brandon Wyman | 2ef48cf | 2017-11-21 15:43:54 -0600 | [diff] [blame] | 196 |         if (sdbusplus::message::variant_ns::get<bool>(valPropMap->second)) | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 197 |         { | 
| Brandon Wyman | 6ccce0b | 2017-10-26 15:13:10 -0500 | [diff] [blame] | 198 |             clearFaults(); | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 199 |             presentTimer.start(presentInterval, Timer::TimerType::oneshot); | 
 | 200 |         } | 
 | 201 |         else | 
 | 202 |         { | 
| Brandon Wyman | 2ef48cf | 2017-11-21 15:43:54 -0600 | [diff] [blame] | 203 |             present = false; | 
| Brandon Wyman | 590fc28 | 2017-11-01 18:22:25 -0500 | [diff] [blame] | 204 |             presentTimer.stop(); | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 205 |  | 
 | 206 |             //Clear out the now outdated inventory properties | 
 | 207 |             updateInventory(); | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 208 |         } | 
 | 209 |     } | 
 | 210 |  | 
 | 211 |     return; | 
 | 212 | } | 
 | 213 |  | 
 | 214 | void PowerSupply::updatePresence() | 
 | 215 | { | 
 | 216 |     // Use getProperty utility function to get presence status. | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 217 |     std::string service = "xyz.openbmc_project.Inventory.Manager"; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 218 |     util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath, | 
| Brandon Wyman | 50bb85d | 2017-11-01 18:36:00 -0500 | [diff] [blame] | 219 |                       service, bus, this->present); | 
| Brandon Wyman | 1029554 | 2017-08-09 18:20:44 -0500 | [diff] [blame] | 220 | } | 
 | 221 |  | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 222 | void PowerSupply::powerStateChanged(sdbusplus::message::message& msg) | 
 | 223 | { | 
 | 224 |     int32_t state = 0; | 
 | 225 |     std::string msgSensor; | 
 | 226 |     std::map<std::string, sdbusplus::message::variant<int32_t, int32_t>> | 
 | 227 |             msgData; | 
 | 228 |     msg.read(msgSensor, msgData); | 
 | 229 |  | 
 | 230 |     // Check if it was the Present property that changed. | 
 | 231 |     auto valPropMap = msgData.find("state"); | 
 | 232 |     if (valPropMap != msgData.end()) | 
 | 233 |     { | 
 | 234 |         state = sdbusplus::message::variant_ns::get<int32_t>(valPropMap->second); | 
 | 235 |  | 
 | 236 |         // Power is on when state=1. Set the fault logged variables to false | 
 | 237 |         // and start the power on timer when the state changes to 1. | 
 | 238 |         if (state) | 
 | 239 |         { | 
| Brandon Wyman | 6ccce0b | 2017-10-26 15:13:10 -0500 | [diff] [blame] | 240 |             clearFaults(); | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 241 |             powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot); | 
 | 242 |         } | 
 | 243 |         else | 
 | 244 |         { | 
 | 245 |             powerOnTimer.stop(); | 
 | 246 |             powerOn = false; | 
 | 247 |         } | 
 | 248 |     } | 
 | 249 |  | 
 | 250 | } | 
 | 251 |  | 
 | 252 | void PowerSupply::updatePowerState() | 
 | 253 | { | 
 | 254 |     // When state = 1, system is powered on | 
 | 255 |     int32_t state = 0; | 
 | 256 |  | 
 | 257 |     try | 
 | 258 |     { | 
 | 259 |         auto service = util::getService(POWER_OBJ_PATH, | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 260 |                                         POWER_IFACE, | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 261 |                                         bus); | 
 | 262 |  | 
 | 263 |         // Use getProperty utility function to get power state. | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 264 |         util::getProperty<int32_t>(POWER_IFACE, | 
| Brandon Wyman | 431fbe4 | 2017-08-18 16:22:09 -0500 | [diff] [blame] | 265 |                                    "state", | 
 | 266 |                                    POWER_OBJ_PATH, | 
 | 267 |                                    service, | 
 | 268 |                                    bus, | 
 | 269 |                                    state); | 
 | 270 |  | 
 | 271 |         if (state) | 
 | 272 |         { | 
 | 273 |             powerOn = true; | 
 | 274 |         } | 
 | 275 |         else | 
 | 276 |         { | 
 | 277 |             powerOn = false; | 
 | 278 |         } | 
 | 279 |     } | 
 | 280 |     catch (std::exception& e) | 
 | 281 |     { | 
 | 282 |         log<level::INFO>("Failed to get power state. Assuming it is off."); | 
 | 283 |         powerOn = false; | 
 | 284 |     } | 
 | 285 |  | 
 | 286 | } | 
 | 287 |  | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 288 | void PowerSupply::checkInputFault(const uint16_t statusWord) | 
 | 289 | { | 
 | 290 |     using namespace witherspoon::pmbus; | 
 | 291 |  | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 292 |     if ((inputFault < FAULT_COUNT) && | 
 | 293 |         ((statusWord & status_word::INPUT_FAULT_WARN) || | 
 | 294 |          (statusWord & status_word::VIN_UV_FAULT))) | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 295 |     { | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 296 |         inputFault++; | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 297 |     } | 
 | 298 |     else | 
 | 299 |     { | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 300 |         if ((inputFault > 0) && | 
| Brandon Wyman | d20686a | 2017-11-01 17:45:23 -0500 | [diff] [blame] | 301 |             !(statusWord & status_word::INPUT_FAULT_WARN) && | 
 | 302 |             !(statusWord & status_word::VIN_UV_FAULT)) | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 303 |         { | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 304 |             inputFault = 0; | 
| Brandon Wyman | 3343e82 | 2017-11-03 16:54:11 -0500 | [diff] [blame] | 305 |             faultFound = false; | 
| Brandon Wyman | 69591bd | 2017-11-01 18:07:23 -0500 | [diff] [blame] | 306 |  | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 307 |             log<level::INFO>("INPUT_FAULT_WARN cleared", | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 308 |                              entry("POWERSUPPLY=%s", inventoryPath.c_str())); | 
| Brandon Wyman | 69591bd | 2017-11-01 18:07:23 -0500 | [diff] [blame] | 309 |  | 
| Brandon Wyman | 08b0571 | 2017-11-30 17:53:56 -0600 | [diff] [blame] | 310 |             resolveError(inventoryPath, | 
 | 311 |                          std::string(PowerSupplyInputFault::errName)); | 
 | 312 |  | 
| Brandon Wyman | 69591bd | 2017-11-01 18:07:23 -0500 | [diff] [blame] | 313 |             if (powerOn) | 
 | 314 |             { | 
 | 315 |                 // The power supply will not be immediately powered on after | 
 | 316 |                 // the input power is restored. | 
 | 317 |                 powerOn = false; | 
 | 318 |                 // Start up the timer that will set the state to indicate we | 
 | 319 |                 // are ready for the powered on fault checks. | 
 | 320 |                 powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot); | 
 | 321 |             } | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 322 |         } | 
 | 323 |     } | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 324 |  | 
 | 325 |     if (!faultFound && (inputFault >= FAULT_COUNT)) | 
 | 326 |     { | 
 | 327 |         util::NamesValues nv; | 
 | 328 |         nv.add("STATUS_WORD", statusWord); | 
 | 329 |         captureCmd(nv, STATUS_INPUT, Type::Debug); | 
 | 330 |  | 
 | 331 |         using metadata = org::open_power::Witherspoon::Fault:: | 
 | 332 |                 PowerSupplyInputFault; | 
 | 333 |  | 
 | 334 |         report<PowerSupplyInputFault>( | 
 | 335 |                 metadata::RAW_STATUS(nv.get().c_str()), | 
 | 336 |                 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); | 
 | 337 |         faultFound = true; | 
 | 338 |     } | 
 | 339 |  | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 340 | } | 
 | 341 |  | 
 | 342 | void PowerSupply::checkPGOrUnitOffFault(const uint16_t statusWord) | 
 | 343 | { | 
 | 344 |     using namespace witherspoon::pmbus; | 
 | 345 |  | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 346 |     if (powerOnFault < FAULT_COUNT) | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 347 |     { | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 348 |         // Check PG# and UNIT_IS_OFF | 
 | 349 |         if ((statusWord & status_word::POWER_GOOD_NEGATED) || | 
 | 350 |             (statusWord & status_word::UNIT_IS_OFF)) | 
 | 351 |         { | 
 | 352 |             log<level::INFO>("PGOOD or UNIT_IS_OFF bit bad", | 
 | 353 |                              entry("STATUS_WORD=0x%04X", statusWord)); | 
 | 354 |             powerOnFault++; | 
 | 355 |         } | 
 | 356 |         else | 
 | 357 |         { | 
 | 358 |             if (powerOnFault > 0) | 
 | 359 |             { | 
 | 360 |                 log<level::INFO>("PGOOD and UNIT_IS_OFF bits good"); | 
 | 361 |                 powerOnFault = 0; | 
 | 362 |             } | 
 | 363 |         } | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 364 |  | 
| Brandon Wyman | e2fc7aa | 2017-11-13 17:37:10 -0600 | [diff] [blame] | 365 |         if (!faultFound && (powerOnFault >= FAULT_COUNT)) | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 366 |         { | 
| Brandon Wyman | 3343e82 | 2017-11-03 16:54:11 -0500 | [diff] [blame] | 367 |             faultFound = true; | 
 | 368 |  | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 369 |             util::NamesValues nv; | 
 | 370 |             nv.add("STATUS_WORD", statusWord); | 
 | 371 |             captureCmd(nv, STATUS_INPUT, Type::Debug); | 
 | 372 |             auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0); | 
 | 373 |             captureCmd(nv, status0Vout, Type::Debug); | 
 | 374 |             captureCmd(nv, STATUS_IOUT, Type::Debug); | 
 | 375 |             captureCmd(nv, STATUS_MFR, Type::Debug); | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 376 |  | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 377 |             using metadata = org::open_power::Witherspoon::Fault:: | 
 | 378 |                     PowerSupplyShouldBeOn; | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 379 |  | 
| Brandon Wyman | 593d24f | 2017-10-13 18:15:23 -0500 | [diff] [blame] | 380 |             // A power supply is OFF (or pgood low) but should be on. | 
 | 381 |             report<PowerSupplyShouldBeOn>( | 
 | 382 |                     metadata::RAW_STATUS(nv.get().c_str()), | 
 | 383 |                     metadata::CALLOUT_INVENTORY_PATH( | 
 | 384 |                             inventoryPath.c_str())); | 
 | 385 |         } | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 386 |     } | 
 | 387 |  | 
 | 388 | } | 
 | 389 |  | 
 | 390 | void PowerSupply::checkCurrentOutOverCurrentFault(const uint16_t statusWord) | 
 | 391 | { | 
 | 392 |     using namespace witherspoon::pmbus; | 
 | 393 |  | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 394 |     if (outputOCFault < FAULT_COUNT) | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 395 |     { | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 396 |         // Check for an output overcurrent fault. | 
 | 397 |         if ((statusWord & status_word::IOUT_OC_FAULT)) | 
 | 398 |         { | 
 | 399 |             outputOCFault++; | 
 | 400 |         } | 
 | 401 |         else | 
 | 402 |         { | 
 | 403 |             if (outputOCFault > 0) | 
 | 404 |             { | 
 | 405 |                 outputOCFault = 0; | 
 | 406 |             } | 
 | 407 |         } | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 408 |  | 
| Brandon Wyman | e2fc7aa | 2017-11-13 17:37:10 -0600 | [diff] [blame] | 409 |         if (!faultFound && (outputOCFault >= FAULT_COUNT)) | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 410 |         { | 
 | 411 |             util::NamesValues nv; | 
 | 412 |             nv.add("STATUS_WORD", statusWord); | 
 | 413 |             captureCmd(nv, STATUS_INPUT, Type::Debug); | 
 | 414 |             auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0); | 
 | 415 |             captureCmd(nv, status0Vout, Type::Debug); | 
 | 416 |             captureCmd(nv, STATUS_IOUT, Type::Debug); | 
 | 417 |             captureCmd(nv, STATUS_MFR, Type::Debug); | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 418 |  | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 419 |             using metadata = org::open_power::Witherspoon::Fault:: | 
 | 420 |                     PowerSupplyOutputOvercurrent; | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 421 |  | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 422 |             report<PowerSupplyOutputOvercurrent>( | 
 | 423 |                     metadata::RAW_STATUS(nv.get().c_str()), | 
 | 424 |                     metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); | 
 | 425 |  | 
 | 426 |             faultFound = true; | 
 | 427 |         } | 
| Brandon Wyman | 603cc00 | 2017-08-28 18:17:58 -0500 | [diff] [blame] | 428 |     } | 
 | 429 | } | 
 | 430 |  | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 431 | void PowerSupply::checkOutputOvervoltageFault(const uint16_t statusWord) | 
 | 432 | { | 
 | 433 |     using namespace witherspoon::pmbus; | 
 | 434 |  | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 435 |     if (outputOVFault < FAULT_COUNT) | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 436 |     { | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 437 |         // Check for an output overvoltage fault. | 
 | 438 |         if (statusWord & status_word::VOUT_OV_FAULT) | 
 | 439 |         { | 
 | 440 |             outputOVFault++; | 
 | 441 |         } | 
 | 442 |         else | 
 | 443 |         { | 
 | 444 |             if (outputOVFault > 0) | 
 | 445 |             { | 
 | 446 |                 outputOVFault = 0; | 
 | 447 |             } | 
 | 448 |         } | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 449 |  | 
| Brandon Wyman | e2fc7aa | 2017-11-13 17:37:10 -0600 | [diff] [blame] | 450 |         if (!faultFound && (outputOVFault >= FAULT_COUNT)) | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 451 |         { | 
 | 452 |             util::NamesValues nv; | 
 | 453 |             nv.add("STATUS_WORD", statusWord); | 
 | 454 |             captureCmd(nv, STATUS_INPUT, Type::Debug); | 
 | 455 |             auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0); | 
 | 456 |             captureCmd(nv, status0Vout, Type::Debug); | 
 | 457 |             captureCmd(nv, STATUS_IOUT, Type::Debug); | 
 | 458 |             captureCmd(nv, STATUS_MFR, Type::Debug); | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 459 |  | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 460 |             using metadata = org::open_power::Witherspoon::Fault:: | 
 | 461 |                     PowerSupplyOutputOvervoltage; | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 462 |  | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 463 |             report<PowerSupplyOutputOvervoltage>( | 
 | 464 |                     metadata::RAW_STATUS(nv.get().c_str()), | 
 | 465 |                     metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); | 
 | 466 |  | 
 | 467 |             faultFound = true; | 
 | 468 |         } | 
| Brandon Wyman | ab05c07 | 2017-08-30 18:26:41 -0500 | [diff] [blame] | 469 |     } | 
 | 470 | } | 
 | 471 |  | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 472 | void PowerSupply::checkFanFault(const uint16_t statusWord) | 
 | 473 | { | 
 | 474 |     using namespace witherspoon::pmbus; | 
 | 475 |  | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 476 |     if (fanFault < FAULT_COUNT) | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 477 |     { | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 478 |         // Check for a fan fault or warning condition | 
 | 479 |         if (statusWord & status_word::FAN_FAULT) | 
 | 480 |         { | 
 | 481 |             fanFault++; | 
 | 482 |         } | 
 | 483 |         else | 
 | 484 |         { | 
 | 485 |             if (fanFault > 0) | 
 | 486 |             { | 
 | 487 |                 fanFault = 0; | 
 | 488 |             } | 
 | 489 |         } | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 490 |  | 
| Brandon Wyman | e2fc7aa | 2017-11-13 17:37:10 -0600 | [diff] [blame] | 491 |         if (!faultFound && (fanFault >= FAULT_COUNT)) | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 492 |         { | 
 | 493 |             util::NamesValues nv; | 
 | 494 |             nv.add("STATUS_WORD", statusWord); | 
 | 495 |             captureCmd(nv, STATUS_MFR, Type::Debug); | 
 | 496 |             captureCmd(nv, STATUS_TEMPERATURE, Type::Debug); | 
 | 497 |             captureCmd(nv, STATUS_FANS_1_2, Type::Debug); | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 498 |  | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 499 |             using metadata = org::open_power::Witherspoon::Fault:: | 
 | 500 |                     PowerSupplyFanFault; | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 501 |  | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 502 |             report<PowerSupplyFanFault>( | 
 | 503 |                     metadata::RAW_STATUS(nv.get().c_str()), | 
 | 504 |                     metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); | 
 | 505 |  | 
 | 506 |             faultFound = true; | 
 | 507 |         } | 
| Brandon Wyman | 12661f1 | 2017-08-31 15:28:21 -0500 | [diff] [blame] | 508 |     } | 
 | 509 | } | 
 | 510 |  | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 511 | void PowerSupply::checkTemperatureFault(const uint16_t statusWord) | 
 | 512 | { | 
 | 513 |     using namespace witherspoon::pmbus; | 
 | 514 |  | 
 | 515 |     // Due to how the PMBus core device driver sends a clear faults command | 
 | 516 |     // the bit in STATUS_WORD will likely be cleared when we attempt to examine | 
 | 517 |     // it for a Thermal Fault or Warning. So, check the STATUS_WORD and the | 
 | 518 |     // STATUS_TEMPERATURE bits. If either indicates a fault, proceed with | 
 | 519 |     // logging the over-temperature condition. | 
 | 520 |     std::uint8_t statusTemperature = 0; | 
 | 521 |     statusTemperature = pmbusIntf.read(STATUS_TEMPERATURE, Type::Debug); | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 522 |     if (temperatureFault < FAULT_COUNT) | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 523 |     { | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 524 |         if ((statusWord & status_word::TEMPERATURE_FAULT_WARN) || | 
 | 525 |             (statusTemperature & status_temperature::OT_FAULT)) | 
 | 526 |         { | 
 | 527 |             temperatureFault++; | 
 | 528 |         } | 
 | 529 |         else | 
 | 530 |         { | 
 | 531 |             if (temperatureFault > 0) | 
 | 532 |             { | 
 | 533 |                 temperatureFault = 0; | 
 | 534 |             } | 
 | 535 |         } | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 536 |  | 
| Brandon Wyman | e2fc7aa | 2017-11-13 17:37:10 -0600 | [diff] [blame] | 537 |         if (!faultFound && (temperatureFault >= FAULT_COUNT)) | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 538 |         { | 
 | 539 |             // The power supply has had an over-temperature condition. | 
 | 540 |             // This may not result in a shutdown if experienced for a short | 
 | 541 |             // duration. | 
 | 542 |             // This should not occur under normal conditions. | 
 | 543 |             // The power supply may be faulty, or the paired supply may be | 
 | 544 |             // putting out less current. | 
 | 545 |             // Capture command responses with potentially relevant information, | 
 | 546 |             // and call out the power supply reporting the condition. | 
 | 547 |             util::NamesValues nv; | 
 | 548 |             nv.add("STATUS_WORD", statusWord); | 
 | 549 |             captureCmd(nv, STATUS_MFR, Type::Debug); | 
 | 550 |             captureCmd(nv, STATUS_IOUT, Type::Debug); | 
 | 551 |             nv.add("STATUS_TEMPERATURE", statusTemperature); | 
 | 552 |             captureCmd(nv, STATUS_FANS_1_2, Type::Debug); | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 553 |  | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 554 |             using metadata = org::open_power::Witherspoon::Fault:: | 
 | 555 |                     PowerSupplyTemperatureFault; | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 556 |  | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 557 |             report<PowerSupplyTemperatureFault>( | 
 | 558 |                     metadata::RAW_STATUS(nv.get().c_str()), | 
 | 559 |                     metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); | 
 | 560 |  | 
 | 561 |             faultFound = true; | 
 | 562 |         } | 
| Brandon Wyman | 875b363 | 2017-09-13 18:46:03 -0500 | [diff] [blame] | 563 |     } | 
 | 564 | } | 
 | 565 |  | 
| Brandon Wyman | 1db9a9e | 2017-07-26 18:50:22 -0500 | [diff] [blame] | 566 | void PowerSupply::clearFaults() | 
 | 567 | { | 
| Brandon Wyman | e4af980 | 2017-11-13 15:58:33 -0600 | [diff] [blame] | 568 |     readFail = 0; | 
| Brandon Wyman | 6ccce0b | 2017-10-26 15:13:10 -0500 | [diff] [blame] | 569 |     readFailLogged = false; | 
| Brandon Wyman | a3c675c | 2017-11-14 14:54:54 -0600 | [diff] [blame] | 570 |     inputFault = 0; | 
| Brandon Wyman | 6ccce0b | 2017-10-26 15:13:10 -0500 | [diff] [blame] | 571 |     powerOnFault = 0; | 
| Brandon Wyman | dd61be4 | 2017-11-07 18:38:54 -0600 | [diff] [blame] | 572 |     outputOCFault = 0; | 
| Brandon Wyman | 2ab319b | 2017-11-08 17:34:59 -0600 | [diff] [blame] | 573 |     outputOVFault = 0; | 
| Brandon Wyman | ba25553 | 2017-11-08 17:44:10 -0600 | [diff] [blame] | 574 |     fanFault = 0; | 
| Brandon Wyman | 50044ea | 2017-11-08 17:58:56 -0600 | [diff] [blame] | 575 |     temperatureFault = 0; | 
| Brandon Wyman | 3343e82 | 2017-11-03 16:54:11 -0500 | [diff] [blame] | 576 |     faultFound = false; | 
| Brandon Wyman | 6ccce0b | 2017-10-26 15:13:10 -0500 | [diff] [blame] | 577 |  | 
| Brandon Wyman | 1db9a9e | 2017-07-26 18:50:22 -0500 | [diff] [blame] | 578 |     return; | 
 | 579 | } | 
 | 580 |  | 
| Brandon Wyman | 43ce208 | 2017-11-30 17:24:01 -0600 | [diff] [blame] | 581 | void PowerSupply::resolveError(const std::string& callout, | 
 | 582 |                                const std::string& message) | 
 | 583 | { | 
| Brandon Wyman | 01741f1 | 2017-12-01 17:22:08 -0600 | [diff] [blame] | 584 |     using EndpointList = std::vector<std::string>; | 
 | 585 |  | 
 | 586 |     try | 
 | 587 |     { | 
 | 588 |         auto path = callout + "/fault"; | 
 | 589 |         // Get the service name from the mapper for the fault callout | 
 | 590 |         auto service = util::getService(path, | 
 | 591 |                                         ASSOCIATION_IFACE, | 
 | 592 |                                         bus); | 
 | 593 |  | 
 | 594 |         // Use getProperty utility function to get log entries (endpoints) | 
 | 595 |         EndpointList logEntries; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 596 |         util::getProperty(ASSOCIATION_IFACE, ENDPOINTS_PROP, path, service, | 
| Brandon Wyman | 01741f1 | 2017-12-01 17:22:08 -0600 | [diff] [blame] | 597 |                           bus, logEntries); | 
 | 598 |  | 
 | 599 |         // It is possible that all such entries for this callout have since | 
 | 600 |         // been deleted. | 
 | 601 |         if (logEntries.empty()) | 
 | 602 |         { | 
 | 603 |             return; | 
 | 604 |         } | 
 | 605 |  | 
 | 606 |         auto logEntryService = util::getService(logEntries[0], LOGGING_IFACE, | 
 | 607 |                                                 bus); | 
 | 608 |         if (logEntryService.empty()) | 
 | 609 |         { | 
 | 610 |             return; | 
 | 611 |         } | 
 | 612 |  | 
 | 613 |         // go through each log entry that matches this callout path | 
 | 614 |         std::string logMessage; | 
 | 615 |         for (const auto& logEntry : logEntries) | 
 | 616 |         { | 
 | 617 |             // Check to see if this logEntry has a message that matches. | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 618 |             util::getProperty(LOGGING_IFACE, MESSAGE_PROP, logEntry, | 
| Brandon Wyman | 01741f1 | 2017-12-01 17:22:08 -0600 | [diff] [blame] | 619 |                               logEntryService, bus, logMessage); | 
 | 620 |  | 
 | 621 |             if (message == logMessage) | 
 | 622 |             { | 
 | 623 |                 // Log entry matches call out and message, set Resolved to true | 
 | 624 |                 bool resolved = true; | 
| Matt Spinler | 589e872 | 2018-01-04 15:24:49 -0600 | [diff] [blame] | 625 |                 util::setProperty(LOGGING_IFACE, RESOLVED_PROP, logEntry, | 
| Brandon Wyman | 01741f1 | 2017-12-01 17:22:08 -0600 | [diff] [blame] | 626 |                                   logEntryService, bus, resolved); | 
 | 627 |             } | 
 | 628 |  | 
 | 629 |         } | 
 | 630 |  | 
 | 631 |     } | 
 | 632 |     catch (std::exception& e) | 
 | 633 |     { | 
 | 634 |         log<level::INFO>("Failed to resolve error", | 
 | 635 |                          entry("CALLOUT=%s", callout.c_str()), | 
| Matt Spinler | 0d09f29 | 2018-01-22 14:51:26 -0600 | [diff] [blame] | 636 |                          entry("ERROR=%s", message.c_str())); | 
| Brandon Wyman | 01741f1 | 2017-12-01 17:22:08 -0600 | [diff] [blame] | 637 |     } | 
 | 638 |  | 
| Brandon Wyman | 43ce208 | 2017-11-30 17:24:01 -0600 | [diff] [blame] | 639 | } | 
 | 640 |  | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 641 | void PowerSupply::updateInventory() | 
 | 642 | { | 
| Matt Spinler | 018a7bc | 2018-01-04 15:36:41 -0600 | [diff] [blame] | 643 |     using namespace witherspoon::pmbus; | 
 | 644 |     using namespace sdbusplus::message; | 
 | 645 |  | 
 | 646 |     // If any of these accesses fail, the fields will just be | 
 | 647 |     // blank in the inventory.  Leave logging ReadFailure errors | 
 | 648 |     // to analyze() as it runs continuously and will most | 
 | 649 |     // likely hit and threshold them first anyway.  The | 
 | 650 |     // readString() function will do the tracing of the failing | 
 | 651 |     // path so this code doesn't need to. | 
 | 652 |     std::string pn; | 
 | 653 |     std::string sn; | 
 | 654 |     std::string ccin; | 
 | 655 |     std::string version; | 
 | 656 |  | 
 | 657 |     if (present) | 
 | 658 |     { | 
 | 659 |         try | 
 | 660 |         { | 
 | 661 |             sn = pmbusIntf.readString(SERIAL_NUMBER, Type::HwmonDeviceDebug); | 
 | 662 |         } | 
 | 663 |         catch (ReadFailure& e) { } | 
 | 664 |  | 
 | 665 |         try | 
 | 666 |         { | 
 | 667 |             pn = pmbusIntf.readString(PART_NUMBER, Type::HwmonDeviceDebug); | 
 | 668 |         } | 
 | 669 |         catch (ReadFailure& e) { } | 
 | 670 |  | 
 | 671 |         try | 
 | 672 |         { | 
 | 673 |             ccin = pmbusIntf.readString(CCIN, Type::HwmonDeviceDebug); | 
 | 674 |         } | 
 | 675 |         catch (ReadFailure& e) { } | 
 | 676 |  | 
 | 677 |         try | 
 | 678 |         { | 
 | 679 |             version = pmbusIntf.readString(FW_VERSION, Type::HwmonDeviceDebug); | 
 | 680 |         } | 
 | 681 |         catch (ReadFailure& e) { } | 
 | 682 |     } | 
 | 683 |  | 
 | 684 |     // Build the object map and send it to the inventory | 
 | 685 |     using Properties = std::map<std::string, variant<std::string>>; | 
 | 686 |     using Interfaces = std::map<std::string, Properties>; | 
 | 687 |     using Object = std::map<object_path, Interfaces>; | 
 | 688 |     Properties assetProps; | 
 | 689 |     Properties versionProps; | 
 | 690 |     Interfaces interfaces; | 
 | 691 |     Object object; | 
 | 692 |  | 
 | 693 |     assetProps.emplace(SN_PROP, sn); | 
 | 694 |     assetProps.emplace(PN_PROP, pn); | 
 | 695 |     assetProps.emplace(MODEL_PROP, ccin); | 
 | 696 |     interfaces.emplace(ASSET_IFACE, std::move(assetProps)); | 
 | 697 |  | 
 | 698 |     versionProps.emplace(VERSION_PROP, version); | 
 | 699 |     interfaces.emplace(VERSION_IFACE, std::move(versionProps)); | 
 | 700 |  | 
 | 701 |     //For Notify(), just send the relative path of the inventory | 
 | 702 |     //object so remove the INVENTORY_OBJ_PATH prefix | 
 | 703 |     auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH)); | 
 | 704 |  | 
 | 705 |     object.emplace(path, std::move(interfaces)); | 
 | 706 |  | 
 | 707 |     try | 
 | 708 |     { | 
 | 709 |         auto service = util::getService( | 
 | 710 |                 INVENTORY_OBJ_PATH, | 
 | 711 |                 INVENTORY_MGR_IFACE, | 
 | 712 |                 bus); | 
 | 713 |  | 
 | 714 |         if (service.empty()) | 
 | 715 |         { | 
 | 716 |             log<level::ERR>("Unable to get inventory manager service"); | 
 | 717 |             return; | 
 | 718 |         } | 
 | 719 |  | 
 | 720 |         auto method = bus.new_method_call( | 
 | 721 |                 service.c_str(), | 
 | 722 |                 INVENTORY_OBJ_PATH, | 
 | 723 |                 INVENTORY_MGR_IFACE, | 
 | 724 |                 "Notify"); | 
 | 725 |  | 
 | 726 |         method.append(std::move(object)); | 
 | 727 |  | 
 | 728 |         auto reply = bus.call(method); | 
 | 729 |         if (reply.is_method_error()) | 
 | 730 |         { | 
 | 731 |             log<level::ERR>( | 
 | 732 |                     "Unable to update power supply inventory properties", | 
 | 733 |                     entry("PATH=%s", path.c_str())); | 
 | 734 |         } | 
 | 735 |  | 
 | 736 |         // TODO: openbmc/openbmc#2756 | 
 | 737 |         // Calling Notify() with an enumerated property crashes inventory | 
 | 738 |         // manager, so let it default to Unknown and now set it to the | 
 | 739 |         // right value. | 
 | 740 |         auto purpose = version::convertForMessage( | 
 | 741 |                 version::Version::VersionPurpose::Other); | 
 | 742 |  | 
 | 743 |         util::setProperty( | 
 | 744 |                 VERSION_IFACE, | 
 | 745 |                 VERSION_PURPOSE_PROP, | 
 | 746 |                 inventoryPath, | 
 | 747 |                 service, | 
 | 748 |                 bus, | 
 | 749 |                 purpose); | 
 | 750 |     } | 
 | 751 |     catch (std::exception& e) | 
 | 752 |     { | 
 | 753 |         log<level::ERR>( | 
 | 754 |                 e.what(), | 
 | 755 |                 entry("PATH=%s", inventoryPath)); | 
 | 756 |     } | 
| Matt Spinler | 234ce0d | 2018-01-04 15:06:57 -0600 | [diff] [blame] | 757 | } | 
 | 758 |  | 
| Matt Spinler | d734e65 | 2018-01-18 14:31:15 -0600 | [diff] [blame] | 759 | void PowerSupply::syncHistory() | 
 | 760 | { | 
 | 761 |     using namespace witherspoon::gpio; | 
 | 762 |  | 
 | 763 |     if (syncGPIODevPath.empty()) | 
 | 764 |     { | 
 | 765 |         //Sync not implemented | 
 | 766 |         return; | 
 | 767 |     } | 
 | 768 |  | 
 | 769 |     GPIO gpio{syncGPIODevPath, | 
 | 770 |               static_cast<gpioNum_t>(syncGPIONumber), | 
 | 771 |               Direction::output}; | 
 | 772 |  | 
 | 773 |     try | 
 | 774 |     { | 
 | 775 |         gpio.set(Value::low); | 
 | 776 |  | 
 | 777 |         std::this_thread::sleep_for(std::chrono::milliseconds{5}); | 
 | 778 |  | 
 | 779 |         gpio.set(Value::high); | 
 | 780 |  | 
 | 781 |         recordManager->clear(); | 
 | 782 |     } | 
 | 783 |     catch (std::exception& e) | 
 | 784 |     { | 
 | 785 |         //Do nothing.  There would already be a journal entry. | 
 | 786 |     } | 
 | 787 | } | 
 | 788 |  | 
| Matt Spinler | 8238414 | 2018-01-18 14:15:03 -0600 | [diff] [blame] | 789 | void PowerSupply::enableHistory(const std::string& objectPath, | 
 | 790 |                                 size_t numRecords, | 
 | 791 |                                 const std::string& syncGPIOPath, | 
 | 792 |                                 size_t syncGPIONum) | 
 | 793 | { | 
 | 794 |     historyObjectPath = objectPath; | 
 | 795 |     syncGPIODevPath = syncGPIOPath; | 
 | 796 |     syncGPIONumber = syncGPIONum; | 
 | 797 |  | 
 | 798 |     recordManager = std::make_unique<history::RecordManager>(numRecords); | 
 | 799 |  | 
 | 800 |     auto avgPath = historyObjectPath + '/' + history::Average::name; | 
 | 801 |     auto maxPath = historyObjectPath + '/' + history::Maximum::name; | 
 | 802 |  | 
 | 803 |     average = std::make_unique<history::Average>(bus, avgPath); | 
 | 804 |  | 
 | 805 |     maximum = std::make_unique<history::Maximum>(bus, maxPath); | 
 | 806 | } | 
 | 807 |  | 
| Matt Spinler | eb169fd | 2018-01-18 14:19:08 -0600 | [diff] [blame] | 808 | void PowerSupply::updateHistory() | 
 | 809 | { | 
 | 810 |     if (!recordManager) | 
 | 811 |     { | 
 | 812 |         //Not enabled | 
 | 813 |         return; | 
 | 814 |     } | 
 | 815 |  | 
 | 816 |     //Read just the most recent average/max record | 
 | 817 |     auto data = pmbusIntf.readBinary( | 
 | 818 |             INPUT_HISTORY, | 
 | 819 |             pmbus::Type::HwmonDeviceDebug, | 
 | 820 |             history::RecordManager::RAW_RECORD_SIZE); | 
 | 821 |  | 
 | 822 |     //Update D-Bus only if something changed (a new record ID, or cleared out) | 
 | 823 |     auto changed = recordManager->add(data); | 
 | 824 |     if (changed) | 
 | 825 |     { | 
 | 826 |         average->values(std::move(recordManager->getAverageRecords())); | 
 | 827 |         maximum->values(std::move(recordManager->getMaximumRecords())); | 
 | 828 |     } | 
 | 829 | } | 
 | 830 |  | 
| Brandon Wyman | 24e422f | 2017-07-25 19:40:14 -0500 | [diff] [blame] | 831 | } | 
 | 832 | } | 
 | 833 | } |