xref: /openbmc/phosphor-hwmon/hwmonio.cpp (revision e8771fd4662ceefac7b75cc0fd6ec8d52105e2d5)
175e56c67SPatrick Venture /**
275e56c67SPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
375e56c67SPatrick Venture  * you may not use this file except in compliance with the License.
475e56c67SPatrick Venture  * You may obtain a copy of the License at
575e56c67SPatrick Venture  *
675e56c67SPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
775e56c67SPatrick Venture  *
875e56c67SPatrick Venture  * Unless required by applicable law or agreed to in writing, software
975e56c67SPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
1075e56c67SPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1175e56c67SPatrick Venture  * See the License for the specific language governing permissions and
1275e56c67SPatrick Venture  * limitations under the License.
1375e56c67SPatrick Venture  */
14043d3230SPatrick Venture #include "config.h"
15043d3230SPatrick Venture 
16043d3230SPatrick Venture #include "hwmonio.hpp"
17043d3230SPatrick Venture 
18043d3230SPatrick Venture #include "sysfs.hpp"
19043d3230SPatrick Venture 
2075e56c67SPatrick Venture #include <algorithm>
2175e56c67SPatrick Venture #include <exception>
2275e56c67SPatrick Venture #include <fstream>
2375e56c67SPatrick Venture #include <thread>
2475e56c67SPatrick Venture 
25043d3230SPatrick Venture namespace hwmonio
26043d3230SPatrick Venture {
2775e56c67SPatrick Venture 
read(const std::string & path) const28caaebd1fSPatrick Venture int64_t FileSystem::read(const std::string& path) const
29caaebd1fSPatrick Venture {
30caaebd1fSPatrick Venture     int64_t val;
31caaebd1fSPatrick Venture     std::ifstream ifs;
32caaebd1fSPatrick Venture     ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
33caaebd1fSPatrick Venture                    std::ifstream::eofbit);
34caaebd1fSPatrick Venture 
35caaebd1fSPatrick Venture     errno = 0;
36caaebd1fSPatrick Venture     if (!ifs.is_open())
37caaebd1fSPatrick Venture         ifs.open(path);
38caaebd1fSPatrick Venture     ifs.clear();
39caaebd1fSPatrick Venture     ifs.seekg(0);
40caaebd1fSPatrick Venture     ifs >> val;
41caaebd1fSPatrick Venture 
42caaebd1fSPatrick Venture     return val;
43caaebd1fSPatrick Venture }
44caaebd1fSPatrick Venture 
write(const std::string & path,uint32_t value) const45caaebd1fSPatrick Venture void FileSystem::write(const std::string& path, uint32_t value) const
46caaebd1fSPatrick Venture {
47caaebd1fSPatrick Venture     std::ofstream ofs;
48caaebd1fSPatrick Venture     ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit |
49caaebd1fSPatrick Venture                    std::ofstream::eofbit);
50caaebd1fSPatrick Venture 
51caaebd1fSPatrick Venture     errno = 0;
52caaebd1fSPatrick Venture     if (!ofs.is_open())
53caaebd1fSPatrick Venture         ofs.open(path);
54caaebd1fSPatrick Venture     ofs.clear();
55caaebd1fSPatrick Venture     ofs.seekp(0);
56caaebd1fSPatrick Venture     ofs << value;
57caaebd1fSPatrick Venture     ofs.flush();
58caaebd1fSPatrick Venture }
59caaebd1fSPatrick Venture 
60caaebd1fSPatrick Venture FileSystem fileSystemImpl;
61caaebd1fSPatrick Venture 
6275e56c67SPatrick Venture static constexpr auto retryableErrors = {
6375e56c67SPatrick Venture     /*
6475e56c67SPatrick Venture      * Retry on bus or device errors or timeouts in case
6575e56c67SPatrick Venture      * they are transient.
6675e56c67SPatrick Venture      */
6775e56c67SPatrick Venture     EIO,
6875e56c67SPatrick Venture     ETIMEDOUT,
6975e56c67SPatrick Venture 
7075e56c67SPatrick Venture     /*
7175e56c67SPatrick Venture      * Retry CRC errors.
7275e56c67SPatrick Venture      */
7375e56c67SPatrick Venture     EBADMSG,
7475e56c67SPatrick Venture 
7575e56c67SPatrick Venture     /*
7675e56c67SPatrick Venture      * Some hwmon drivers do this when they aren't ready
7775e56c67SPatrick Venture      * instead of blocking.  Retry.
7875e56c67SPatrick Venture      */
7975e56c67SPatrick Venture     EAGAIN,
8075e56c67SPatrick Venture     /*
8175e56c67SPatrick Venture      * We'll see this when for example i2c devices are
8275e56c67SPatrick Venture      * unplugged but the driver is still bound.  Retry
8375e56c67SPatrick Venture      * rather than exit on the off chance the device is
8475e56c67SPatrick Venture      * plugged back in and the driver doesn't do a
8575e56c67SPatrick Venture      * remove/probe.  If a remove does occur, we'll
8675e56c67SPatrick Venture      * eventually get ENOENT.
8775e56c67SPatrick Venture      */
8875e56c67SPatrick Venture     ENXIO,
8975e56c67SPatrick Venture 
9075e56c67SPatrick Venture     /*
9175e56c67SPatrick Venture      * Some devices return this when they are busy doing
9275e56c67SPatrick Venture      * something else.  Even if being busy isn't the cause,
9375e56c67SPatrick Venture      * a retry still gives this app a shot at getting data
9475e56c67SPatrick Venture      * as opposed to failing out on the first try.
9575e56c67SPatrick Venture      */
9675e56c67SPatrick Venture     ENODATA,
97e289100eSEddie James 
98e289100eSEddie James     /*
99e289100eSEddie James      * Some devices return this if the hardware is being
100e289100eSEddie James      * powered off in a normal manner, as incomplete data
101e289100eSEddie James      * is received. Retrying allows time for the system to
102e289100eSEddie James      * clean up driver devices, or in the event of a real
103e289100eSEddie James      * failure, attempt to get the rest of the data.
104e289100eSEddie James      */
105e289100eSEddie James     EMSGSIZE,
10675e56c67SPatrick Venture };
10775e56c67SPatrick Venture 
HwmonIO(const std::string & path,const FileSystemInterface * intf)108caaebd1fSPatrick Venture HwmonIO::HwmonIO(const std::string& path, const FileSystemInterface* intf) :
109caaebd1fSPatrick Venture     _p(path), _intf(intf)
110*e8771fd4SPatrick Williams {}
11175e56c67SPatrick Venture 
read(const std::string & type,const std::string & id,const std::string & sensor,size_t retries,std::chrono::milliseconds delay) const112043d3230SPatrick Venture int64_t HwmonIO::read(const std::string& type, const std::string& id,
113043d3230SPatrick Venture                       const std::string& sensor, size_t retries,
1140b305058SMatthew Barth                       std::chrono::milliseconds delay) const
11575e56c67SPatrick Venture {
11675e56c67SPatrick Venture     int64_t val;
1174d9506ccSPatrick Venture     auto fullPath = sysfs::make_sysfs_path(_p, type, id, sensor);
11875e56c67SPatrick Venture 
11975e56c67SPatrick Venture     while (true)
12075e56c67SPatrick Venture     {
12175e56c67SPatrick Venture         try
12275e56c67SPatrick Venture         {
123caaebd1fSPatrick Venture             val = _intf->read(fullPath);
12475e56c67SPatrick Venture         }
12575e56c67SPatrick Venture         catch (const std::exception& e)
12675e56c67SPatrick Venture         {
12775e56c67SPatrick Venture             auto rc = errno;
12875e56c67SPatrick Venture 
12975e56c67SPatrick Venture             if (!rc)
13075e56c67SPatrick Venture             {
13175e56c67SPatrick Venture                 throw;
13275e56c67SPatrick Venture             }
13375e56c67SPatrick Venture 
13475e56c67SPatrick Venture             if (rc == ENOENT || rc == ENODEV)
13575e56c67SPatrick Venture             {
13675e56c67SPatrick Venture                 // If the directory or device disappeared then this application
137043d3230SPatrick Venture                 // should gracefully exit.  There are race conditions between
138043d3230SPatrick Venture                 // the unloading of a hwmon driver and the stopping of this
139043d3230SPatrick Venture                 // service by systemd.  To prevent this application from falsely
140043d3230SPatrick Venture                 // failing in these scenarios, it will simply exit if the
141043d3230SPatrick Venture                 // directory or file can not be found.  It is up to the user(s)
142043d3230SPatrick Venture                 // of this provided hwmon object to log the appropriate errors
143043d3230SPatrick Venture                 // if the object disappears when it should not.
14475e56c67SPatrick Venture                 exit(0);
14575e56c67SPatrick Venture             }
14675e56c67SPatrick Venture 
147043d3230SPatrick Venture             if (0 == std::count(retryableErrors.begin(), retryableErrors.end(),
14875e56c67SPatrick Venture                                 rc) ||
14975e56c67SPatrick Venture                 !retries)
15075e56c67SPatrick Venture             {
15175e56c67SPatrick Venture                 // Not a retryable error or out of retries.
152d8cacfd4SMatt Spinler #if NEGATIVE_ERRNO_ON_FAIL
15375e56c67SPatrick Venture                 return -rc;
15475e56c67SPatrick Venture #endif
15575e56c67SPatrick Venture 
15675e56c67SPatrick Venture                 // Work around GCC bugs 53984 and 66145 for callers by
15775e56c67SPatrick Venture                 // explicitly raising system_error here.
15875e56c67SPatrick Venture                 throw std::system_error(rc, std::generic_category());
15975e56c67SPatrick Venture             }
16075e56c67SPatrick Venture 
16175e56c67SPatrick Venture             --retries;
16275e56c67SPatrick Venture             std::this_thread::sleep_for(delay);
16375e56c67SPatrick Venture             continue;
16475e56c67SPatrick Venture         }
16575e56c67SPatrick Venture         break;
16675e56c67SPatrick Venture     }
16775e56c67SPatrick Venture 
16875e56c67SPatrick Venture     return val;
16975e56c67SPatrick Venture }
17075e56c67SPatrick Venture 
write(uint32_t val,const std::string & type,const std::string & id,const std::string & sensor,size_t retries,std::chrono::milliseconds delay) const171043d3230SPatrick Venture void HwmonIO::write(uint32_t val, const std::string& type,
172043d3230SPatrick Venture                     const std::string& id, const std::string& sensor,
173043d3230SPatrick Venture                     size_t retries, std::chrono::milliseconds delay) const
17475e56c67SPatrick Venture 
17575e56c67SPatrick Venture {
1764d9506ccSPatrick Venture     auto fullPath = sysfs::make_sysfs_path(_p, type, id, sensor);
17775e56c67SPatrick Venture 
17875e56c67SPatrick Venture     // See comments in the read method for an explanation of the odd exception
17975e56c67SPatrick Venture     // handling behavior here.
18075e56c67SPatrick Venture 
18175e56c67SPatrick Venture     while (true)
18275e56c67SPatrick Venture     {
18375e56c67SPatrick Venture         try
18475e56c67SPatrick Venture         {
185caaebd1fSPatrick Venture             _intf->write(fullPath, val);
18675e56c67SPatrick Venture         }
18775e56c67SPatrick Venture         catch (const std::exception& e)
18875e56c67SPatrick Venture         {
18975e56c67SPatrick Venture             auto rc = errno;
19075e56c67SPatrick Venture 
19175e56c67SPatrick Venture             if (!rc)
19275e56c67SPatrick Venture             {
19375e56c67SPatrick Venture                 throw;
19475e56c67SPatrick Venture             }
19575e56c67SPatrick Venture 
19675e56c67SPatrick Venture             if (rc == ENOENT)
19775e56c67SPatrick Venture             {
19875e56c67SPatrick Venture                 exit(0);
19975e56c67SPatrick Venture             }
20075e56c67SPatrick Venture 
201043d3230SPatrick Venture             if (0 == std::count(retryableErrors.begin(), retryableErrors.end(),
20275e56c67SPatrick Venture                                 rc) ||
20375e56c67SPatrick Venture                 !retries)
20475e56c67SPatrick Venture             {
20575e56c67SPatrick Venture                 // Not a retryable error or out of retries.
20675e56c67SPatrick Venture 
20775e56c67SPatrick Venture                 // Work around GCC bugs 53984 and 66145 for callers by
20875e56c67SPatrick Venture                 // explicitly raising system_error here.
20975e56c67SPatrick Venture                 throw std::system_error(rc, std::generic_category());
21075e56c67SPatrick Venture             }
21175e56c67SPatrick Venture 
21275e56c67SPatrick Venture             --retries;
21375e56c67SPatrick Venture             std::this_thread::sleep_for(delay);
21475e56c67SPatrick Venture             continue;
21575e56c67SPatrick Venture         }
21675e56c67SPatrick Venture         break;
21775e56c67SPatrick Venture     }
21875e56c67SPatrick Venture }
21975e56c67SPatrick Venture 
path() const22075e56c67SPatrick Venture std::string HwmonIO::path() const
22175e56c67SPatrick Venture {
2224d9506ccSPatrick Venture     return _p;
22375e56c67SPatrick Venture }
22475e56c67SPatrick Venture 
225043d3230SPatrick Venture } // namespace hwmonio
226