Print this page
NEX-2846 Enable Automatic/Intelligent Hot Sparing capability
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
 #include <sys/fm/protocol.h>
 #include <fm/topo_hc.h>

@@ -756,10 +757,83 @@
                     "topo handle: %p\n", (void *)thp);
 
         fmd_module_unlock(mp);
 }
 
+/*
+ * Visit a libtopo node trying to find a disk with the specified devid.
+ * If we find it, copy it's FRU and resource fields.
+ */
+static int
+fmd_hdl_topo_walk_cb(topo_hdl_t *thp, tnode_t *tn, void *arg)
+{
+
+        fmd_hdl_topo_node_info_t *node = (fmd_hdl_topo_node_info_t *)arg;
+        char *cur_devid;
+        nvlist_t *fru;
+        nvlist_t *resource;
+        int err = 0;
+        _NOTE(ARGUNUSED(thp));
+
+        if (strcmp(topo_node_name(tn), "disk") != 0)
+                return (TOPO_WALK_NEXT);
+
+        if (topo_prop_get_string(tn, "io", "devid", &cur_devid, &err) != 0)
+                return (TOPO_WALK_NEXT);
+
+        if (strcmp(cur_devid, node->device) == 0) {
+                if (topo_node_fru(tn, &fru, NULL, &err) == 0 && err == 0 &&
+                    topo_node_resource(tn, &resource, &err) == 0 && err == 0) {
+                        node->fru = fnvlist_dup(fru);
+                        node->resource = fnvlist_dup(resource);
+                        return (TOPO_WALK_TERMINATE);
+                }
+        }
+
+        return (TOPO_WALK_NEXT);
+}
+
+/*
+ * Extract FRU and resource values from a libtopo node with the matching devid
+ */
+fmd_hdl_topo_node_info_t *
+fmd_hdl_topo_node_get_by_devid(fmd_hdl_t *hdl, char *device)
+{
+
+        int err = 0;
+        topo_hdl_t *thp;
+        topo_walk_t *twp;
+
+        fmd_hdl_topo_node_info_t *node = (fmd_hdl_topo_node_info_t *)
+            fmd_hdl_zalloc(hdl, sizeof (fmd_hdl_topo_node_info_t), FMD_SLEEP);
+
+        thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
+
+        node->device = device;
+
+        if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, fmd_hdl_topo_walk_cb,
+            node, &err)) == NULL) {
+                fmd_hdl_error(hdl, "failed to get topology: %s",
+                    topo_strerror(err));
+                fmd_hdl_topo_rele(hdl, thp);
+                return (NULL);
+        }
+
+        (void) topo_walk_step(twp, TOPO_WALK_CHILD);
+        topo_walk_fini(twp);
+        fmd_hdl_topo_rele(hdl, thp);
+
+        if (node->fru == NULL || node->resource == NULL) {
+                fmd_hdl_debug(hdl, "Could not find device with matching FRU");
+                fmd_hdl_free(hdl, node, sizeof (fmd_hdl_topo_node_info_t));
+                return (NULL);
+        } else {
+                fmd_hdl_debug(hdl, "Found FRU for device %s", device);
+                return (node);
+        }
+}
+
 static void *
 fmd_hdl_alloc_locked(fmd_module_t *mp, size_t size, int flags)
 {
         void *data;