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 
NONUNIQUE_NVLIST_FN(string,DATA_TYPE_STRING,char *)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 *
dm_fmri_to_diskmon(fmd_hdl_t * hdl,nvlist_t * fmri)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 *
find_disk_monitor_private_pgroup(tnode_t * node)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 *
fmri2ptr(topo_hdl_t * thp,tnode_t * node,char ** str,int * err)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
topo_add_disk(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)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
indicator_breakup(char * identifier,ind_state_t * state,char ** name)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
topoprop_indicator_add(indicator_t ** indp,char * ind_name,char * ind_action)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
str2dmstate(char * str)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
topoprop_indrule_add(indrule_t ** indrp,char * sts,char * acts)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
topo_add_bay(topo_hdl_t * thp,tnode_t * node,walk_diskmon_t * wdp)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 			nvlist_free(dmap_nvl);
711 			if (indp)
712 				ind_free(indp);
713 			if (indrp)
714 				indrule_free(indrp);
715 			nvlist_free(diskprops);
716 		}
717 
718 		wdp->pfmri = cstr;
719 	}
720 
721 
722 	return (0);
723 }
724 
725 /*ARGSUSED*/
726 static int
gather_topo_cfg(topo_hdl_t * thp,tnode_t * node,void * arg)727 gather_topo_cfg(topo_hdl_t *thp, tnode_t *node, void *arg)
728 {
729 	char *nodename = topo_node_name(node);
730 	if (strcmp(DISK, nodename) == 0)
731 		return (topo_add_disk(thp, node, (walk_diskmon_t *)arg)
732 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
733 	else if (strcmp(BAY, nodename) == 0)
734 		return (topo_add_bay(thp, node, (walk_diskmon_t *)arg)
735 		    ? TOPO_WALK_ERR : TOPO_WALK_NEXT);
736 
737 	return (TOPO_WALK_NEXT);
738 }
739 
740 
741 /*ARGSUSED*/
742 int
update_configuration_from_topo(fmd_hdl_t * hdl,diskmon_t * diskp)743 update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp)
744 {
745 	int err;
746 	topo_hdl_t *thp;
747 	topo_walk_t *twp;
748 	walk_diskmon_t wd;
749 
750 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
751 		return (TOPO_OPEN_ERROR);
752 	}
753 
754 	wd.target = diskp;
755 	wd.pfmri = NULL;
756 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg,
757 	    &wd, &err)) == NULL) {
758 		fmd_hdl_topo_rele(hdl, thp);
759 		return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS);
760 	}
761 
762 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
763 
764 		topo_walk_fini(twp);
765 		if (wd.pfmri != NULL)
766 			dstrfree(wd.pfmri);
767 
768 		fmd_hdl_topo_rele(hdl, thp);
769 		return (TOPO_WALK_ERROR);
770 	}
771 
772 	topo_walk_fini(twp);
773 	fmd_hdl_topo_rele(hdl, thp);
774 	if (wd.pfmri != NULL)
775 		dstrfree(wd.pfmri);
776 
777 	return (TOPO_SUCCESS);
778 }
779 
780 int
init_configuration_from_topo(void)781 init_configuration_from_topo(void)
782 {
783 	return (nvlist_alloc(&g_topo2diskmon, NV_UNIQUE_NAME, 0));
784 }
785 
786 void
fini_configuration_from_topo(void)787 fini_configuration_from_topo(void)
788 {
789 	if (g_topo2diskmon) {
790 		nvlist_free(g_topo2diskmon);
791 	}
792 }
793