Home | History | Annotate | Download | only in disk-monitor
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Gathers properties exported by libtopo and uses them to construct diskmon
     29  * data structures, which hold the configuration information for the
     30  * DE.
     31  */
     32 
     33 #include <limits.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <strings.h>
     38 #include <ctype.h>
     39 #include <pthread.h>
     40 #include <libnvpair.h>
     41 #include <config_admin.h>
     42 #include <sys/fm/protocol.h>
     43 #include <fm/libtopo.h>
     44 #include <fm/topo_hc.h>
     45 
     46 #include "disk.h"
     47 #include "disk_monitor.h"
     48 #include "hotplug_mgr.h"
     49 #include "topo_gather.h"
     50 
     51 #define	TOPO_PGROUP_IO		"io"	/* duplicated from did_props.h */
     52 #define	MAX_CONF_MSG_LEN	256
     53 
     54 static nvlist_t *g_topo2diskmon = NULL;
     55 
     56 /*
     57  * The following function template is required for nvlists that were
     58  * create with no flags (so there can be multiple identical name or name-value
     59  * pairs).  The function defined below returns the first match for the name
     60  * provided.
     61  */
     62 #define	NONUNIQUE_NVLIST_FN(suffix, type, atype) \
     63 static int								\
     64 nonunique_nvlist_lookup_##suffix(nvlist_t *nvlp, const char *n, atype *rpp) \
     65 {									\
     66 	nvpair_t *nvp = NULL;						\
     67 	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {		\
     68 		if (nvpair_type(nvp) != type)				\
     69 			continue;					\
     70 		if (strcmp(nvpair_name(nvp), n) == 0)			\
     71 			return (nvpair_value_##suffix(nvp, rpp));	\
     72 	}								\
     73 	return (ENOENT);						\
     74 }
     75 
     76 NONUNIQUE_NVLIST_FN(string, DATA_TYPE_STRING, char *)
     77 
     78 static diskmon_t *
     79 dm_fmristring_to_diskmon(char *str)
     80 {
     81 	diskmon_t *p = NULL;
     82 	uint64_t u64val;
     83 	char ch;
     84 	char *lastsl = strrchr(str, '/');
     85 
     86 	ch = *lastsl;
     87 	*lastsl = 0;
     88 
     89 	if (nvlist_lookup_uint64(g_topo2diskmon, str, &u64val) == 0) {
     90 
     91 		p = (diskmon_t *)(uintptr_t)u64val;
     92 	}
     93 
     94 	*lastsl = ch;
     95 
     96 	return (p);
     97 }
     98 
     99 diskmon_t *
    100 dm_fmri_to_diskmon(fmd_hdl_t *hdl, nvlist_t *fmri)
    101 {
    102 	topo_hdl_t *thdl;
    103 	nvlist_t *dupfmri;
    104 	diskmon_t *diskp;
    105 	char *buf;
    106 	int err;
    107 
    108 	if (nvlist_dup(fmri, &dupfmri, 0) != 0)
    109 		return (NULL);
    110 
    111 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_REVISION, DATA_TYPE_STRING);
    112 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_SERIAL_ID, DATA_TYPE_STRING);
    113 	(void) nvlist_remove(dupfmri, FM_FMRI_HC_PART, DATA_TYPE_STRING);
    114 
    115 	thdl = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
    116 	if (topo_fmri_nvl2str(thdl, dupfmri, &buf, &err) != 0) {
    117 		fmd_hdl_topo_rele(hdl, thdl);
    118 		nvlist_free(dupfmri);
    119 		return (NULL);
    120 	}
    121 	fmd_hdl_topo_rele(hdl, thdl);
    122 
    123 	diskp = dm_fmristring_to_diskmon(buf);
    124 
    125 	nvlist_free(dupfmri);
    126 	topo_hdl_strfree(thdl, buf);
    127 
    128 	return (diskp);
    129 }
    130 
    131 static nvlist_t *
    132 find_disk_monitor_private_pgroup(tnode_t *node)
    133 {
    134 	int err;
    135 	nvlist_t *list_of_lists, *nvlp, *dupnvlp;
    136 	nvlist_t *disk_monitor_pgrp = NULL;
    137 	nvpair_t *nvp = NULL;
    138 	char *pgroup_name;
    139 
    140 	/*
    141 	 * topo_prop_get_all() returns an nvlist that contains other
    142 	 * nvlists (some of which are property groups).  Since the private
    143 	 * property group we need will be among the list of property
    144 	 * groups returned (hopefully), we need to walk the list of nvlists
    145 	 * in the topo node's properties to find the property groups, then
    146 	 * check inside each embedded nvlist to see if it's the pgroup we're
    147 	 * looking for.
    148 	 */
    149 	if ((list_of_lists = topo_prop_getprops(node, &err)) != NULL) {
    150 		/*
    151 		 * Go through the list of nvlists, looking for the
    152 		 * property group we need.
    153 		 */
    154 		while ((nvp = nvlist_next_nvpair(list_of_lists, nvp)) != NULL) {
    155 
    156 			if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
    157 			    strcmp(nvpair_name(nvp), TOPO_PROP_GROUP) != 0 ||
    158 			    nvpair_value_nvlist(nvp, &nvlp) != 0)
    159 				continue;
    160 
    161 			dm_assert(nvlp != NULL);
    162 			pgroup_name = NULL;
    163 
    164 			if (nonunique_nvlist_lookup_string(nvlp,
    165 			    TOPO_PROP_GROUP_NAME, &pgroup_name) != 0 ||
    166 			    strcmp(pgroup_name, DISK_MONITOR_PROPERTIES) != 0)
    167 				continue;
    168 			else {
    169 				/*
    170 				 * Duplicate the nvlist so that when the
    171 				 * master nvlist is freed (below), we will
    172 				 * still refer to allocated memory.
    173 				 */
    174 				if (nvlist_dup(nvlp, &dupnvlp, 0) == 0)
    175 					disk_monitor_pgrp = dupnvlp;
    176 				else
    177 					disk_monitor_pgrp = NULL;
    178 				break;
    179 			}
    180 		}
    181 
    182 		nvlist_free(list_of_lists);
    183 	}
    184 
    185 	return (disk_monitor_pgrp);
    186 }
    187 
    188 /*
    189  * Look up the FMRI corresponding to the node in the global
    190  * hash table and return the pointer stored (if any).  Save the
    191  * FMRI string in *str if str is non-NULL.
    192  */
    193 static void *
    194 fmri2ptr(topo_hdl_t *thp, tnode_t *node, char **str, int *err)
    195 {
    196 	nvlist_t	*fmri = NULL;
    197 	char		*cstr = NULL;
    198 	uint64_t	u64val;
    199 	void		*p = NULL;
    200 
    201 	if (topo_node_resource(node, &fmri, err) != 0)
    202 		return (NULL);
    203 
    204 	if (topo_fmri_nvl2str(thp, fmri, &cstr, err) != 0) {
    205 		nvlist_free(fmri);
    206 		return (NULL);
    207 	}
    208 
    209 	if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &u64val) == 0) {
    210 
    211 		p = (void *)(uintptr_t)u64val;
    212 	}
    213 
    214 	nvlist_free(fmri);
    215 	if (str != NULL)
    216 		*str = dstrdup(cstr);
    217 	topo_hdl_strfree(thp, cstr);
    218 	return (p);
    219 }
    220 
    221 typedef struct walk_diskmon {
    222 	diskmon_t *target;
    223 	char *pfmri;
    224 } walk_diskmon_t;
    225 
    226 static int
    227 topo_add_disk(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
    228 {
    229 	diskmon_t *target_diskp = wdp->target;
    230 	char		*devpath = NULL;
    231 	char		*capacity = NULL;
    232 	char		*firmrev = NULL;
    233 	char		*serial = NULL;
    234 	char		*manuf = NULL;
    235 	char		*model = NULL;
    236 	char		*label;
    237 	uint64_t	ptr = 0;
    238 	int		err;
    239 	dm_fru_t	*frup;
    240 	diskmon_t	*diskp;
    241 
    242 	if (wdp->pfmri == NULL) {
    243 		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
    244 		return (0);
    245 	}
    246 
    247 	if (nvlist_lookup_uint64(g_topo2diskmon, wdp->pfmri, &ptr) != 0) {
    248 		log_msg(MM_TOPO, "No diskmon for %s: parent of node %p.\n",
    249 		    wdp->pfmri, node);
    250 		dstrfree(wdp->pfmri);
    251 		/* Skip this disk: */
    252 		return (0);
    253 	}
    254 
    255 	dstrfree(wdp->pfmri);
    256 	wdp->pfmri = NULL;
    257 
    258 	diskp = (diskmon_t *)(uintptr_t)ptr;
    259 
    260 	/* If we were called upon to update a particular disk, do it */
    261 	if (target_diskp != NULL && diskp != target_diskp) {
    262 		return (0);
    263 	}
    264 
    265 	/*
    266 	 * Update the diskmon's location field with the disk's label
    267 	 */
    268 	if (diskp->location)
    269 		dstrfree(diskp->location);
    270 	if (topo_node_label(node, &label, &err) == 0) {
    271 		diskp->location = dstrdup(label);
    272 		topo_hdl_strfree(thp, label);
    273 	} else
    274 		diskp->location = dstrdup("unknown location");
    275 
    276 	/*
    277 	 * Check for a device path property (if the disk is configured,
    278 	 * it will be present) and add it to the diskmon's properties)
    279 	 */
    280 	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
    281 	    &devpath, &err) == 0) {
    282 		char devp[PATH_MAX];
    283 		/*
    284 		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
    285 		 * minor device node
    286 		 */
    287 		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
    288 		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
    289 		    devp);
    290 		topo_hdl_strfree(thp, devpath);
    291 	}
    292 
    293 	/*
    294 	 * Add the logical disk node, if it exists
    295 	 */
    296 	if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    297 	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
    298 		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
    299 		    devpath);
    300 		topo_hdl_strfree(thp, devpath);
    301 	}
    302 
    303 	/*
    304 	 * Add the FRU information (if present in the node) to the diskmon's
    305 	 * fru data structure:
    306 	 */
    307 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    308 	    TOPO_STORAGE_MODEL, &model, &err);
    309 
    310 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    311 	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);
    312 
    313 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    314 	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);
    315 
    316 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    317 	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);
    318 
    319 	(void) topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
    320 	    TOPO_STORAGE_CAPACITY, &capacity, &err);
    321 
    322 	frup = new_dmfru(manuf != NULL ? manuf : "", model != NULL ? model : "",
    323 	    firmrev != NULL ? firmrev : "", serial != NULL ? serial : "",
    324 	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));
    325 
    326 	if (model)
    327 		topo_hdl_strfree(thp, model);
    328 	if (manuf)
    329 		topo_hdl_strfree(thp, manuf);
    330 	if (serial)
    331 		topo_hdl_strfree(thp, serial);
    332 	if (firmrev)
    333 		topo_hdl_strfree(thp, firmrev);
    334 	if (capacity)
    335 		topo_hdl_strfree(thp, capacity);
    336 
    337 	/* Add the fru information to the diskmon: */
    338 	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
    339 	dm_assert(diskp->frup == NULL);
    340 	diskp->frup = frup;
    341 	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
    342 
    343 	return (0);
    344 }
    345 
    346 static int
    347 indicator_breakup(char *identifier, ind_state_t *state, char **name)
    348 {
    349 	if (identifier[0] != '+' && identifier[0] != '-') {
    350 		log_msg(MM_CONF, "Invalid indicator name `%s'\n", identifier);
    351 		return (-1);
    352 	}
    353 
    354 	*state = (identifier[0] == '+') ? INDICATOR_ON : INDICATOR_OFF;
    355 	*name = &identifier[1];
    356 	return (0);
    357 }
    358 
    359 static int
    360 topoprop_indicator_add(indicator_t **indp, char *ind_name, char *ind_action)
    361 {
    362 	/* The Indicator name is of the form: "[+-][A-Za-z][A-Za-z0-9]+" */
    363 	indicator_t *newindp;
    364 	ind_state_t state;
    365 	char *name;
    366 
    367 	if (indicator_breakup(ind_name, &state, &name) != 0)
    368 		return (-1);
    369 	newindp = new_indicator(state, name, ind_action);
    370 
    371 	link_indicator(indp, newindp);
    372 
    373 	return (0);
    374 }
    375 
    376 static hotplug_state_t
    377 str2dmstate(char *str)
    378 {
    379 	if (strcasecmp("configured", str) == 0) {
    380 		return (HPS_CONFIGURED);
    381 	} else if (strcasecmp("unconfigured", str) == 0) {
    382 		return (HPS_UNCONFIGURED);
    383 	} else if (strcasecmp("absent", str) == 0) {
    384 		return (HPS_ABSENT);
    385 	} else if (strcasecmp("present", str) == 0) {
    386 		return (HPS_PRESENT);
    387 	} else
    388 		return (HPS_UNKNOWN);
    389 }
    390 
    391 static int
    392 topoprop_indrule_add(indrule_t **indrp, char *sts, char *acts)
    393 {
    394 	ind_action_t		*indactp = NULL;
    395 	ind_state_t		state;
    396 	char			*name, *lasts, *p;
    397 	int			stateslen = strlen(sts) + 1;
    398 	int			actionslen = strlen(acts) + 1;
    399 	char			*states = dstrdup(sts);
    400 	char			*actions = dstrdup(acts);
    401 	state_transition_t	strans;
    402 	boolean_t		failed = B_FALSE;
    403 	conf_err_t		err;
    404 	char			msgbuf[MAX_CONF_MSG_LEN];
    405 
    406 	/* The state string is of the form "{STATE}>{STATE}" */
    407 	p = strchr(states, '>');
    408 	dm_assert(p != NULL);
    409 	*p = 0;
    410 	strans.begin = str2dmstate(states);
    411 	*p = '>';
    412 	strans.end = str2dmstate(p + 1);
    413 
    414 	if (strans.begin == HPS_UNKNOWN || strans.end == HPS_UNKNOWN) {
    415 		log_msg(MM_CONF, "Invalid states property `%s'\n", sts);
    416 		failed = B_TRUE;
    417 	} else if ((err = check_state_transition(strans.begin, strans.end))
    418 	    != E_NO_ERROR) {
    419 		conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, &strans);
    420 		log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
    421 		failed = B_TRUE;
    422 	}
    423 
    424 	/* Actions are of the form "{ACTION}[&{ACTION}]" */
    425 	if (!failed && (p = strtok_r(actions, "&", &lasts)) != NULL) {
    426 		/* At least 2 tokens */
    427 		do {
    428 			if (indicator_breakup(p, &state, &name) != 0) {
    429 				failed = B_TRUE;
    430 				break;
    431 			}
    432 
    433 			link_indaction(&indactp, new_indaction(state, name));
    434 
    435 		} while ((p = strtok_r(NULL, "&", &lasts)) != NULL);
    436 	} else if (!failed) {
    437 		/* One token */
    438 		if (indicator_breakup(actions, &state, &name) != 0)
    439 			return (-1);
    440 		indactp = new_indaction(state, name);
    441 	}
    442 
    443 	dfree(states, stateslen);
    444 	dfree(actions, actionslen);
    445 
    446 	if (!failed && (err = check_indactions(indactp)) != E_NO_ERROR) {
    447 		conf_error_msg(err, msgbuf, MAX_CONF_MSG_LEN, NULL);
    448 		log_msg(MM_CONF, "%s: Not adding disk to list!\n", msgbuf);
    449 		failed = B_TRUE;
    450 	}
    451 
    452 	if (failed) {
    453 		indaction_free(indactp);
    454 		return (-1);
    455 	} else
    456 		link_indrule(indrp, new_indrule(&strans, indactp));
    457 	return (0);
    458 }
    459 
    460 
    461 static int
    462 topo_add_bay(topo_hdl_t *thp, tnode_t *node, walk_diskmon_t *wdp)
    463 {
    464 	diskmon_t *target_diskp = wdp->target;
    465 	nvlist_t	*nvlp = find_disk_monitor_private_pgroup(node);
    466 	nvlist_t	*prop_nvlp;
    467 	nvpair_t	*nvp = NULL;
    468 	char		*prop_name, *prop_value;
    469 #define	PNAME_MAX 128
    470 	char		pname[PNAME_MAX];
    471 	char		msgbuf[MAX_CONF_MSG_LEN];
    472 	char		*indicator_name, *indicator_action;
    473 	char		*indrule_states, *indrule_actions;
    474 	int		err = 0, i;
    475 	conf_err_t	conferr;
    476 	boolean_t	conf_failure = B_FALSE;
    477 	char		*unadj_physid = NULL;
    478 	char		physid[MAXPATHLEN];
    479 	char		*label;
    480 	nvlist_t	*diskprops = NULL;
    481 	char		*cstr = NULL;
    482 	indicator_t	*indp = NULL;
    483 	indrule_t	*indrp = NULL;
    484 	void		*p;
    485 	diskmon_t	*diskp;
    486 	void		*ptr;
    487 
    488 	/* No private properties -- just ignore the port */
    489 	if (nvlp == NULL)
    490 		return (0);
    491 
    492 	/*
    493 	 * Look for a diskmon based on this node's FMRI string.
    494 	 * Once a diskmon has been created, it's not re-created.  This is
    495 	 * essential for the times when the tree-walk is called after a
    496 	 * disk is inserted (or removed) -- in that case, the disk node
    497 	 * handler simply updates the FRU information in the diskmon.
    498 	 */
    499 	if ((p = fmri2ptr(thp, node, &cstr, &err)) != NULL) {
    500 
    501 		diskp = (diskmon_t *)p;
    502 
    503 		/*
    504 		 * Delete the FRU information from the diskmon.  If a disk
    505 		 * is connected, its FRU information will be refreshed by
    506 		 * the disk node code.
    507 		 */
    508 		if (diskp->frup && (target_diskp == NULL ||
    509 		    diskp == target_diskp)) {
    510 			dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
    511 			dmfru_free(diskp->frup);
    512 			diskp->frup = NULL;
    513 			dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
    514 		}
    515 
    516 		wdp->pfmri = cstr;
    517 		nvlist_free(nvlp);
    518 		return (0);
    519 	}
    520 
    521 	/*
    522 	 * Determine the physical path to the attachment point
    523 	 */
    524 	if (topo_prop_get_string(node, TOPO_PGROUP_IO,
    525 	    TOPO_IO_AP_PATH, &unadj_physid, &err) == 0) {
    526 
    527 		adjust_dynamic_ap(unadj_physid, physid);
    528 		topo_hdl_strfree(thp, unadj_physid);
    529 	} else {
    530 
    531 		/* unadj_physid cannot have been allocated */
    532 		if (cstr)
    533 			dstrfree(cstr);
    534 		nvlist_free(nvlp);
    535 		return (-1);
    536 	}
    537 
    538 	/*
    539 	 */
    540 
    541 	/*
    542 	 * Process the properties.  If we encounter a property that
    543 	 * is not an indicator name, action, or rule, add it to the
    544 	 * disk's props list.
    545 	 */
    546 
    547 	/* Process indicators */
    548 	i = 0;
    549 	indicator_name = NULL;
    550 	indicator_action = NULL;
    551 	do {
    552 		if (indicator_name != NULL && indicator_action != NULL) {
    553 
    554 			if (topoprop_indicator_add(&indp, indicator_name,
    555 			    indicator_action) != 0) {
    556 
    557 				conf_failure = B_TRUE;
    558 			}
    559 
    560 			topo_hdl_strfree(thp, indicator_name);
    561 			topo_hdl_strfree(thp, indicator_action);
    562 		}
    563 
    564 		(void) snprintf(pname, PNAME_MAX, BAY_IND_NAME "-%d", i);
    565 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
    566 		    pname, &indicator_name, &err) != 0)
    567 			break;
    568 
    569 		(void) snprintf(pname, PNAME_MAX, BAY_IND_ACTION "-%d", i);
    570 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
    571 		    pname, &indicator_action, &err) != 0)
    572 			break;
    573 
    574 		i++;
    575 	} while (!conf_failure && indicator_name != NULL &&
    576 	    indicator_action != NULL);
    577 
    578 	if (!conf_failure && indp != NULL &&
    579 	    (conferr = check_inds(indp)) != E_NO_ERROR) {
    580 		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, NULL);
    581 		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
    582 		conf_failure = B_TRUE;
    583 	}
    584 
    585 	/* Process state rules and indicator actions */
    586 	i = 0;
    587 	indrule_states = NULL;
    588 	indrule_actions = NULL;
    589 	do {
    590 		if (indrule_states != NULL && indrule_actions != NULL) {
    591 
    592 			if (topoprop_indrule_add(&indrp, indrule_states,
    593 			    indrule_actions) != 0) {
    594 
    595 				conf_failure = B_TRUE;
    596 			}
    597 
    598 			topo_hdl_strfree(thp, indrule_states);
    599 			topo_hdl_strfree(thp, indrule_actions);
    600 		}
    601 
    602 		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_STATES "-%d", i);
    603 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
    604 		    pname, &indrule_states, &err) != 0)
    605 			break;
    606 
    607 		(void) snprintf(pname, PNAME_MAX, BAY_INDRULE_ACTIONS "-%d",
    608 		    i);
    609 		if (topo_prop_get_string(node, DISK_MONITOR_PROPERTIES,
    610 		    pname, &indrule_actions, &err) != 0)
    611 			break;
    612 
    613 		i++;
    614 	} while (!conf_failure && indrule_states != NULL &&
    615 	    indrule_actions != NULL);
    616 
    617 	if (!conf_failure && indrp != NULL && indp != NULL &&
    618 	    ((conferr = check_indrules(indrp, (state_transition_t **)&ptr))
    619 	    != E_NO_ERROR ||
    620 	    (conferr = check_consistent_ind_indrules(indp, indrp,
    621 	    (ind_action_t **)&ptr)) != E_NO_ERROR)) {
    622 
    623 		conf_error_msg(conferr, msgbuf, MAX_CONF_MSG_LEN, ptr);
    624 		log_msg(MM_CONF, "%s: Not adding disk to list\n", msgbuf);
    625 		conf_failure = B_TRUE;
    626 
    627 	}
    628 
    629 	/*
    630 	 * Now collect miscellaneous properties.
    631 	 * Each property is stored as an embedded nvlist named
    632 	 * TOPO_PROP_VAL.  The property name is stored in the value for
    633 	 * key=TOPO_PROP_VAL_NAME and the property's value is
    634 	 * stored in the value for key=TOPO_PROP_VAL_VAL.  This is all
    635 	 * necessary so we can subtractively decode the properties that
    636 	 * we do not directly handle (so that these properties are added to
    637 	 * the per-disk properties nvlist), increasing flexibility.
    638 	 */
    639 	(void) nvlist_alloc(&diskprops, NV_UNIQUE_NAME, 0);
    640 	while ((nvp = nvlist_next_nvpair(nvlp, nvp)) != NULL) {
    641 		/* Only care about embedded nvlists named TOPO_PROP_VAL */
    642 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST ||
    643 		    strcmp(nvpair_name(nvp), TOPO_PROP_VAL) != 0 ||
    644 		    nvpair_value_nvlist(nvp, &prop_nvlp) != 0)
    645 			continue;
    646 
    647 		if (nonunique_nvlist_lookup_string(prop_nvlp,
    648 		    TOPO_PROP_VAL_NAME, &prop_name) != 0)
    649 			continue;
    650 
    651 		/* Filter out indicator properties */
    652 		if (strstr(prop_name, BAY_IND_NAME) != NULL ||
    653 		    strstr(prop_name, BAY_IND_ACTION) != NULL ||
    654 		    strstr(prop_name, BAY_INDRULE_STATES) != NULL ||
    655 		    strstr(prop_name, BAY_INDRULE_ACTIONS) != NULL)
    656 			continue;
    657 
    658 		if (nonunique_nvlist_lookup_string(prop_nvlp, TOPO_PROP_VAL_VAL,
    659 		    &prop_value) != 0)
    660 			continue;
    661 
    662 		/* Add the property to the disk's prop list: */
    663 		if (nvlist_add_string(diskprops, prop_name, prop_value) != 0)
    664 			log_msg(MM_TOPO,
    665 			    "Could not add disk property `%s' with "
    666 			    "value `%s'\n", prop_name, prop_value);
    667 	}
    668 
    669 	nvlist_free(nvlp);
    670 
    671 	if (cstr != NULL) {
    672 		namevalpr_t nvpr;
    673 		nvlist_t *dmap_nvl;
    674 
    675 		nvpr.name = DISK_AP_PROP_APID;
    676 		nvpr.value = strncmp(physid, "/devices", 8) == 0 ?
    677 		    (physid + 8) : physid;
    678 
    679 		/*
    680 		 * Set the diskmon's location to the value in this port's label.
    681 		 * If there's a disk plugged in, the location will be updated
    682 		 * to be the disk label (e.g. HD_ID_00).  Until a disk is
    683 		 * inserted, though, there won't be a disk libtopo node
    684 		 * created.
    685 		 */
    686 
    687 		/* Pass physid without the leading "/devices": */
    688 		dmap_nvl = namevalpr_to_nvlist(&nvpr);
    689 
    690 		diskp = new_diskmon(dmap_nvl, indp, indrp, diskprops);
    691 
    692 		if (topo_node_label(node, &label, &err) == 0) {
    693 			diskp->location = dstrdup(label);
    694 			topo_hdl_strfree(thp, label);
    695 		} else
    696 			diskp->location = dstrdup("unknown location");
    697 
    698 		if (!conf_failure && diskp != NULL) {
    699 			/* Add this diskmon to the disk list */
    700 			cfgdata_add_diskmon(config_data, diskp);
    701 			if (nvlist_add_uint64(g_topo2diskmon, cstr,
    702 			    (uint64_t)(uintptr_t)diskp) != 0) {
    703 				log_msg(MM_TOPO,
    704 				    "Could not add pointer to nvlist "
    705 				    "for `%s'!\n", cstr);
    706 			}
    707 		} else if (diskp != NULL) {
    708 			diskmon_free(diskp);
    709 		} else {
    710 			if (dmap_nvl)
    711 				nvlist_free(dmap_nvl);
    712 			if (indp)
    713 				ind_free(indp);
    714 			if (indrp)
    715 				indrule_free(indrp);
    716 			if (diskprops)
    717 				nvlist_free(diskprops);
    718 		}
    719 
    720 		wdp->pfmri = cstr;
    721 	}
    722 
    723 
    724 	return (0);
    725 }
    726 
    727 /*ARGSUSED*/
    728 static int
    729 gather_topo_cfg(topo_hdl_t *thp, tnode_t *node, void *arg)
    730 {
    731 	char *nodename = topo_node_name(node);
    732 	if (strcmp(DISK, nodename) == 0)
    733 		return (topo_add_disk(thp, node, (walk_diskmon_t *)arg)
    734 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
    735 	else if (strcmp(BAY, nodename) == 0)
    736 		return (topo_add_bay(thp, node, (walk_diskmon_t *)arg)
    737 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
    738 
    739 	return (TOPO_WALK_NEXT);
    740 }
    741 
    742 
    743 /*ARGSUSED*/
    744 int
    745 update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp)
    746 {
    747 	int err;
    748 	topo_hdl_t *thp;
    749 	topo_walk_t *twp;
    750 	walk_diskmon_t wd;
    751 
    752 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
    753 		return (TOPO_OPEN_ERROR);
    754 	}
    755 
    756 	wd.target = diskp;
    757 	wd.pfmri = NULL;
    758 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg,
    759 	    &wd, &err)) == NULL) {
    760 		fmd_hdl_topo_rele(hdl, thp);
    761 		return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS);
    762 	}
    763 
    764 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
    765 
    766 		topo_walk_fini(twp);
    767 		if (wd.pfmri != NULL)
    768 			dstrfree(wd.pfmri);
    769 
    770 		fmd_hdl_topo_rele(hdl, thp);
    771 		return (TOPO_WALK_ERROR);
    772 	}
    773 
    774 	topo_walk_fini(twp);
    775 	fmd_hdl_topo_rele(hdl, thp);
    776 	if (wd.pfmri != NULL)
    777 		dstrfree(wd.pfmri);
    778 
    779 	return (TOPO_SUCCESS);
    780 }
    781 
    782 int
    783 init_configuration_from_topo(void)
    784 {
    785 	return (nvlist_alloc(&g_topo2diskmon, NV_UNIQUE_NAME, 0));
    786 }
    787 
    788 void
    789 fini_configuration_from_topo(void)
    790 {
    791 	if (g_topo2diskmon) {
    792 		nvlist_free(g_topo2diskmon);
    793 	}
    794 }
    795