blob: deab95f236ec3815be680a63cc84fc542e66b360 [file] [log] [blame]
Lei YUd19df252019-10-25 17:31:52 +08001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "config.h"
17
18#include "updater.hpp"
19
Lei YUcfc040c2019-10-29 17:10:26 +080020#include "types.hpp"
Lei YU9ab6d752019-10-28 17:03:20 +080021#include "utility.hpp"
22
23#include <fstream>
24#include <phosphor-logging/log.hpp>
25
26using namespace phosphor::logging;
27namespace util = phosphor::power::util;
28
Lei YUd19df252019-10-25 17:31:52 +080029namespace updater
30{
31
Lei YU9ab6d752019-10-28 17:03:20 +080032namespace internal
33{
34
35/* Get the device name from the device path */
36std::string getDeviceName(std::string devPath)
37{
38 if (devPath.back() == '/')
39 {
40 devPath.pop_back();
41 }
42 return fs::path(devPath).stem().string();
43}
44
45std::string getDevicePath(const std::string& psuInventoryPath)
46{
47 auto data = util::loadJSONFromFile(PSU_JSON_PATH);
48
49 if (data == nullptr)
50 {
51 return {};
52 }
53
54 auto devicePath = data["psuDevices"][psuInventoryPath];
55 if (devicePath.empty())
56 {
57 log<level::WARNING>("Unable to find psu devices or path");
58 }
59 return devicePath;
60}
61
62} // namespace internal
63
Lei YUd19df252019-10-25 17:31:52 +080064bool update(const std::string& psuInventoryPath, const std::string& imageDir)
65{
Lei YU9ab6d752019-10-28 17:03:20 +080066 auto devPath = internal::getDevicePath(psuInventoryPath);
67 if (devPath.empty())
68 {
69 return false;
70 }
71
Lei YU9ab6d752019-10-28 17:03:20 +080072 Updater updater(psuInventoryPath, devPath, imageDir);
Lei YU575ed132019-10-29 17:22:16 +080073 if (!updater.isReadyToUpdate())
74 {
75 log<level::ERR>("PSU not ready to update",
76 entry("PSU=%s", psuInventoryPath.c_str()));
77 return false;
78 }
79
80 updater.bindUnbind(false);
Lei YU9ab6d752019-10-28 17:03:20 +080081 int ret = updater.doUpdate();
Lei YU575ed132019-10-29 17:22:16 +080082 updater.bindUnbind(true);
Lei YU9ab6d752019-10-28 17:03:20 +080083 return ret == 0;
84}
85
86Updater::Updater(const std::string& psuInventoryPath,
87 const std::string& devPath, const std::string& imageDir) :
88 bus(sdbusplus::bus::new_default()),
89 psuInventoryPath(psuInventoryPath), devPath(devPath),
90 devName(internal::getDeviceName(devPath)), imageDir(imageDir)
91{
92 fs::path p = fs::path(devPath) / "driver";
93 try
94 {
95 driverPath =
96 fs::canonical(p); // Get the path that points to the driver dir
97 }
98 catch (const fs::filesystem_error& e)
99 {
100 log<level::ERR>("Failed to get canonical path",
101 entry("DEVPATH=%s", devPath.c_str()),
102 entry("ERROR=%s", e.what()));
103 throw;
104 }
Lei YU9ab6d752019-10-28 17:03:20 +0800105}
106
107// During PSU update, it needs to access the PSU i2c device directly, so it
108// needs to unbind the driver during the update, and re-bind after it's done.
109// After unbind, the hwmon sysfs will be gone, and the psu-monitor will report
110// errors. So set the PSU inventory's Present property to false so that
111// psu-monitor will not report any errors.
112void Updater::bindUnbind(bool doBind)
113{
114 if (!doBind)
115 {
116 // Set non-present before unbind the driver
117 setPresent(doBind);
118 }
119 auto p = driverPath;
120 p /= doBind ? "bind" : "unbind";
121 std::ofstream out(p.string());
122 out << devName;
123
124 if (doBind)
125 {
126 // Set to present after bind the driver
127 setPresent(doBind);
128 }
129}
130
131void Updater::setPresent(bool present)
132{
133 try
134 {
135 auto service = util::getService(psuInventoryPath, INVENTORY_IFACE, bus);
136 util::setProperty(INVENTORY_IFACE, PRESENT_PROP, psuInventoryPath,
137 service, bus, present);
138 }
139 catch (const std::exception& e)
140 {
141 log<level::ERR>("Failed to set present property",
142 entry("PSU=%s", psuInventoryPath.c_str()),
143 entry("PRESENT=%d", present));
144 }
145}
146
Lei YU575ed132019-10-29 17:22:16 +0800147bool Updater::isReadyToUpdate()
148{
149 // Pre-condition for updating PSU:
150 // * Host is powered off
151 // * All other PSUs are having AC input
152 // * All other PSUs are having standby output
153 if (util::isPoweredOn(bus))
154 {
155 return false;
156 }
157 // TODO
158 return true;
159}
160
Lei YU9ab6d752019-10-28 17:03:20 +0800161int Updater::doUpdate()
162{
Lei YUd19df252019-10-25 17:31:52 +0800163 // TODO
Lei YU9ab6d752019-10-28 17:03:20 +0800164 return 0;
Lei YUd19df252019-10-25 17:31:52 +0800165}
166
167} // namespace updater