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