1 /**
2  * Copyright (C) 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  */
16 #include "registration.hpp"
17 
18 #include <experimental/filesystem>
19 #include <fstream>
20 #include <org/open_power/Proc/FSI/error.hpp>
21 #include <phosphor-logging/log.hpp>
22 
23 namespace openpower
24 {
25 namespace openfsi
26 {
27 
28 using namespace phosphor::logging;
29 namespace fs = std::experimental::filesystem;
30 namespace fsi_error = sdbusplus::org::open_power::Proc::FSI::Error;
31 
32 constexpr auto masterScanPath =
33     "/sys/bus/platform/devices/gpio-fsi/fsi0/rescan";
34 
35 constexpr auto hubScanPath = "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/"
36                              "00:00:00:0a/fsi1/rescan";
37 
38 constexpr auto masterCalloutPath =
39     "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/raw";
40 
41 /**
42  * Writes a 1 to the sysfs file passed in to trigger
43  * the device driver to do an FSI scan.
44  *
45  * @param[in] path - the sysfs path to write a 1 to
46  */
47 static void doScan(const std::string& path)
48 {
49     std::ofstream file;
50 
51     file.exceptions(std::ofstream::failbit | // logic error on operation
52                     std::ofstream::badbit |  // read/write error on operation
53                     std::ofstream::eofbit);  // end of file reached
54     try
55     {
56         file.open(path);
57         file << "1";
58     }
59     catch (std::exception& e)
60     {
61         auto err = errno;
62         throw std::system_error(err, std::generic_category());
63     }
64 }
65 
66 /**
67  * Performs an FSI master scan followed by an FSI hub scan.
68  * This is where the device driver detects which chips are present.
69  *
70  * This is unrelated to scanning a ring out of a chip.
71  */
72 void scan()
73 {
74     // Note: Currently the FSI device driver will always return success on both
75     // the master and hub scans.  The only way we can detect something
76     // went wrong is if the master scan didn't create the hub scan file, so
77     // we will check for that.
78     // It is possible the driver will be updated in the future to actually
79     // return a failure so the code will still check for them.
80 
81     try
82     {
83         doScan(masterScanPath);
84     }
85     catch (std::system_error& e)
86     {
87         log<level::ERR>("Failed to run the FSI master scan");
88 
89         using metadata = org::open_power::Proc::FSI::MasterDetectionFailure;
90 
91         elog<fsi_error::MasterDetectionFailure>(
92             metadata::CALLOUT_ERRNO(e.code().value()),
93             metadata::CALLOUT_DEVICE_PATH(masterCalloutPath));
94     }
95 
96     if (!fs::exists(hubScanPath))
97     {
98         log<level::ERR>("The FSI master scan did not create a hub scan file");
99 
100         using metadata = org::open_power::Proc::FSI::MasterDetectionFailure;
101 
102         elog<fsi_error::MasterDetectionFailure>(
103             metadata::CALLOUT_ERRNO(0),
104             metadata::CALLOUT_DEVICE_PATH(masterCalloutPath));
105     }
106 
107     try
108     {
109         doScan(hubScanPath);
110     }
111     catch (std::system_error& e)
112     {
113         // If the device driver is ever updated in the future to fail the sysfs
114         // write call on a scan failure then it should also provide some hints
115         // about which hardware failed so we can do an appropriate callout
116         // here.  At this point in time, the driver shouldn't ever fail so
117         // we won't worry about guessing at the callout.
118 
119         log<level::ERR>("Failed to run the FSI hub scan");
120 
121         using metadata = org::open_power::Proc::FSI::SlaveDetectionFailure;
122 
123         elog<fsi_error::SlaveDetectionFailure>(
124             metadata::ERRNO(e.code().value()));
125     }
126 }
127 
128 REGISTER_PROCEDURE("scanFSI", scan);
129 
130 } // namespace openfsi
131 } // namespace openpower
132