summaryrefslogtreecommitdiffstats
path: root/procedures/openfsi/scan.cpp
blob: a9693fba5f82b86290938472773992995c05126f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
 * Copyright (C) 2017 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "registration.hpp"

#include <experimental/filesystem>
#include <fstream>
#include <org/open_power/Proc/FSI/error.hpp>
#include <phosphor-logging/log.hpp>

namespace openpower
{
namespace openfsi
{

using namespace phosphor::logging;
namespace fs = std::experimental::filesystem;
namespace fsi_error = sdbusplus::org::open_power::Proc::FSI::Error;

constexpr auto masterScanPath =
    "/sys/bus/platform/devices/gpio-fsi/fsi0/rescan";

constexpr auto hubScanPath = "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/"
                             "00:00:00:0a/fsi1/rescan";

constexpr auto masterCalloutPath =
    "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/raw";

/**
 * Writes a 1 to the sysfs file passed in to trigger
 * the device driver to do an FSI scan.
 *
 * @param[in] path - the sysfs path to write a 1 to
 */
static void doScan(const std::string& path)
{
    std::ofstream file;

    file.exceptions(std::ofstream::failbit | // logic error on operation
                    std::ofstream::badbit |  // read/write error on operation
                    std::ofstream::eofbit);  // end of file reached
    try
    {
        file.open(path);
        file << "1";
    }
    catch (std::exception& e)
    {
        auto err = errno;
        throw std::system_error(err, std::generic_category());
    }
}

/**
 * Performs an FSI master scan followed by an FSI hub scan.
 * This is where the device driver detects which chips are present.
 *
 * This is unrelated to scanning a ring out of a chip.
 */
void scan()
{
    // Note: Currently the FSI device driver will always return success on both
    // the master and hub scans.  The only way we can detect something
    // went wrong is if the master scan didn't create the hub scan file, so
    // we will check for that.
    // It is possible the driver will be updated in the future to actually
    // return a failure so the code will still check for them.

    try
    {
        doScan(masterScanPath);
    }
    catch (std::system_error& e)
    {
        log<level::ERR>("Failed to run the FSI master scan");

        using metadata = org::open_power::Proc::FSI::MasterDetectionFailure;

        elog<fsi_error::MasterDetectionFailure>(
            metadata::CALLOUT_ERRNO(e.code().value()),
            metadata::CALLOUT_DEVICE_PATH(masterCalloutPath));
    }

    if (!fs::exists(hubScanPath))
    {
        log<level::ERR>("The FSI master scan did not create a hub scan file");

        using metadata = org::open_power::Proc::FSI::MasterDetectionFailure;

        elog<fsi_error::MasterDetectionFailure>(
            metadata::CALLOUT_ERRNO(0),
            metadata::CALLOUT_DEVICE_PATH(masterCalloutPath));
    }

    try
    {
        doScan(hubScanPath);
    }
    catch (std::system_error& e)
    {
        // If the device driver is ever updated in the future to fail the sysfs
        // write call on a scan failure then it should also provide some hints
        // about which hardware failed so we can do an appropriate callout
        // here.  At this point in time, the driver shouldn't ever fail so
        // we won't worry about guessing at the callout.

        log<level::ERR>("Failed to run the FSI hub scan");

        using metadata = org::open_power::Proc::FSI::SlaveDetectionFailure;

        elog<fsi_error::SlaveDetectionFailure>(
            metadata::ERRNO(e.code().value()));
    }
}

REGISTER_PROCEDURE("scanFSI", scan);

} // namespace openfsi
} // namespace openpower
OpenPOWER on IntegriCloud