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