xref: /onnv-gate/usr/src/cmd/fm/modules/common/disk-monitor/topo_gather.c (revision 7913:dd434c36cf78)
14582Scth /*
24582Scth  * CDDL HEADER START
34582Scth  *
44582Scth  * The contents of this file are subject to the terms of the
54582Scth  * Common Development and Distribution License (the "License").
64582Scth  * You may not use this file except in compliance with the License.
74582Scth  *
84582Scth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94582Scth  * or http://www.opensolaris.org/os/licensing.
104582Scth  * See the License for the specific language governing permissions
114582Scth  * and limitations under the License.
124582Scth  *
134582Scth  * When distributing Covered Code, include this CDDL HEADER in each
144582Scth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154582Scth  * If applicable, add the following below this CDDL HEADER, with the
164582Scth  * fields enclosed by brackets "[]" replaced with your own identifying
174582Scth  * information: Portions Copyright [yyyy] [name of copyright owner]
184582Scth  *
194582Scth  * CDDL HEADER END
204582Scth  */
214582Scth 
224582Scth /*
236640Scth  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
244582Scth  * Use is subject to license terms.
254582Scth  */
264582Scth 
274582Scth /*
284582Scth  * Gathers properties exported by libtopo and uses them to construct diskmon
294582Scth  * data structures, which hold the configuration information for the
304582Scth  * DE.
314582Scth  */
324582Scth 
334582Scth #include <limits.h>
344582Scth #include <stdio.h>
354582Scth #include <stdlib.h>
364582Scth #include <string.h>
374582Scth #include <strings.h>
384582Scth #include <ctype.h>
394582Scth #include <pthread.h>
404582Scth #include <libnvpair.h>
414582Scth #include <config_admin.h>
424582Scth #include <sys/fm/protocol.h>
434582Scth #include <fm/libtopo.h>
444582Scth #include <fm/topo_hc.h>
454582Scth 
464582Scth #include "disk.h"
474582Scth #include "disk_monitor.h"
485117Smyers #include "hotplug_mgr.h"
494582Scth #include "topo_gather.h"
504582Scth 
514582Scth #define	TOPO_PGROUP_IO		"io"	/* duplicated from did_props.h */
524582Scth #define	MAX_CONF_MSG_LEN	256
534582Scth 
544582Scth static nvlist_t *g_topo2diskmon = NULL;
554582Scth 
564582Scth /*
574582Scth  * The following function template is required for nvlists that were
584582Scth  * create with no flags (so there can be multiple identical name or name-value
594582Scth  * pairs).  The function defined below returns the first match for the name
604582Scth  * provided.
614582Scth  */
624582Scth #define	NONUNIQUE_NVLIST_FN(suffix, type, atype) \
634582Scth static int								\
644582Scth nonunique_nvlist_lookup_##suffix(nvlist_t *nvlp, const char *n, atype *rpp) \
654582Scth {									\
664582Scth 	nvpair_t *nvp = NULL;						\
674582Scth 	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {		\
684582Scth 		if (nvpair_type(nvp) != type)				\
694582Scth 			continue;					\
704582Scth 		if (strcmp(nvpair_name(nvp), n) == 0)			\
714582Scth 			return (nvpair_value_##suffix(nvp, rpp));	\
724582Scth 	}								\
734582Scth 	return (ENOENT);						\
744582Scth }
754582Scth 
NONUNIQUE_NVLIST_FN(string,DATA_TYPE_STRING,char *)764582Scth NONUNIQUE_NVLIST_FN(string, DATA_TYPE_STRING, char *)
774582Scth 
784582Scth static diskmon_t *
794582Scth dm_fmristring_to_diskmon(char *str)
804582Scth {
814582Scth 	diskmon_t *p = NULL;
824582Scth 	uint64_t u64val;
834582Scth 	char ch;
844582Scth 	char *lastsl = strrchr(str, '/');
854582Scth 
864582Scth 	ch = *lastsl;
874582Scth 	*lastsl = 0;
884582Scth 
894582Scth 	if (nvlist_lookup_uint64(g_topo2diskmon, str, &u64val) == 0) {
904582Scth 
914582Scth 		p = (diskmon_t *)(uintptr_t)u64val;
924582Scth 	}
934582Scth 
944582Scth 	*lastsl = ch;
954582Scth 
964582Scth 	return (p);
974582Scth }
984582Scth 
994582Scth diskmon_t *
dm_fmri_to_diskmon(fmd_hdl_t * hdl,nvlist_t * fmri)1004582Scth dm_fmri_to_diskmon(fmd_hdl_t *hdl, nvlist_t *fmri)
1014582Scth {
1024582Scth 	topo_hdl_t *thdl;
1034582Scth 	nvlist_t *dupfmri;
1044582Scth 	diskmon_t *diskp;
1054582Scth 	char *buf;
1064582Scth 	int err;
1074582Scth 
1084582Scth 	if (nvlist_dup(fmri, &dupfmri, 0) != 0)
1094582Scth 		return (NULL);
1104582Scth 
1114582Scth 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_REVISION, DATA_TYPE_STRING);
1124582Scth 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_SERIAL_ID, DATA_TYPE_STRING);
1134582Scth 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_PART, DATA_TYPE_STRING);
1144582Scth 
1154582Scth 	thdl = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
1164582Scth 	if (topo_fmri_nvl2str(thdl, dupfmri, &buf, &err) != 0) {
1174582Scth 		fmd_hdl_topo_rele(hdl, thdl);
1184582Scth 		nvlist_free(dupfmri);
1194582Scth 		return (NULL);
1204582Scth 	}
1214582Scth 	fmd_hdl_topo_rele(hdl, thdl);
1224582Scth 
1234582Scth 	diskp = dm_fmristring_to_diskmon(buf);
1244582Scth 
1254582Scth 	nvlist_free(dupfmri);
1264582Scth 	topo_hdl_strfree(thdl, buf);
1274582Scth 
1284582Scth 	return (diskp);
1294582Scth }
1304582Scth 
1314582Scth static nvlist_t *
find_disk_monitor_private_pgroup(tnode_t * node)1324582Scth find_disk_monitor_private_pgroup(tnode_t *node)
1334582Scth {
1344582Scth 	int err;
1354582Scth 	nvlist_t *list_of_lists, *nvlp, *dupnvlp;
1364582Scth 	nvlist_t *disk_monitor_pgrp = NULL;
1374582Scth 	nvpair_t *nvp = NULL;
1384582Scth 	char *pgroup_name;
1394582Scth 
1404582Scth 	/*
1414582Scth 	 * topo_prop_get_all() returns an nvlist that contains other
1424582Scth 	 * nvlists (some of which are property groups).  Since the private
1434582Scth 	 * property group we need will be among the list of property
1444582Scth 	 * groups returned (hopefully), we need to walk the list of nvlists
1454582Scth 	 * in the topo node's properties to find the property groups, then
1464582Scth 	 * check inside each embedded nvlist to see if it's the pgroup we're
1474582Scth 	 * looking for.
1484582Scth 	 */
1494582Scth 	if ((list_of_lists = topo_prop_getprops(node, &err)) != NULL) {
1504582Scth 		/*
1514582Scth 		 * Go through the list of nvlists, looking for the
1524582Scth 		 * property group we need.
1534582Scth 		 */
1544582Scth 		while ((nvp = nvlist_next_nvpair(list_of_lists, nvp)) != NULL) {
1554582Scth 
1564582Scth 			if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
1574582Scth 			    strcmp(nvpair_name(nvp), TOPO_PROP_GROUP) != 0 ||
1584582Scth 			    nvpair_value_nvlist(nvp, &nvlp) != 0)
1594582Scth 				continue;
1604582Scth 
1614582Scth 			dm_assert(nvlp != NULL);
1624582Scth 			pgroup_name = NULL;
1634582Scth 
1644582Scth 			if (nonunique_nvlist_lookup_string(nvlp,
1654582Scth 			    TOPO_PROP_GROUP_NAME, &pgroup_name) != 0 ||
1664582Scth 			    strcmp(pgroup_name, DISK_MONITOR_PROPERTIES) != 0)
1674582Scth 				continue;
1684582Scth 			else {
1694582Scth 				/*
1704582Scth 				 * Duplicate the nvlist so that when the
1714582Scth 				 * master nvlist is freed (below), we will
1724582Scth 				 * still refer to allocated memory.
1734582Scth 				 */
1744582Scth 				if (nvlist_dup(nvlp, &dupnvlp, 0) == 0)
1754582Scth 					disk_monitor_pgrp = dupnvlp;
1764582Scth 				else
1774582Scth 					disk_monitor_pgrp = NULL;
1784582Scth 				break;
1794582Scth 			}
1804582Scth 		}
1814582Scth 
1824582Scth 		nvlist_free(list_of_lists);
1834582Scth 	}
1844582Scth 
1854582Scth 	return (disk_monitor_pgrp);
1864582Scth }
1874582Scth 
1884582Scth /*
1894582Scth  * Look up the FMRI corresponding to the node in the global
1904582Scth  * hash table and return the pointer stored (if any).  Save the
1914582Scth  * FMRI string in *str if str is non-NULL.
1924582Scth  */
1934582Scth static void *
fmri2ptr(topo_hdl_t * thp,tnode_t * node,char ** str,int * err)1944582Scth fmri2ptr(topo_hdl_t *thp, tnode_t *node, char **str, int *err)
1954582Scth {
1964582Scth 	nvlist_t	*fmri = NULL;
1974582Scth 	char		*cstr = NULL;
1984582Scth 	uint64_t	u64val;
1994582Scth 	void		*p = NULL;
2004582Scth 
2014582Scth 	if (topo_node_resource(node, &fmri, err) != 0)
2024582Scth 		return (NULL);
2034582Scth 
2044582Scth 	if (topo_fmri_nvl2str(thp, fmri, &cstr, err) != 0) {
2054582Scth 		nvlist_free(fmri);
2064582Scth 		return (NULL);
2074582Scth 	}
2084582Scth 
2094582Scth 	if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &u64val) == 0) {
2104582Scth 
2114582Scth 		p = (void *)(uintptr_t)u64val;
2124582Scth 	}
2134582Scth 
2144582Scth 	nvlist_free(fmri);
2154582Scth 	if (str != NULL)
2164582Scth 		*str = dstrdup(cstr);
2174582Scth 	topo_hdl_strfree(thp, cstr);
2184582Scth 	return (p);
2194582Scth }
2204582Scth 
2214582Scth typedef struct walk_diskmon {
2224582Scth 	diskmon_t *target;
2234582Scth 	char *pfmri;
2244582Scth } walk_diskmon_t;
2254582Scth 
2264582Scth static int
topo_add_disk(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)2274582Scth topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
2284582Scth {
2294582Scth 	diskmon_t *target_diskp = wdp->target;
2304582Scth 	char		*devpath = NULL;
2314582Scth 	char		*capacity = NULL;
2324582Scth 	char		*firmrev = NULL;
2334582Scth 	char		*serial = NULL;
2344582Scth 	char		*manuf = NULL;
2354582Scth 	char		*model = NULL;
2364582Scth 	char		*label;
2374582Scth 	uint64_t	ptr = 0;
2384582Scth 	int		err;
2394582Scth 	dm_fru_t	*frup;
2404582Scth 	diskmon_t	*diskp;
2414582Scth 
2424582Scth 	if (wdp->pfmri == NULL) {
2434582Scth 		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
2444582Scth 		return (0);
2454582Scth 	}
2464582Scth 
2474582Scth 	if (nvlist_lookup_uint64(g_topo2diskmon, wdp->pfmri, &ptr) != 0) {
2484582Scth 		log_msg(MM_TOPO, "No diskmon for %s: parent of node %p.\n",
2494582Scth 		    wdp->pfmri, node);
2504582Scth 		dstrfree(wdp->pfmri);
2514582Scth 		/* Skip this disk: */
2524582Scth 		return (0);
2534582Scth 	}
2544582Scth 
2554582Scth 	dstrfree(wdp->pfmri);
2564582Scth 	wdp->pfmri = NULL;
2574582Scth 
2584582Scth 	diskp = (diskmon_t *)(uintptr_t)ptr;
2594582Scth 
2604582Scth 	/* If we were called upon to update a particular disk, do it */
2614582Scth 	if (target_diskp != NULL && diskp != target_diskp) {
2624582Scth 		return (0);
2634582Scth 	}
2644582Scth 
2654582Scth 	/*
2664582Scth 	 * Update the diskmon's location field with the disk's label
2674582Scth 	 */
2684582Scth 	if (diskp->location)
2694582Scth 		dstrfree(diskp->location);
2704582Scth 	if (topo_node_label(node, &label, &err) == 0) {
2714582Scth 		diskp->location = dstrdup(label);
2724582Scth 		topo_hdl_strfree(thp, label);
2734582Scth 	} else
2744582Scth 		diskp->location = dstrdup("unknown location");
2754582Scth 
2764582Scth 	/*
2774582Scth 	 * Check for a device path property (if the disk is configured,
2784582Scth 	 * it will be present) and add it to the diskmon's properties)
2794582Scth 	 */
2804582Scth 	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
2814582Scth 	    &devpath, &err) == 0) {
2824582Scth 		char devp[PATH_MAX];
2834582Scth 		/*
2844582Scth 		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
2854582Scth 		 * minor device node
2864582Scth 		 */
2874582Scth 		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
2884582Scth 		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
2894582Scth 		    devp);
2904582Scth 		topo_hdl_strfree(thp, devpath);
2914582Scth 	}
2924582Scth 
2934582Scth 	/*
2944582Scth 	 * Add the logical disk node, if it exists
2954582Scth 	 */
2966640Scth 	if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
2974582Scth 	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
2984582Scth 		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
2994582Scth 		    devpath);
3004582Scth 		topo_hdl_strfree(thp, devpath);
3014582Scth 	}
3024582Scth 
3034582Scth 	/*
3044582Scth 	 * Add the FRU information (if present in the node) to the diskmon's
3054582Scth 	 * fru data structure:
3064582Scth 	 */
3076640Scth 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3084582Scth 	    TOPO_STORAGE_MODEL, &model, &err);
3094582Scth 
3106640Scth 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3114582Scth 	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);
3124582Scth 
3136640Scth 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3144582Scth 	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);
3154582Scth 
3166640Scth 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3174582Scth 	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);
3184582Scth 
3196640Scth 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
3204582Scth 	    TOPO_STORAGE_CAPACITY, &capacity, &err);
3214582Scth 
322*7913SStephen.Hanson@Sun.COM 	frup = new_dmfru(manuf != NULL ? manuf : "", model != NULL ? model : "",
323*7913SStephen.Hanson@Sun.COM 	    firmrev != NULL ? firmrev : "", serial != NULL ? serial : "",
3244582Scth 	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));
3254582Scth 
3264582Scth 	if (model)
3274582Scth 		topo_hdl_strfree(thp, model);
3284582Scth 	if (manuf)
3294582Scth 		topo_hdl_strfree(thp, manuf);
3304582Scth 	if (serial)
3314582Scth 		topo_hdl_strfree(thp, serial);
3324582Scth 	if (firmrev)
3334582Scth 		topo_hdl_strfree(thp, firmrev);
3344582Scth 	if (capacity)
3354582Scth 		topo_hdl_strfree(thp, capacity);
3364582Scth 
3374582Scth 	/* Add the fru information to the diskmon: */
3384582Scth 	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
3394582Scth 	dm_assert(diskp->frup == NULL);
3404582Scth 	diskp->frup = frup;
3414582Scth 	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
3424582Scth 
3434582Scth 	return (0);
3444582Scth }
3454582Scth 
3464582Scth static int
indicator_breakup(char * identifier,ind_state_t * state,char ** name)3474582Scth indicator_breakup(char *identifier, ind_state_t *state, char **name)
3484582Scth {
3494582Scth 	if (identifier[0] != '+' && identifier[0] != '-') {
3504582Scth 		log_msg(MM_CONF, "Invalid indicator name `%s'\n", identifier);
3514582Scth 		return (-1);
3524582Scth 	}
3534582Scth 
3544582Scth 	*state = (identifier[0] == '+') ? INDICATOR_ON : INDICATOR_OFF;
3554582Scth 	*name = &identifier[1];
3564582Scth 	return (0);
3574582Scth }
3584582Scth 
3594582Scth static int
topoprop_indicator_add(indicator_t ** indp,char * ind_name,char * ind_action)3604582Scth topoprop_indicator_add(indicator_t **indp, char *ind_name, char *ind_action)
3614582Scth {
3624582Scth 	/* The Indicator name is of the form: "[+-][A-Za-z][A-Za-z0-9]+" */
3634582Scth 	indicator_t *newindp;
3644582Scth 	ind_state_t state;
3654582Scth 	char *name;
3664582Scth 
3674582Scth 	if (indicator_breakup(ind_name, &state, &name) != 0)
3684582Scth 		return (-1);
3694582Scth 	newindp = new_indicator(state, name, ind_action);
3704582Scth 
3714582Scth 	link_indicator(indp, newindp);
3724582Scth 
3734582Scth 	return (0);
3744582Scth }
3754582Scth 
3764582Scth static hotplug_state_t
str2dmstate(char * str)3774582Scth str2dmstate(char *str)
3784582Scth {
3794582Scth 	if (strcasecmp("configured", str) == 0) {
3804582Scth 		return (HPS_CONFIGURED);
3814582Scth 	} else if (strcasecmp("unconfigured", str) == 0) {
3824582Scth 		return (HPS_UNCONFIGURED);
3834582Scth 	} else if (strcasecmp("absent", str) == 0) {
3844582Scth 		return (HPS_ABSENT);
3854582Scth 	} else if (strcasecmp("present", str) == 0) {
3864582Scth 		return (HPS_PRESENT);
3874582Scth 	} else
3884582Scth 		return (HPS_UNKNOWN);
3894582Scth }
3904582Scth 
3914582Scth static int
topoprop_indrule_add(indrule_t ** indrp,char * sts,char * acts)3924582Scth topoprop_indrule_add(indrule_t **indrp, char *sts, char *acts)
3934582Scth {
3944582Scth 	ind_action_t		*indactp = NULL;
3954582Scth 	ind_state_t		state;
3964582Scth 	char			*name, *lasts, *p;
3974582Scth 	int			stateslen = strlen(sts) + 1;
3984582Scth 	int			actionslen = strlen(acts) + 1;
3994582Scth 	char			*states = dstrdup(sts);
4004582Scth 	char			*actions = dstrdup(acts);
4014582Scth 	state_transition_t	strans;
4024582Scth 	boolean_t		failed = B_FALSE;
4034582Scth 	conf_err_t		err;
4044582Scth 	char			msgbuf[MAX_CONF_MSG_LEN];
4054582Scth 
4064582Scth 	/* The state string is of the form "{STATE}>{STATE}" */
4074582Scth 	p = strchr(states, '>');
4084582Scth 	dm_assert(p != NULL);
4094582Scth 	*p = 0;
4104582Scth 	strans.begin = str2dmstate(states);
4114582Scth 	*p = '>';
4124582Scth 	strans.end = str2dmstate(p + 1);
4134582Scth 
4144582Scth 	if (strans.begin == HPS_UNKNOWN || strans.end == HPS_UNKNOWN) {
4154582Scth 		log_msg(MM_CONF, "Invalid states property `%s'\n", sts);
4164582Scth 		failed = B_TRUE;
4174582Scth 	} else if ((err = check_state_transition(strans.begin, strans.end))
4184582Scth 	    != E_NO_ERROR) {
4194582Scth 		conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, &strans);
4204582Scth 		log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
4214582Scth 		failed = B_TRUE;
4224582Scth 	}
4234582Scth 
4244582Scth 	/* Actions are of the form "{ACTION}[&{ACTION}]" */
4254582Scth 	if (!failed && (p = strtok_r(actions, "&", &lasts)) != NULL) {
4264582Scth 		/* At least 2 tokens */
4274582Scth 		do {
4284582Scth 			if (indicator_breakup(p, &state, &name) != 0) {
4294582Scth 				failed = B_TRUE;
4304582Scth 				break;
4314582Scth 			}
4324582Scth 
4334582Scth 			link_indaction(&indactp, new_indaction(state, name));
4344582Scth 
4354582Scth 		} while ((p = strtok_r(NULL, "&", &lasts)) != NULL);
4364582Scth 	} else if (!failed) {
4374582Scth 		/* One token */
4384582Scth 		if (indicator_breakup(actions, &state, &name) != 0)
4394582Scth 			return (-1);
4404582Scth 		indactp = new_indaction(state, name);
4414582Scth 	}
4424582Scth 
4434582Scth 	dfree(states, stateslen);
4444582Scth 	dfree(actions, actionslen);
4454582Scth 
4464582Scth 	if (!failed && (err = check_indactions(indactp)) != E_NO_ERROR) {
4474582Scth 		conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, NULL);
4484582Scth 		log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
4494582Scth 		failed = B_TRUE;
4504582Scth 	}
4514582Scth 
4524582Scth 	if (failed) {
4534582Scth 		indaction_free(indactp);
4544582Scth 		return (-1);
4554582Scth 	} else
4564582Scth 		link_indrule(indrp, new_indrule(&strans, indactp));
4574582Scth 	return (0);
4584582Scth }
4594582Scth 
4604582Scth 
4614582Scth static int
topo_add_bay(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)4624582Scth topo_add_bay(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
4634582Scth {
4644582Scth 	diskmon_t *target_diskp = wdp->target;
4654582Scth 	nvlist_t	*nvlp = find_disk_monitor_private_pgroup(node);
4664582Scth 	nvlist_t	*prop_nvlp;
4674582Scth 	nvpair_t	*nvp = NULL;
4684582Scth 	char		*prop_name, *prop_value;
4694582Scth #define	PNAME_MAX 128
4704582Scth 	char		pname[PNAME_MAX];
4714582Scth 	char		msgbuf[MAX_CONF_MSG_LEN];
4724582Scth 	char		*indicator_name, *indicator_action;
4734582Scth 	char		*indrule_states, *indrule_actions;
4744582Scth 	int		err = 0, i;
4754582Scth 	conf_err_t	conferr;
4764582Scth 	boolean_t	conf_failure = B_FALSE;
4775117Smyers 	char		*unadj_physid = NULL;
4785117Smyers 	char		physid[MAXPATHLEN];
4794582Scth 	char		*label;
4804582Scth 	nvlist_t	*diskprops = NULL;
4814582Scth 	char		*cstr = NULL;
4824582Scth 	indicator_t	*indp = NULL;
4834582Scth 	indrule_t	*indrp = NULL;
4844582Scth 	void		*p;
4854582Scth 	diskmon_t	*diskp;
4864582Scth 	void		*ptr;
4874582Scth 
4884582Scth 	/* No private properties -- just ignore the port */
4894582Scth 	if (nvlp == NULL)
4904582Scth 		return (0);
4914582Scth 
4924582Scth 	/*
4934582Scth 	 * Look for a diskmon based on this node's FMRI string.
4944582Scth 	 * Once a diskmon has been created, it's not re-created.  This is
4954582Scth 	 * essential for the times when the tree-walk is called after a
4964582Scth 	 * disk is inserted (or removed) -- in that case, the disk node
4974582Scth 	 * handler simply updates the FRU information in the diskmon.
4984582Scth 	 */
4994582Scth 	if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {
5004582Scth 
5014582Scth 		diskp = (diskmon_t *)p;
5024582Scth 
5034582Scth 		/*
5044582Scth 		 * Delete the FRU information from the diskmon.  If a disk
5054582Scth 		 * is connected, its FRU information will be refreshed by
5064582Scth 		 * the disk node code.
5074582Scth 		 */
5084582Scth 		if (diskp->frup && (target_diskp == NULL ||
5094582Scth 		    diskp == target_diskp)) {
5104582Scth 			dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
5114582Scth 			dmfru_free(diskp->frup);
5124582Scth 			diskp->frup = NULL;
5134582Scth 			dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
5144582Scth 		}
5154582Scth 
5164582Scth 		wdp->pfmri = cstr;
5174582Scth 		nvlist_free(nvlp);
5184582Scth 		return (0);
5194582Scth 	}
5204582Scth 
5214582Scth 	/*
5224582Scth 	 * Determine the physical path to the attachment point
5234582Scth 	 */
5244582Scth 	if (topo_prop_get_string(node, TOPO_PGROUP_IO,
5255117Smyers 	    TOPO_IO_AP_PATH, &unadj_physid, &err) == 0) {
5264582Scth 
5275117Smyers 		adjust_dynamic_ap(unadj_physid, physid);
5285117Smyers 		topo_hdl_strfree(thp, unadj_physid);
5295117Smyers 	} else {
5305117Smyers 
5315117Smyers 		/* unadj_physid cannot have been allocated */
5324582Scth 		if (cstr)
5334582Scth 			dstrfree(cstr);
5344582Scth 		nvlist_free(nvlp);
5354582Scth 		return (-1);
5364582Scth 	}
5374582Scth 
5384582Scth 	/*
5395117Smyers 	 */
5405117Smyers 
5415117Smyers 	/*
5424582Scth 	 * Process the properties.  If we encounter a property that
5434582Scth 	 * is not an indicator name, action, or rule, add it to the
5444582Scth 	 * disk's props list.
5454582Scth 	 */
5464582Scth 
5474582Scth 	/* Process indicators */
5484582Scth 	i = 0;
5494582Scth 	indicator_name = NULL;
5504582Scth 	indicator_action = NULL;
5514582Scth 	do {
5524582Scth 		if (indicator_name != NULL && indicator_action != NULL) {
5534582Scth 
5544582Scth 			if (topoprop_indicator_add(&indp, indicator_name,
5554582Scth 			    indicator_action) != 0) {
5564582Scth 
5574582Scth 				conf_failure = B_TRUE;
5584582Scth 			}
5594582Scth 
5604582Scth 			topo_hdl_strfree(thp, indicator_name);
5614582Scth 			topo_hdl_strfree(thp, indicator_action);
5624582Scth 		}
5634582Scth 
5644582Scth 		(void) snprintf(pname, PNAME_MAX, BAY_IND_NAME "-%d", i);
5654582Scth 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
5664582Scth 		    pname, &indicator_name, &err) != 0)
5674582Scth 			break;
5684582Scth 
5694582Scth 		(void) snprintf(pname, PNAME_MAX, BAY_IND_ACTION "-%d", i);
5704582Scth 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
5714582Scth 		    pname, &indicator_action, &err) != 0)
5724582Scth 			break;
5734582Scth 
5744582Scth 		i++;
5754582Scth 	} while (!conf_failure && indicator_name != NULL &&
5764582Scth 	    indicator_action != NULL);
5774582Scth 
5784582Scth 	if (!conf_failure && indp != NULL &&
5794582Scth 	    (conferr = check_inds(indp)) != E_NO_ERROR) {
5804582Scth 		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
5814582Scth 		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
5824582Scth 		conf_failure = B_TRUE;
5834582Scth 	}
5844582Scth 
5854582Scth 	/* Process state rules and indicator actions */
5864582Scth 	i = 0;
5874582Scth 	indrule_states = NULL;
5884582Scth 	indrule_actions = NULL;
5894582Scth 	do {
5904582Scth 		if (indrule_states != NULL && indrule_actions != NULL) {
5914582Scth 
5924582Scth 			if (topoprop_indrule_add(&indrp, indrule_states,
5934582Scth 			    indrule_actions) != 0) {
5944582Scth 
5954582Scth 				conf_failure = B_TRUE;
5964582Scth 			}
5974582Scth 
5984582Scth 			topo_hdl_strfree(thp, indrule_states);
5994582Scth 			topo_hdl_strfree(thp, indrule_actions);
6004582Scth 		}
6014582Scth 
6024582Scth 		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_STATES "-%d", i);
6034582Scth 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
6044582Scth 		    pname, &indrule_states, &err) != 0)
6054582Scth 			break;
6064582Scth 
6074582Scth 		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_ACTIONS "-%d",
6084582Scth 		    i);
6094582Scth 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
6104582Scth 		    pname, &indrule_actions, &err) != 0)
6114582Scth 			break;
6124582Scth 
6134582Scth 		i++;
6144582Scth 	} while (!conf_failure && indrule_states != NULL &&
6154582Scth 	    indrule_actions != NULL);
6164582Scth 
6174582Scth 	if (!conf_failure && indrp != NULL && indp != NULL &&
6184582Scth 	    ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
6194582Scth 	    != E_NO_ERROR ||
6204582Scth 	    (conferr = check_consistent_ind_indrules(indp, indrp,
6214582Scth 	    (ind_action_t **)&ptr)) != E_NO_ERROR)) {
6224582Scth 
6234582Scth 		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
6244582Scth 		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
6254582Scth 		conf_failure = B_TRUE;
6264582Scth 
6274582Scth 	}
6284582Scth 
6294582Scth 	/*
6304582Scth 	 * Now collect miscellaneous properties.
6314582Scth 	 * Each property is stored as an embedded nvlist named
6324582Scth 	 * TOPO_PROP_VAL.  The property name is stored in the value for
6334582Scth 	 * key=TOPO_PROP_VAL_NAME and the property's value is
6344582Scth 	 * stored in the value for key=TOPO_PROP_VAL_VAL.  This is all
6354582Scth 	 * necessary so we can subtractively decode the properties that
6364582Scth 	 * we do not directly handle (so that these properties are added to
6374582Scth 	 * the per-disk properties nvlist), increasing flexibility.
6384582Scth 	 */
6394582Scth 	(void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
6404582Scth 	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
6414582Scth 		/* Only care about embedded nvlists named TOPO_PROP_VAL */
6424582Scth 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
6434582Scth 		    strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
6444582Scth 		    nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
6454582Scth 			continue;
6464582Scth 
6474582Scth 		if (nonunique_nvlist_lookup_string(prop_nvlp,
6484582Scth 		    TOPO_PROP_VAL_NAME, &prop_name) != 0)
6494582Scth 			continue;
6504582Scth 
6514582Scth 		/* Filter out indicator properties */
6524582Scth 		if (strstr(prop_name, BAY_IND_NAME) != NULL ||
6534582Scth 		    strstr(prop_name, BAY_IND_ACTION) != NULL ||
6544582Scth 		    strstr(prop_name, BAY_INDRULE_STATES) != NULL ||
6554582Scth 		    strstr(prop_name, BAY_INDRULE_ACTIONS) != NULL)
6564582Scth 			continue;
6574582Scth 
6584582Scth 		if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
6594582Scth 		    &prop_value) != 0)
6604582Scth 			continue;
6614582Scth 
6624582Scth 		/* Add the property to the disk's prop list: */
6634582Scth 		if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
6644582Scth 			log_msg(MM_TOPO,
6654582Scth 			    "Could not add disk property `%s' with "
6664582Scth 			    "value `%s'\n", prop_name, prop_value);
6674582Scth 	}
6684582Scth 
6694582Scth 	nvlist_free(nvlp);
6704582Scth 
6714582Scth 	if (cstr != NULL) {
6724582Scth 		namevalpr_t nvpr;
6734582Scth 		nvlist_t *dmap_nvl;
6744582Scth 
6754582Scth 		nvpr.name = DISK_AP_PROP_APID;
6764582Scth 		nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
6774582Scth 		    (physid + 8) : physid;
6784582Scth 
6794582Scth 		/*
6804582Scth 		 * Set the diskmon's location to the value in this port's label.
6814582Scth 		 * If there's a disk plugged in, the location will be updated
6824582Scth 		 * to be the disk label (e.g. HD_ID_00).  Until a disk is
6834582Scth 		 * inserted, though, there won't be a disk libtopo node
6844582Scth 		 * created.
6854582Scth 		 */
6864582Scth 
6874582Scth 		/* Pass physid without the leading "/devices": */
6884582Scth 		dmap_nvl = namevalpr_to_nvlist(&nvpr);
6894582Scth 
6904582Scth 		diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);
6914582Scth 
6924582Scth 		if (topo_node_label(node, &label, &err) == 0) {
6934582Scth 			diskp->location = dstrdup(label);
6944582Scth 			topo_hdl_strfree(thp, label);
6954582Scth 		} else
6964582Scth 			diskp->location = dstrdup("unknown location");
6974582Scth 
6984582Scth 		if (!conf_failure && diskp != NULL) {
6994582Scth 			/* Add this diskmon to the disk list */
7004582Scth 			cfgdata_add_diskmon(config_data, diskp);
7014582Scth 			if (nvlist_add_uint64(g_topo2diskmon, cstr,
7024582Scth 			    (uint64_t)(uintptr_t)diskp) != 0) {
7034582Scth 				log_msg(MM_TOPO,
7044582Scth 				    "Could not add pointer to nvlist "
7054582Scth 				    "for `%s'!\n", cstr);
7064582Scth 			}
7074582Scth 		} else if (diskp != NULL) {
7084582Scth 			diskmon_free(diskp);
7094582Scth 		} else {
7104582Scth 			if (dmap_nvl)
7114582Scth 				nvlist_free(dmap_nvl);
7124582Scth 			if (indp)
7134582Scth 				ind_free(indp);
7144582Scth 			if (indrp)
7154582Scth 				indrule_free(indrp);
7164582Scth 			if (diskprops)
7174582Scth 				nvlist_free(diskprops);
7184582Scth 		}
7194582Scth 
7204582Scth 		wdp->pfmri = cstr;
7214582Scth 	}
7224582Scth 
7234582Scth 
7244582Scth 	return (0);
7254582Scth }
7264582Scth 
7274582Scth /*ARGSUSED*/
7284582Scth static int
gather_topo_cfg(topo_hdl_t * thp,tnode_t * node,void * arg)7294582Scth gather_topo_cfg(topo_hdl_t *thp, tnode_t *node, void *arg)
7304582Scth {
7314582Scth 	char *nodename = topo_node_name(node);
7324582Scth 	if (strcmp(DISK, nodename) == 0)
7334582Scth 		return (topo_add_disk(thp, node, (walk_diskmon_t *)arg)
7344582Scth 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
7354582Scth 	else if (strcmp(BAY, nodename) == 0)
7364582Scth 		return (topo_add_bay(thp, node, (walk_diskmon_t *)arg)
7374582Scth 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
7384582Scth 
7394582Scth 	return (TOPO_WALK_NEXT);
7404582Scth }
7414582Scth 
7424582Scth 
7434582Scth /*ARGSUSED*/
7444582Scth int
update_configuration_from_topo(fmd_hdl_t * hdl,diskmon_t * diskp)7454582Scth update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp)
7464582Scth {
7474582Scth 	int err;
7484582Scth 	topo_hdl_t *thp;
7494582Scth 	topo_walk_t *twp;
7504582Scth 	walk_diskmon_t wd;
7514582Scth 
7524582Scth 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
7534582Scth 		return (TOPO_OPEN_ERROR);
7544582Scth 	}
7554582Scth 
7564582Scth 	wd.target = diskp;
7574582Scth 	wd.pfmri = NULL;
7584582Scth 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg,
7594582Scth 	    &wd, &err)) == NULL) {
7604582Scth 		fmd_hdl_topo_rele(hdl, thp);
7614582Scth 		return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS);
7624582Scth 	}
7634582Scth 
7644582Scth 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
7654582Scth 
7664582Scth 		topo_walk_fini(twp);
7674582Scth 		if (wd.pfmri != NULL)
7684582Scth 			dstrfree(wd.pfmri);
7694582Scth 
7704582Scth 		fmd_hdl_topo_rele(hdl, thp);
7714582Scth 		return (TOPO_WALK_ERROR);
7724582Scth 	}
7734582Scth 
7744582Scth 	topo_walk_fini(twp);
7754582Scth 	fmd_hdl_topo_rele(hdl, thp);
7764582Scth 	if (wd.pfmri != NULL)
7774582Scth 		dstrfree(wd.pfmri);
7784582Scth 
7794582Scth 	return (TOPO_SUCCESS);
7804582Scth }
7814582Scth 
7824582Scth int
init_configuration_from_topo(void)7834582Scth init_configuration_from_topo(void)
7844582Scth {
7854582Scth 	return (nvlist_alloc(&g_topo2diskmon, NV_UNIQUE_NAME, 0));
7864582Scth }
7874582Scth 
7884582Scth void
fini_configuration_from_topo(void)7894582Scth fini_configuration_from_topo(void)
7904582Scth {
7914582Scth 	if (g_topo2diskmon) {
7924582Scth 		nvlist_free(g_topo2diskmon);
7934582Scth 	}
7944582Scth }
795