blob: 41aa3ebc96dbad5ca52735a8792d08f7742879cf [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 YU9ab6d752019-10-28 17:03:20 +080020#include "utility.hpp"
21
22#include <fstream>
23#include <phosphor-logging/log.hpp>
24
25using namespace phosphor::logging;
26namespace util = phosphor::power::util;
27
Lei YUd19df252019-10-25 17:31:52 +080028namespace updater
29{
30
Lei YU9ab6d752019-10-28 17:03:20 +080031constexpr auto INVENTORY_IFACE = "xyz.openbmc_project.Inventory.Item";
32constexpr auto PRESENT_PROP = "Present";
33
34namespace internal
35{
36
37/* Get the device name from the device path */
38std::string getDeviceName(std::string devPath)
39{
40 if (devPath.back() == '/')
41 {
42 devPath.pop_back();
43 }
44 return fs::path(devPath).stem().string();
45}
46
47std::string getDevicePath(const std::string& psuInventoryPath)
48{
49 auto data = util::loadJSONFromFile(PSU_JSON_PATH);
50
51 if (data == nullptr)
52 {
53 return {};
54 }
55
56 auto devicePath = data["psuDevices"][psuInventoryPath];
57 if (devicePath.empty())
58 {
59 log<level::WARNING>("Unable to find psu devices or path");
60 }
61 return devicePath;
62}
63
64} // namespace internal
65
Lei YUd19df252019-10-25 17:31:52 +080066bool update(const std::string& psuInventoryPath, const std::string& imageDir)
67{
Lei YU9ab6d752019-10-28 17:03:20 +080068 auto devPath = internal::getDevicePath(psuInventoryPath);
69 if (devPath.empty())
70 {
71 return false;
72 }
73
74 // TODO: check if it is ready to update
75 // and return if not ready
76
77 Updater updater(psuInventoryPath, devPath, imageDir);
78 int ret = updater.doUpdate();
79 return ret == 0;
80}
81
82Updater::Updater(const std::string& psuInventoryPath,
83 const std::string& devPath, const std::string& imageDir) :
84 bus(sdbusplus::bus::new_default()),
85 psuInventoryPath(psuInventoryPath), devPath(devPath),
86 devName(internal::getDeviceName(devPath)), imageDir(imageDir)
87{
88 fs::path p = fs::path(devPath) / "driver";
89 try
90 {
91 driverPath =
92 fs::canonical(p); // Get the path that points to the driver dir
93 }
94 catch (const fs::filesystem_error& e)
95 {
96 log<level::ERR>("Failed to get canonical path",
97 entry("DEVPATH=%s", devPath.c_str()),
98 entry("ERROR=%s", e.what()));
99 throw;
100 }
101 bindUnbind(false);
102}
103
104Updater::~Updater()
105{
106 bindUnbind(true);
107}
108
109// During PSU update, it needs to access the PSU i2c device directly, so it
110// needs to unbind the driver during the update, and re-bind after it's done.
111// After unbind, the hwmon sysfs will be gone, and the psu-monitor will report
112// errors. So set the PSU inventory's Present property to false so that
113// psu-monitor will not report any errors.
114void Updater::bindUnbind(bool doBind)
115{
116 if (!doBind)
117 {
118 // Set non-present before unbind the driver
119 setPresent(doBind);
120 }
121 auto p = driverPath;
122 p /= doBind ? "bind" : "unbind";
123 std::ofstream out(p.string());
124 out << devName;
125
126 if (doBind)
127 {
128 // Set to present after bind the driver
129 setPresent(doBind);
130 }
131}
132
133void Updater::setPresent(bool present)
134{
135 try
136 {
137 auto service = util::getService(psuInventoryPath, INVENTORY_IFACE, bus);
138 util::setProperty(INVENTORY_IFACE, PRESENT_PROP, psuInventoryPath,
139 service, bus, present);
140 }
141 catch (const std::exception& e)
142 {
143 log<level::ERR>("Failed to set present property",
144 entry("PSU=%s", psuInventoryPath.c_str()),
145 entry("PRESENT=%d", present));
146 }
147}
148
149int Updater::doUpdate()
150{
Lei YUd19df252019-10-25 17:31:52 +0800151 // TODO
Lei YU9ab6d752019-10-28 17:03:20 +0800152 return 0;
Lei YUd19df252019-10-25 17:31:52 +0800153}
154
155} // namespace updater