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