Add Target and Targeting classes

These classes are used to target certain processors
for operations.

Change-Id: Iab7a9fc0f1b0a901963e4e899ded370435cfb418
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 28dee78..f1af749 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,8 @@
 
 openpower_proc_control_SOURCES = \
 	proc_control.cpp \
-	p9_procedures.cpp
+	p9_procedures.cpp \
+	targeting.cpp
 
-openpower_proc_control_LDFLAGS = $(PHOSPHOR_LOGGING_LIBS)
+openpower_proc_control_LDFLAGS = $(PHOSPHOR_LOGGING_LIBS) -lstdc++fs
 openpower_proc_control_CXXFLAGS = $(PHOSPHOR_LOGGING_CFLAGS)
diff --git a/targeting.cpp b/targeting.cpp
new file mode 100644
index 0000000..11c359c
--- /dev/null
+++ b/targeting.cpp
@@ -0,0 +1,69 @@
+/**
+ * Copyright © 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 <experimental/filesystem>
+#include <phosphor-logging/log.hpp>
+#include <regex>
+#include "targeting.hpp"
+
+namespace openpower
+{
+namespace targeting
+{
+
+using namespace phosphor::logging;
+namespace fs = std::experimental::filesystem;
+
+Targeting::Targeting(const std::string& fsiMasterDev,
+                     const std::string& fsiSlaveDir) :
+    fsiMasterPath(fsiMasterDev),
+    fsiSlaveBasePath(fsiSlaveDir)
+{
+    //Always create P0, the FSI master.
+    targets.push_back(std::make_unique<Target>(0, fsiMasterPath));
+
+    //Find the the remaining P9s dynamically based on which files show up
+    std::regex exp{"slave@([0-9]{2}):00", std::regex::extended};
+
+    for (auto& file : fs::directory_iterator(fsiSlaveBasePath))
+    {
+        std::smatch match;
+        std::string path = file.path();
+        if (std::regex_search(path, match, exp))
+        {
+            auto pos = atoi(match[1].str().c_str());
+            if (pos == 0)
+            {
+                log<level::ERR>("Unexpected FSI slave device name found",
+                                entry("DEVICE_NAME=%d", path.c_str()));
+                continue;
+            }
+
+            path += "/raw";
+
+            targets.push_back(std::make_unique<Target>(pos, path));
+        }
+    }
+
+    auto sortTargets = [](const std::unique_ptr<Target>& left,
+                          const std::unique_ptr<Target>& right)
+    {
+        return left->getPos() < right->getPos();
+    };
+    std::sort(targets.begin(), targets.end(), sortTargets);
+}
+
+}
+}
diff --git a/targeting.hpp b/targeting.hpp
new file mode 100644
index 0000000..92c224e
--- /dev/null
+++ b/targeting.hpp
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+
+namespace openpower
+{
+namespace targeting
+{
+
+constexpr auto fsiMasterDevPath =
+    "/sys/devices/platform/fsi-master/slave@00:00/raw";
+
+constexpr auto fsiSlaveBaseDir = "/sys/devices/hub@00/";
+
+/**
+ * Represents a specific P9 processor in the system.  Used by
+ * the access APIs to specify the chip to operate on.
+ */
+class Target
+{
+    public:
+
+        /**
+         * Constructor
+         *
+         * @param[in] - The logical position of the target
+         * @param[in] - The sysfs device path
+         */
+        Target(size_t position, const std::string& devPath) :
+            pos(position), path(devPath)
+        {
+        }
+
+        Target() = delete;
+        ~Target() = default;
+        Target(const Target&) = default;
+        Target(Target&&) = default;
+        Target& operator=(Target&&) = default;
+
+        /**
+         * Returns the position
+         */
+        inline auto getPos() const
+        {
+            return pos;
+        }
+
+        /**
+         * Returns the path
+         */
+        inline auto getPath() const
+        {
+            return path;
+        }
+
+    private:
+
+        /**
+         * The logical position of this target
+         */
+        size_t pos;
+
+        /**
+         * The sysfs device path
+         */
+        const std::string path;
+};
+
+
+/**
+ * Class that manages processor targeting for FSI operations.
+ */
+class Targeting
+{
+    public:
+
+        /**
+         * Scans sysfs to find all processors and creates Target objects
+         * for them.
+         * @param[in] fsiMasterDev - the sysfs device for the master
+         * @param[in] fsiSlaveDirectory - the base sysfs dir for slaves
+         */
+        Targeting(const std::string& fsiMasterDev,
+                  const std::string& fsiSlaveDir);
+
+        Targeting() : Targeting(fsiMasterDevPath, fsiSlaveBaseDir) {}
+
+        ~Targeting() = default;
+        Targeting(const Targeting&) = default;
+        Targeting(Targeting&&) = default;
+        Targeting& operator=(Targeting&&) = default;
+
+        /**
+         * Returns a const iterator to the first target
+         */
+        inline auto begin()
+        {
+            return targets.cbegin();
+        }
+
+        /**
+         * Returns a const iterator to the last (highest position) target.
+         */
+        inline auto end()
+        {
+            return targets.cend();
+        }
+
+        /**
+         * Returns the number of targets
+         */
+        inline auto size()
+        {
+            return targets.size();
+        }
+
+    private:
+
+        /**
+         * The path to the fsi-master sysfs device to access
+         */
+        const std::string fsiMasterPath;
+
+        /**
+         * The path to the fsi slave sysfs base directory
+         */
+        const std::string fsiSlaveBasePath;
+
+        /**
+         * A container of Targets in the system
+         */
+        std::vector<std::unique_ptr<Target>> targets;
+};
+
+}
+}