Stop reading devices that don't like it

Attempting to read devices that don't respond well
to reading causes the fru device scan time to go up,
stop doing that.

Tested: Scan time went down, less messages like
failed to read bus X address XX

Change-Id: I56847f957b7c6bf88ad158ecb4c6a621599c11ab
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 48cec11..42ca311 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -78,6 +78,8 @@
     std::pair<size_t, size_t>, std::shared_ptr<sdbusplus::asio::dbus_interface>>
     foundDevices;
 
+static boost::container::flat_map<size_t, std::set<size_t>> failedAddresses;
+
 boost::asio::io_service io;
 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
 auto objServer = sdbusplus::asio::object_server(systemBus);
@@ -248,6 +250,27 @@
     return read(fd, buf, len);
 }
 
+static int getRootBus(size_t bus)
+{
+    auto ec = std::error_code();
+    auto path = std::filesystem::read_symlink(
+        std::filesystem::path("/sys/bus/i2c/devices/i2c-" +
+                              std::to_string(bus) + "/mux_device"),
+        ec);
+    if (ec)
+    {
+        return -1;
+    }
+
+    std::string filename = path.filename();
+    auto findBus = filename.find("-");
+    if (findBus == std::string::npos)
+    {
+        return -1;
+    }
+    return std::stoi(filename.substr(0, findBus));
+}
+
 static bool isMuxBus(size_t bus)
 {
     return is_symlink(std::filesystem::path(
@@ -467,6 +490,15 @@
 
         // Scan for i2c eeproms loaded on this bus.
         std::set<int> skipList = findI2CEeproms(bus, devices);
+        std::set<size_t>& failedItems = failedAddresses[bus];
+
+        std::set<size_t>* rootFailures = nullptr;
+        int rootBus = getRootBus(bus);
+
+        if (rootBus >= 0)
+        {
+            rootFailures = &(failedAddresses[rootBus]);
+        }
 
         for (int ii = first; ii <= last; ii++)
         {
@@ -496,12 +528,27 @@
 
             makeProbeInterface(bus, ii);
 
+            if (failedItems.find(ii) != failedItems.end())
+            {
+                // if we failed to read it once, unlikely we can read it later
+                continue;
+            }
+
+            if (rootFailures != nullptr)
+            {
+                if (rootFailures->find(ii) != rootFailures->end())
+                {
+                    continue;
+                }
+            }
+
             /* Check for Device type if it is 8 bit or 16 bit */
             int flag = isDevice16Bit(file);
             if (flag < 0)
             {
                 std::cerr << "failed to read bus " << bus << " address " << ii
                           << "\n";
+                failedItems.insert(ii);
                 continue;
             }