summaryrefslogtreecommitdiff
path: root/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/picl/plugins/common/devtree/picldevtree.c')
-rw-r--r--usr/src/cmd/picl/plugins/common/devtree/picldevtree.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c b/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c
index f825a88930..bebc9da33c 100644
--- a/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c
+++ b/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c
@@ -1011,6 +1011,240 @@ add_bytes_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
(void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL);
}
+static const char *
+path_state_name(di_path_state_t st)
+{
+ switch (st) {
+ case DI_PATH_STATE_ONLINE:
+ return ("online");
+ case DI_PATH_STATE_STANDBY:
+ return ("standby");
+ case DI_PATH_STATE_OFFLINE:
+ return ("offline");
+ case DI_PATH_STATE_FAULT:
+ return ("faulted");
+ }
+ return ("unknown");
+}
+
+/*
+ * This function is the volatile property handler for the multipath node
+ * "State" property. It must locate the associated devinfo node in order to
+ * determine the current state. Since the devinfo node can have multiple
+ * paths the devfs_path is used to locate the correct path.
+ */
+static int
+get_path_state_name(ptree_rarg_t *rarg, void *vbuf)
+{
+ int err;
+ picl_nodehdl_t parh;
+ char devfs_path[PATH_MAX];
+ di_node_t di_node;
+ di_node_t di_root;
+ di_path_t pi = DI_PATH_NIL;
+ picl_nodehdl_t mpnode;
+
+ (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
+
+ mpnode = rarg->nodeh;
+
+ /*
+ * The parent node represents the vHCI.
+ */
+ err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh,
+ sizeof (picl_nodehdl_t));
+ if (err != PICL_SUCCESS) {
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * The PICL_PROP_DEVFS_PATH property will be used to locate the
+ * devinfo node for the vHCI driver.
+ */
+ err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path,
+ sizeof (devfs_path));
+ if (err != PICL_SUCCESS) {
+ return (PICL_SUCCESS);
+ }
+ /*
+ * Find the di_node for the vHCI driver. It will be used to scan
+ * the path information nodes.
+ */
+ di_root = di_init("/", DINFOCACHE);
+ if (di_root == DI_NODE_NIL) {
+ return (PICL_SUCCESS);
+ }
+ di_node = di_lookup_node(di_root, devfs_path);
+ if (di_node == DI_NODE_NIL) {
+ di_fini(di_root);
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * The devfs_path will be used below to match the
+ * proper path information node.
+ */
+ err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH,
+ devfs_path, sizeof (devfs_path));
+ if (err != PICL_SUCCESS) {
+ di_fini(di_root);
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * Scan the path information nodes looking for the matching devfs
+ * path. When found obtain the state information.
+ */
+ while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
+ char *di_path;
+ di_node_t phci_node = di_path_phci_node(pi);
+
+ if (phci_node == DI_PATH_NIL)
+ continue;
+
+ di_path = di_devfs_path(phci_node);
+ if (di_path) {
+ if (strcmp(di_path, devfs_path) != 0) {
+ di_devfs_path_free(di_path);
+ continue;
+ }
+ (void) strlcpy(vbuf, path_state_name(di_path_state(pi)),
+ MAX_STATE_SIZE);
+ di_devfs_path_free(di_path);
+ break;
+ }
+ }
+
+ di_fini(di_root);
+ return (PICL_SUCCESS);
+}
+
+static void
+add_di_path_prop(picl_nodehdl_t nodeh, di_path_prop_t di_path_prop)
+{
+ int di_ptype;
+ char *di_val;
+ ptree_propinfo_t propinfo;
+ int *idata;
+ char *sdata;
+ unsigned char *bdata;
+ int len;
+
+ di_ptype = di_path_prop_type(di_path_prop);
+ di_val = di_path_prop_name(di_path_prop);
+
+ switch (di_ptype) {
+ case DI_PROP_TYPE_BOOLEAN:
+ add_boolean_prop(nodeh, propinfo, di_val);
+ break;
+ case DI_PROP_TYPE_INT:
+ case DI_PROP_TYPE_INT64:
+ len = di_path_prop_ints(di_path_prop, &idata);
+ if (len < 0)
+ /* Received error, so ignore prop */
+ break;
+ add_uints_prop(nodeh, propinfo, di_val, idata, len);
+ break;
+ case DI_PROP_TYPE_STRING:
+ len = di_path_prop_strings(di_path_prop, &sdata);
+ if (len <= 0)
+ break;
+ add_strings_prop(nodeh, propinfo, di_val, sdata, len);
+ break;
+ case DI_PROP_TYPE_BYTE:
+ len = di_path_prop_bytes(di_path_prop, &bdata);
+ if (len < 0)
+ break;
+ add_bytes_prop(nodeh, propinfo, di_val, bdata, len);
+ break;
+ case DI_PROP_TYPE_UNKNOWN:
+ /*
+ * Unknown type, we'll try and guess what it should be.
+ */
+ len = di_path_prop_strings(di_path_prop, &sdata);
+ if ((len > 0) && (sdata[0] != 0)) {
+ add_strings_prop(nodeh, propinfo, di_val, sdata,
+ len);
+ break;
+ }
+ len = di_path_prop_ints(di_path_prop, &idata);
+ if (len > 0) {
+ add_uints_prop(nodeh, propinfo, di_val,
+ idata, len);
+ break;
+ }
+ len = di_path_prop_bytes(di_path_prop, &bdata);
+ if (len > 0)
+ add_bytes_prop(nodeh, propinfo,
+ di_val, bdata, len);
+ else if (len == 0)
+ add_boolean_prop(nodeh, propinfo,
+ di_val);
+ break;
+ case DI_PROP_TYPE_UNDEF_IT:
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Add nodes for path information (PSARC/1999/647, PSARC/2008/437)
+ */
+static void
+construct_mpath_node(picl_nodehdl_t parh, di_node_t di_node)
+{
+ di_path_t pi = DI_PATH_NIL;
+
+ while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
+ di_node_t phci_node = di_path_phci_node(pi);
+ di_path_prop_t di_path_prop;
+ picl_nodehdl_t nodeh;
+ ptree_propinfo_t propinfo;
+ int err;
+ int instance;
+ char *di_val;
+
+ if (phci_node == DI_PATH_NIL)
+ continue;
+
+ err = ptree_create_and_add_node(parh, PICL_CLASS_MULTIPATH,
+ PICL_CLASS_MULTIPATH, &nodeh);
+ if (err != PICL_SUCCESS)
+ continue;
+
+ instance = di_instance(phci_node);
+ (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+ PICL_PTYPE_INT, PICL_READ, sizeof (instance),
+ PICL_PROP_INSTANCE, NULL, NULL);
+ (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance,
+ NULL);
+
+ di_val = di_devfs_path(phci_node);
+ if (di_val) {
+ (void) ptree_init_propinfo(&propinfo,
+ PTREE_PROPINFO_VERSION,
+ PICL_PTYPE_CHARSTRING, PICL_READ,
+ strlen(di_val) + 1, PICL_PROP_DEVFS_PATH,
+ NULL, NULL);
+ (void) ptree_create_and_add_prop(nodeh,
+ &propinfo, di_val, NULL);
+ di_devfs_path_free(di_val);
+ }
+
+ (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+ PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE),
+ MAX_STATE_SIZE, PICL_PROP_STATE, get_path_state_name, NULL);
+ (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
+
+ for (di_path_prop = di_path_prop_next(pi, DI_PROP_NIL);
+ di_path_prop != DI_PROP_NIL;
+ di_path_prop = di_path_prop_next(pi, di_path_prop)) {
+ add_di_path_prop(nodeh, di_path_prop);
+ }
+ }
+}
+
/*
* Add properties provided by libdevinfo
*/
@@ -1251,6 +1485,7 @@ construct_devtype_node(picl_nodehdl_t parh, char *nodename,
(void) add_devinfo_props(anodeh, dn);
(void) add_openprom_props(anodeh, dn);
+ construct_mpath_node(anodeh, dn);
*chdh = anodeh;
return (err);