xref: /titanic_44/usr/src/cmd/picl/plugins/sun4u/snowbird/frutree/piclfrutree.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * platform independent module to manage nodes under frutree
31  */
32 
33 /*
34  * This file has the frutree initialization code:
35  * 1) parse the config file to create all locations in the chassis
36  * 2) probe each location to find fru and probe the fru recursively to
37  *    create locations, port nodes
38  * 3) handle hotswap picl events (dr_ap_state_change, dr_req)
39  *    - update the frutree
40  *    - send out picl-state-change, picl-condition-events
41  * 4) Monitor the port nodes state and condition
42  */
43 
44 #include <stdlib.h>
45 #include <sys/param.h>
46 #include <strings.h>
47 #include <string.h>
48 #include <limits.h>
49 #include <syslog.h>
50 #include <pthread.h>
51 #include <thread.h>
52 #include <libintl.h>
53 #include <sys/systeminfo.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56 #include <sys/stat.h>
57 #include <dirent.h>
58 #include <fcntl.h>
59 #include <ctype.h>
60 #include <time.h>
61 #include <poll.h>
62 #include <assert.h>
63 #include <libnvpair.h>
64 #include <alloca.h>
65 #include <stdarg.h>
66 #include <config_admin.h>
67 #include <libdevinfo.h>
68 #include <synch.h>
69 #include <sys/time.h>
70 #include <picl.h>
71 #include <picltree.h>
72 #include <picldefs.h>
73 #include <picld_pluginutil.h>
74 #include <libfru.h>
75 #include <sys/sysevent/dr.h>
76 #include <ptree_impl.h>
77 #include "piclfrutree.h"
78 
79 #pragma	init(piclfrutree_register)
80 
81 /*
82  * following values are tunables that can be changed using
83  * environment variables
84  */
85 int frutree_debug = NONE;		/* debug switch */
86 static int frutree_poll_timeout = 5;	/* polling time to monitor ports */
87 static int frutree_drwait_time  = 10;	/* wait time for dr operation */
88 
89 #define	PICL_PROP_CONF_FILE	"conf_name"
90 #define	PICL_ADMINLOCK_DISABLED	"disabled"
91 #define	PICL_ADMINLOCK_ENABLED	"enabled"
92 #define	HASH_TABLE_SIZE		(64)
93 #define	BUF_SIZE		25
94 #define	HASH_INDEX(s, x)	((int)((x) & ((s) - 1)))
95 #define	FRUDATA_PTR(_X)	((frutree_frunode_t *)(((hashdata_t *)(_X))->data))
96 #define	LOCDATA_PTR(_X)	((frutree_locnode_t *)(((hashdata_t *)(_X))->data))
97 #define	PORTDATA_PTR(_X) ((frutree_portnode_t *)(((hashdata_t *)(_X))->data))
98 
99 /* Hash table structure */
100 typedef struct frutree_hash_elm {
101 	picl_nodehdl_t hdl;
102 	void *nodep;
103 	struct frutree_hash_elm	*nextp;
104 } frutree_hashelm_t;
105 
106 typedef struct {
107 	int hash_size;
108 	frutree_hashelm_t **tbl;
109 } frutree_hash_t;
110 
111 typedef struct {
112 	frutree_datatype_t type;
113 	void *data;
114 } hashdata_t;
115 
116 typedef int (*callback_t)(picl_nodehdl_t, void *);
117 typedef enum {
118 	INIT_FRU = 0x0,
119 	CREATE_DEVICES_ENTRIES,
120 	CONFIGURE_FRU,
121 	UNCONFIGURE_FRU,
122 	CPU_OFFLINE,
123 	CPU_ONLINE,
124 	HANDLE_CONFIGURE,
125 	HANDLE_UNCONFIGURE,
126 	HANDLE_INSERT,
127 	HANDLE_REMOVE,
128 	HANDLE_LOCSTATE_CHANGE,
129 	POST_COND_EVENT,
130 	POST_EVENTS
131 } action_t;
132 
133 typedef struct {
134 	action_t	action;
135 	void 		*data;
136 } frutree_dr_arg_t;
137 
138 typedef struct event_queue {
139 	frutree_dr_arg_t arg;
140 	struct event_queue *next;
141 }ev_queue_t;
142 
143 typedef struct {
144 	char node_name[PICL_PROPNAMELEN_MAX];
145 	picl_nodehdl_t retnodeh;
146 } frutree_callback_data_t;
147 
148 typedef struct remove_list {
149 	picl_nodehdl_t nodeh;
150 	struct remove_list *next;
151 } delete_list_t;
152 
153 typedef struct {
154 	frutree_frunode_t *frup;
155 	delete_list_t *first;
156 } frutree_init_callback_arg_t;
157 
158 boolean_t frutree_connects_initiated = B_FALSE;
159 static ev_queue_t *queue_head = NULL;
160 static ev_queue_t *queue_tail = NULL;
161 static pthread_mutex_t ev_mutex;
162 static pthread_cond_t ev_cond;
163 
164 static frutree_hash_t node_hash_table = {0, NULL};
165 static picl_nodehdl_t chassish = 0;
166 static picl_nodehdl_t frutreeh = 0;
167 static picl_nodehdl_t rooth = 0;
168 static picl_nodehdl_t platformh = 0;
169 static boolean_t post_picl_events = B_FALSE;
170 static int piclevent_pending = 0;
171 static char conf_file[MAXPATHLEN];
172 static char sys_name[SYS_NMLN];
173 
174 static mutex_t piclevent_mutex = DEFAULTMUTEX;
175 static cond_t piclevent_completed_cv = DEFAULTCV;
176 static rwlock_t	hash_lock;
177 
178 static pthread_t tid;
179 static void *dr_thread(void *);
180 
181 static pthread_t init_threadID;
182 static pthread_t monitor_tid;
183 static pthread_mutex_t monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
184 static pthread_cond_t monitor_cv = PTHREAD_COND_INITIALIZER;
185 static int fini_called = 0;
186 static void *monitor_node_status(void *);
187 static ev_queue_t *remove_from_queue(void);
188 static picl_errno_t handle_chassis_configure(frutree_frunode_t *frup);
189 
190 /*
191  * location states.
192  */
193 static char *loc_state[] = {
194 	PICLEVENTARGVAL_UNKNOWN,
195 	PICLEVENTARGVAL_EMPTY,
196 	PICLEVENTARGVAL_CONNECTED,
197 	PICLEVENTARGVAL_DISCONNECTED,
198 	PICLEVENTARGVAL_CONNECTING,
199 	PICLEVENTARGVAL_DISCONNECTING,
200 	NULL
201 };
202 
203 /*
204  * fru states.
205  */
206 static char *fru_state[] = {
207 	PICLEVENTARGVAL_UNKNOWN,
208 	PICLEVENTARGVAL_CONFIGURED,
209 	PICLEVENTARGVAL_UNCONFIGURED,
210 	PICLEVENTARGVAL_CONFIGURING,
211 	PICLEVENTARGVAL_UNCONFIGURING,
212 	NULL
213 };
214 
215 /*
216  * fru condition.
217  */
218 static char *fru_cond[] = {
219 	PICLEVENTARGVAL_UNKNOWN,
220 	PICLEVENTARGVAL_FAILED,
221 	PICLEVENTARGVAL_FAILING,
222 	PICLEVENTARGVAL_OK,
223 	PICLEVENTARGVAL_TESTING,
224 	NULL
225 };
226 
227 /*
228  * port states.
229  */
230 static char *port_state[] = {
231 	PICLEVENTARGVAL_DOWN,
232 	PICLEVENTARGVAL_UP,
233 	PICLEVENTARGVAL_UNKNOWN,
234 	NULL
235 };
236 
237 /*
238  * port condition.
239  */
240 static char *port_cond[] = {
241 	PICLEVENTARGVAL_OK,
242 	PICLEVENTARGVAL_FAILING,
243 	PICLEVENTARGVAL_FAILED,
244 	PICLEVENTARGVAL_TESTING,
245 	PICLEVENTARGVAL_UNKNOWN,
246 	NULL
247 };
248 
249 /* mapping between libcfgadm error codes to picl error codes */
250 static const int cfg2picl_errmap[][2] =  {
251 	{CFGA_OK, PICL_SUCCESS},
252 	{CFGA_NACK, PICL_NORESPONSE},
253 	{CFGA_NOTSUPP, PICL_NOTSUPPORTED},
254 	{CFGA_OPNOTSUPP, PICL_NOTSUPPORTED},
255 	{CFGA_PRIV, PICL_FAILURE},
256 	{CFGA_BUSY, PICL_TREEBUSY},
257 	{CFGA_SYSTEM_BUSY, PICL_TREEBUSY},
258 	{CFGA_DATA_ERROR, PICL_FAILURE},
259 	{CFGA_LIB_ERROR, PICL_FAILURE},
260 	{CFGA_NO_LIB, PICL_FAILURE},
261 	{CFGA_INSUFFICENT_CONDITION, PICL_FAILURE},
262 	{CFGA_INVAL, PICL_INVALIDARG},
263 	{CFGA_ERROR, PICL_FAILURE},
264 	{CFGA_APID_NOEXIST, PICL_NODENOTFOUND},
265 	{CFGA_ATTR_INVAL, PICL_INVALIDARG}
266 };
267 
268 /* local functions */
269 static void piclfrutree_register(void);
270 static void piclfrutree_init(void);
271 static void piclfrutree_fini(void);
272 static void * init_thread(void *);
273 static void frutree_wd_evhandler(const char *, const void *, size_t, void *);
274 static void frutree_dr_apstate_change_evhandler(const char *, const void *,
275 		size_t, void *);
276 static void frutree_dr_req_evhandler(const char *, const void *,
277 		size_t, void *);
278 static void frutree_cpu_state_change_evhandler(const char *, const void *,
279 		size_t, void *);
280 static void init_queue(void);
281 static void frutree_get_env();
282 static picl_errno_t hash_init(void);
283 static picl_errno_t hash_remove_entry(picl_nodehdl_t);
284 static picl_errno_t hash_lookup_entry(picl_nodehdl_t, void **);
285 static void hash_destroy();
286 static picl_errno_t initialize_frutree();
287 static picl_errno_t update_loc_state(frutree_locnode_t *, boolean_t *);
288 static int is_autoconfig_enabled(char *);
289 static picl_errno_t do_action(picl_nodehdl_t, int action, void *);
290 static picl_errno_t probe_fru(frutree_frunode_t *, boolean_t);
291 static picl_errno_t handle_fru_unconfigure(frutree_frunode_t *);
292 static picl_errno_t update_loc_state(frutree_locnode_t *, boolean_t *);
293 static picl_errno_t update_fru_state(frutree_frunode_t *, boolean_t *);
294 static picl_errno_t update_port_state(frutree_portnode_t *, boolean_t);
295 static picl_errno_t configure_fru(frutree_frunode_t *, cfga_flags_t);
296 static picl_errno_t post_piclevent(const char *, char *, char *,
297 			picl_nodehdl_t, frutree_wait_t);
298 static picl_errno_t fru_init(frutree_frunode_t *);
299 
300 /* External functions */
301 extern boolean_t is_fru_present_under_location(frutree_locnode_t *);
302 extern int kstat_port_state(frutree_port_type_t, char *, int);
303 extern int kstat_port_cond(frutree_port_type_t, char *, int);
304 extern picl_errno_t probe_libdevinfo(frutree_frunode_t *,
305 		frutree_device_args_t **, boolean_t);
306 extern picl_errno_t get_scsislot_name(char *, char *, char *);
307 extern picl_errno_t probe_for_scsi_frus(frutree_frunode_t *);
308 extern picl_errno_t get_fru_path(char *, frutree_frunode_t *);
309 extern picl_errno_t scsi_info_init();
310 extern void scsi_info_fini();
311 extern picl_errno_t get_port_info(frutree_portnode_t *);
312 extern char *strtok_r(char *s1, const char *s2, char **lasts);
313 
314 /* Plugin initialization */
315 static picld_plugin_reg_t frutree_reg_info = {
316 	PICLD_PLUGIN_VERSION_1,
317 	PICLD_PLUGIN_CRITICAL,
318 	"SUNW_piclfrutree",
319 	piclfrutree_init,
320 	piclfrutree_fini
321 };
322 
323 /* ptree entry points */
324 static void
piclfrutree_register(void)325 piclfrutree_register(void)
326 {
327 	FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree register");
328 	(void) picld_plugin_register(&frutree_reg_info);
329 }
330 
331 static void
piclfrutree_init(void)332 piclfrutree_init(void)
333 {
334 	FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree_init begin");
335 	(void) rwlock_init(&hash_lock, USYNC_THREAD, NULL);
336 	fini_called = 0;
337 
338 	/* read the environment variables */
339 	frutree_get_env();
340 
341 	if (sysinfo(SI_PLATFORM, sys_name, sizeof (sys_name)) == -1) {
342 		return;
343 	}
344 
345 	if (hash_init() != PICL_SUCCESS) {
346 		return;
347 	}
348 	if (initialize_frutree() != PICL_SUCCESS) {
349 		return;
350 	}
351 
352 	/* initialize the event queue */
353 	(void) init_queue();
354 
355 	(void) pthread_cond_init(&ev_cond, NULL);
356 	(void) pthread_mutex_init(&ev_mutex, NULL);
357 	if (pthread_create(&tid, NULL, &dr_thread, NULL) != 0) {
358 		return;
359 	}
360 	/* register for picl events */
361 	if (ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
362 		frutree_dr_apstate_change_evhandler, NULL) !=
363 		PICL_SUCCESS) {
364 		return;
365 	}
366 
367 	if (ptree_register_handler(PICLEVENT_DR_REQ,
368 		frutree_dr_req_evhandler, NULL) != PICL_SUCCESS) {
369 		return;
370 	}
371 
372 	if (ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE,
373 		frutree_cpu_state_change_evhandler, NULL) !=
374 		PICL_SUCCESS) {
375 		return;
376 	}
377 
378 	if (ptree_register_handler(PICLEVENT_STATE_CHANGE,
379 		frutree_wd_evhandler, NULL) != PICL_SUCCESS) {
380 		return;
381 	}
382 	FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree_init end");
383 }
384 
385 static void
piclfrutree_fini(void)386 piclfrutree_fini(void)
387 {
388 	ev_queue_t	*event = NULL;
389 	void		*exitval;
390 
391 	FRUTREE_DEBUG0(EVENTS, "piclfrutree_fini begin");
392 
393 	fini_called = 1;
394 	/* unregister event handlers */
395 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
396 		frutree_dr_apstate_change_evhandler, NULL);
397 	(void) ptree_unregister_handler(PICLEVENT_DR_REQ,
398 		frutree_dr_req_evhandler, NULL);
399 	(void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE,
400 		frutree_cpu_state_change_evhandler, NULL);
401 	(void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE,
402 		frutree_wd_evhandler, NULL);
403 
404 	/* flush the event queue */
405 	(void) pthread_mutex_lock(&ev_mutex);
406 	event = remove_from_queue();
407 	while (event) {
408 		free(event);
409 		event = remove_from_queue();
410 	}
411 	queue_head = queue_tail = NULL;
412 
413 	(void) pthread_cond_broadcast(&ev_cond);
414 	(void) pthread_mutex_unlock(&ev_mutex);
415 	(void) pthread_cancel(tid);
416 	(void) pthread_join(tid, &exitval);
417 	(void) pthread_cancel(monitor_tid);
418 	(void) pthread_join(monitor_tid, &exitval);
419 	(void) pthread_cancel(init_threadID);
420 	(void) pthread_join(init_threadID, &exitval);
421 
422 	hash_destroy();
423 	(void) ptree_delete_node(frutreeh);
424 	(void) ptree_destroy_node(frutreeh);
425 
426 	frutree_connects_initiated = B_FALSE;
427 	chassish = frutreeh = rooth = platformh = 0;
428 	post_picl_events = B_FALSE;
429 	piclevent_pending = 0;
430 	FRUTREE_DEBUG0(EVENTS, "piclfrutree_fini end");
431 }
432 
433 /* read the ENVIRONMENT variables and initialize tunables */
434 static void
frutree_get_env()435 frutree_get_env()
436 {
437 	char *val;
438 	int intval = 0;
439 
440 	/* read frutree debug flag value */
441 	if (val = getenv(FRUTREE_DEBUG)) {
442 		errno = 0;
443 		intval = strtol(val, (char **)NULL, 0);
444 		if (errno == 0) {
445 			frutree_debug = intval;
446 			FRUTREE_DEBUG1(PRINT_ALL, "SUNW_frutree:debug = %x",
447 				frutree_debug);
448 		}
449 	}
450 
451 	/* read poll timeout value */
452 	if (val = getenv(FRUTREE_POLL_TIMEOUT)) {
453 		errno = 0;
454 		intval = strtol(val, (char **)NULL, 0);
455 		if (errno == 0) {
456 			frutree_poll_timeout = intval;
457 		}
458 	}
459 
460 	/* read drwait time value */
461 	if (val = getenv(FRUTREE_DRWAIT)) {
462 		errno = 0;
463 		intval = strtol(val, (char **)NULL, 0);
464 		if (errno == 0) {
465 			frutree_drwait_time = intval;
466 		}
467 	}
468 }
469 
470 /*
471  * callback function for ptree_walk_tree_class to get the
472  * node handle of node
473  * matches a node with same class and name
474  */
475 static int
frutree_get_nodehdl(picl_nodehdl_t nodeh,void * c_args)476 frutree_get_nodehdl(picl_nodehdl_t nodeh, void *c_args)
477 {
478 	picl_errno_t rc;
479 	char name[PICL_PROPNAMELEN_MAX];
480 	frutree_callback_data_t *fru_arg;
481 
482 	if (c_args == NULL)
483 		return (PICL_INVALIDARG);
484 	fru_arg = (frutree_callback_data_t *)c_args;
485 
486 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
487 		sizeof (name))) != PICL_SUCCESS) {
488 		return (rc);
489 	}
490 
491 	if (strcmp(fru_arg->node_name, name) == 0) {
492 		fru_arg->retnodeh = nodeh;
493 		return (PICL_WALK_TERMINATE);
494 	}
495 	return (PICL_WALK_CONTINUE);
496 }
497 
498 /* queue implementation (used to  queue hotswap events) */
499 static void
init_queue(void)500 init_queue(void)
501 {
502 	queue_head = NULL;
503 	queue_tail = NULL;
504 }
505 
506 /* add an event to the queue */
507 static int
add_to_queue(frutree_dr_arg_t dr_data)508 add_to_queue(frutree_dr_arg_t  dr_data)
509 {
510 	ev_queue_t	*new_event;
511 
512 	new_event = (ev_queue_t *)malloc(sizeof (ev_queue_t));
513 	if (new_event == NULL)
514 		return (PICL_NOSPACE);
515 
516 	new_event->arg.action = dr_data.action;
517 	new_event->arg.data = dr_data.data;
518 	new_event->next = NULL;
519 
520 	if (queue_head == NULL) {
521 		queue_head = new_event;
522 	} else {
523 		queue_tail->next = new_event;
524 	}
525 	queue_tail = new_event;
526 
527 	return (PICL_SUCCESS);
528 }
529 
530 static ev_queue_t *
remove_from_queue(void)531 remove_from_queue(void)
532 {
533 	ev_queue_t	*event = NULL;
534 
535 	if (queue_head == NULL)
536 		return (NULL);
537 
538 	event = queue_head;
539 	queue_head = queue_head->next;
540 
541 	if (queue_head == NULL)
542 		queue_tail = NULL;
543 	return (event);
544 }
545 
546 /*
547  * event handler for watchdog expiry event (picl-state-change) event on
548  * watchdog-timer node
549  */
550 /* ARGSUSED */
551 static void
frutree_wd_evhandler(const char * ename,const void * earg,size_t size,void * cookie)552 frutree_wd_evhandler(const char	*ename, const void *earg, size_t size,
553 	void *cookie)
554 {
555 	nvlist_t *nvlp;
556 	char *wd_state = NULL;
557 	picl_errno_t rc;
558 	picl_nodehdl_t wd_nodehdl;
559 	char value[PICL_PROPNAMELEN_MAX];
560 	frutree_callback_data_t fru_arg;
561 
562 	if (ename == NULL)
563 		return;
564 
565 	if (strncmp(ename, PICLEVENT_STATE_CHANGE,
566 		strlen(PICLEVENT_STATE_CHANGE))) {
567 		return;
568 	}
569 
570 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
571 		return;
572 	}
573 
574 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE,
575 		&wd_nodehdl) == -1) {
576 		nvlist_free(nvlp);
577 		return;
578 	}
579 
580 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_STATE,
581 		&wd_state) != 0) {
582 		nvlist_free(nvlp);
583 		return;
584 	}
585 
586 	if ((rc = ptree_get_propval_by_name(wd_nodehdl,
587 		PICL_PROP_CLASSNAME, value, sizeof (value))) != PICL_SUCCESS) {
588 		nvlist_free(nvlp);
589 		return;
590 	}
591 
592 	/* if the event is not of watchdog-timer, return */
593 	if (strcmp(value, PICL_CLASS_WATCHDOG_TIMER) != 0) {
594 		nvlist_free(nvlp);
595 		return;
596 	}
597 
598 	FRUTREE_DEBUG1(EVENTS, "frutree:Received WD event(%s)", wd_state);
599 	/* frutree plugin handles only watchdog expiry events */
600 	if (strcmp(wd_state, PICL_PROPVAL_WD_STATE_EXPIRED) != 0) {
601 		nvlist_free(nvlp);
602 		return;
603 	}
604 
605 	if ((rc = ptree_get_propval_by_name(wd_nodehdl,
606 		PICL_PROP_WATCHDOG_ACTION, value, sizeof (value))) !=
607 		PICL_SUCCESS) {
608 		nvlist_free(nvlp);
609 		return;
610 	}
611 
612 	/* if action is none, dont do anything */
613 	if (strcmp(value, PICL_PROPVAL_WD_ACTION_NONE) == 0) {
614 		nvlist_free(nvlp);
615 		return;
616 	}
617 
618 	/* find the CPU nodehdl */
619 	(void) strncpy(fru_arg.node_name, SANIBEL_PICLNODE_CPU,
620 		sizeof (fru_arg.node_name));
621 	fru_arg.retnodeh = 0;
622 	if ((rc = ptree_walk_tree_by_class(chassish, PICL_CLASS_FRU,
623 		&fru_arg, frutree_get_nodehdl)) != PICL_SUCCESS) {
624 		nvlist_free(nvlp);
625 		return;
626 	}
627 
628 	if (fru_arg.retnodeh == NULL) {
629 		nvlist_free(nvlp);
630 		return;
631 	}
632 
633 	if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
634 		PICLEVENTARGVAL_FAILED, NULL, fru_arg.retnodeh,
635 		NO_WAIT)) != PICL_SUCCESS) {
636 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
637 			SANIBEL_PICLNODE_CPU, PICLEVENT_CONDITION_CHANGE, rc);
638 	}
639 	nvlist_free(nvlp);
640 }
641 
642 /*
643  * event handler for dr_ap_state_change event
644  * - determine the event type and queue it in dr_queue to handle it
645  */
646 /* ARGSUSED */
647 static void
frutree_dr_apstate_change_evhandler(const char * ename,const void * earg,size_t size,void * cookie)648 frutree_dr_apstate_change_evhandler(const char *ename, const void *earg,
649 	size_t size, void *cookie)
650 {
651 	nvlist_t *nvlp;
652 	char *name = NULL;
653 	char *ap_id = NULL;
654 	char *hint = NULL;
655 	picl_nodehdl_t	nodeh, childh;
656 	hashdata_t *hashptr = NULL;
657 	frutree_dr_arg_t dr_arg;
658 	frutree_frunode_t *frup = NULL;
659 	frutree_locnode_t *locp = NULL;
660 	frutree_callback_data_t fru_arg;
661 	boolean_t state_changed = B_FALSE;
662 
663 	if (ename == NULL)
664 		return;
665 
666 	if (strncmp(ename, PICLEVENT_DR_AP_STATE_CHANGE,
667 		strlen(PICLEVENT_DR_AP_STATE_CHANGE)) != 0) {
668 		return;
669 	}
670 
671 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
672 		return;
673 	}
674 
675 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id) == -1) {
676 		nvlist_free(nvlp);
677 		return;
678 	}
679 
680 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint) == -1) {
681 		nvlist_free(nvlp);
682 		return;
683 	}
684 
685 	/* check for empty strings */
686 	if (!ap_id || !hint) {
687 		FRUTREE_DEBUG0(EVENTS, "Empty hint/ap_id");
688 		nvlist_free(nvlp);
689 		return;
690 	}
691 
692 	/* get the location name */
693 	name = strrchr(ap_id, ':');
694 	if (name == NULL) {
695 		name = ap_id;
696 	} else {
697 		name++;
698 	}
699 
700 	/* find the loc object */
701 	(void) strncpy(fru_arg.node_name, name, sizeof (fru_arg.node_name));
702 	fru_arg.retnodeh = 0;
703 	if (ptree_walk_tree_by_class(chassish, PICL_CLASS_LOCATION,
704 		&fru_arg, frutree_get_nodehdl) != PICL_SUCCESS) {
705 		nvlist_free(nvlp);
706 		return;
707 	}
708 
709 	if (fru_arg.retnodeh == NULL) {
710 		nvlist_free(nvlp);
711 		return;
712 	}
713 	nodeh = fru_arg.retnodeh;
714 
715 	if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
716 		nvlist_free(nvlp);
717 		return;
718 	}
719 	locp = LOCDATA_PTR(hashptr);
720 	if (locp == NULL) {
721 		nvlist_free(nvlp);
722 		return;
723 	}
724 
725 	if (strcmp(hint, DR_HINT_INSERT) == 0) {
726 		dr_arg.action = HANDLE_INSERT;
727 		dr_arg.data   = locp;
728 		(void) pthread_mutex_lock(&ev_mutex);
729 		if (add_to_queue(dr_arg) != PICL_SUCCESS) {
730 			(void) pthread_mutex_unlock(&ev_mutex);
731 			nvlist_free(nvlp);
732 			return;
733 		}
734 		(void) pthread_cond_signal(&ev_cond);
735 		(void) pthread_mutex_unlock(&ev_mutex);
736 		nvlist_free(nvlp);
737 		return;
738 	}
739 
740 	if (strcmp(hint, DR_HINT_REMOVE) == 0) {
741 		dr_arg.action = HANDLE_REMOVE;
742 		dr_arg.data = locp;
743 		(void) pthread_mutex_lock(&ev_mutex);
744 		if (add_to_queue(dr_arg) != PICL_SUCCESS) {
745 			(void) pthread_mutex_unlock(&ev_mutex);
746 			nvlist_free(nvlp);
747 			return;
748 		}
749 		(void) pthread_cond_signal(&ev_cond);
750 		(void) pthread_mutex_unlock(&ev_mutex);
751 		nvlist_free(nvlp);
752 		return;
753 	}
754 
755 	if (strcmp(hint, DR_RESERVED_ATTR) != 0) {	/* unknown event */
756 		nvlist_free(nvlp);
757 		return;
758 	}
759 
760 	/* handle DR_RESERVED_ATTR HINT */
761 	/* check if this is a fru event */
762 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
763 		&childh, sizeof (childh)) == PICL_SUCCESS) {
764 		/* get the child fru information */
765 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
766 			PICL_SUCCESS) {
767 			frup = FRUDATA_PTR(hashptr);
768 		}
769 	}
770 	if (frup == NULL) {
771 		nvlist_free(nvlp);
772 		return;
773 	}
774 
775 	(void) pthread_mutex_lock(&frup->mutex);
776 	if (frup->dr_in_progress) {
777 		/* dr in progress, neglect the event */
778 		(void) pthread_mutex_unlock(&frup->mutex);
779 		nvlist_free(nvlp);
780 		return;
781 	}
782 	(void) pthread_mutex_unlock(&frup->mutex);
783 
784 	if (update_fru_state(frup, &state_changed) != PICL_SUCCESS) {
785 		nvlist_free(nvlp);
786 		return;
787 	}
788 
789 	if (state_changed) {
790 		(void) pthread_mutex_lock(&frup->mutex);
791 		/* figure out if this is config/unconfig operation */
792 		if (frup->state == FRU_STATE_CONFIGURED) {
793 			dr_arg.action = HANDLE_CONFIGURE;
794 			dr_arg.data = frup;
795 		} else if (frup->state == FRU_STATE_UNCONFIGURED) {
796 			dr_arg.action = HANDLE_UNCONFIGURE;
797 			dr_arg.data = frup;
798 		}
799 		(void) pthread_mutex_unlock(&frup->mutex);
800 
801 		(void) pthread_mutex_lock(&ev_mutex);
802 		if (add_to_queue(dr_arg) != PICL_SUCCESS) {
803 			(void) pthread_mutex_unlock(&ev_mutex);
804 			nvlist_free(nvlp);
805 			return;
806 		}
807 		(void) pthread_cond_signal(&ev_cond);
808 		(void) pthread_mutex_unlock(&ev_mutex);
809 		nvlist_free(nvlp);
810 		return;
811 	}
812 
813 	/* check if this event is related to location */
814 	(void) pthread_mutex_lock(&locp->mutex);
815 	if (locp->dr_in_progress) {
816 		/* dr in progress, neglect the event */
817 		(void) pthread_mutex_unlock(&locp->mutex);
818 		nvlist_free(nvlp);
819 		return;
820 	}
821 	(void) pthread_mutex_unlock(&locp->mutex);
822 	if (update_loc_state(locp, &state_changed) != PICL_SUCCESS) {
823 		nvlist_free(nvlp);
824 		return;
825 	}
826 
827 	if (state_changed) {	/* location state has changed */
828 		dr_arg.action = HANDLE_LOCSTATE_CHANGE;
829 		dr_arg.data  = locp;
830 
831 		(void) pthread_mutex_lock(&ev_mutex);
832 		if (add_to_queue(dr_arg) != PICL_SUCCESS) {
833 			(void) pthread_mutex_unlock(&ev_mutex);
834 			nvlist_free(nvlp);
835 			return;
836 		}
837 		(void) pthread_cond_signal(&ev_cond);
838 		(void) pthread_mutex_unlock(&ev_mutex);
839 		nvlist_free(nvlp);
840 		return;
841 	}
842 	/* duplicate event */
843 	nvlist_free(nvlp);
844 }
845 
846 /*
847  * Event handler for dr_req event
848  */
849 /* ARGSUSED */
850 static void
frutree_dr_req_evhandler(const char * ename,const void * earg,size_t size,void * cookie)851 frutree_dr_req_evhandler(const char *ename, const void *earg, size_t size,
852 	void *cookie)
853 {
854 	nvlist_t *nvlp;
855 	char *name = NULL;
856 	char *ap_id = NULL;
857 	char *dr_req = NULL;
858 	picl_nodehdl_t nodeh;
859 	frutree_dr_arg_t dr_arg;
860 	hashdata_t *hashptr = NULL;
861 	frutree_frunode_t *frup = NULL;
862 	frutree_callback_data_t fru_arg;
863 
864 	if (ename == NULL)
865 		return;
866 
867 	if (strncmp(ename, PICLEVENT_DR_REQ, strlen(PICLEVENT_DR_REQ)) != 0) {
868 		return;
869 	}
870 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
871 		return;
872 	}
873 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id) == -1) {
874 		nvlist_free(nvlp);
875 		return;
876 	}
877 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DR_REQ_TYPE,
878 		&dr_req) == -1) {
879 		nvlist_free(nvlp);
880 		return;
881 	}
882 
883 	if (!ap_id || !dr_req) {
884 		FRUTREE_DEBUG0(EVENTS, "Empty dr_req/ap_id");
885 		nvlist_free(nvlp);
886 		return;
887 	}
888 
889 	/* get the location name */
890 	name = strrchr(ap_id, ':');
891 	if (name == NULL) {
892 		name = ap_id;
893 	} else {
894 		name++;
895 	}
896 
897 	if (name == NULL) {
898 		nvlist_free(nvlp);
899 		return;
900 	}
901 
902 	FRUTREE_DEBUG2(EVENTS, "DR_REQ:%s on %s", dr_req, name);
903 	(void) strncpy(fru_arg.node_name, name, sizeof (fru_arg.node_name));
904 	fru_arg.retnodeh = 0;
905 	if (ptree_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
906 		&fru_arg, frutree_get_nodehdl) != PICL_SUCCESS) {
907 		nvlist_free(nvlp);
908 		return;
909 	}
910 
911 	if (fru_arg.retnodeh == NULL) {
912 		nvlist_free(nvlp);
913 		return;
914 	}
915 	nodeh = fru_arg.retnodeh;
916 
917 	/* find the fru object */
918 	if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
919 		nvlist_free(nvlp);
920 		return;
921 	}
922 	frup = FRUDATA_PTR(hashptr);
923 	if (frup == NULL) {
924 		nvlist_free(nvlp);
925 		return;
926 	}
927 
928 	if (strcmp(dr_req, DR_REQ_INCOMING_RES) == 0) {
929 		dr_arg.action = CONFIGURE_FRU;
930 		dr_arg.data = frup;
931 
932 	} else if (strcmp(dr_req, DR_REQ_OUTGOING_RES) == 0) {
933 		dr_arg.action = UNCONFIGURE_FRU;
934 		dr_arg.data = frup;
935 
936 	} else {
937 		nvlist_free(nvlp);
938 		return;
939 	}
940 
941 	(void) pthread_mutex_lock(&ev_mutex);
942 	if (add_to_queue(dr_arg) != PICL_SUCCESS) {
943 		(void) pthread_mutex_unlock(&ev_mutex);
944 		nvlist_free(nvlp);
945 		return;
946 	}
947 	(void) pthread_cond_signal(&ev_cond);
948 	(void) pthread_mutex_unlock(&ev_mutex);
949 	nvlist_free(nvlp);
950 }
951 
952 /*
953  * Event handler for cpu_state_change event
954  */
955 /* ARGSUSED */
956 static void
frutree_cpu_state_change_evhandler(const char * ename,const void * earg,size_t size,void * cookie)957 frutree_cpu_state_change_evhandler(const char *ename, const void *earg,
958 	size_t size, void *cookie)
959 {
960 	char		*hint = NULL;
961 	nvlist_t	*nvlp;
962 	frutree_frunode_t	*frup = NULL;
963 	hashdata_t	*hashptr = NULL;
964 	picl_nodehdl_t	nodeh;
965 	frutree_dr_arg_t dr_arg;
966 
967 	if (ename == NULL)
968 		return;
969 
970 	if (strncmp(ename, PICLEVENT_CPU_STATE_CHANGE,
971 		strlen(PICLEVENT_CPU_STATE_CHANGE)) != 0) {
972 		return;
973 	}
974 
975 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
976 		return;
977 	}
978 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) {
979 		nvlist_free(nvlp);
980 		return;
981 	}
982 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_CPU_EV_TYPE, &hint) == -1) {
983 		nvlist_free(nvlp);
984 		return;
985 	}
986 
987 	if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
988 		nvlist_free(nvlp);
989 		return;
990 	}
991 	frup = FRUDATA_PTR(hashptr);
992 	if (frup == NULL) {
993 		nvlist_free(nvlp);
994 		return;
995 	}
996 
997 	if (strcmp(hint, PICLEVENTARGVAL_OFFLINE) == 0) {
998 		dr_arg.action = CPU_OFFLINE;
999 		dr_arg.data = frup;
1000 	} else if (strcmp(hint, PICLEVENTARGVAL_ONLINE) == 0) {
1001 		dr_arg.action = CPU_ONLINE;
1002 		dr_arg.data = frup;
1003 	} else {
1004 		nvlist_free(nvlp);
1005 		return;
1006 	}
1007 
1008 	(void) pthread_mutex_lock(&ev_mutex);
1009 	if (add_to_queue(dr_arg) != PICL_SUCCESS) {
1010 		(void) pthread_mutex_unlock(&ev_mutex);
1011 		nvlist_free(nvlp);
1012 		return;
1013 	}
1014 	(void) pthread_cond_signal(&ev_cond);
1015 	(void) pthread_mutex_unlock(&ev_mutex);
1016 	nvlist_free(nvlp);
1017 }
1018 
1019 static void
attach_driver(char * driver)1020 attach_driver(char *driver)
1021 {
1022 	char	cmd[BUF_SIZE];
1023 	cmd[0] = '\0';
1024 	(void) snprintf(cmd, sizeof (cmd), "%s %s",
1025 		DEVFSADM_CMD, driver);
1026 	(void) pclose(popen(cmd, "r"));
1027 }
1028 
1029 /*
1030  * Find the node in platform tree with given devfs-path.
1031  * ptree_find_node is getting a node with devfs-path /pci@1f,0/pci@1,1
1032  * when we want to find node with /pci@1f,0/pci@1. The fix
1033  * is required in libpicltree. For now use ptree_walk_tree_by_class
1034  * to find the node.
1035  */
1036 static int
find_ref_parent(picl_nodehdl_t nodeh,void * c_args)1037 find_ref_parent(picl_nodehdl_t nodeh, void *c_args)
1038 {
1039 	picl_prophdl_t		proph;
1040 	ptree_propinfo_t	propinfo;
1041 	void			*vbuf;
1042 	frutree_callback_data_t *fru_arg;
1043 
1044 	if (c_args ==  NULL)
1045 		return (PICL_INVALIDARG);
1046 	fru_arg = (frutree_callback_data_t *)c_args;
1047 
1048 	if (ptree_get_prop_by_name(nodeh, PICL_PROP_DEVFS_PATH,
1049 		&proph) != PICL_SUCCESS) {
1050 		return (PICL_WALK_CONTINUE);
1051 	}
1052 
1053 	if (ptree_get_propinfo(proph, &propinfo) != PICL_SUCCESS) {
1054 		return (PICL_WALK_CONTINUE);
1055 	}
1056 
1057 	vbuf = alloca(propinfo.piclinfo.size);
1058 	if (vbuf == NULL)
1059 		return (PICL_WALK_CONTINUE);
1060 
1061 	if (ptree_get_propval(proph, vbuf,
1062 		propinfo.piclinfo.size) != PICL_SUCCESS) {
1063 		return (PICL_WALK_CONTINUE);
1064 	}
1065 
1066 	/* compare the devfs_path */
1067 	if (strcmp(fru_arg->node_name, (char *)vbuf) == 0) {
1068 		fru_arg->retnodeh = nodeh;
1069 		return (PICL_WALK_TERMINATE);
1070 	}
1071 	return (PICL_WALK_CONTINUE);
1072 }
1073 /*
1074  * Find the reference node in /platform tree
1075  * return : 0  - if node is not found
1076  */
1077 static picl_nodehdl_t
get_reference_handle(picl_nodehdl_t nodeh)1078 get_reference_handle(picl_nodehdl_t nodeh)
1079 {
1080 	picl_prophdl_t		proph;
1081 	ptree_propinfo_t	propinfo;
1082 	void			*vbuf;
1083 	picl_errno_t		rc = PICL_SUCCESS;
1084 	char			devfs_path[PICL_PROPNAMELEN_MAX];
1085 	char			value[PICL_PROPNAMELEN_MAX];
1086 	char			class[PICL_PROPNAMELEN_MAX];
1087 	frutree_callback_data_t fru_arg;
1088 	picl_nodehdl_t refhdl = 0, ref_parent = 0, nodehdl = 0;
1089 
1090 	/*
1091 	 * for fru node, get the devfspath and bus-addr of
1092 	 * its parent.
1093 	 */
1094 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
1095 		class, sizeof (class)) != PICL_SUCCESS) {
1096 		return (0);
1097 	}
1098 
1099 	if (strcmp(class, PICL_CLASS_FRU) == 0) {
1100 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
1101 			&nodehdl, sizeof (nodehdl)) != PICL_SUCCESS) {
1102 			return (0);
1103 		}
1104 	} else if (strcmp(class, PICL_CLASS_PORT) == 0) {
1105 		nodehdl = nodeh;
1106 	} else {
1107 		return (0);
1108 	}
1109 
1110 	if (ptree_get_propval_by_name(nodehdl, PICL_PROP_DEVFS_PATH,
1111 		devfs_path, sizeof (devfs_path)) != PICL_SUCCESS) {
1112 		return (0);
1113 	}
1114 	if (ptree_get_propval_by_name(nodehdl, PICL_PROP_BUS_ADDR,
1115 		value, sizeof (value)) != PICL_SUCCESS) {
1116 		return (0);
1117 	}
1118 
1119 	/* find the node with same devfs-path */
1120 	(void) strncpy(fru_arg.node_name, devfs_path,
1121 		sizeof (fru_arg.node_name));
1122 	fru_arg.retnodeh = 0;
1123 	if (ptree_walk_tree_by_class(platformh, NULL,
1124 		(void *)&fru_arg, find_ref_parent) != PICL_SUCCESS) {
1125 		return (0);
1126 	}
1127 
1128 	if (fru_arg.retnodeh == NULL)
1129 		return (0);
1130 
1131 	ref_parent = fru_arg.retnodeh;
1132 	/* traverse thru childeren and find the reference node */
1133 	rc = ptree_get_propval_by_name(ref_parent, PICL_PROP_CHILD,
1134 		&refhdl, sizeof (picl_nodehdl_t));
1135 	while (rc == PICL_SUCCESS) {
1136 		nodehdl = refhdl;
1137 		rc = ptree_get_propval_by_name(refhdl, PICL_PROP_PEER,
1138 			&refhdl, sizeof (picl_nodehdl_t));
1139 		/*
1140 		 * compare the bus_addr or Unit address
1141 		 * format of bus_addr can be either (1,3 or 0x6)
1142 		 */
1143 		if (ptree_get_prop_by_name(nodehdl, PICL_PROP_BUS_ADDR,
1144 			&proph) != PICL_SUCCESS) {
1145 			if (ptree_get_prop_by_name(nodehdl,
1146 				PICL_PROP_UNIT_ADDRESS, &proph) !=
1147 				PICL_SUCCESS) {
1148 				continue;
1149 			}
1150 		}
1151 
1152 		if (ptree_get_propinfo(proph, &propinfo) != PICL_SUCCESS) {
1153 			continue;
1154 		}
1155 
1156 		vbuf = alloca(propinfo.piclinfo.size);
1157 		if (vbuf == NULL)
1158 			continue;
1159 
1160 		if (ptree_get_propval(proph, vbuf,
1161 			propinfo.piclinfo.size) != PICL_SUCCESS) {
1162 			continue;
1163 		}
1164 
1165 		if (strchr((char *)vbuf, ',') != NULL) {
1166 			if (strcmp(value, (char *)vbuf) == 0) {
1167 				return (nodehdl);
1168 			}
1169 		} else {
1170 			if (strtoul((char *)vbuf, NULL, 16) ==
1171 				strtoul(value, NULL, 16)) {
1172 				return (nodehdl);
1173 			}
1174 		}
1175 	}
1176 	return (0);
1177 }
1178 
1179 /* Hash Table Management */
1180 static void
free_data(frutree_datatype_t type,hashdata_t * datap)1181 free_data(frutree_datatype_t type, hashdata_t *datap)
1182 {
1183 	frutree_frunode_t *frup = NULL;
1184 	frutree_locnode_t *locp = NULL;
1185 	frutree_portnode_t *portp = NULL;
1186 
1187 	if (datap == NULL) {
1188 		return;
1189 	}
1190 
1191 	switch (type) {
1192 	case FRU_TYPE:
1193 		frup = (frutree_frunode_t *)datap->data;
1194 		free(frup->name);
1195 		(void) pthread_mutex_destroy(&frup->mutex);
1196 		(void) pthread_cond_destroy(&frup->cond_cv);
1197 		(void) pthread_cond_destroy(&frup->busy_cond_cv);
1198 		free(frup);
1199 		break;
1200 	case LOC_TYPE:
1201 		locp = (frutree_locnode_t *)datap->data;
1202 		free(locp->name);
1203 		(void) pthread_mutex_destroy(&locp->mutex);
1204 		(void) pthread_cond_destroy(&locp->cond_cv);
1205 		free(locp);
1206 		break;
1207 	case PORT_TYPE:
1208 		portp = (frutree_portnode_t *)datap->data;
1209 		free(portp->name);
1210 		free(portp);
1211 		break;
1212 	}
1213 	free(datap);
1214 }
1215 
1216 /*
1217  * Initialize the hash table
1218  */
1219 static picl_errno_t
hash_init(void)1220 hash_init(void)
1221 {
1222 	int	i;
1223 
1224 	FRUTREE_DEBUG0(HASHTABLE, "hash_init begin");
1225 	node_hash_table.tbl = (frutree_hashelm_t **)malloc(
1226 		sizeof (frutree_hashelm_t *) * HASH_TABLE_SIZE);
1227 
1228 	if (node_hash_table.tbl == NULL) {
1229 		return (PICL_NOSPACE);
1230 	}
1231 
1232 	/* initialize each entry in hashtable */
1233 	node_hash_table.hash_size = HASH_TABLE_SIZE;
1234 	for (i = 0; i < node_hash_table.hash_size; ++i) {
1235 		node_hash_table.tbl[i] = NULL;
1236 	}
1237 	return (PICL_SUCCESS);
1238 }
1239 
1240 /*
1241  * Destroy the hash table
1242  */
1243 static void
hash_destroy(void)1244 hash_destroy(void)
1245 {
1246 	int i;
1247 	frutree_hashelm_t	*el;
1248 	hashdata_t	*datap = NULL;
1249 
1250 	(void) rw_wrlock(&hash_lock);
1251 	if (node_hash_table.tbl == NULL) {
1252 		(void) rw_unlock(&hash_lock);
1253 		return;
1254 	}
1255 
1256 	/* loop thru each linked list in the table and free */
1257 	for (i = 0; i < node_hash_table.hash_size; ++i) {
1258 		while (node_hash_table.tbl[i] != NULL) {
1259 			el = node_hash_table.tbl[i];
1260 			node_hash_table.tbl[i] = el->nextp;
1261 			datap = (hashdata_t *)el->nodep;
1262 			free_data(datap->type, datap);
1263 			el->nodep = NULL;
1264 			free(el);
1265 			el = NULL;
1266 		}
1267 	}
1268 	free(node_hash_table.tbl);
1269 	(void) rw_unlock(&hash_lock);
1270 }
1271 
1272 /*
1273  * Add an entry to the hash table
1274  */
1275 static picl_errno_t
hash_add_entry(picl_nodehdl_t hdl,void * nodep)1276 hash_add_entry(picl_nodehdl_t hdl, void	*nodep)
1277 {
1278 	int indx;
1279 	frutree_hashelm_t *el;
1280 
1281 	FRUTREE_DEBUG0(HASHTABLE, "hash_add_entry : begin");
1282 	(void) rw_wrlock(&hash_lock);
1283 
1284 	if (node_hash_table.tbl == NULL) {
1285 		(void) rw_unlock(&hash_lock);
1286 		return (PICL_NOTINITIALIZED);
1287 	}
1288 
1289 	el = (frutree_hashelm_t *)malloc(sizeof (frutree_hashelm_t));
1290 	if (el == NULL) {
1291 		(void) rw_unlock(&hash_lock);
1292 		return (PICL_NOSPACE);
1293 	}
1294 
1295 	el->hdl = hdl;
1296 	el->nodep = nodep;
1297 	el->nextp = NULL;
1298 
1299 	if (frutree_debug & HASHTABLE) {
1300 		picl_nodehdl_t	nodeid;
1301 		nodeid = hdl;
1302 		cvt_ptree2picl(&nodeid);
1303 		FRUTREE_DEBUG1(HASHTABLE, "added node: %llx", nodeid);
1304 	}
1305 
1306 	indx = HASH_INDEX(node_hash_table.hash_size, hdl);
1307 	if (node_hash_table.tbl[indx] == NULL) {
1308 		/* first element for this index */
1309 		node_hash_table.tbl[indx] = el;
1310 		(void) rw_unlock(&hash_lock);
1311 		return (PICL_SUCCESS);
1312 	}
1313 
1314 	el->nextp = node_hash_table.tbl[indx];
1315 	node_hash_table.tbl[indx] = el;
1316 	(void) rw_unlock(&hash_lock);
1317 	return (PICL_SUCCESS);
1318 }
1319 
1320 /*
1321  * Remove a hash entry from the table
1322  */
1323 static picl_errno_t
hash_remove_entry(picl_nodehdl_t hdl)1324 hash_remove_entry(picl_nodehdl_t hdl)
1325 {
1326 	int i;
1327 	hashdata_t *datap = NULL;
1328 	frutree_hashelm_t *prev, *cur;
1329 
1330 	(void) rw_wrlock(&hash_lock);
1331 
1332 	if (node_hash_table.tbl == NULL) {
1333 		(void) rw_unlock(&hash_lock);
1334 		return (PICL_NOTINITIALIZED);
1335 	}
1336 
1337 	i = HASH_INDEX(node_hash_table.hash_size, hdl);
1338 
1339 	/* check that the hash chain is not empty */
1340 	if (node_hash_table.tbl[i] == NULL) {
1341 		(void) rw_wrlock(&hash_lock);
1342 		return (PICL_NODENOTFOUND);
1343 	}
1344 
1345 	/* search hash chain for entry to be removed */
1346 	prev = NULL;
1347 	cur = node_hash_table.tbl[i];
1348 	while (cur) {
1349 		if (cur->hdl == hdl) {
1350 			if (prev == NULL) {	/* 1st elem in hash chain */
1351 				node_hash_table.tbl[i] = cur->nextp;
1352 			} else {
1353 				prev->nextp = cur->nextp;
1354 			}
1355 			datap = (hashdata_t *)cur->nodep;
1356 			free_data(datap->type, datap);
1357 			cur->nodep = NULL;
1358 			free(cur);
1359 			cur = NULL;
1360 
1361 			if (frutree_debug & HASHTABLE) {
1362 				picl_nodehdl_t	nodeid;
1363 				nodeid = hdl;
1364 				cvt_ptree2picl(&nodeid);
1365 				FRUTREE_DEBUG1(HASHTABLE, "removed node: %llx",
1366 					nodeid);
1367 			}
1368 
1369 			(void) rw_unlock(&hash_lock);
1370 			return (PICL_SUCCESS);
1371 		}
1372 		prev = cur;
1373 		cur = cur->nextp;
1374 	}
1375 
1376 	/*  entry was not found */
1377 	(void) rw_unlock(&hash_lock);
1378 	return (PICL_NODENOTFOUND);
1379 }
1380 
1381 /*
1382  * Lookup a handle in the table
1383  */
1384 static picl_errno_t
hash_lookup_entry(picl_nodehdl_t hdl,void ** nodepp)1385 hash_lookup_entry(picl_nodehdl_t hdl, void **nodepp)
1386 {
1387 	int i;
1388 	frutree_hashelm_t *el;
1389 
1390 	FRUTREE_DEBUG1(HASHTABLE, "hash_lookup begin: %llx", hdl);
1391 	(void) rw_rdlock(&hash_lock);
1392 
1393 	if (node_hash_table.tbl == NULL) {
1394 		(void) rw_unlock(&hash_lock);
1395 		return (PICL_NOTINITIALIZED);
1396 	}
1397 	if (nodepp == NULL) {
1398 		(void) rw_unlock(&hash_lock);
1399 		return (PICL_INVALIDHANDLE);
1400 	}
1401 
1402 	i = HASH_INDEX(node_hash_table.hash_size, hdl);
1403 
1404 	if (node_hash_table.tbl[i] == NULL) {
1405 		(void) rw_unlock(&hash_lock);
1406 		return (PICL_NODENOTFOUND);
1407 	}
1408 
1409 	el = node_hash_table.tbl[i];
1410 	while (el) {
1411 		if (el->hdl == hdl) {
1412 			*nodepp = el->nodep;
1413 			(void) rw_unlock(&hash_lock);
1414 			return (PICL_SUCCESS);
1415 		}
1416 		el = el->nextp;
1417 	}
1418 	(void) rw_unlock(&hash_lock);
1419 	return (PICL_NODENOTFOUND);
1420 }
1421 
1422 /* create and initialize data structure for a loc node */
1423 static picl_errno_t
make_loc_data(char * full_name,hashdata_t ** hashptr)1424 make_loc_data(char *full_name, hashdata_t **hashptr)
1425 {
1426 	char		*name_copy;
1427 	frutree_locnode_t	*locp;
1428 	hashdata_t	*datap = NULL;
1429 
1430 	datap = (hashdata_t *)malloc(sizeof (hashdata_t));
1431 	if (datap == NULL) {
1432 		return (PICL_NOSPACE);
1433 	}
1434 	datap->type = LOC_TYPE;
1435 
1436 	/* allocate the data */
1437 	locp = (frutree_locnode_t *)malloc(sizeof (frutree_locnode_t));
1438 	if (locp == NULL) {
1439 		free(datap);
1440 		return (PICL_NOSPACE);
1441 	}
1442 
1443 	/* make a copy of the name */
1444 	name_copy = strdup(full_name);
1445 	if (name_copy == NULL) {
1446 		free(locp);
1447 		free(datap);
1448 		return (PICL_NOSPACE);
1449 	}
1450 
1451 	/* initialize the data */
1452 	locp->name = name_copy;
1453 	locp->locnodeh = 0;
1454 	locp->state = LOC_STATE_UNKNOWN;
1455 	locp->prev_state = LOC_STATE_UNKNOWN;
1456 	locp->cpu_node = B_FALSE;
1457 	locp->autoconfig_enabled = B_FALSE;
1458 	locp->state_mgr = UNKNOWN;
1459 	locp->dr_in_progress = B_FALSE;
1460 	(void) pthread_mutex_init(&locp->mutex, NULL);
1461 	(void) pthread_cond_init(&locp->cond_cv, NULL);
1462 
1463 	datap->data = locp;
1464 	*hashptr = datap;
1465 	return (PICL_SUCCESS);
1466 }
1467 
1468 /* create and initialize data structure for a fru node */
1469 static picl_errno_t
make_fru_data(char * full_name,hashdata_t ** hashptr)1470 make_fru_data(char *full_name, hashdata_t **hashptr)
1471 {
1472 	char		*name_copy;
1473 	frutree_frunode_t	*frup;
1474 	hashdata_t	*datap = NULL;
1475 
1476 	datap = (hashdata_t *)malloc(sizeof (hashdata_t));
1477 	if (datap == NULL) {
1478 		return (PICL_NOSPACE);
1479 	}
1480 	datap->type = FRU_TYPE;
1481 
1482 	/* allocate the data */
1483 	frup = (frutree_frunode_t *)malloc(sizeof (frutree_frunode_t));
1484 	if (frup == NULL) {
1485 		free(datap);
1486 		return (PICL_NOSPACE);
1487 	}
1488 
1489 	/* make a copy of the name */
1490 	name_copy = strdup(full_name);
1491 	if (name_copy == NULL) {
1492 		free(frup);
1493 		free(datap);
1494 		return (PICL_NOSPACE);
1495 	}
1496 
1497 	/* initialize the data */
1498 	frup->name = name_copy;
1499 	frup->frunodeh = 0;
1500 	frup->state = FRU_STATE_UNCONFIGURED;
1501 	frup->prev_state = FRU_STATE_UNKNOWN;
1502 	frup->cond = FRU_COND_UNKNOWN;
1503 	frup->prev_cond = FRU_COND_UNKNOWN;
1504 	frup->cpu_node = B_FALSE;
1505 	frup->autoconfig_enabled = B_FALSE;
1506 	frup->dr_in_progress = B_FALSE;
1507 	frup->busy = B_FALSE;
1508 	frup->state_mgr = UNKNOWN;
1509 	frup->fru_path[0] = '\0';
1510 	(void) pthread_mutex_init(&frup->mutex, NULL);
1511 	(void) pthread_cond_init(&frup->cond_cv, NULL);
1512 	(void) pthread_cond_init(&frup->busy_cond_cv, NULL);
1513 
1514 	datap->data = frup;
1515 	*hashptr = datap;
1516 	return (PICL_SUCCESS);
1517 }
1518 
1519 /* create and initialize data structure for a port node */
1520 static picl_errno_t
make_port_data(char * full_name,hashdata_t ** hashptr)1521 make_port_data(char *full_name, hashdata_t **hashptr)
1522 {
1523 	char *name_copy;
1524 	frutree_portnode_t *portp;
1525 	hashdata_t *datap = NULL;
1526 
1527 	datap = (hashdata_t *)malloc(sizeof (hashdata_t));
1528 	if (datap == NULL) {
1529 		return (PICL_NOSPACE);
1530 	}
1531 	datap->type = PORT_TYPE;
1532 
1533 	/* allocate the data */
1534 	portp = (frutree_portnode_t *)malloc(sizeof (frutree_portnode_t));
1535 	if (portp == NULL) {
1536 		free(datap);
1537 		return (PICL_NOSPACE);
1538 	}
1539 	/* make a copy of the name */
1540 	name_copy = strdup(full_name);
1541 	if (name_copy == NULL) {
1542 		free(portp);
1543 		free(datap);
1544 		return (PICL_NOSPACE);
1545 	}
1546 
1547 	/* initialize the data */
1548 	portp->name = name_copy;
1549 	portp->portnodeh = 0;
1550 	portp->state = PORT_STATE_UNKNOWN;
1551 	portp->cond = PORT_COND_UNKNOWN;
1552 	datap->data = portp;
1553 	*hashptr = datap;
1554 	return (PICL_SUCCESS);
1555 }
1556 
1557 /*
1558  * utility routine to create table entries
1559  */
1560 static picl_errno_t
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)1561 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
1562 {
1563 	picl_errno_t		rc;
1564 	ptree_propinfo_t	propinfo;
1565 	picl_prophdl_t		prophdl[2];
1566 	char			buf[PICL_CLASSNAMELEN_MAX];
1567 
1568 	/* first column is class */
1569 	if ((rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1570 		PICL_PTYPE_CHARSTRING, PICL_READ, PICL_CLASSNAMELEN_MAX,
1571 		PICL_PROP_CLASS, NULLREAD,
1572 		NULLWRITE)) != PICL_SUCCESS) {
1573 		return (rc);
1574 	}
1575 
1576 	if ((rc = ptree_create_prop(&propinfo, class,
1577 		&prophdl[0])) != PICL_SUCCESS) {
1578 		return (rc);
1579 	}
1580 
1581 	/* second column is reference property */
1582 	(void) snprintf(buf, sizeof (buf), "_%s_", class);
1583 	if ((rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1584 		PICL_PTYPE_REFERENCE, PICL_READ,
1585 		sizeof (picl_nodehdl_t), buf, NULLREAD,
1586 		NULLWRITE)) != PICL_SUCCESS) {
1587 		return (rc);
1588 	}
1589 
1590 	if ((rc = ptree_create_prop(&propinfo, &refhdl,
1591 		&prophdl[1])) != PICL_SUCCESS) {
1592 		return (rc);
1593 	}
1594 
1595 	/* add row to table */
1596 	if ((rc = ptree_add_row_to_table(tblhdl, 2, prophdl)) != PICL_SUCCESS) {
1597 		return (rc);
1598 	}
1599 	return (PICL_SUCCESS);
1600 }
1601 
1602 /*
1603  * Utility routine to create picl property
1604  */
1605 static picl_errno_t
create_property(int ptype,int pmode,size_t psize,char * pname,int (* readfn)(ptree_rarg_t *,void *),int (* writefn)(ptree_warg_t *,const void *),picl_nodehdl_t nodeh,picl_prophdl_t * prophp,void * vbuf)1606 create_property(int ptype, int pmode, size_t psize, char *pname,
1607 	int (*readfn)(ptree_rarg_t *, void *),
1608 	int (*writefn)(ptree_warg_t *, const void *),
1609 	picl_nodehdl_t nodeh, picl_prophdl_t *prophp, void *vbuf)
1610 {
1611 	picl_errno_t		rc;
1612 	ptree_propinfo_t	propinfo;
1613 	picl_prophdl_t		proph;
1614 
1615 	if (pname == NULL || vbuf == NULL) {
1616 		return (PICL_FAILURE);
1617 	}
1618 
1619 	if (ptype == PICL_PTYPE_TABLE) {
1620 		if ((rc = ptree_create_table((picl_prophdl_t *)vbuf))
1621 			!= PICL_SUCCESS) {
1622 			return (rc);
1623 		}
1624 	}
1625 
1626 	if ((rc = ptree_get_prop_by_name(nodeh, pname, &proph)) ==
1627 		PICL_SUCCESS) {	/* property already exists */
1628 		return (rc);
1629 	}
1630 
1631 	rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1632 		ptype, pmode, psize, pname, readfn, writefn);
1633 	if (rc != PICL_SUCCESS) {
1634 		return (rc);
1635 	}
1636 
1637 	rc = ptree_create_and_add_prop(nodeh, &propinfo, vbuf, prophp);
1638 	if (rc != PICL_SUCCESS) {
1639 		return (rc);
1640 	}
1641 	return (PICL_SUCCESS);
1642 }
1643 
1644 /*
1645  *  create frutree node, chassis node
1646  */
1647 static picl_errno_t
initialize_frutree()1648 initialize_frutree()
1649 {
1650 	int rc = PICL_SUCCESS;
1651 	hashdata_t *datap = NULL;
1652 	frutree_frunode_t *frup = NULL;
1653 	uint64_t ap_status_time;
1654 
1655 	FRUTREE_DEBUG0(FRUTREE_INIT, "initialize_frutree begin");
1656 	/* Get the root of the PICL tree */
1657 	if ((rc = ptree_get_root(&rooth)) != PICL_SUCCESS) {
1658 		return (rc);
1659 	}
1660 	FRUTREE_DEBUG1(FRUTREE_INIT, "roothdl = %llx", rooth);
1661 
1662 	/* create /frutree node */
1663 	if ((rc = ptree_create_and_add_node(rooth, PICL_NODE_FRUTREE,
1664 		PICL_CLASS_PICL, &frutreeh)) != PICL_SUCCESS) {
1665 		return (rc);
1666 	}
1667 	FRUTREE_DEBUG1(FRUTREE_INIT, "frutreeh = %llx", frutreeh);
1668 
1669 	/* create chassis node */
1670 	if ((rc = ptree_create_node(PICL_NODE_CHASSIS, PICL_CLASS_FRU,
1671 		&chassish)) != PICL_SUCCESS) {
1672 		return (rc);
1673 	}
1674 	FRUTREE_DEBUG1(FRUTREE_INIT, "chassish = %llx", chassish);
1675 
1676 	/* Allocate fru data */
1677 	if ((rc = make_fru_data(PICL_NODE_CHASSIS, &datap)) !=
1678 		PICL_SUCCESS) {
1679 		(void) ptree_destroy_node(chassish);
1680 		return (rc);
1681 	}
1682 	/* initialise chassis handle and parent handle */
1683 	frup = FRUDATA_PTR(datap);
1684 	frup->frunodeh = chassish;
1685 
1686 	/* Add the chassis node to the tree */
1687 	if ((rc = ptree_add_node(frutreeh, chassish)) != PICL_SUCCESS) {
1688 		free_data(datap->type, datap);
1689 		(void) ptree_destroy_node(chassish);
1690 		return (rc);
1691 	}
1692 
1693 	/* create chassis  state property */
1694 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
1695 		PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_STATE,
1696 		NULLREAD, NULLWRITE, chassish, (picl_prophdl_t *)NULL,
1697 		PICLEVENTARGVAL_UNCONFIGURED)) != PICL_SUCCESS) {
1698 		free_data(datap->type, datap);
1699 		(void) ptree_delete_node(chassish);
1700 		(void) ptree_destroy_node(chassish);
1701 		return (rc);
1702 	}
1703 	ap_status_time = (uint64_t)(time(NULL));
1704 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
1705 		sizeof (ap_status_time), PICL_PROP_STATUS_TIME,
1706 		NULLREAD, NULLWRITE, chassish,
1707 		NULL, &ap_status_time)) != PICL_SUCCESS) {
1708 		free_data(datap->type, datap);
1709 		(void) ptree_delete_node(chassish);
1710 		(void) ptree_destroy_node(chassish);
1711 		return (rc);
1712 	}
1713 
1714 	/* save chassis info in hashtable */
1715 	if ((rc = hash_add_entry(chassish,
1716 		(void *)datap)) != PICL_SUCCESS) {
1717 		free_data(datap->type, datap);
1718 		(void) ptree_delete_node(chassish);
1719 		(void) ptree_destroy_node(chassish);
1720 		return (rc);
1721 	}
1722 	return (PICL_SUCCESS);
1723 }
1724 
1725 /*
1726  * Read the temporary property created by platform specific
1727  * plugin to get the config file name.
1728  */
1729 static picl_errno_t
get_configuration_file()1730 get_configuration_file()
1731 {
1732 	picl_errno_t rc;
1733 	picl_prophdl_t proph;
1734 	char file_name[PICL_PROPNAMELEN_MAX];
1735 
1736 	if ((rc = ptree_get_prop_by_name(chassish,
1737 		PICL_PROP_CONF_FILE, &proph)) != PICL_SUCCESS) {
1738 		return (rc);
1739 	}
1740 
1741 	if ((rc = ptree_get_propval(proph, file_name,
1742 		sizeof (file_name))) != PICL_SUCCESS) {
1743 		return (rc);
1744 	}
1745 
1746 	(void) snprintf(conf_file, sizeof (conf_file),
1747 		PICLD_PLAT_PLUGIN_DIRF"%s", sys_name, file_name);
1748 	/* delete the tmp prop created by platform specific plugin */
1749 	(void) ptree_delete_prop(proph);
1750 	(void) ptree_destroy_prop(proph);
1751 	FRUTREE_DEBUG1(EVENTS, "Using %s conf file", conf_file);
1752 	return (PICL_SUCCESS);
1753 }
1754 
1755 /*
1756  * Read the cfgadm data and get the latest information
1757  */
1758 static picl_errno_t
get_cfgadm_state(cfga_list_data_t * data,char * ap_id)1759 get_cfgadm_state(cfga_list_data_t *data, char *ap_id)
1760 {
1761 	int nlist;
1762 	cfga_err_t	ap_list_err;
1763 	cfga_list_data_t *list = NULL;
1764 	char * const *p = &ap_id;
1765 
1766 	if (data == NULL || ap_id == NULL) {
1767 		return (PICL_INVALIDARG);
1768 	}
1769 
1770 	ap_list_err = config_list_ext(1, p, &list, &nlist, NULL,
1771 		NULL, NULL, 0);
1772 	if (ap_list_err != CFGA_OK) {
1773 		free(list);
1774 		return (cfg2picl_errmap[ap_list_err][1]);
1775 	}
1776 
1777 	(void) memcpy(data, list, sizeof (cfga_list_data_t));
1778 	free(list);
1779 	return (PICL_SUCCESS);
1780 }
1781 
1782 /*
1783  * syncup with cfgadm data and read latest location state information
1784  */
1785 static picl_errno_t
update_loc_state(frutree_locnode_t * locp,boolean_t * updated)1786 update_loc_state(frutree_locnode_t *locp, boolean_t *updated)
1787 {
1788 	int i = 0;
1789 	cfga_list_data_t *list = NULL;
1790 	picl_errno_t rc, rc1;
1791 	char valbuf[PICL_PROPNAMELEN_MAX];
1792 	char slot_type[PICL_PROPNAMELEN_MAX];
1793 	uint64_t ap_status_time;
1794 
1795 	*updated = B_FALSE;
1796 	if (locp->state_mgr == PLUGIN_PVT) {
1797 		if ((rc = ptree_get_propval_by_name(locp->locnodeh,
1798 			PICL_PROP_STATE, (void *)valbuf,
1799 			PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
1800 			return (rc);
1801 		}
1802 
1803 		/* if there is a change in state, update the internal value */
1804 		if (strcmp(loc_state[locp->state], valbuf) != 0) {
1805 			ap_status_time = (uint64_t)(time(NULL));
1806 			if ((rc = ptree_update_propval_by_name(locp->locnodeh,
1807 				PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
1808 				sizeof (ap_status_time))) != PICL_SUCCESS) {
1809 				FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
1810 					PICL_PROP_STATUS_TIME, locp->name, rc);
1811 			}
1812 			*updated = B_TRUE;
1813 			locp->prev_state = locp->state;
1814 			for (i = 0; (loc_state[i] != NULL); i++) {
1815 				if (strcmp(loc_state[i], valbuf) == 0) {
1816 					locp->state = i;
1817 					return (PICL_SUCCESS);
1818 				}
1819 			}
1820 		}
1821 		return (PICL_SUCCESS);
1822 	} else if (locp->state_mgr == STATIC_LOC) {
1823 		return (PICL_SUCCESS);
1824 	}
1825 
1826 	/*  get the info from the libcfgadm interface */
1827 	list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
1828 	if (list == NULL) {
1829 		return (PICL_NOSPACE);
1830 	}
1831 
1832 	if ((rc = get_cfgadm_state(list, locp->name)) != PICL_SUCCESS) {
1833 		if ((rc1 = ptree_get_propval_by_name(locp->locnodeh,
1834 			PICL_PROP_SLOT_TYPE, slot_type,
1835 			sizeof (slot_type))) != PICL_SUCCESS) {
1836 			free(list);
1837 			return (rc1);
1838 		}
1839 		if (strcmp(slot_type, SANIBEL_SCSI_SLOT) != 0 &&
1840 			strcmp(slot_type, SANIBEL_IDE_SLOT) != 0) {
1841 			free(list);
1842 			return (rc);
1843 		}
1844 		/* this is a scsi location */
1845 		if (rc != PICL_NODENOTFOUND) {
1846 			free(list);
1847 			return (rc);
1848 		}
1849 
1850 		/*
1851 		 * for scsi locations, if node is not found,
1852 		 * consider location state as empty
1853 		 */
1854 		(void) pthread_mutex_lock(&locp->mutex);
1855 		if (locp->state != LOC_STATE_EMPTY) {
1856 			*updated = B_TRUE;
1857 			locp->prev_state = locp->state;
1858 			locp->state = LOC_STATE_EMPTY;
1859 			ap_status_time = (uint64_t)(time(NULL));
1860 			if ((rc = ptree_update_propval_by_name(locp->locnodeh,
1861 				PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
1862 				sizeof (ap_status_time))) != PICL_SUCCESS) {
1863 				FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
1864 					PICL_PROP_STATUS_TIME, locp->name, rc);
1865 			}
1866 		}
1867 		(void) pthread_mutex_unlock(&locp->mutex);
1868 		free(list);
1869 		return (PICL_SUCCESS);
1870 	}
1871 
1872 	(void) pthread_mutex_lock(&locp->mutex);
1873 	switch (list->ap_r_state) {
1874 	case CFGA_STAT_CONNECTED:
1875 		if (locp->state != LOC_STATE_CONNECTED) {
1876 			*updated = B_TRUE;
1877 			locp->prev_state = locp->state;
1878 			locp->state = LOC_STATE_CONNECTED;
1879 		}
1880 		break;
1881 	case CFGA_STAT_DISCONNECTED:
1882 		if (locp->state != LOC_STATE_DISCONNECTED) {
1883 			*updated = B_TRUE;
1884 			locp->prev_state = locp->state;
1885 			locp->state = LOC_STATE_DISCONNECTED;
1886 		}
1887 		break;
1888 	case CFGA_STAT_EMPTY:
1889 		if (locp->state != LOC_STATE_EMPTY) {
1890 			*updated = B_TRUE;
1891 			locp->prev_state = locp->state;
1892 			locp->state = LOC_STATE_EMPTY;
1893 		}
1894 		break;
1895 	default:
1896 		if (locp->state != LOC_STATE_UNKNOWN) {
1897 			*updated = B_TRUE;
1898 			locp->prev_state = locp->state;
1899 			locp->state = LOC_STATE_UNKNOWN;
1900 		}
1901 	}
1902 
1903 	if (*updated == B_TRUE) {
1904 		ap_status_time = (uint64_t)(time(NULL));
1905 		if ((rc = ptree_update_propval_by_name(locp->locnodeh,
1906 			PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
1907 			sizeof (ap_status_time))) != PICL_SUCCESS) {
1908 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
1909 				PICL_PROP_STATUS_TIME, locp->name, rc);
1910 		}
1911 	}
1912 
1913 	/* update the autoconfig flag */
1914 	switch (is_autoconfig_enabled(locp->name)) {
1915 		case 1:
1916 			locp->autoconfig_enabled = B_TRUE;
1917 			break;
1918 		case 0:
1919 		default:
1920 			locp->autoconfig_enabled = B_FALSE;
1921 			break;
1922 	}
1923 	(void) pthread_mutex_unlock(&locp->mutex);
1924 
1925 	free(list);
1926 	return (PICL_SUCCESS);
1927 }
1928 
1929 /*
1930  * volatile callback function to return the state value for a location
1931  */
1932 static int
get_loc_state(ptree_rarg_t * rarg,void * buf)1933 get_loc_state(ptree_rarg_t  *rarg, void *buf)
1934 {
1935 	picl_errno_t rc;
1936 	frutree_dr_arg_t dr_arg;
1937 	hashdata_t *hashptr = NULL;
1938 	frutree_locnode_t *locp = NULL;
1939 	boolean_t state_change = B_FALSE;
1940 
1941 	if (buf == NULL) {
1942 		return (PICL_INVALIDARG);
1943 	}
1944 
1945 	if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
1946 		PICL_SUCCESS) {
1947 		return (rc);
1948 	}
1949 
1950 	locp = LOCDATA_PTR(hashptr);
1951 	if (locp == NULL) {
1952 		return (PICL_FAILURE);
1953 	}
1954 
1955 	(void) pthread_mutex_lock(&locp->mutex);
1956 	if (locp->dr_in_progress == B_TRUE) {
1957 		/* return the cached value */
1958 		(void) strncpy((char *)buf, loc_state[locp->state],
1959 			PICL_PROPNAMELEN_MAX);
1960 		(void) pthread_mutex_unlock(&locp->mutex);
1961 		return (PICL_SUCCESS);
1962 	}
1963 	(void) pthread_mutex_unlock(&locp->mutex);
1964 
1965 	if ((rc = update_loc_state(locp, &state_change)) != PICL_SUCCESS) {
1966 		FRUTREE_DEBUG2(EVENTS, GET_LOC_STATE_ERR, locp->name, rc);
1967 		/* return the cached value */
1968 		(void) strncpy((char *)buf, loc_state[locp->state],
1969 			PICL_PROPNAMELEN_MAX);
1970 		return (rc);
1971 	}
1972 
1973 	/* if there is a state change, handle the event */
1974 	if (state_change) {
1975 		(void) pthread_mutex_lock(&locp->mutex);
1976 		if (locp->state == LOC_STATE_EMPTY) { /* card removed */
1977 			dr_arg.action = HANDLE_REMOVE;
1978 		} else if (locp->prev_state == LOC_STATE_EMPTY) {
1979 			dr_arg.action = HANDLE_INSERT; /* card inserted */
1980 		} else {
1981 			/* loc state changed */
1982 			dr_arg.action = HANDLE_LOCSTATE_CHANGE;
1983 		}
1984 		(void) pthread_mutex_unlock(&locp->mutex);
1985 		dr_arg.data = locp;
1986 		(void) pthread_mutex_lock(&ev_mutex);
1987 		if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
1988 			(void) pthread_mutex_unlock(&ev_mutex);
1989 			FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
1990 				"dr_ap_state_change", locp->name, rc);
1991 		} else {
1992 			(void) pthread_cond_signal(&ev_cond);
1993 			(void) pthread_mutex_unlock(&ev_mutex);
1994 		}
1995 	}
1996 
1997 	(void) strncpy((char *)buf, loc_state[locp->state],
1998 		PICL_PROPNAMELEN_MAX);
1999 	return (PICL_SUCCESS);
2000 }
2001 
2002 /*
2003  * syncup with cfgadm data and read latest fru state information
2004  */
2005 static picl_errno_t
update_fru_state(frutree_frunode_t * frup,boolean_t * updated)2006 update_fru_state(frutree_frunode_t *frup, boolean_t *updated)
2007 {
2008 	int i;
2009 	picl_errno_t rc;
2010 	picl_nodehdl_t loch;
2011 	uint64_t ap_status_time;
2012 	hashdata_t *hashptr = NULL;
2013 	cfga_list_data_t *list = NULL;
2014 	frutree_locnode_t *locp = NULL;
2015 	char valbuf[PICL_PROPNAMELEN_MAX];
2016 
2017 	*updated = B_FALSE;
2018 	if (frup->state_mgr == PLUGIN_PVT) {
2019 		if ((rc = ptree_get_propval_by_name(frup->frunodeh,
2020 			PICL_PROP_STATE, (void *)valbuf,
2021 			PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
2022 			return (rc);
2023 		}
2024 
2025 		/* if there is a change in state, update the internal value */
2026 		if (strcmp(fru_state[frup->state], valbuf) != 0) {
2027 			*updated = B_TRUE;
2028 			frup->prev_state = frup->state;
2029 			ap_status_time = (uint64_t)(time(NULL));
2030 			if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2031 				PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
2032 				sizeof (ap_status_time))) != PICL_SUCCESS) {
2033 				if (rc == PICL_PROPNOTFOUND) {
2034 					(void) create_property(
2035 						PICL_PTYPE_TIMESTAMP, PICL_READ,
2036 							sizeof (ap_status_time),
2037 							PICL_PROP_STATUS_TIME,
2038 							NULLREAD, NULLWRITE,
2039 							frup->frunodeh,
2040 							NULL, &ap_status_time);
2041 				} else {
2042 					FRUTREE_DEBUG3(EVENTS,
2043 						PTREE_UPDATE_PROP_ERR,
2044 						PICL_PROP_STATUS_TIME,
2045 						frup->name, rc);
2046 				}
2047 			}
2048 			for (i = 0; (fru_state[i] != NULL); i++) {
2049 				if (strcmp(fru_state[i], valbuf) == 0) {
2050 					frup->state = i;
2051 					return (PICL_SUCCESS);
2052 				}
2053 			}
2054 		}
2055 		return (PICL_SUCCESS);
2056 	} else if (frup->state_mgr == STATIC_LOC) {
2057 		frup->state = FRU_STATE_CONFIGURED;
2058 		return (PICL_SUCCESS);
2059 	}
2060 
2061 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
2062 		&loch, sizeof (loch))) != PICL_SUCCESS) {
2063 		return (rc);
2064 	}
2065 
2066 	if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
2067 		PICL_SUCCESS) {
2068 		return (rc);
2069 	}
2070 	locp = LOCDATA_PTR(hashptr);
2071 	if (locp == NULL) {
2072 		return (PICL_FAILURE);
2073 	}
2074 
2075 	list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
2076 	if (list == NULL) {
2077 		return (PICL_NOSPACE);
2078 	}
2079 
2080 	if ((rc = get_cfgadm_state(list, locp->name)) != PICL_SUCCESS) {
2081 		free(list);
2082 		return (rc);
2083 	}
2084 
2085 	(void) pthread_mutex_lock(&frup->mutex);
2086 	switch (list->ap_o_state) {
2087 	case CFGA_STAT_CONFIGURED:
2088 		if (frup->state != FRU_STATE_CONFIGURED) {
2089 			*updated = B_TRUE;
2090 			frup->prev_state = frup->state;
2091 			frup->state = FRU_STATE_CONFIGURED;
2092 		}
2093 		break;
2094 	case CFGA_STAT_UNCONFIGURED:
2095 		if (frup->state != FRU_STATE_UNCONFIGURED) {
2096 			*updated = B_TRUE;
2097 			frup->prev_state = frup->state;
2098 			frup->state = FRU_STATE_UNCONFIGURED;
2099 		}
2100 		break;
2101 	default:
2102 		if (frup->state != FRU_STATE_UNKNOWN) {
2103 			*updated = B_TRUE;
2104 			frup->prev_state = frup->state;
2105 			frup->state = FRU_STATE_UNKNOWN;
2106 		}
2107 		break;
2108 	}
2109 
2110 	/* update the fru_type property */
2111 	if (list->ap_type) {
2112 		if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2113 			PICL_PROP_FRU_TYPE, list->ap_type,
2114 			sizeof (list->ap_type))) != PICL_SUCCESS) {
2115 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2116 				PICL_PROP_FRU_TYPE, frup->name, rc);
2117 		}
2118 	}
2119 
2120 	if (*updated == B_TRUE) {
2121 		ap_status_time = (uint64_t)(time(NULL));
2122 		if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2123 			PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
2124 			sizeof (ap_status_time))) != PICL_SUCCESS) {
2125 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2126 				PICL_PROP_STATUS_TIME, frup->name, rc);
2127 		}
2128 	}
2129 	(void) pthread_mutex_unlock(&frup->mutex);
2130 
2131 	free(list);
2132 	return (PICL_SUCCESS);
2133 }
2134 
2135 /*
2136  * syncup with cfgadm data and read latest fru condition information
2137  */
2138 static picl_errno_t
update_fru_condition(frutree_frunode_t * frup,boolean_t * updated)2139 update_fru_condition(frutree_frunode_t *frup, boolean_t *updated)
2140 {
2141 	int i = 0;
2142 	picl_errno_t rc;
2143 	picl_nodehdl_t loch;
2144 	uint64_t ap_cond_time;
2145 	hashdata_t *hashptr = NULL;
2146 	cfga_list_data_t *list = NULL;
2147 	frutree_locnode_t *locp = NULL;
2148 	char valbuf[PICL_PROPNAMELEN_MAX];
2149 
2150 	*updated = B_FALSE;
2151 	if (frup->state_mgr == PLUGIN_PVT) {
2152 		if ((rc = ptree_get_propval_by_name(frup->frunodeh,
2153 			PICL_PROP_CONDITION, (void *)valbuf,
2154 			PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
2155 			return (rc);
2156 		}
2157 
2158 		/*
2159 		 * if there is a change in condition, update the
2160 		 * internal value
2161 		 */
2162 		if (strcmp(fru_cond[frup->cond], valbuf) != 0) {
2163 			*updated = B_TRUE;
2164 			ap_cond_time = (uint64_t)(time(NULL));
2165 			if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2166 				PICL_PROP_CONDITION_TIME, (void *)&ap_cond_time,
2167 				sizeof (ap_cond_time))) != PICL_SUCCESS) {
2168 				FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2169 					PICL_PROP_CONDITION_TIME, frup->name,
2170 					rc);
2171 			}
2172 			frup->prev_cond = frup->cond;
2173 
2174 			for (i = 0; (fru_cond[i] != NULL); i++) {
2175 				if (strcmp(fru_cond[i], valbuf) == 0) {
2176 					frup->cond = i;
2177 					return (PICL_SUCCESS);
2178 				}
2179 			}
2180 		}
2181 		return (PICL_SUCCESS);
2182 	} else if (frup->state_mgr == STATIC_LOC) {
2183 		frup->cond = FRU_COND_OK;
2184 		return (PICL_SUCCESS);
2185 	}
2186 
2187 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
2188 		&loch, sizeof (loch))) != PICL_SUCCESS) {
2189 		return (rc);
2190 	}
2191 
2192 	if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
2193 		PICL_SUCCESS) {
2194 		return (rc);
2195 	}
2196 
2197 	locp = LOCDATA_PTR(hashptr);
2198 	if (locp == NULL) {
2199 		return (PICL_FAILURE);
2200 	}
2201 	list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
2202 	if (list == NULL) {
2203 		return (PICL_NOSPACE);
2204 	}
2205 
2206 	if ((rc = get_cfgadm_state(list, locp->name)) != PICL_SUCCESS) {
2207 		free(list);
2208 		return (rc);
2209 	}
2210 
2211 	switch (list->ap_cond) {
2212 	case CFGA_COND_OK:
2213 		if (frup->cond != FRU_COND_OK) {
2214 			*updated = B_TRUE;
2215 			frup->prev_cond = frup->cond;
2216 			frup->cond = FRU_COND_OK;
2217 		}
2218 		break;
2219 	case CFGA_COND_FAILING:
2220 		if (frup->cond != FRU_COND_FAILING) {
2221 			*updated = B_TRUE;
2222 			frup->prev_cond = frup->cond;
2223 			frup->cond = FRU_COND_FAILING;
2224 		}
2225 		break;
2226 	case CFGA_COND_FAILED:
2227 	case CFGA_COND_UNUSABLE:
2228 		if (frup->cond != FRU_COND_FAILED) {
2229 			*updated = B_TRUE;
2230 			frup->prev_cond = frup->cond;
2231 			frup->cond = FRU_COND_FAILED;
2232 		}
2233 		break;
2234 	default:
2235 		if (frup->cond != FRU_COND_UNKNOWN) {
2236 			*updated = B_TRUE;
2237 			frup->prev_cond = frup->cond;
2238 			frup->cond = FRU_COND_UNKNOWN;
2239 		}
2240 	}
2241 
2242 	if (*updated == B_TRUE) {
2243 		ap_cond_time = (uint64_t)(time(NULL));
2244 		if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2245 			PICL_PROP_CONDITION_TIME, (void *)&ap_cond_time,
2246 			sizeof (ap_cond_time))) != PICL_SUCCESS) {
2247 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2248 				PICL_PROP_CONDITION_TIME, frup->name, rc);
2249 		}
2250 	}
2251 	free(list);
2252 	return (PICL_SUCCESS);
2253 }
2254 
2255 /*
2256  * Volatile callback function to read fru state
2257  */
2258 static int
get_fru_state(ptree_rarg_t * rarg,void * buf)2259 get_fru_state(ptree_rarg_t  *rarg, void *buf)
2260 {
2261 	picl_errno_t		rc;
2262 	hashdata_t		*hashptr = NULL;
2263 	frutree_frunode_t	*frup = NULL;
2264 	boolean_t state_change = B_FALSE;
2265 	frutree_dr_arg_t dr_arg;
2266 
2267 	if (buf == NULL) {
2268 		return (PICL_INVALIDARG);
2269 	}
2270 
2271 	if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
2272 		PICL_SUCCESS) {
2273 		return (rc);
2274 	}
2275 
2276 	frup = FRUDATA_PTR(hashptr);
2277 	if (frup == NULL) {
2278 		return (PICL_FAILURE);
2279 	}
2280 
2281 	/* return the cached value, if dr is in progress */
2282 	(void) pthread_mutex_lock(&frup->mutex);
2283 	if (frup->dr_in_progress) {
2284 		(void) pthread_mutex_unlock(&frup->mutex);
2285 		(void) strncpy((char *)buf, fru_state[frup->state],
2286 			PICL_PROPNAMELEN_MAX);
2287 		return (PICL_SUCCESS);
2288 	}
2289 	(void) pthread_mutex_unlock(&frup->mutex);
2290 
2291 	if ((rc = update_fru_state(frup, &state_change)) != PICL_SUCCESS) {
2292 		FRUTREE_DEBUG2(EVENTS, GET_FRU_STATE_ERR, frup->name, rc);
2293 		/* return the cached value */
2294 		(void) strncpy((char *)buf, fru_state[frup->state],
2295 			PICL_PROPNAMELEN_MAX);
2296 		return (rc);
2297 	}
2298 
2299 	/* if there is a state change, handle the event */
2300 	if (state_change) {
2301 		(void) pthread_mutex_lock(&frup->mutex);
2302 		/* figure out if this is config/unconfig operation */
2303 		if (frup->state == FRU_STATE_CONFIGURED) {
2304 			dr_arg.action = HANDLE_CONFIGURE;
2305 			dr_arg.data = frup;
2306 		} else if (frup->state == FRU_STATE_UNCONFIGURED) {
2307 			dr_arg.action = HANDLE_UNCONFIGURE;
2308 			dr_arg.data = frup;
2309 		}
2310 		(void) pthread_mutex_unlock(&frup->mutex);
2311 
2312 		(void) pthread_mutex_lock(&ev_mutex);
2313 		if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
2314 			(void) pthread_mutex_unlock(&ev_mutex);
2315 			FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
2316 				"dr_ap_state_chage", frup->name, rc);
2317 		} else {
2318 			(void) pthread_cond_signal(&ev_cond);
2319 			(void) pthread_mutex_unlock(&ev_mutex);
2320 		}
2321 	}
2322 
2323 	(void) strncpy((char *)buf, fru_state[frup->state],
2324 		PICL_PROPNAMELEN_MAX);
2325 
2326 	return (PICL_SUCCESS);
2327 }
2328 
2329 /*
2330  * Volatile callback function to read fru condition
2331  */
2332 static int
get_fru_condition(ptree_rarg_t * rarg,void * buf)2333 get_fru_condition(ptree_rarg_t  *rarg, void *buf)
2334 {
2335 	picl_errno_t rc;
2336 	frutree_dr_arg_t dr_arg;
2337 	hashdata_t *hashptr = NULL;
2338 	frutree_frunode_t *frup = NULL;
2339 	boolean_t cond_changed = B_FALSE;
2340 
2341 	if (buf == NULL) {
2342 		return (PICL_INVALIDARG);
2343 	}
2344 
2345 	if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
2346 		PICL_SUCCESS) {
2347 		return (rc);
2348 	}
2349 
2350 	frup = FRUDATA_PTR(hashptr);
2351 	if (frup == NULL) {
2352 		return (PICL_FAILURE);
2353 	}
2354 
2355 	/* return the cached value, if dr is in progress */
2356 	(void) pthread_mutex_lock(&frup->mutex);
2357 	if (frup->dr_in_progress) {
2358 		(void) pthread_mutex_unlock(&frup->mutex);
2359 		(void) strncpy((char *)buf, fru_cond[frup->cond],
2360 			PICL_PROPNAMELEN_MAX);
2361 		return (PICL_SUCCESS);
2362 
2363 	}
2364 	(void) pthread_mutex_unlock(&frup->mutex);
2365 
2366 	if ((rc = update_fru_condition(frup, &cond_changed)) != PICL_SUCCESS) {
2367 		FRUTREE_DEBUG2(EVENTS, GET_FRU_COND_ERR, frup->name, rc);
2368 		/* return the cached value */
2369 		(void) strncpy((char *)buf, fru_cond[frup->cond],
2370 			PICL_PROPNAMELEN_MAX);
2371 		return (rc);
2372 	}
2373 	if (cond_changed) {
2374 		dr_arg.action = POST_COND_EVENT;
2375 		dr_arg.data = frup;
2376 		(void) pthread_mutex_lock(&ev_mutex);
2377 		if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
2378 			(void) pthread_mutex_unlock(&ev_mutex);
2379 			FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
2380 				"condition event", frup->name, rc);
2381 		} else {
2382 			(void) pthread_cond_signal(&ev_cond);
2383 			(void) pthread_mutex_unlock(&ev_mutex);
2384 		}
2385 	}
2386 
2387 	/* if there is a condition change, post picl event */
2388 	(void) strncpy((char *)buf, fru_cond[frup->cond],
2389 		PICL_PROPNAMELEN_MAX);
2390 
2391 	return (PICL_SUCCESS);
2392 }
2393 
2394 static void
free_cache(frutree_cache_t * cachep)2395 free_cache(frutree_cache_t *cachep)
2396 {
2397 	frutree_cache_t	*tmp = NULL;
2398 	if (cachep == NULL)
2399 		return;
2400 
2401 	while (cachep != NULL) {
2402 		tmp = cachep;
2403 		cachep = cachep->next;
2404 		free(tmp);
2405 	}
2406 }
2407 
2408 /*
2409  * traverse the /platform tree in PICL tree to create logical devices table
2410  */
2411 static picl_errno_t
probe_platform_tree(frutree_frunode_t * frup,frutree_device_args_t ** devp)2412 probe_platform_tree(frutree_frunode_t *frup, frutree_device_args_t **devp)
2413 {
2414 	picl_errno_t  rc;
2415 	picl_nodehdl_t refhdl = 0;
2416 	char class[PICL_CLASSNAMELEN_MAX];
2417 	frutree_device_args_t *device = NULL;
2418 	picl_prophdl_t tblprophdl;
2419 	picl_prophdl_t dev_tblhdl, env_tblhdl = 0;
2420 
2421 	if (devp == NULL) {
2422 		return (PICL_FAILURE);
2423 	}
2424 	device = *(frutree_device_args_t **)devp;
2425 	if (device == NULL) {
2426 		return (PICL_FAILURE);
2427 	}
2428 
2429 	/* traverse thru platform tree and add entries to Devices table */
2430 	if ((refhdl = get_reference_handle(frup->frunodeh)) == 0) {
2431 		return (PICL_NODENOTFOUND);
2432 	}
2433 
2434 	/* create Devices table property */
2435 	if ((rc = create_property(PICL_PTYPE_TABLE, PICL_READ,
2436 		sizeof (picl_prophdl_t), PICL_PROP_DEVICES, NULLREAD,
2437 		NULLWRITE, frup->frunodeh, &tblprophdl, &dev_tblhdl)) !=
2438 		PICL_SUCCESS) {
2439 		return (rc);
2440 	}
2441 
2442 	if ((rc = ptree_get_propval_by_name(refhdl, PICL_PROP_CLASSNAME,
2443 		class, sizeof (class))) != PICL_SUCCESS) {
2444 		return (rc);
2445 	}
2446 
2447 	if ((rc = create_table_entry(dev_tblhdl, refhdl, class)) !=
2448 		PICL_SUCCESS) {
2449 		return (rc);
2450 	}
2451 
2452 	/* create Environment devices table property */
2453 	if ((rc = create_property(PICL_PTYPE_TABLE, PICL_READ,
2454 		sizeof (picl_prophdl_t), PICL_PROP_ENV, NULLREAD,
2455 		NULLWRITE, frup->frunodeh, &tblprophdl, &env_tblhdl)) !=
2456 		PICL_SUCCESS) {
2457 		return (rc);
2458 	}
2459 
2460 	device->nodeh  = refhdl;
2461 	device->device_tblhdl = dev_tblhdl;
2462 	device->env_tblhdl = env_tblhdl;
2463 	device->first  = NULL;
2464 	device->last   = NULL;
2465 	device->create_cache   = B_FALSE;
2466 
2467 	/* probe using platform tree info */
2468 	if ((rc = do_action(refhdl, CREATE_DEVICES_ENTRIES,
2469 		device)) != PICL_SUCCESS) {
2470 		free_cache(device->first);
2471 		return (rc);
2472 	}
2473 	return (PICL_SUCCESS);
2474 }
2475 
2476 /*
2477  * create temp conf file to pass it to picld util lib to create
2478  * nodes under the fru
2479  */
2480 static picl_errno_t
create_fru_children(frutree_frunode_t * frup,frutree_device_args_t device)2481 create_fru_children(frutree_frunode_t *frup, frutree_device_args_t device)
2482 {
2483 	int fd;
2484 	picl_errno_t	rc;
2485 	char 		conffile[MAXPATHLEN];
2486 	char 		dir[MAXPATHLEN];
2487 	struct stat	file_stat;
2488 	char		version[BUF_SIZE];
2489 	frutree_cache_t	*cachep = NULL;
2490 
2491 	cachep = device.first;
2492 	if (cachep == NULL) {
2493 		return (PICL_SUCCESS);
2494 	}
2495 
2496 	/* create the configuration file for the fru */
2497 	(void) snprintf(dir, MAXPATHLEN, "%s%s", TEMP_DIR, frup->name);
2498 	bzero(&file_stat, sizeof (file_stat));
2499 	if (stat(conffile, &file_stat) == -1) {
2500 		if (mkdir(conffile, 0755) == -1) {
2501 			return (PICL_FAILURE);
2502 		}
2503 	}
2504 
2505 	(void) snprintf(conffile, MAXPATHLEN, "%s/%s", dir, PROBE_FILE);
2506 	if ((fd = open(conffile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
2507 		(void) rmdir(dir);
2508 		return (PICL_FAILURE);
2509 	}
2510 
2511 	(void) snprintf(version, sizeof (version), "VERSION %d.0",
2512 		PTREE_PROPINFO_VERSION);
2513 	if (write(fd, version, strlen(version)) != strlen(version)) {
2514 		(void) remove(conffile);
2515 		(void) rmdir(dir);
2516 		(void) close(fd);
2517 		return (PICL_FAILURE);
2518 	}
2519 
2520 	/* traverse thru each cache entry and append to conf file */
2521 	while (cachep != NULL) {
2522 		if (write(fd, cachep->buf, strlen(cachep->buf))
2523 			!= strlen(cachep->buf)) {
2524 			(void) close(fd);
2525 			(void) remove(conffile);
2526 			(void) rmdir(dir);
2527 			return (PICL_FAILURE);
2528 		}
2529 		cachep = cachep->next;
2530 	}
2531 	(void) close(fd);
2532 
2533 	/* create child nodes for fru using the conffile created */
2534 	if ((rc = picld_pluginutil_parse_config_file(frup->frunodeh,
2535 		conffile)) != PICL_SUCCESS) {
2536 		(void) remove(conffile);
2537 		(void) rmdir(dir);
2538 		return (rc);
2539 	}
2540 	(void) remove(conffile);
2541 	(void) rmdir(dir);
2542 
2543 	if ((rc = fru_init(frup)) != PICL_SUCCESS) {
2544 		return (rc);
2545 	}
2546 	return (PICL_SUCCESS);
2547 }
2548 
2549 /*
2550  * probes libdevinfo and create the port nodes under a fru
2551  * probes for any scsi devices under a fru
2552  */
2553 static picl_errno_t
probe_fru(frutree_frunode_t * frup,boolean_t load_drivers)2554 probe_fru(frutree_frunode_t *frup, boolean_t load_drivers)
2555 {
2556 	picl_errno_t rc;
2557 	picl_nodehdl_t child, loch;
2558 	char slot_type[PICL_PROPNAMELEN_MAX];
2559 	char devfs_path[PICL_PROPNAMELEN_MAX];
2560 	char probe_path[PICL_PROPNAMELEN_MAX];
2561 	frutree_device_args_t *device = NULL;
2562 
2563 	if (frup == NULL) {
2564 		return (PICL_FAILURE);
2565 	}
2566 	FRUTREE_DEBUG1(EVENTS, "probing :%s", frup->name);
2567 
2568 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
2569 		&loch, sizeof (loch))) != PICL_SUCCESS) {
2570 		return (rc);
2571 	}
2572 
2573 	bzero(devfs_path, PICL_PROPNAMELEN_MAX);
2574 	bzero(probe_path, PICL_PROPNAMELEN_MAX);
2575 	if ((rc = ptree_get_propval_by_name(loch, PICL_PROP_DEVFS_PATH,
2576 		devfs_path, sizeof (devfs_path))) == PICL_SUCCESS) {
2577 		device = (frutree_device_args_t *)malloc(
2578 				sizeof (frutree_device_args_t));
2579 		if (device == NULL) {
2580 			return (PICL_NOSPACE);
2581 		}
2582 		device->first  = NULL;
2583 		device->last   = NULL;
2584 		(void) probe_platform_tree(frup, &device);
2585 		free_cache(device->first);
2586 		free(device);
2587 	}
2588 
2589 	/*
2590 	 * if parent has NULL probe-path, skip probing this fru
2591 	 * probe only child locations (if present).
2592 	 * if probe-path is not present use devfs-path as path for
2593 	 * probing the fru.
2594 	 */
2595 	rc = ptree_get_propval_by_name(loch, PICL_PROP_PROBE_PATH,
2596 		probe_path, sizeof (probe_path));
2597 	if (rc != PICL_SUCCESS) {
2598 		if (!devfs_path[0]) {	/* devfspath is also not present */
2599 			return (PICL_SUCCESS);	/* nothing to probe */
2600 		} else {
2601 			/* use devfs-path as path for probing */
2602 			if ((rc = get_fru_path(devfs_path, frup)) !=
2603 				PICL_SUCCESS) {
2604 				return (rc);
2605 			}
2606 		}
2607 	} else {
2608 		/* NULL path, skip probing this fru */
2609 		if (strlen(probe_path) == 0) {
2610 			rc =  fru_init(frup); /* probe its children */
2611 			return (rc);
2612 		} else {
2613 			/* valid probe-path */
2614 			if ((rc = get_fru_path(probe_path, frup)) !=
2615 				PICL_SUCCESS) {
2616 				return (rc);
2617 			}
2618 		}
2619 	}
2620 
2621 	/* children present already, no need to probe libdevinfo */
2622 	rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_CHILD,
2623 		&child, sizeof (picl_nodehdl_t));
2624 	if (rc == PICL_SUCCESS) {	/* child present */
2625 		if ((rc = fru_init(frup)) != PICL_SUCCESS) {
2626 			return (rc);
2627 		}
2628 		/* now create the scsi nodes for this fru */
2629 		if ((rc = probe_for_scsi_frus(frup)) != PICL_SUCCESS) {
2630 			return (rc);
2631 		}
2632 		return (PICL_SUCCESS);
2633 	}
2634 
2635 	if (ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
2636 		&loch, sizeof (loch)) != PICL_SUCCESS) {
2637 		return (rc);
2638 	}
2639 	if ((rc = ptree_get_propval_by_name(loch, PICL_PROP_SLOT_TYPE,
2640 		slot_type, sizeof (slot_type))) != PICL_SUCCESS) {
2641 		return (rc);
2642 	}
2643 	/* no need to probe further for scsi frus */
2644 	if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
2645 		strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
2646 		return (PICL_SUCCESS);
2647 	}
2648 
2649 	device = (frutree_device_args_t *)malloc(
2650 			sizeof (frutree_device_args_t));
2651 	if (device == NULL) {
2652 		return (PICL_NOSPACE);
2653 	}
2654 	device->first  = NULL;
2655 	device->last   = NULL;
2656 
2657 	if ((rc = probe_libdevinfo(frup, &device, load_drivers)) !=
2658 		PICL_SUCCESS) {
2659 		free_cache(device->first);
2660 		free(device);
2661 		return (rc);
2662 	}
2663 
2664 	if (device->first != NULL) {
2665 		if ((rc = create_fru_children(frup, *device)) != PICL_SUCCESS) {
2666 			free_cache(device->first);
2667 			free(device);
2668 			return (rc);
2669 		}
2670 	}
2671 	free_cache(device->first);
2672 	free(device);
2673 
2674 	/* now create the scsi nodes for this fru */
2675 	if ((rc = probe_for_scsi_frus(frup)) != PICL_SUCCESS) {
2676 		return (rc);
2677 	}
2678 	return (PICL_SUCCESS);
2679 }
2680 
2681 /*
2682  * callback function for ptree_walk_tree_by_class,
2683  * used to update hashtable during DR_HINT_REMOVE event
2684  */
2685 /*ARGSUSED*/
2686 static int
frutree_update_hash(picl_nodehdl_t nodeh,void * c_args)2687 frutree_update_hash(picl_nodehdl_t nodeh, void *c_args)
2688 {
2689 	picl_errno_t rc = 0;
2690 	if ((rc = hash_remove_entry(nodeh)) != PICL_SUCCESS) {
2691 		return (rc);
2692 	}
2693 	return (PICL_WALK_CONTINUE);
2694 }
2695 
2696 /*
2697  * routine to handle  DR_HINT_REMOVE
2698  */
2699 static picl_errno_t
handle_fru_remove(frutree_frunode_t * frup)2700 handle_fru_remove(frutree_frunode_t *frup)
2701 {
2702 	picl_errno_t	rc = PICL_SUCCESS;
2703 
2704 	if (frup == NULL) {
2705 		return (PICL_FAILURE);
2706 	}
2707 
2708 	if ((rc = ptree_walk_tree_by_class(frup->frunodeh,
2709 		NULL, NULL, frutree_update_hash)) != PICL_SUCCESS) {
2710 		return (rc);
2711 	}
2712 	(void) ptree_delete_node(frup->frunodeh);
2713 	(void) ptree_destroy_node(frup->frunodeh);
2714 	if ((rc = hash_remove_entry(frup->frunodeh)) !=
2715 		PICL_SUCCESS) {
2716 		return (rc);
2717 	}
2718 	return (PICL_SUCCESS);
2719 }
2720 
2721 /* remove State and Condition props for all the nodes under fru */
2722 /*ARGSUSED*/
2723 static int
frutree_handle_unconfigure(picl_nodehdl_t nodeh,void * c_args)2724 frutree_handle_unconfigure(picl_nodehdl_t nodeh, void *c_args)
2725 {
2726 	picl_errno_t rc = 0;
2727 	picl_prophdl_t proph;
2728 	char class[PICL_PROPNAMELEN_MAX];
2729 
2730 	if (ptree_get_prop_by_name(nodeh, PICL_PROP_STATE,
2731 		&proph) == PICL_SUCCESS) {
2732 		(void) ptree_delete_prop(proph);
2733 		(void) ptree_destroy_prop(proph);
2734 	}
2735 	if (ptree_get_prop_by_name(nodeh, PICL_PROP_STATUS_TIME,
2736 		&proph) == PICL_SUCCESS) {
2737 		(void) ptree_delete_prop(proph);
2738 		(void) ptree_destroy_prop(proph);
2739 	}
2740 
2741 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2742 		class, sizeof (class))) != PICL_SUCCESS) {
2743 		return (rc);
2744 	}
2745 
2746 	if (strcmp(class, PICL_CLASS_PORT) == 0) {
2747 		if (ptree_get_prop_by_name(nodeh, PICL_PROP_CONDITION,
2748 			&proph) == PICL_SUCCESS) {
2749 			(void) ptree_delete_prop(proph);
2750 			(void) ptree_destroy_prop(proph);
2751 		}
2752 		if (ptree_get_prop_by_name(nodeh, PICL_PROP_CONDITION_TIME,
2753 			&proph) == PICL_SUCCESS) {
2754 			(void) ptree_delete_prop(proph);
2755 			(void) ptree_destroy_prop(proph);
2756 		}
2757 		/* delete devices table */
2758 		if (ptree_get_prop_by_name(nodeh, PICL_PROP_DEVICES,
2759 			&proph) ==  PICL_SUCCESS) {
2760 			(void) ptree_delete_prop(proph);
2761 			(void) ptree_destroy_prop(proph);
2762 		}
2763 	}
2764 	return (PICL_WALK_CONTINUE);
2765 }
2766 
2767 /*
2768  * traverse thru each node fru node and do cleanup
2769  */
2770 static picl_errno_t
handle_fru_unconfigure(frutree_frunode_t * frup)2771 handle_fru_unconfigure(frutree_frunode_t *frup)
2772 {
2773 	picl_errno_t rc = 0, retval = 0;
2774 	picl_prophdl_t	proph;
2775 	picl_nodehdl_t childh, peerh, nodeh;
2776 	hashdata_t *hashptr = NULL;
2777 	frutree_frunode_t *child_frup = NULL;
2778 	char class[PICL_PROPNAMELEN_MAX];
2779 
2780 	if (frup == NULL) {
2781 		return (PICL_FAILURE);
2782 	}
2783 
2784 	/* delete devices table */
2785 	if (ptree_get_prop_by_name(frup->frunodeh, PICL_PROP_DEVICES,
2786 		&proph) == PICL_SUCCESS) {
2787 		(void) ptree_delete_prop(proph);
2788 		(void) ptree_destroy_prop(proph);
2789 	}
2790 
2791 	/* delete Environment devices table */
2792 	if (ptree_get_prop_by_name(frup->frunodeh, PICL_PROP_ENV,
2793 		&proph) == PICL_SUCCESS) {
2794 		(void) ptree_delete_prop(proph);
2795 		(void) ptree_destroy_prop(proph);
2796 	}
2797 
2798 	if ((rc = ptree_walk_tree_by_class(frup->frunodeh,
2799 		NULL, NULL, frutree_handle_unconfigure)) != PICL_SUCCESS) {
2800 		return (rc);
2801 	}
2802 
2803 	/* remove all the fru nodes under the child locations */
2804 	retval = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_CHILD,
2805 		&peerh, sizeof (peerh));
2806 	while (retval ==  PICL_SUCCESS) {
2807 		nodeh = peerh;
2808 		retval = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
2809 			&peerh, sizeof (peerh));
2810 		if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2811 			class, sizeof (class))) != PICL_SUCCESS) {
2812 			return (rc);
2813 		}
2814 
2815 		if (strcmp(class, PICL_CLASS_PORT) == 0) {
2816 			continue;
2817 		}
2818 
2819 		/* if the child location has fru, delete the fru */
2820 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
2821 			&childh, sizeof (childh)) !=  PICL_SUCCESS) {
2822 			continue;
2823 		}
2824 
2825 		/* child is present under the location */
2826 		if ((rc = hash_lookup_entry(childh, (void **)&hashptr)) !=
2827 			PICL_SUCCESS) {
2828 			return (rc);
2829 		}
2830 		child_frup = FRUDATA_PTR(hashptr);
2831 		(void) handle_fru_remove(child_frup);
2832 	}
2833 	return (PICL_SUCCESS);
2834 }
2835 
2836 /*
2837  * create the properties under the fru
2838  */
2839 static picl_errno_t
create_fru_props(frutree_frunode_t * frup)2840 create_fru_props(frutree_frunode_t *frup)
2841 {
2842 	picl_errno_t rc;
2843 	uint64_t ap_status_time = 0;
2844 	boolean_t state_change;
2845 
2846 	/* create state props */
2847 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
2848 		PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
2849 		PICL_PROP_STATE, get_fru_state, NULLWRITE,
2850 		frup->frunodeh, NULL, fru_state[frup->state])) !=
2851 		PICL_SUCCESS) {
2852 		FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2853 			PICL_PROP_STATE, frup->name, rc);
2854 	}
2855 
2856 	ap_status_time = (uint64_t)(time(NULL));
2857 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
2858 		sizeof (ap_status_time), PICL_PROP_STATUS_TIME,
2859 		NULLREAD, NULLWRITE, frup->frunodeh,
2860 		NULL, &ap_status_time)) != PICL_SUCCESS) {
2861 		FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2862 			PICL_PROP_STATUS_TIME, frup->name, rc);
2863 	}
2864 
2865 	if ((rc = update_fru_state(frup, &state_change)) != PICL_SUCCESS) {
2866 		FRUTREE_DEBUG2(EVENTS, GET_FRU_STATE_ERR, frup->name, rc);
2867 		return (rc);
2868 	}
2869 
2870 	/* create condition props */
2871 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
2872 		PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
2873 		PICL_PROP_CONDITION, get_fru_condition, NULLWRITE,
2874 		frup->frunodeh, NULL, fru_cond[frup->cond])) !=
2875 		PICL_SUCCESS) {
2876 		FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2877 			PICL_PROP_CONDITION, frup->name, rc);
2878 	}
2879 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
2880 		sizeof (ap_status_time), PICL_PROP_CONDITION_TIME,
2881 		NULLREAD, NULLWRITE, frup->frunodeh, NULL,
2882 		&ap_status_time)) != PICL_SUCCESS) {
2883 		FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2884 			PICL_PROP_CONDITION_TIME, frup->name, rc);
2885 	}
2886 
2887 	if ((rc = update_fru_condition(frup, &state_change)) != PICL_SUCCESS) {
2888 		FRUTREE_DEBUG2(EVENTS, GET_FRU_COND_ERR, frup->name, rc);
2889 		return (rc);
2890 	}
2891 
2892 	/* create admin lock prop */
2893 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
2894 		PICL_READ + PICL_WRITE, PICL_PROPNAMELEN_MAX,
2895 		PICL_PROP_ADMIN_LOCK, NULLREAD, NULLWRITE,
2896 		frup->frunodeh, NULL, PICL_ADMINLOCK_DISABLED)) !=
2897 		PICL_SUCCESS) {
2898 		FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2899 			PICL_PROP_ADMIN_LOCK, frup->name, rc);
2900 	}
2901 	return (rc);
2902 }
2903 
2904 /*
2905  * calls libcfgadm API to do a connect on a location
2906  */
2907 static picl_errno_t
connect_fru(frutree_locnode_t * locp)2908 connect_fru(frutree_locnode_t	*locp)
2909 {
2910 	picl_errno_t	rc;
2911 	cfga_err_t	ap_list_err;
2912 	cfga_flags_t	flags = 0;
2913 	boolean_t	state_change;
2914 	uint64_t	ap_status_time;
2915 	hrtime_t	start;
2916 	hrtime_t	end;
2917 
2918 	if (locp == NULL) {
2919 		return (PICL_FAILURE);
2920 	}
2921 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
2922 		PICLEVENTARGVAL_CONNECTING, loc_state[locp->state],
2923 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
2924 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
2925 			locp->name, PICLEVENT_STATE_CHANGE, rc);
2926 	}
2927 
2928 	(void) pthread_mutex_lock(&locp->mutex);
2929 	locp->dr_in_progress = B_TRUE;
2930 	(void) pthread_mutex_unlock(&locp->mutex);
2931 
2932 	if (frutree_debug & PERF_DATA) {
2933 		start = gethrtime();
2934 	}
2935 	ap_list_err = config_change_state(CFGA_CMD_CONNECT, 1, &(locp->name),
2936 		NULL, NULL, NULL, NULL, flags);
2937 
2938 	if (frutree_debug & PERF_DATA) {
2939 		end = gethrtime();
2940 		FRUTREE_DEBUG2(PERF_DATA, "time for connect on %s: %lld nsec",
2941 			locp->name, (end - start));
2942 	}
2943 	if (ap_list_err != CFGA_OK) {
2944 		(void) pthread_mutex_lock(&locp->mutex);
2945 		locp->dr_in_progress = B_FALSE;
2946 		(void) pthread_mutex_unlock(&locp->mutex);
2947 
2948 		/* release mutex before updating state */
2949 		(void) update_loc_state(locp, &state_change);
2950 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
2951 			loc_state[locp->state], PICLEVENTARGVAL_CONNECTING,
2952 			locp->locnodeh, WAIT)) != PICL_SUCCESS) {
2953 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
2954 				locp->name, PICLEVENT_STATE_CHANGE, rc);
2955 		}
2956 		if (locp->state == LOC_STATE_CONNECTED) {
2957 			/* wakeup threads sleeping on this condition */
2958 			(void) pthread_mutex_lock(&locp->mutex);
2959 			(void) pthread_cond_broadcast(&locp->cond_cv);
2960 			(void) pthread_mutex_unlock(&locp->mutex);
2961 			return (PICL_SUCCESS);
2962 		}
2963 		return (cfg2picl_errmap[ap_list_err][1]);
2964 	}
2965 	(void) pthread_mutex_lock(&locp->mutex);
2966 
2967 	locp->dr_in_progress = B_FALSE;
2968 	locp->prev_state = LOC_STATE_DISCONNECTED;
2969 	locp->state = LOC_STATE_CONNECTED;
2970 	ap_status_time = (uint64_t)(time(NULL));
2971 	if ((rc = ptree_update_propval_by_name(locp->locnodeh,
2972 		PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
2973 		sizeof (ap_status_time))) != PICL_SUCCESS) {
2974 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2975 			PICL_PROP_STATUS_TIME, locp->name, rc);
2976 	}
2977 
2978 	/* wakeup threads sleeping on this condition */
2979 	(void) pthread_cond_broadcast(&locp->cond_cv);
2980 	(void) pthread_mutex_unlock(&locp->mutex);
2981 
2982 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
2983 		PICLEVENTARGVAL_CONNECTED, PICLEVENTARGVAL_CONNECTING,
2984 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
2985 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
2986 			locp->name, PICLEVENT_STATE_CHANGE, rc);
2987 	}
2988 	return (PICL_SUCCESS);
2989 }
2990 
2991 /*
2992  * calls libcfgadm API to do a disconnect on a location
2993  */
2994 static picl_errno_t
disconnect_fru(frutree_locnode_t * locp)2995 disconnect_fru(frutree_locnode_t *locp)
2996 {
2997 	picl_errno_t rc;
2998 	picl_nodehdl_t childh;
2999 	hashdata_t *hashptr = NULL;
3000 	timestruc_t to;
3001 	struct timeval tp;
3002 	hrtime_t start, end;
3003 	cfga_err_t ap_list_err;
3004 	cfga_flags_t flags = 0;
3005 	boolean_t state_change;
3006 	uint64_t ap_status_time;
3007 	frutree_frunode_t *frup = NULL;
3008 
3009 	if (locp == NULL) {
3010 		return (PICL_FAILURE);
3011 	}
3012 
3013 	(void) pthread_mutex_lock(&locp->mutex);
3014 	if (locp->state == LOC_STATE_DISCONNECTED) {
3015 		(void) pthread_mutex_unlock(&locp->mutex);
3016 		return (PICL_SUCCESS);
3017 	}
3018 	(void) pthread_mutex_unlock(&locp->mutex);
3019 
3020 	/* get the child fru information */
3021 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
3022 		&childh, sizeof (childh)) == PICL_SUCCESS) {
3023 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
3024 			PICL_SUCCESS) {
3025 			frup = FRUDATA_PTR(hashptr);
3026 		}
3027 	}
3028 
3029 	if (frup == NULL) {
3030 		return (PICL_SUCCESS);
3031 	}
3032 
3033 	(void) pthread_mutex_lock(&frup->mutex);
3034 
3035 	(void) gettimeofday(&tp, NULL);
3036 	to.tv_sec = tp.tv_sec + frutree_drwait_time;
3037 	to.tv_nsec = tp.tv_usec * 1000;
3038 
3039 	if (frup->state != FRU_STATE_UNCONFIGURED) {
3040 		(void) pthread_cond_timedwait(&frup->cond_cv,
3041 			&frup->mutex, &to);
3042 	}
3043 
3044 	if (frup->state != FRU_STATE_UNCONFIGURED) {
3045 		FRUTREE_DEBUG1(LOG_ERR, "SUNW_frutree:Disconnect operation on"
3046 			" %s failed", locp->name);
3047 		(void) pthread_mutex_unlock(&frup->mutex);
3048 		return (PICL_FAILURE);
3049 	}
3050 	(void) pthread_mutex_unlock(&frup->mutex);
3051 
3052 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3053 		PICLEVENTARGVAL_DISCONNECTING, loc_state[locp->state],
3054 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
3055 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3056 			locp->name, PICLEVENT_STATE_CHANGE, rc);
3057 	}
3058 
3059 	(void) pthread_mutex_lock(&locp->mutex);
3060 	locp->dr_in_progress = B_TRUE;
3061 	(void) pthread_mutex_unlock(&locp->mutex);
3062 
3063 	if (frutree_debug & PERF_DATA) {
3064 		start = gethrtime();
3065 	}
3066 
3067 	ap_list_err = config_change_state(CFGA_CMD_DISCONNECT, 1, &(locp->name),
3068 		NULL, NULL, NULL, NULL, flags);
3069 	if (frutree_debug & PERF_DATA) {
3070 		end = gethrtime();
3071 		FRUTREE_DEBUG2(PERF_DATA, "time for disconnect on %s: %lld ns",
3072 			locp->name, (end - start));
3073 	}
3074 	if (ap_list_err != CFGA_OK) {
3075 		(void) pthread_mutex_lock(&locp->mutex);
3076 		locp->dr_in_progress = B_FALSE;
3077 		(void) pthread_mutex_unlock(&locp->mutex);
3078 
3079 		/* release mutex before updating state */
3080 		(void) update_loc_state(locp, &state_change);
3081 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3082 			loc_state[locp->state], PICLEVENTARGVAL_DISCONNECTING,
3083 			locp->locnodeh, WAIT)) != PICL_SUCCESS) {
3084 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3085 				locp->name, PICLEVENT_STATE_CHANGE, rc);
3086 		}
3087 		(void) pthread_mutex_lock(&locp->mutex);
3088 		if (locp->state == LOC_STATE_DISCONNECTED) {
3089 			(void) pthread_mutex_unlock(&locp->mutex);
3090 			return (PICL_SUCCESS);
3091 		}
3092 		(void) pthread_mutex_unlock(&locp->mutex);
3093 		return (cfg2picl_errmap[ap_list_err][1]);
3094 	}
3095 	(void) pthread_mutex_lock(&locp->mutex);
3096 	locp->dr_in_progress = B_FALSE;
3097 	locp->prev_state = LOC_STATE_CONNECTED;
3098 	locp->state = LOC_STATE_DISCONNECTED;
3099 	ap_status_time = (uint64_t)(time(NULL));
3100 	if ((rc = ptree_update_propval_by_name(locp->locnodeh,
3101 		PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
3102 		sizeof (ap_status_time))) != PICL_SUCCESS) {
3103 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
3104 			PICL_PROP_STATUS_TIME, locp->name, rc);
3105 	}
3106 	(void) pthread_mutex_unlock(&locp->mutex);
3107 
3108 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3109 		PICLEVENTARGVAL_DISCONNECTED, PICLEVENTARGVAL_DISCONNECTING,
3110 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
3111 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3112 			locp->name, PICLEVENT_STATE_CHANGE, rc);
3113 	}
3114 	return (PICL_SUCCESS);
3115 }
3116 
3117 /*
3118  * Handle DR_INCOMING_RES event
3119  */
3120 static void
handle_fru_configure(frutree_frunode_t * frup)3121 handle_fru_configure(frutree_frunode_t *frup)
3122 {
3123 	picl_errno_t rc;
3124 	boolean_t cond_changed;
3125 
3126 	if (frup == NULL)
3127 		return;
3128 
3129 	if ((rc = probe_fru(frup, B_FALSE)) != PICL_SUCCESS) {
3130 		FRUTREE_DEBUG2(EVENTS, PROBE_FRU_ERR, frup->name, rc);
3131 	}
3132 
3133 	/* update the  fru condition */
3134 	(void) update_fru_condition(frup, &cond_changed);
3135 	if (cond_changed) {
3136 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3137 			fru_cond[frup->cond], fru_cond[frup->prev_cond],
3138 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3139 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3140 				frup->name, PICLEVENT_CONDITION_CHANGE, rc);
3141 		}
3142 	}
3143 
3144 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3145 		fru_state[frup->state], fru_state[frup->prev_state],
3146 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3147 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3148 			frup->name, PICLEVENT_STATE_CHANGE, rc);
3149 	}
3150 }
3151 
3152 /*
3153  * call libcfgadm API to configure a fru
3154  * (Handle DR_INCOMING_RES event)
3155  */
3156 static picl_errno_t
configure_fru(frutree_frunode_t * frup,cfga_flags_t flags)3157 configure_fru(frutree_frunode_t *frup, cfga_flags_t flags)
3158 {
3159 	picl_errno_t rc;
3160 	picl_nodehdl_t parenth;
3161 	timestruc_t to;
3162 	struct timeval tp;
3163 	hrtime_t start, end;
3164 	cfga_err_t ap_list_err;
3165 	uint64_t ap_status_time;
3166 	hashdata_t *hashptr = NULL;
3167 	frutree_locnode_t *locp = NULL;
3168 	boolean_t state_change, cond_changed;
3169 
3170 	if (frup == NULL) {
3171 		return (PICL_FAILURE);
3172 	}
3173 
3174 	(void) pthread_mutex_lock(&frup->mutex);
3175 	if (frup->state == FRU_STATE_CONFIGURED) {
3176 		(void) pthread_mutex_unlock(&frup->mutex);
3177 		ap_list_err = config_change_state(CFGA_CMD_CONFIGURE, 1,
3178 			&(frup->name), NULL, NULL, NULL, NULL, flags);
3179 		return (PICL_SUCCESS);
3180 	}
3181 	(void) pthread_mutex_unlock(&frup->mutex);
3182 
3183 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
3184 		&parenth, sizeof (parenth))) != PICL_SUCCESS) {
3185 		return (rc);
3186 	}
3187 
3188 	if ((rc = hash_lookup_entry(parenth, (void **)&hashptr)) !=
3189 		PICL_SUCCESS) {
3190 		return (rc);
3191 	}
3192 	locp = LOCDATA_PTR(hashptr);
3193 	if (locp == NULL) {
3194 		return (PICL_FAILURE);
3195 	}
3196 
3197 	(void) pthread_mutex_lock(&locp->mutex);
3198 
3199 	(void) gettimeofday(&tp, NULL);
3200 	to.tv_sec = tp.tv_sec + frutree_drwait_time;
3201 	to.tv_nsec = tp.tv_usec * 1000;
3202 
3203 	/* wait for sometime for location to get connected */
3204 	if (locp->state != LOC_STATE_CONNECTED) {
3205 		(void) pthread_cond_timedwait(&locp->cond_cv,
3206 			&locp->mutex, &to);
3207 	}
3208 
3209 	if (locp->state != LOC_STATE_CONNECTED) {	/* give up */
3210 		FRUTREE_DEBUG1(EVENTS, "SUNW_frutree:Configure operation on"
3211 			" %s failed as loc is not connected", locp->name);
3212 		(void) pthread_mutex_unlock(&locp->mutex);
3213 		return (PICL_FAILURE);
3214 	}
3215 	(void) pthread_mutex_unlock(&locp->mutex);
3216 
3217 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3218 		PICLEVENTARGVAL_CONFIGURING, fru_state[frup->state],
3219 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3220 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3221 			frup->name, PICLEVENT_STATE_CHANGE, rc);
3222 	}
3223 
3224 	(void) pthread_mutex_lock(&frup->mutex);
3225 	frup->dr_in_progress = B_TRUE;
3226 	(void) pthread_mutex_unlock(&frup->mutex);
3227 
3228 	if (frutree_debug & PERF_DATA) {
3229 		start = gethrtime();
3230 	}
3231 	ap_list_err = config_change_state(CFGA_CMD_CONFIGURE, 1,
3232 		&(frup->name), NULL, NULL, NULL, NULL, flags);
3233 
3234 	if (frutree_debug & PERF_DATA) {
3235 		end = gethrtime();
3236 		FRUTREE_DEBUG2(PERF_DATA, "time for configure on %s: %lld nsec",
3237 			frup->name, (end - start));
3238 	}
3239 
3240 	if (ap_list_err != CFGA_OK) {
3241 		(void) pthread_mutex_lock(&frup->mutex);
3242 		frup->dr_in_progress = B_FALSE;
3243 		(void) pthread_mutex_unlock(&frup->mutex);
3244 		/* release mutex before updating state */
3245 		(void) update_fru_state(frup, &state_change);
3246 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3247 			fru_state[frup->state], PICLEVENTARGVAL_CONFIGURING,
3248 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3249 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3250 				frup->name, PICLEVENT_STATE_CHANGE, rc);
3251 		}
3252 		/* update the  fru condition */
3253 		(void) update_fru_condition(frup, &state_change);
3254 		if (state_change) {
3255 			if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3256 				fru_cond[frup->cond], fru_cond[frup->prev_cond],
3257 				frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3258 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3259 					frup->name, PICLEVENT_CONDITION_CHANGE,
3260 					rc);
3261 			}
3262 		}
3263 		return (cfg2picl_errmap[ap_list_err][1]);
3264 	}
3265 	(void) pthread_mutex_lock(&frup->mutex);
3266 	frup->dr_in_progress = B_FALSE;
3267 	frup->prev_state = FRU_STATE_UNCONFIGURED;
3268 	frup->state = FRU_STATE_CONFIGURED;
3269 	ap_status_time = (uint64_t)(time(NULL));
3270 	if ((rc = ptree_update_propval_by_name(frup->frunodeh,
3271 		PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
3272 		sizeof (ap_status_time))) != PICL_SUCCESS) {
3273 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
3274 			PICL_PROP_STATUS_TIME, frup->name, rc);
3275 	}
3276 	(void) pthread_mutex_unlock(&frup->mutex);
3277 
3278 	if ((rc = probe_fru(frup, B_FALSE)) != PICL_SUCCESS) {
3279 		FRUTREE_DEBUG2(FRUTREE_INIT, PROBE_FRU_ERR, frup->name, rc);
3280 	}
3281 	/* update the  fru condition */
3282 	(void) update_fru_condition(frup, &cond_changed);
3283 	if (cond_changed) {
3284 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3285 			fru_cond[frup->cond], fru_cond[frup->prev_cond],
3286 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3287 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3288 				frup->name, PICLEVENT_CONDITION_CHANGE, rc);
3289 		}
3290 	}
3291 
3292 	/* send the state change event */
3293 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3294 		fru_state[frup->state], PICLEVENTARGVAL_CONFIGURING,
3295 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3296 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3297 			frup->name, PICLEVENT_STATE_CHANGE, rc);
3298 	}
3299 	return (PICL_SUCCESS);
3300 }
3301 
3302 /*
3303  * Handle DR_OUTGOING_RES event
3304  * (call libcfgadm API to unconfigure a fru)
3305  */
3306 static picl_errno_t
unconfigure_fru(frutree_frunode_t * frup,cfga_flags_t flags)3307 unconfigure_fru(frutree_frunode_t *frup, cfga_flags_t flags)
3308 {
3309 	picl_errno_t	rc;
3310 	cfga_err_t	ap_list_err;
3311 	boolean_t	state_change;
3312 	uint64_t	ap_status_time;
3313 	hrtime_t	start;
3314 	hrtime_t	end;
3315 
3316 	if (frup == NULL) {
3317 		return (PICL_FAILURE);
3318 	}
3319 
3320 	(void) pthread_mutex_lock(&frup->mutex);
3321 	if (frup->state == FRU_STATE_UNCONFIGURED) {
3322 		(void) pthread_mutex_unlock(&frup->mutex);
3323 		return (PICL_SUCCESS);
3324 	}
3325 	(void) pthread_mutex_unlock(&frup->mutex);
3326 
3327 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3328 		PICLEVENTARGVAL_UNCONFIGURING, fru_state[frup->state],
3329 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3330 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3331 			frup->name, PICLEVENT_STATE_CHANGE, rc);
3332 	}
3333 
3334 	(void) pthread_mutex_lock(&frup->mutex);
3335 	while (frup->busy == B_TRUE) {
3336 		(void) pthread_cond_wait(&frup->busy_cond_cv,
3337 			&frup->mutex);
3338 	}
3339 
3340 	frup->dr_in_progress = B_TRUE;
3341 	(void) pthread_mutex_unlock(&frup->mutex);
3342 
3343 	if (frutree_debug & PERF_DATA) {
3344 		start = gethrtime();
3345 	}
3346 	ap_list_err = config_change_state(CFGA_CMD_UNCONFIGURE, 1,
3347 		&(frup->name), NULL, NULL, NULL, NULL, flags);
3348 	if (frutree_debug & PERF_DATA) {
3349 		end = gethrtime();
3350 		FRUTREE_DEBUG2(PERF_DATA, "time for unconfigure on %s: %lld ns",
3351 			frup->name, (end - start));
3352 	}
3353 	if (ap_list_err != CFGA_OK) {
3354 		/*
3355 		 * call configure again (workaround for
3356 		 * ENUM# to get generated for next attempt)
3357 		 */
3358 		config_change_state(CFGA_CMD_CONFIGURE, 1,
3359 			&(frup->name), NULL, NULL, NULL, NULL, flags);
3360 
3361 		(void) pthread_mutex_lock(&frup->mutex);
3362 		frup->dr_in_progress = B_FALSE;
3363 		(void) pthread_mutex_unlock(&frup->mutex);
3364 
3365 		/* release mutex before updating state */
3366 		(void) update_fru_condition(frup, &state_change);
3367 		if (state_change) {
3368 			if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3369 				fru_cond[frup->cond], fru_cond[frup->prev_cond],
3370 				frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3371 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3372 					frup->name, PICLEVENT_CONDITION_CHANGE,
3373 					rc);
3374 			}
3375 		}
3376 		(void) update_fru_state(frup, &state_change);
3377 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3378 			fru_state[frup->state], PICLEVENTARGVAL_UNCONFIGURING,
3379 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3380 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3381 				frup->name, PICLEVENT_STATE_CHANGE, rc);
3382 		}
3383 		return (cfg2picl_errmap[ap_list_err][1]);
3384 	}
3385 
3386 	(void) pthread_mutex_lock(&frup->mutex);
3387 
3388 	frup->dr_in_progress = B_FALSE;
3389 	frup->prev_state = FRU_STATE_CONFIGURED;
3390 	frup->state = FRU_STATE_UNCONFIGURED;
3391 	ap_status_time = (uint64_t)(time(NULL));
3392 	if ((rc = ptree_update_propval_by_name(frup->frunodeh,
3393 		PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
3394 		sizeof (ap_status_time))) != PICL_SUCCESS) {
3395 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
3396 			PICL_PROP_STATUS_TIME, frup->name, rc);
3397 	}
3398 	/* wakeup threads sleeping on this condition */
3399 	(void) pthread_cond_broadcast(&frup->cond_cv);
3400 	(void) pthread_mutex_unlock(&frup->mutex);
3401 
3402 	/* update the  fru condition */
3403 	if ((rc = update_fru_condition(frup, &state_change)) != PICL_SUCCESS) {
3404 			FRUTREE_DEBUG2(EVENTS, GET_FRU_STATE_ERR,
3405 				frup->name, rc);
3406 	}
3407 	if (state_change) {
3408 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3409 			fru_cond[frup->cond], fru_cond[frup->prev_cond],
3410 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3411 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3412 				frup->name, PICLEVENT_CONDITION_CHANGE, rc);
3413 		}
3414 	}
3415 
3416 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
3417 		PICLEVENTARGVAL_UNCONFIGURED, PICLEVENTARGVAL_UNCONFIGURING,
3418 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3419 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3420 			frup->name, PICLEVENT_STATE_CHANGE, rc);
3421 	}
3422 	return (PICL_SUCCESS);
3423 }
3424 
3425 /* creates fru nodes with basic properties and sends out intializing events */
3426 static int
create_fru_node(frutree_locnode_t * locp,frutree_frunode_t ** child_frupp)3427 create_fru_node(frutree_locnode_t *locp, frutree_frunode_t **child_frupp)
3428 {
3429 	picl_errno_t rc;
3430 	hashdata_t *fru_data = NULL;
3431 	frutree_frunode_t *frup = NULL;
3432 	picl_nodehdl_t fruh, child;
3433 	char slot_type[PICL_PROPNAMELEN_MAX];
3434 	char fru_name[PICL_PROPNAMELEN_MAX];
3435 	char apid_type[PICL_PROPNAMELEN_MAX];
3436 	boolean_t fru_present = B_FALSE;
3437 	boolean_t state_changed = B_FALSE;
3438 
3439 	if (locp->state == LOC_STATE_EMPTY) {
3440 		return (PICL_SUCCESS);
3441 	}
3442 
3443 	/* check if fru is present or not */
3444 	rc = ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
3445 		&child, sizeof (picl_nodehdl_t));
3446 	if (rc == PICL_SUCCESS) {
3447 		fru_present = B_TRUE;
3448 		fruh = child;
3449 		(void) ptree_get_propval_by_name(child, PICL_PROP_NAME,
3450 			fru_name, sizeof (fru_name));
3451 	}
3452 
3453 	/* create fru node */
3454 	if (fru_present == B_FALSE) {
3455 		(void) strncpy(fru_name, locp->name, sizeof (fru_name));
3456 		if ((rc = ptree_create_node(fru_name, PICL_CLASS_FRU,
3457 			&fruh)) != PICL_SUCCESS) {
3458 			return (rc);
3459 		}
3460 	}
3461 
3462 	/* initialize internal data structures */
3463 	if ((rc = make_fru_data(fru_name, &fru_data)) != PICL_SUCCESS) {
3464 		return (rc);
3465 	}
3466 	frup = FRUDATA_PTR(fru_data);
3467 
3468 	frup->frunodeh = fruh;
3469 	frup->cpu_node = locp->cpu_node;
3470 	frup->state_mgr = locp->state_mgr;
3471 	*child_frupp = frup;
3472 
3473 	if ((rc = hash_add_entry(fruh, (void *)(fru_data))) != PICL_SUCCESS) {
3474 		(void) ptree_destroy_node(fruh);
3475 		free_data(FRU_TYPE, (fru_data));
3476 		return (rc);
3477 	}
3478 
3479 	if (locp->state_mgr == STATIC_LOC) {
3480 		if ((rc = ptree_get_propval_by_name(locp->locnodeh,
3481 			PICL_PROP_SLOT_TYPE, slot_type,
3482 			sizeof (slot_type))) == PICL_SUCCESS) {
3483 			(void) strncpy(apid_type, slot_type,
3484 				sizeof (apid_type));
3485 		}
3486 	}
3487 
3488 	/* create fru type property */
3489 	if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
3490 		PICL_PROPNAMELEN_MAX, PICL_PROP_FRU_TYPE, NULLREAD,
3491 		NULLWRITE, fruh, NULL, apid_type)) !=
3492 		PICL_SUCCESS) {
3493 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
3494 			PICL_PROP_FRU_TYPE, frup->name, rc);
3495 	}
3496 
3497 	if (fru_present == B_FALSE) {
3498 		if ((rc = ptree_add_node(locp->locnodeh, fruh)) !=
3499 			PICL_SUCCESS) {
3500 			(void) ptree_destroy_node(fruh);
3501 			(void) hash_remove_entry(fruh);
3502 			return (rc);
3503 		}
3504 	}
3505 
3506 	if (locp->state_mgr == PLUGIN_PVT) {
3507 		(void) update_fru_state(frup, &state_changed);
3508 		return (PICL_SUCCESS);
3509 	}
3510 
3511 	if ((rc = create_fru_props(frup)) != PICL_SUCCESS) {
3512 		return (rc);
3513 	}
3514 	return (PICL_SUCCESS);
3515 }
3516 
3517 static picl_errno_t
add_node2cache(picl_nodehdl_t nodeh,char * class,frutree_cache_t ** cacheptr)3518 add_node2cache(picl_nodehdl_t nodeh, char *class, frutree_cache_t **cacheptr)
3519 {
3520 	int instance;
3521 	picl_errno_t rc;
3522 	char driver[PICL_PROPNAMELEN_MAX];
3523 	char bus_addr[PICL_PROPNAMELEN_MAX];
3524 	char devfs_path[PICL_PROPNAMELEN_MAX];
3525 	char node_name[PICL_PROPNAMELEN_MAX];
3526 	char port_type[PICL_PROPNAMELEN_MAX];
3527 	char label[PICL_PROPNAMELEN_MAX];
3528 	frutree_cache_t	*cachep = NULL;
3529 
3530 	if (strcmp(class, SANIBEL_NETWORK_PORT) == 0) {
3531 		(void) strncpy(label, SANIBEL_NETWORK_LABEL, sizeof (label));
3532 		(void) strncpy(node_name, PICL_CLASS_PORT, sizeof (node_name));
3533 		(void) strncpy(port_type, SANIBEL_NETWORK_PORT,
3534 			sizeof (port_type));
3535 
3536 	} else if (strcmp(class, SANIBEL_SERIAL_PORT) == 0) {
3537 		(void) strncpy(label, SANIBEL_SERIAL_PORT, sizeof (label));
3538 		(void) strncpy(node_name, PICL_CLASS_PORT, sizeof (node_name));
3539 		(void) strncpy(port_type, SANIBEL_SERIAL_PORT,
3540 			sizeof (port_type));
3541 
3542 	} else if (strcmp(class, SANIBEL_PARALLEL_PORT) == 0) {
3543 		(void) strncpy(label, SANIBEL_PARALLEL_PORT, sizeof (label));
3544 		(void) strncpy(node_name, PICL_CLASS_PORT, sizeof (node_name));
3545 		(void) strncpy(port_type, SANIBEL_PARALLEL_PORT,
3546 			sizeof (port_type));
3547 
3548 	} else {
3549 		return (PICL_FAILURE);
3550 	}
3551 
3552 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_INSTANCE,
3553 		&instance, sizeof (instance))) != PICL_SUCCESS) {
3554 		return (rc);
3555 	}
3556 
3557 	/* load the driver */
3558 	if (instance < 0) {
3559 		attach_driver(driver);
3560 	}
3561 
3562 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
3563 		devfs_path, sizeof (devfs_path))) != PICL_SUCCESS) {
3564 		return (rc);
3565 	}
3566 
3567 	/* get either bus address or unit address */
3568 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_BUS_ADDR, bus_addr,
3569 		sizeof (bus_addr))) != PICL_SUCCESS) {
3570 		if ((rc = ptree_get_propval_by_name(nodeh,
3571 			PICL_PROP_UNIT_ADDRESS, bus_addr,
3572 			sizeof (bus_addr))) != PICL_SUCCESS) {
3573 			return (rc);
3574 		}
3575 	}
3576 
3577 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_DRIVER_NAME,
3578 		driver, sizeof (driver))) != PICL_SUCCESS) {
3579 		return (rc);
3580 	}
3581 
3582 	cachep = (frutree_cache_t *)malloc(sizeof (frutree_cache_t));
3583 	if (NULL == cachep) {
3584 		return (PICL_NOSPACE);
3585 	}
3586 	cachep->buf[0] = '\0';
3587 
3588 	/* update the cache buffer in PICL configuration format */
3589 	(void) snprintf(cachep->buf, sizeof (cachep->buf),
3590 		"\n%s %s%d %s\n"
3591 		"\t%s %s %s %s 0 \"%s %d\"\n"
3592 		"\t%s %s %s %s 0 \"%s\"\n"
3593 		"\t%s %s %s %s 1 %d\n"
3594 		"\t%s %s %s %s 0 \"%s\"\n"
3595 		"\t%s %s %s %s 0 \"%s\"\n"
3596 		"%s\n",
3597 		"NODE", driver, instance, node_name,
3598 		"PROP", PICL_PROP_LABEL, "string", "r", label, instance,
3599 		"PROP", PICL_PROP_BUS_ADDR, "string", "r", bus_addr,
3600 		"PROP", PICL_PROP_GEO_ADDR, "uint", "r", instance,
3601 		"PROP", PICL_PROP_PORT_TYPE, "string", "r", port_type,
3602 		"PROP", PICL_PROP_DEVFS_PATH, "string", "r", devfs_path,
3603 		"ENDNODE");
3604 	*cacheptr = cachep;
3605 	return (PICL_SUCCESS);
3606 }
3607 
3608 /* ARGSUSED */
3609 static int
create_device_entries(picl_nodehdl_t nodeh,void * c_args)3610 create_device_entries(picl_nodehdl_t nodeh, void *c_args)
3611 {
3612 	char class[PICL_CLASSNAMELEN_MAX];
3613 	char name[PICL_PROPNAMELEN_MAX];
3614 	frutree_device_args_t *device  = NULL;
3615 	frutree_cache_t	*cachep = NULL;
3616 
3617 	if (c_args == NULL) { /* need not create cache */
3618 		return (PICL_INVALIDARG);
3619 	}
3620 	device = (frutree_device_args_t *)c_args;
3621 
3622 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
3623 		class, sizeof (class)) != PICL_SUCCESS) {
3624 		return (PICL_WALK_CONTINUE);
3625 	}
3626 
3627 	/* add reference handle to Devices table */
3628 	(void) create_table_entry(device->device_tblhdl, nodeh, class);
3629 
3630 	/* add to Environment Devices table */
3631 	if (strcmp(class, PICL_CLASS_TEMPERATURE_SENSOR) == 0) {
3632 		if (device->env_tblhdl) {
3633 			(void) create_table_entry(device->env_tblhdl, nodeh,
3634 				class);
3635 		}
3636 	}
3637 
3638 	if (device->create_cache != B_TRUE) {	/* dont create cache */
3639 		return (PICL_WALK_CONTINUE);
3640 	}
3641 
3642 	/* compare the classname and create the cache entry for the child */
3643 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
3644 		sizeof (name)) != PICL_SUCCESS) {
3645 		return (PICL_WALK_CONTINUE);
3646 	}
3647 
3648 	if (strcmp(name, SANIBEL_PICLNODE_PARALLEL) == 0) {
3649 		(void) strncpy(class, SANIBEL_PARALLEL_PORT, sizeof (class));
3650 	}
3651 
3652 	if (add_node2cache(nodeh, class, &cachep) != PICL_SUCCESS) {
3653 		return (PICL_WALK_CONTINUE);
3654 	}
3655 
3656 	/* add cache to the linked list */
3657 	if (cachep != NULL) {
3658 		cachep->next = NULL;
3659 		if (device->first == NULL) {		/* 1st node */
3660 			device->first = cachep;
3661 			device->last = NULL;
3662 
3663 		} else if (device->last != NULL) {	 /* last node */
3664 			device->last->next = cachep;
3665 			device->last = cachep;
3666 
3667 		} else {				/* 2nd node */
3668 			device->first->next = cachep;
3669 			device->last = cachep;
3670 		}
3671 	}
3672 	return (PICL_WALK_CONTINUE);
3673 }
3674 
3675 /*
3676  * determine the state manager for this node
3677  */
3678 static picl_errno_t
get_loc_type(frutree_locnode_t * locp)3679 get_loc_type(frutree_locnode_t *locp)
3680 {
3681 	picl_errno_t rc;
3682 	cfga_list_data_t *list = NULL;
3683 	char valbuf[PICL_PROPNAMELEN_MAX];
3684 	char slot_type[PICL_PROPNAMELEN_MAX];
3685 
3686 	if (locp->state_mgr != UNKNOWN)
3687 		return (PICL_SUCCESS);
3688 
3689 	rc = ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_STATE,
3690 		(void *)valbuf, PICL_PROPNAMELEN_MAX);
3691 	if (rc == PICL_SUCCESS) { /* managed by platform specific plugin */
3692 		locp->state_mgr = PLUGIN_PVT;
3693 		return (PICL_SUCCESS);
3694 	}
3695 
3696 	/*  get the info from the libcfgadm interface */
3697 	list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
3698 	if (list == NULL) {
3699 		return (PICL_NOSPACE);
3700 	}
3701 
3702 	if ((rc = get_cfgadm_state(list, locp->name)) == PICL_SUCCESS) {
3703 		locp->state_mgr = CFGADM_AP;
3704 	} else {
3705 		if ((rc = ptree_get_propval_by_name(locp->locnodeh,
3706 			PICL_PROP_SLOT_TYPE, slot_type,
3707 			sizeof (slot_type))) != PICL_SUCCESS) {
3708 			free(list);
3709 			return (rc);
3710 		}
3711 		if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
3712 			strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
3713 			/*
3714 			 * for scsi locations, if cfgadm ap is
3715 			 * not present, then consider it as device
3716 			 * not present
3717 			 */
3718 			locp->state_mgr = CFGADM_AP;
3719 		} else {
3720 			/*
3721 			 * devices like PMC card doesnt showup in cfgadm
3722 			 */
3723 			locp->state_mgr = STATIC_LOC;
3724 		}
3725 	}
3726 	free(list);
3727 	return (PICL_SUCCESS);
3728 }
3729 
3730 /*
3731  * Initialize the location node.(create all the props)
3732  */
3733 static picl_errno_t
location_init(frutree_locnode_t * locp)3734 location_init(frutree_locnode_t *locp)
3735 {
3736 	picl_errno_t rc;
3737 	boolean_t state_change;
3738 	uint64_t ap_status_time = 0;
3739 	char valbuf[PICL_PROPNAMELEN_MAX];
3740 
3741 	/* check if it is a CPU location node or not */
3742 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_NAME,
3743 		(void *)valbuf, PICL_PROPNAMELEN_MAX) == PICL_SUCCESS) {
3744 		if (strncmp(valbuf, SANIBEL_PICLNODE_CPU,
3745 			strlen(SANIBEL_PICLNODE_CPU)) == 0) {
3746 			locp->cpu_node = B_TRUE;
3747 		}
3748 	}
3749 	/*
3750 	 * Algorithm:
3751 	 * if "State" prop is already created (node is managed by other plugin)
3752 	 *  	does nothing
3753 	 * else if cfgadm ap is found
3754 	 *	creates State prop and intializes it
3755 	 * else
3756 	 *	find the nodes using libdevinfo under a given path
3757 	 *		at given geoaddr
3758 	 *	if node is found
3759 	 *		mark node state a connected
3760 	 *	else
3761 	 *		mark node state a empty
3762 	 */
3763 	(void) get_loc_type(locp);
3764 	if (locp->state_mgr == PLUGIN_PVT) {
3765 		(void) update_loc_state(locp, &state_change);
3766 		return (PICL_SUCCESS);
3767 	}
3768 
3769 	if (locp->state_mgr == STATIC_LOC) {
3770 		/*
3771 		 * in case of scsi locations,, loc state will be connected
3772 		 * no need to check again if the fru is present using libdevinfo
3773 		 */
3774 		if (locp->state != LOC_STATE_CONNECTED) {
3775 			if (is_fru_present_under_location(locp) == B_TRUE) {
3776 				locp->state = LOC_STATE_CONNECTED;
3777 			} else {
3778 				locp->state = LOC_STATE_EMPTY;
3779 			}
3780 		}
3781 	}
3782 	/* create state property */
3783 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
3784 		PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
3785 		PICL_PROP_STATE, get_loc_state, NULLWRITE, locp->locnodeh,
3786 		NULL, loc_state[locp->state])) != PICL_SUCCESS) {
3787 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
3788 			PICL_PROP_STATE, locp->name, rc);
3789 		return (rc);
3790 	}
3791 	ap_status_time = (uint64_t)(time(NULL));
3792 
3793 	/* create location StatusTime prop. */
3794 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
3795 		sizeof (uint64_t), PICL_PROP_STATUS_TIME, NULLREAD,
3796 		NULLWRITE, locp->locnodeh, NULL, &ap_status_time)) !=
3797 		PICL_SUCCESS) {
3798 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
3799 			PICL_PROP_STATUS_TIME, locp->name, rc);
3800 		return (rc);
3801 	}
3802 
3803 	if ((rc = update_loc_state(locp, &state_change)) != PICL_SUCCESS) {
3804 		FRUTREE_DEBUG2(FRUTREE_INIT, GET_LOC_STATE_ERR, locp->name, rc);
3805 		return (rc);
3806 	}
3807 	return (PICL_SUCCESS);
3808 }
3809 
3810 static frutree_port_type_t
frutree_get_port_type(frutree_portnode_t * portp)3811 frutree_get_port_type(frutree_portnode_t *portp)
3812 {
3813 	char device_type[PICL_PROPNAMELEN_MAX];
3814 	frutree_port_type_t port_type = UNKNOWN_PORT;
3815 
3816 	if (portp == NULL) {
3817 		return (port_type);
3818 	}
3819 
3820 	if (ptree_get_propval_by_name(portp->portnodeh,
3821 		PICL_PROP_PORT_TYPE, device_type,
3822 		sizeof (device_type)) == PICL_SUCCESS) {
3823 		if (strcmp(device_type, SANIBEL_NETWORK_PORT) == 0) {
3824 			port_type = NETWORK_PORT;
3825 		} else if (strcmp(device_type,
3826 			SANIBEL_SERIAL_PORT) == 0) {
3827 			port_type = SERIAL_PORT;
3828 		} else if (strcmp(device_type,
3829 			SANIBEL_PARALLEL_PORT) == 0) {
3830 			port_type = PARALLEL_PORT;
3831 		}
3832 	}
3833 	return (port_type);
3834 }
3835 
3836 /* volatile callback function to get port condition */
3837 static int
get_port_condition(ptree_rarg_t * rarg,void * buf)3838 get_port_condition(ptree_rarg_t *rarg, void *buf)
3839 {
3840 	picl_errno_t rc;
3841 	hashdata_t *hashptr = NULL;
3842 	frutree_portnode_t *portp = NULL;
3843 	frutree_port_type_t port_type;
3844 
3845 	if (buf == NULL) {
3846 		return (PICL_INVALIDARG);
3847 	}
3848 
3849 	if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
3850 		PICL_SUCCESS) {
3851 		return (rc);
3852 	}
3853 
3854 	portp = PORTDATA_PTR(hashptr);
3855 	if (portp == NULL) {
3856 		return (PICL_FAILURE);
3857 	}
3858 	port_type = frutree_get_port_type(portp);
3859 
3860 	if (port_type == UNKNOWN_PORT) {
3861 		portp->cond = PORT_COND_UNKNOWN;
3862 		(void) strncpy((char *)buf, port_cond[portp->cond],
3863 			PICL_PROPNAMELEN_MAX);
3864 		return (PICL_SUCCESS);
3865 	}
3866 
3867 	if ((rc = update_port_state(portp, B_TRUE)) != PICL_SUCCESS) {
3868 		return (rc);
3869 	}
3870 
3871 	(void) strncpy((char *)buf, port_cond[portp->cond],
3872 		PICL_PROPNAMELEN_MAX);
3873 	return (PICL_SUCCESS);
3874 }
3875 
3876 /* volatile callback function to get port state */
3877 static int
get_port_state(ptree_rarg_t * rarg,void * buf)3878 get_port_state(ptree_rarg_t *rarg, void *buf)
3879 {
3880 	picl_errno_t rc;
3881 	hashdata_t *hashptr = NULL;
3882 	frutree_portnode_t *portp = NULL;
3883 	frutree_port_type_t port_type;
3884 
3885 	if (buf == NULL) {
3886 		return (PICL_INVALIDARG);
3887 	}
3888 	if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
3889 		PICL_SUCCESS) {
3890 		return (rc);
3891 	}
3892 	portp = PORTDATA_PTR(hashptr);
3893 	if (portp == NULL) {
3894 		return (PICL_FAILURE);
3895 	}
3896 
3897 	port_type = frutree_get_port_type(portp);
3898 	if (port_type == UNKNOWN_PORT) {
3899 		portp->state = PORT_STATE_UNKNOWN;
3900 		(void) strncpy((char *)buf, port_state[portp->state],
3901 			PICL_PROPNAMELEN_MAX);
3902 		return (PICL_SUCCESS);
3903 	}
3904 
3905 	if ((rc = update_port_state(portp, B_TRUE)) != PICL_SUCCESS) {
3906 		return (rc);
3907 	}
3908 	(void) strncpy((char *)buf, port_state[portp->state],
3909 		PICL_PROPNAMELEN_MAX);
3910 	return (PICL_SUCCESS);
3911 }
3912 
3913 /*
3914  * Creates State and Condition property for a port node
3915  */
3916 static picl_errno_t
port_init(frutree_portnode_t * portp)3917 port_init(frutree_portnode_t *portp)
3918 {
3919 	picl_prophdl_t		proph;
3920 	ptree_propinfo_t	propinfo;
3921 	void			*vbuf;
3922 	picl_errno_t 		rc;
3923 	uint64_t 		status_time;
3924 	picl_nodehdl_t 		refhdl;
3925 	frutree_device_args_t 	device;
3926 	picl_prophdl_t 		tblprophdl, tblhdl;
3927 	char class[PICL_PROPNAMELEN_MAX];
3928 
3929 	if (portp == NULL) {
3930 		return (PICL_FAILURE);
3931 	}
3932 	refhdl = get_reference_handle(portp->portnodeh);
3933 
3934 	/* traverse thru platform tree and add entries to Devices table */
3935 	if (refhdl != 0) {
3936 		/* create Devices table property */
3937 		if ((rc = create_property(PICL_PTYPE_TABLE, PICL_READ,
3938 			sizeof (picl_prophdl_t), PICL_PROP_DEVICES,
3939 			NULLREAD, NULLWRITE, portp->portnodeh, &tblprophdl,
3940 			&tblhdl)) != PICL_SUCCESS) {
3941 			return (rc);
3942 		}
3943 
3944 		/* walk down the subtree and populate Devices */
3945 		if ((rc = ptree_get_propval_by_name(refhdl,
3946 			PICL_PROP_CLASSNAME, class,
3947 			sizeof (class))) != PICL_SUCCESS) {
3948 			return (rc);
3949 		}
3950 		if ((rc = create_table_entry(tblhdl, refhdl, class)) !=
3951 			PICL_SUCCESS) {
3952 			return (rc);
3953 		}
3954 
3955 		device.nodeh = refhdl;
3956 		device.device_tblhdl = tblhdl;
3957 		device.first = NULL;
3958 		device.last = NULL;
3959 		device.create_cache = B_FALSE;
3960 
3961 		if ((rc = do_action(refhdl, CREATE_DEVICES_ENTRIES,
3962 			(void *)&device)) != PICL_SUCCESS) {
3963 			return (rc);
3964 		}
3965 
3966 		if ((rc = ptree_get_prop_by_name(refhdl, PICL_PROP_INSTANCE,
3967 			&proph)) != PICL_SUCCESS) {
3968 			return (rc);
3969 		}
3970 		if ((rc = ptree_get_propinfo(proph, &propinfo)) !=
3971 			PICL_SUCCESS) {
3972 			return (rc);
3973 		}
3974 		vbuf = alloca(propinfo.piclinfo.size);
3975 		if (vbuf == NULL)
3976 			return (PICL_NOSPACE);
3977 
3978 		if ((rc = ptree_get_propval(proph, vbuf,
3979 			propinfo.piclinfo.size)) != PICL_SUCCESS) {
3980 			return (rc);
3981 		}
3982 		portp->instance = *(int *)vbuf;
3983 
3984 		if ((rc = ptree_get_prop_by_name(refhdl,
3985 			PICL_PROP_DRIVER_NAME, &proph)) != PICL_SUCCESS) {
3986 			return (rc);
3987 		}
3988 		if ((rc = ptree_get_propinfo(proph, &propinfo)) !=
3989 			PICL_SUCCESS) {
3990 			return (rc);
3991 		}
3992 		vbuf = alloca(propinfo.piclinfo.size);
3993 		if (vbuf == NULL)
3994 			return (PICL_NOSPACE);
3995 
3996 		if ((rc = ptree_get_propval(proph, vbuf,
3997 			propinfo.piclinfo.size)) != PICL_SUCCESS) {
3998 			return (rc);
3999 		}
4000 
4001 		(void) strncpy(portp->driver, (char *)vbuf,
4002 			sizeof (portp->driver));
4003 	} else {
4004 		/* this node is created using libdevinfo or conf file */
4005 		if ((rc = get_port_info(portp)) != PICL_SUCCESS) {
4006 			return (rc);
4007 		}
4008 	}
4009 
4010 	/* create state and condition properties */
4011 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
4012 		PICL_READ | PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
4013 		PICL_PROP_STATE, get_port_state, NULLWRITE, portp->portnodeh,
4014 		NULL, port_state[portp->state])) != PICL_SUCCESS) {
4015 		return (rc);
4016 	}
4017 
4018 	status_time = (uint64_t)(time(NULL));
4019 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
4020 		sizeof (uint64_t), PICL_PROP_STATUS_TIME, NULLREAD,
4021 		NULLWRITE, portp->portnodeh, NULL, &status_time)) !=
4022 		PICL_SUCCESS) {
4023 		return (rc);
4024 	}
4025 
4026 	if ((rc = create_property(PICL_PTYPE_CHARSTRING,
4027 		PICL_READ | PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
4028 		PICL_PROP_CONDITION, get_port_condition, NULLWRITE,
4029 		portp->portnodeh, NULL, port_cond[portp->cond])) !=
4030 		PICL_SUCCESS) {
4031 		return (rc);
4032 	}
4033 	if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
4034 		sizeof (uint64_t), PICL_PROP_CONDITION_TIME, NULLREAD,
4035 		NULLWRITE, portp->portnodeh, NULL, &status_time)) !=
4036 		PICL_SUCCESS) {
4037 		return (rc);
4038 	}
4039 	(void) update_port_state(portp, B_FALSE);
4040 	return (PICL_SUCCESS);
4041 }
4042 
4043 /*
4044  * This routine dynamically determines the scsi name (using libcfgadm)
4045  * that corresponds to the node specified in configuration file
4046  */
4047 static picl_errno_t
init_scsi_slot(frutree_frunode_t * frup,frutree_locnode_t ** ptr2locp,boolean_t * node_name_changed)4048 init_scsi_slot(frutree_frunode_t *frup, frutree_locnode_t **ptr2locp,
4049 	boolean_t *node_name_changed)
4050 {
4051 	picl_errno_t rc;
4052 	char devfs_path[PICL_PROPNAMELEN_MAX];
4053 	char bus_addr[PICL_PROPNAMELEN_MAX];
4054 	char label[PICL_PROPNAMELEN_MAX];
4055 	char name[MAXPATHLEN];
4056 	uint8_t	 geo_addr = 0;
4057 	frutree_locnode_t *locp = NULL, *new_locp = NULL;
4058 	hashdata_t *hashptr = NULL;
4059 	picl_nodehdl_t	nodeh;
4060 
4061 	if (ptr2locp == NULL) {
4062 		return (PICL_INVALIDARG);
4063 	}
4064 	locp  = (frutree_locnode_t *)*ptr2locp;
4065 	*node_name_changed = B_FALSE;
4066 
4067 	if (locp == NULL) {
4068 		return (PICL_FAILURE);
4069 	}
4070 
4071 	if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4072 		PICL_PROP_DEVFS_PATH, devfs_path,
4073 		sizeof (devfs_path))) != PICL_SUCCESS) {
4074 		return (rc);
4075 	}
4076 
4077 	if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4078 		PICL_PROP_BUS_ADDR, bus_addr,
4079 		sizeof (bus_addr))) != PICL_SUCCESS) {
4080 		return (rc);
4081 	}
4082 
4083 	/* find the dynamic ap_id from libcfgadm */
4084 	if ((rc = get_scsislot_name(devfs_path, bus_addr,
4085 		name)) != PICL_SUCCESS) {
4086 		/* if rc is NODENOTFOUND, then slot is empty */
4087 		if (rc != PICL_NODENOTFOUND) {
4088 			return (rc);
4089 		} else {
4090 			return (PICL_SUCCESS);
4091 		}
4092 	}
4093 
4094 	/* node name is same, so dont change anything */
4095 	if (strcmp(name, locp->name) == 0) {
4096 		return (PICL_SUCCESS);
4097 	}
4098 
4099 	if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4100 		PICL_PROP_GEO_ADDR, &geo_addr,
4101 		sizeof (geo_addr))) != PICL_SUCCESS) {
4102 		geo_addr = 0;
4103 	}
4104 
4105 	if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4106 		PICL_PROP_LABEL, label,
4107 		sizeof (label))) != PICL_SUCCESS) {
4108 		return (rc);
4109 	}
4110 
4111 	/* Now recreate the node with new name */
4112 	if ((rc = ptree_create_node(name, PICL_CLASS_LOCATION,
4113 		&nodeh)) != PICL_SUCCESS) {
4114 		return (rc);
4115 	}
4116 
4117 	/* add all the properties now */
4118 	(void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4119 		PICL_PROPNAMELEN_MAX, PICL_PROP_SLOT_TYPE, NULLREAD,
4120 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4121 		SANIBEL_SCSI_SLOT);
4122 
4123 	(void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4124 		PICL_PROPNAMELEN_MAX, PICL_PROP_LABEL, NULLREAD,
4125 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4126 		label);
4127 
4128 	(void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4129 		PICL_PROPNAMELEN_MAX, PICL_PROP_BUS_ADDR, NULLREAD,
4130 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4131 		bus_addr);
4132 
4133 	(void) create_property(PICL_PTYPE_UNSIGNED_INT, PICL_READ,
4134 		sizeof (uint8_t), PICL_PROP_GEO_ADDR, NULLREAD,
4135 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4136 		&geo_addr);
4137 
4138 	(void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4139 		PICL_PROPNAMELEN_MAX, PICL_PROP_DEVFS_PATH, NULLREAD,
4140 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4141 		devfs_path);
4142 	(void) ptree_add_node(frup->frunodeh, nodeh);
4143 
4144 	if ((rc = make_loc_data(name, &hashptr)) != PICL_SUCCESS) {
4145 		return (rc);
4146 	}
4147 	/* save data in hash table */
4148 	if ((rc = hash_add_entry(nodeh, (void *)hashptr)) != PICL_SUCCESS) {
4149 		free_data(hashptr->type, hashptr);
4150 		return (rc);
4151 	}
4152 
4153 	new_locp = LOCDATA_PTR(hashptr);
4154 	new_locp->locnodeh = nodeh;
4155 	*ptr2locp = new_locp;
4156 	*node_name_changed = B_TRUE;
4157 	return (PICL_SUCCESS);
4158 }
4159 
4160 /*
4161  * find the child nodes under a fru and initialize them
4162  */
4163 static int
frutree_initialize_children(picl_nodehdl_t childh,void * c_args)4164 frutree_initialize_children(picl_nodehdl_t childh, void *c_args)
4165 {
4166 	picl_errno_t rc;
4167 	picl_nodehdl_t parenth;
4168 	boolean_t node_changed = B_FALSE;
4169 	hashdata_t *datap = NULL;
4170 	char name[PICL_PROPNAMELEN_MAX];
4171 	char class[PICL_PROPNAMELEN_MAX];
4172 	frutree_frunode_t *frup = NULL;
4173 	frutree_init_callback_arg_t *arg;
4174 
4175 	if (c_args ==  NULL) {
4176 		return (PICL_INVALIDARG);
4177 	}
4178 	arg = (frutree_init_callback_arg_t *)c_args;
4179 	frup = arg->frup;
4180 
4181 	if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_PARENT,
4182 		&parenth, sizeof (parenth))) != PICL_SUCCESS) {
4183 		return (rc);
4184 	}
4185 
4186 	if (parenth != frup->frunodeh)
4187 		return (PICL_WALK_CONTINUE);
4188 
4189 	if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_CLASSNAME, class,
4190 		sizeof (class))) != PICL_SUCCESS) {
4191 		return (rc);
4192 	}
4193 
4194 	if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_NAME, name,
4195 		sizeof (name))) != PICL_SUCCESS) {
4196 		return (rc);
4197 	}
4198 
4199 	if (strcmp(class, PICL_CLASS_LOCATION) == 0) {
4200 		char slot_type[PICL_PROPNAMELEN_MAX];
4201 		frutree_locnode_t *locp = NULL;
4202 		frutree_frunode_t *child_frup = NULL;
4203 		/* initialize internal data structure */
4204 		if ((rc = make_loc_data(name, &datap)) != PICL_SUCCESS) {
4205 			return (PICL_WALK_CONTINUE);
4206 		}
4207 		locp = LOCDATA_PTR(datap);
4208 		locp->locnodeh = childh;
4209 		/* save data in hash table */
4210 		(void) hash_add_entry(childh, (void *)datap);
4211 		if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4212 			PICL_PROP_SLOT_TYPE, slot_type,
4213 			sizeof (slot_type))) != PICL_SUCCESS) {
4214 			FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_GET_PROPVAL_ERR,
4215 				PICL_PROP_SLOT_TYPE, locp->name, rc);
4216 			return (PICL_WALK_CONTINUE);
4217 		} else {
4218 			if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
4219 				strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
4220 				/*
4221 				 * this rountine finds the valid cfgadm
4222 				 * ap_id name for a given node and
4223 				 * creates a new node with that name.
4224 				 * If the node name is changed, the present
4225 				 * node must be added to the list of nodes
4226 				 * to be deleted from tree after ptree walk.
4227 				 */
4228 				(void) init_scsi_slot(frup, &locp,
4229 					&node_changed);
4230 				if (node_changed) {
4231 					delete_list_t *nodep = NULL;
4232 					/*
4233 					 * add this node to list of nodes
4234 					 * to be removed
4235 					 */
4236 					nodep = (delete_list_t *)malloc(
4237 							sizeof (delete_list_t));
4238 					if (nodep == NULL) {
4239 						return (PICL_NOSPACE);
4240 					}
4241 					nodep->nodeh = childh;
4242 					nodep->next = NULL;
4243 
4244 					if (arg->first == NULL) {
4245 						arg->first = nodep;
4246 					} else { /* add 2 front */
4247 						nodep->next = arg->first;
4248 						arg->first = nodep;
4249 					}
4250 				}
4251 			}
4252 		}
4253 		if ((rc = location_init(locp)) != PICL_SUCCESS) {
4254 			return (PICL_WALK_CONTINUE);
4255 		}
4256 
4257 		/* if location is empty, done */
4258 		if (locp->state == LOC_STATE_EMPTY ||
4259 			locp->state == LOC_STATE_UNKNOWN) {
4260 			return (PICL_WALK_CONTINUE);
4261 		}
4262 
4263 		/* create the fru node and initialize it */
4264 		if ((rc = create_fru_node(locp, &child_frup)) !=
4265 			PICL_SUCCESS) {
4266 			return (PICL_WALK_CONTINUE);
4267 		}
4268 
4269 		/*
4270 		 * if fru is already configured, create the
4271 		 * subtree under the child fru
4272 		 */
4273 		if (child_frup->state == FRU_STATE_CONFIGURED) {
4274 			/* initialize the fru_path */
4275 			if ((rc = probe_fru(child_frup, B_TRUE)) !=
4276 				PICL_SUCCESS) {
4277 				FRUTREE_DEBUG2(EVENTS, PROBE_FRU_ERR,
4278 					child_frup->name, rc);
4279 			}
4280 		}
4281 	} else if (strcmp(class, PICL_CLASS_PORT) == 0) {
4282 		frutree_portnode_t *portp = NULL;
4283 		if ((rc = make_port_data(name, &datap)) != PICL_SUCCESS) {
4284 			return (PICL_WALK_CONTINUE);
4285 		}
4286 		(void) hash_add_entry(childh, (void *)datap);
4287 		portp = PORTDATA_PTR(datap);
4288 		portp->portnodeh = childh;
4289 		(void) port_init(portp);
4290 	}
4291 	return (PICL_WALK_CONTINUE);
4292 }
4293 
4294 /* traverse thru all locations under fru and initiate connects */
4295 static int
initiate_connects(picl_nodehdl_t nodeh,void * args)4296 initiate_connects(picl_nodehdl_t nodeh, void *args)
4297 {
4298 	picl_errno_t rc;
4299 	hashdata_t *hashptr = NULL;
4300 	picl_nodehdl_t parenth;
4301 	frutree_frunode_t *frup = NULL;
4302 	frutree_locnode_t *locp = NULL;
4303 
4304 	if (args ==  NULL) {
4305 		return (PICL_INVALIDARG);
4306 	}
4307 	frup = (frutree_frunode_t *)args;
4308 
4309 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
4310 		&parenth, sizeof (parenth))) != PICL_SUCCESS) {
4311 		return (rc);
4312 	}
4313 
4314 	if (parenth != frup->frunodeh)
4315 		return (PICL_WALK_CONTINUE);
4316 
4317 	if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
4318 		PICL_SUCCESS) {
4319 		return (PICL_WALK_CONTINUE);
4320 	}
4321 	locp = LOCDATA_PTR(hashptr);
4322 
4323 	if (locp->state == LOC_STATE_EMPTY ||
4324 		locp->state == LOC_STATE_UNKNOWN ||
4325 		locp->state == LOC_STATE_CONNECTED) {
4326 		return (PICL_WALK_CONTINUE);
4327 	}
4328 
4329 	/* if loc is not connected, do a connect operation */
4330 	if (locp->autoconfig_enabled) {
4331 		if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
4332 			FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
4333 				locp->name, rc);
4334 		}
4335 	}
4336 	return (PICL_WALK_CONTINUE);
4337 }
4338 
4339 /*
4340  * Initializes the subtree under a FRU
4341  */
4342 static picl_errno_t
fru_init(frutree_frunode_t * frup)4343 fru_init(frutree_frunode_t *frup)
4344 {
4345 	picl_errno_t rc;
4346 	delete_list_t *tmp = NULL, *curr = NULL;
4347 	frutree_init_callback_arg_t arg;
4348 
4349 	if (frup ==  NULL) {
4350 		return (PICL_INVALIDARG);
4351 	}
4352 
4353 	arg.frup = frup;
4354 	arg.first = NULL;
4355 
4356 	/*
4357 	 * this routine creates internal data structures for
4358 	 * all the children under this fru and initializes them
4359 	 */
4360 	if ((rc = do_action(frup->frunodeh, INIT_FRU,
4361 		(void *)&arg)) != PICL_SUCCESS) {
4362 		return (rc);
4363 	}
4364 
4365 	/* traverse thru delete_nodes_list and delete the nodes from tree */
4366 	curr = arg.first;
4367 	while (curr) {
4368 		tmp = curr;
4369 		(void) ptree_delete_node(tmp->nodeh);
4370 		(void) ptree_destroy_node(tmp->nodeh);
4371 		(void) hash_remove_entry(tmp->nodeh);
4372 		free(tmp);
4373 		curr = curr->next;
4374 	}
4375 
4376 	/*
4377 	 * dont post events during intialization (for other FRUs)
4378 	 * chassis intialization will take care of posting events
4379 	 * for complete frutree
4380 	 */
4381 	if ((frup->frunodeh == chassish) ||
4382 		(post_picl_events == B_TRUE)) {
4383 		if ((rc = do_action(frup->frunodeh, POST_EVENTS, NULL)) !=
4384 			PICL_SUCCESS) {
4385 			FRUTREE_DEBUG1(LOG_ERR, "SUNW_frutree:Error in "
4386 				"posting picl events(error=%d)", rc);
4387 		}
4388 	}
4389 
4390 	if (frup->frunodeh == chassish) {
4391 		post_picl_events = B_TRUE;
4392 		frutree_connects_initiated = B_TRUE;
4393 	}
4394 
4395 	/* initiate connects */
4396 	if ((rc = ptree_walk_tree_by_class(frup->frunodeh, PICL_CLASS_LOCATION,
4397 		(void *)frup, initiate_connects)) != PICL_SUCCESS) {
4398 		return (rc);
4399 	}
4400 	return (PICL_SUCCESS);
4401 }
4402 
4403 /*ARGSUSED*/
4404 static int
post_events(picl_nodehdl_t childh,void * c_args)4405 post_events(picl_nodehdl_t childh, void *c_args)
4406 {
4407 	int rc;
4408 	hashdata_t *hashptr = NULL;
4409 	frutree_frunode_t *frup = NULL;
4410 	frutree_locnode_t *locp = NULL;
4411 	frutree_portnode_t *portp = NULL;
4412 	char classval[PICL_CLASSNAMELEN_MAX];
4413 
4414 	if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_CLASSNAME,
4415 		classval, sizeof (classval))) != PICL_SUCCESS) {
4416 		return (PICL_WALK_CONTINUE);
4417 	}
4418 
4419 	if ((rc = hash_lookup_entry(childh, (void **)&hashptr)) !=
4420 		PICL_SUCCESS) {
4421 		return (PICL_WALK_CONTINUE);
4422 	}
4423 
4424 	if (strcmp(classval, PICL_CLASS_LOCATION) == 0) {
4425 		locp = LOCDATA_PTR(hashptr);
4426 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
4427 			loc_state[locp->state], loc_state[locp->prev_state],
4428 			childh, WAIT)) != PICL_SUCCESS) {
4429 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4430 				locp->name, PICLEVENT_STATE_CHANGE, rc);
4431 		}
4432 		return (PICL_WALK_CONTINUE);
4433 	}
4434 
4435 	if (strcmp(classval, PICL_CLASS_FRU) == 0) {
4436 		frup = FRUDATA_PTR(hashptr);
4437 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
4438 			fru_state[frup->state], fru_state[frup->prev_state],
4439 			childh, WAIT)) != PICL_SUCCESS) {
4440 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4441 				frup->name, PICLEVENT_STATE_CHANGE, rc);
4442 		}
4443 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
4444 			fru_cond[frup->cond], fru_cond[frup->prev_cond],
4445 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
4446 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4447 				frup->name, PICLEVENT_CONDITION_CHANGE, rc);
4448 		}
4449 		return (PICL_WALK_CONTINUE);
4450 	}
4451 
4452 	if (strcmp(classval, PICL_CLASS_PORT) == 0) {
4453 		portp = PORTDATA_PTR(hashptr);
4454 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
4455 			port_state[portp->state], NULL,
4456 			portp->portnodeh, WAIT)) != PICL_SUCCESS) {
4457 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4458 				portp->name, PICLEVENT_STATE_CHANGE, rc);
4459 		}
4460 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
4461 			port_cond[portp->cond], NULL,
4462 			portp->portnodeh, WAIT)) != PICL_SUCCESS) {
4463 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4464 				portp->name, PICLEVENT_CONDITION_CHANGE, rc);
4465 		}
4466 		return (PICL_WALK_CONTINUE);
4467 	}
4468 	return (PICL_WALK_CONTINUE);
4469 }
4470 
4471 /*
4472  * This function is a utility function that calls the
4473  * appropriate call back function for the all the nodes under
4474  * the specified root node.
4475  * future additions can be done by defining new action and callback.
4476  */
4477 static picl_errno_t
do_action(picl_nodehdl_t root,int action,void * cargs)4478 do_action(picl_nodehdl_t root, int action, void *cargs)
4479 {
4480 	int rc;
4481 	callback_t func_ptr;
4482 	char *class = NULL;
4483 
4484 	switch (action) {
4485 
4486 	case INIT_FRU:
4487 		func_ptr = frutree_initialize_children;
4488 		class = NULL;
4489 		break;
4490 	case CREATE_DEVICES_ENTRIES:
4491 		func_ptr = create_device_entries;
4492 		class = NULL;
4493 		break;
4494 	case POST_EVENTS:
4495 		func_ptr = post_events;
4496 		class = NULL;
4497 		break;
4498 	default:
4499 		return (PICL_INVALIDARG);
4500 	}
4501 
4502 	if ((rc = ptree_walk_tree_by_class(root, class, cargs,
4503 		func_ptr)) != PICL_SUCCESS) {
4504 		return (rc);
4505 	}
4506 	return (PICL_SUCCESS);
4507 }
4508 
4509 static picl_errno_t
frutree_update_chassis_state(frutree_frustate_t state,frutree_frustate_t prev_state)4510 frutree_update_chassis_state(frutree_frustate_t state,
4511 	frutree_frustate_t prev_state)
4512 {
4513 	uint64_t ap_status_time;
4514 	picl_errno_t rc = 0;
4515 	char present_state[PICL_PROPNAMELEN_MAX];
4516 
4517 	(void) strncpy(present_state, fru_state[state], sizeof (present_state));
4518 	(void) ptree_update_propval_by_name(chassish,
4519 		PICL_PROP_STATE, present_state, sizeof (present_state));
4520 
4521 	ap_status_time = (uint64_t)(time(NULL));
4522 	if ((rc = ptree_update_propval_by_name(chassish,
4523 		PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
4524 		sizeof (ap_status_time))) != PICL_SUCCESS) {
4525 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
4526 			PICL_PROP_STATUS_TIME, PICL_NODE_CHASSIS, rc);
4527 	}
4528 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
4529 		fru_state[state], fru_state[prev_state],
4530 		chassish, WAIT)) != PICL_SUCCESS) {
4531 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4532 			PICL_NODE_CHASSIS, PICLEVENT_STATE_CHANGE, rc);
4533 	}
4534 	return (PICL_SUCCESS);
4535 }
4536 
4537 static picl_errno_t
frutree_init()4538 frutree_init()
4539 {
4540 	picl_errno_t rc;
4541 	frutree_frunode_t *frup = NULL;
4542 	hashdata_t *hashptr = NULL;
4543 
4544 	if ((rc = ptree_get_node_by_path(PLATFORM_PATH, &platformh)) !=
4545 		PICL_SUCCESS) {
4546 		return (rc);
4547 	}
4548 
4549 	if ((rc = hash_lookup_entry(chassish, (void **)&hashptr)) !=
4550 		PICL_SUCCESS) {
4551 		return (rc);
4552 	}
4553 	frup = FRUDATA_PTR(hashptr);
4554 
4555 	/* create the nodes in conf file under chassis node */
4556 	if ((rc = picld_pluginutil_parse_config_file(chassish,
4557 		conf_file)) != PICL_SUCCESS) {
4558 		/* update chassis state to unconfigured */
4559 		(void) frutree_update_chassis_state(
4560 			FRU_STATE_UNCONFIGURED, FRU_STATE_UNKNOWN);
4561 		return (rc);
4562 	}
4563 
4564 	/* update chassis state to configuring */
4565 	(void) frutree_update_chassis_state(
4566 		FRU_STATE_CONFIGURING, FRU_STATE_UNCONFIGURED);
4567 
4568 	if (scsi_info_init() != PICL_SUCCESS) {
4569 		/* update chassis state to unconfigured */
4570 		(void) frutree_update_chassis_state(
4571 			FRU_STATE_UNCONFIGURED, FRU_STATE_CONFIGURING);
4572 		return (PICL_FAILURE);
4573 	}
4574 
4575 	/* traverse thru all the nodes under chassis, initialize them */
4576 	if ((rc = fru_init(frup)) != PICL_SUCCESS) {
4577 		/* update chassis state to unconfigured */
4578 		(void) frutree_update_chassis_state(
4579 			FRU_STATE_UNCONFIGURED, FRU_STATE_CONFIGURING);
4580 		scsi_info_fini();
4581 		return (rc);
4582 	}
4583 	/* free the memory used during initialization */
4584 	scsi_info_fini();
4585 	/* start node monitoring thread */
4586 	if (pthread_create(&monitor_tid, NULL, monitor_node_status,
4587 		NULL) != 0) {
4588 		FRUTREE_DEBUG0(EVENTS, "SUNW_frutree:Error in creating node"
4589 			" monitoring thread");
4590 	}
4591 
4592 	(void) pthread_mutex_lock(&frup->mutex);
4593 	frup->state = FRU_STATE_CONFIGURED;
4594 	(void) pthread_mutex_unlock(&frup->mutex);
4595 
4596 	/* update chassis state to configured */
4597 	(void) frutree_update_chassis_state(
4598 		FRU_STATE_CONFIGURED, FRU_STATE_CONFIGURING);
4599 	return (PICL_SUCCESS);
4600 }
4601 
4602 /* ARGSUSED */
4603 static void *
init_thread(void * arg)4604 init_thread(void *arg)
4605 {
4606 	picl_errno_t rc;
4607 
4608 	FRUTREE_DEBUG0(FRUTREE_INIT, "init_thread begin");
4609 
4610 	(void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
4611 	(void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
4612 
4613 	if (get_configuration_file() != PICL_SUCCESS) {
4614 		return (NULL);
4615 	}
4616 	FRUTREE_DEBUG1(FRUTREE_INIT, "conf_file = %s", conf_file);
4617 	if ((rc = frutree_init()) != PICL_SUCCESS) {
4618 		FRUTREE_DEBUG1(FRUTREE_INIT, "frutree_init failed, error = %d",
4619 			rc);
4620 	}
4621 	FRUTREE_DEBUG0(FRUTREE_INIT, "init_thread end");
4622 	return (NULL);
4623 }
4624 
4625 /* ARGSUSED */
4626 static void
event_completion_handler(char * ename,void * earg,size_t size)4627 event_completion_handler(char *ename, void *earg, size_t size)
4628 {
4629 	if (frutree_debug & EV_COMPLETION) {
4630 		char name[PICL_PROPNAMELEN_MAX];
4631 		nvlist_t *nvlp;
4632 		char *value = NULL;
4633 		char *arg = NULL;
4634 		picl_nodehdl_t fruhdl;
4635 		time_t current_time;
4636 
4637 		if (strncmp(ename, PICLEVENT_STATE_CHANGE,
4638 			strlen(PICLEVENT_STATE_CHANGE)) == 0) {
4639 			arg = PICLEVENTARG_STATE;
4640 		} else if (strncmp(ename, PICLEVENT_CONDITION_CHANGE,
4641 			strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
4642 			arg = PICLEVENTARG_CONDITION;
4643 		}
4644 
4645 		(void) nvlist_unpack((char *)earg, size, &nvlp, NULL);
4646 		(void) nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE,
4647 			&fruhdl);
4648 		if (arg != NULL)
4649 			(void) nvlist_lookup_string(nvlp, arg, &value);
4650 
4651 		(void) ptree_get_propval_by_name(fruhdl, PICL_PROP_NAME,
4652 			(void *)name, sizeof (name));
4653 		current_time = (uint64_t)(time(NULL));
4654 		if (value != NULL) {
4655 			FRUTREE_DEBUG4(EV_COMPLETION, "ev_completed[%s]%s(%s) "
4656 			"on %s", ctime(&current_time), ename, value, name);
4657 		}
4658 		nvlist_free(nvlp);
4659 	}
4660 
4661 	(void) mutex_lock(&piclevent_mutex);
4662 	piclevent_pending = 0;
4663 	(void) cond_broadcast(&piclevent_completed_cv);
4664 	(void) mutex_unlock(&piclevent_mutex);
4665 	free(earg);
4666 	free(ename);
4667 }
4668 
4669 picl_errno_t
post_piclevent(const char * event,char * val1,char * val2,picl_nodehdl_t nodeh,frutree_wait_t wait)4670 post_piclevent(const char *event, char *val1,
4671 	char *val2, picl_nodehdl_t nodeh, frutree_wait_t wait)
4672 {
4673 	nvlist_t *nvl;
4674 	size_t nvl_size;
4675 	char *pack_buf = NULL;
4676 	char *ename = NULL;
4677 	char *arg = NULL;
4678 	picl_errno_t rc;
4679 	timestruc_t to;
4680 	struct timeval tp;
4681 
4682 	if (event == NULL || val1 == NULL) {
4683 		return (PICL_INVALIDARG);
4684 	}
4685 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) {
4686 		return (PICL_FAILURE);
4687 	}
4688 	if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, nodeh)) {
4689 		nvlist_free(nvl);
4690 		return (PICL_FAILURE);
4691 	}
4692 
4693 	if ((ename = strdup(event)) == NULL) {
4694 		nvlist_free(nvl);
4695 		return (PICL_NOSPACE);
4696 	}
4697 
4698 	if (strncmp(ename, PICLEVENT_STATE_CHANGE,
4699 		strlen(PICLEVENT_STATE_CHANGE)) == 0) {
4700 		arg = PICLEVENTARG_STATE;
4701 	} else if (strncmp(ename, PICLEVENT_CONDITION_CHANGE,
4702 		strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
4703 		arg = PICLEVENTARG_CONDITION;
4704 	} else {
4705 		free(ename);
4706 		nvlist_free(nvl);
4707 		return (PICL_INVALIDARG);
4708 	}
4709 
4710 	if (nvlist_add_string(nvl, arg, val1)) {
4711 		free(ename);
4712 		nvlist_free(nvl);
4713 		return (PICL_FAILURE);
4714 	}
4715 
4716 	if (strncmp(ename, PICLEVENT_CONDITION_CHANGE,
4717 		strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
4718 		if (nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE,
4719 			NULL)) {
4720 			free(ename);
4721 			nvlist_free(nvl);
4722 			return (PICL_FAILURE);
4723 		}
4724 	} else {	/* state change event */
4725 
4726 		if (val2 != NULL) {
4727 			/* if there is a last state, add it to nvlist */
4728 			if (nvlist_add_string(nvl,
4729 				PICLEVENTARG_LAST_STATE, val2)) {
4730 				free(ename);
4731 				nvlist_free(nvl);
4732 				return (PICL_FAILURE);
4733 			}
4734 		}
4735 	}
4736 
4737 	if (nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, NULL)) {
4738 		free(ename);
4739 		nvlist_free(nvl);
4740 		return (PICL_FAILURE);
4741 	}
4742 
4743 	(void) mutex_lock(&piclevent_mutex);
4744 	while (piclevent_pending) {
4745 		(void) cond_wait(&piclevent_completed_cv,
4746 			&piclevent_mutex);
4747 	}
4748 	piclevent_pending = 1;
4749 	(void) mutex_unlock(&piclevent_mutex);
4750 
4751 	if ((rc = ptree_post_event(ename, pack_buf, nvl_size,
4752 		event_completion_handler)) != PICL_SUCCESS) {
4753 		free(ename);
4754 		free(pack_buf);
4755 		nvlist_free(nvl);
4756 		(void) mutex_lock(&piclevent_mutex);
4757 		piclevent_pending = 0;
4758 		(void) mutex_unlock(&piclevent_mutex);
4759 		return (rc);
4760 	}
4761 
4762 	if (frutree_debug) {
4763 		char	name[PICL_PROPNAMELEN_MAX];
4764 		(void) ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
4765 			name, sizeof (name));
4766 		if (val2 != NULL) {
4767 			FRUTREE_DEBUG4(EVENTS, "%s(%s -> %s) on %s", ename,
4768 				val2, val1, name);
4769 		} else {
4770 			FRUTREE_DEBUG3(EVENTS, "%s(%s) on %s", ename,
4771 				val1, name);
4772 		}
4773 	}
4774 
4775 	if (wait) {	/* wait for the event to be handled */
4776 		(void) mutex_lock(&piclevent_mutex);
4777 		while (piclevent_pending) {
4778 			(void) gettimeofday(&tp, NULL);
4779 			to.tv_sec = tp.tv_sec + 1;
4780 			to.tv_nsec = tp.tv_usec * 1000;
4781 			(void) cond_timedwait(&piclevent_completed_cv,
4782 				&piclevent_mutex, &to);
4783 		}
4784 		(void) mutex_unlock(&piclevent_mutex);
4785 	}
4786 	nvlist_free(nvl);
4787 	return (PICL_SUCCESS);
4788 }
4789 
4790 /*
4791  * return values
4792  * -1	: error
4793  *  0	: not enabled
4794  *  1	: enabled
4795  */
4796 /* ARGSUSED */
4797 static int
is_autoconfig_enabled(char * loc_name)4798 is_autoconfig_enabled(char *loc_name)
4799 {
4800 	return (1);
4801 }
4802 
4803 static picl_errno_t
update_loc_type(frutree_locnode_t * locp)4804 update_loc_type(frutree_locnode_t *locp)
4805 {
4806 	cfga_list_data_t *list = NULL;
4807 	/*  get the info from the libcfgadm interface */
4808 	list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
4809 	if (list == NULL) {
4810 		return (PICL_NOSPACE);
4811 	}
4812 
4813 	if (get_cfgadm_state(list, locp->name) == PICL_SUCCESS) {
4814 		locp->state_mgr = CFGADM_AP;
4815 		free(list);
4816 		return (PICL_SUCCESS);
4817 	}
4818 	free(list);
4819 	return (PICL_NODENOTFOUND);
4820 }
4821 
4822 /*
4823  * handles DR_INCOMING_RES on chassis node
4824  * (refresh piclfrutree tree)
4825  */
4826 static int
reconfigure_chassis(picl_nodehdl_t nodeh,void * args)4827 reconfigure_chassis(picl_nodehdl_t nodeh, void *args)
4828 {
4829 	picl_errno_t rc;
4830 	hashdata_t *hashptr = NULL;
4831 	picl_nodehdl_t parenth, childh;
4832 	frutree_frunode_t *frup = NULL, *child_frup = NULL;
4833 	frutree_locnode_t *locp = NULL;
4834 	boolean_t state_changed = B_FALSE;
4835 	boolean_t cond_changed = B_FALSE;
4836 	frutree_dr_arg_t dr_arg;
4837 
4838 	if (args ==  NULL) {
4839 		return (PICL_INVALIDARG);
4840 	}
4841 	frup = (frutree_frunode_t *)args;
4842 
4843 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
4844 		&parenth, sizeof (parenth))) != PICL_SUCCESS) {
4845 		return (rc);
4846 	}
4847 
4848 	if (parenth != frup->frunodeh)
4849 		return (PICL_WALK_CONTINUE);
4850 
4851 	if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
4852 		PICL_SUCCESS) {
4853 		return (PICL_WALK_CONTINUE);
4854 	}
4855 	locp = LOCDATA_PTR(hashptr);
4856 
4857 	/* if the location has child fru, get its information */
4858 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
4859 		&childh, sizeof (childh)) == PICL_SUCCESS) {
4860 		/* get the child fru information */
4861 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
4862 			PICL_SUCCESS) {
4863 			child_frup = FRUDATA_PTR(hashptr);
4864 		}
4865 	}
4866 
4867 	/* for each location, update the state */
4868 	if (locp->state_mgr == STATIC_LOC) {
4869 		/* check if cfgadm ap_id is present */
4870 		rc = update_loc_type(locp);
4871 		if (rc == PICL_SUCCESS) {
4872 			if (child_frup) {
4873 				child_frup->state_mgr = locp->state_mgr;
4874 				(void) update_fru_state(child_frup,
4875 					&state_changed);
4876 			}
4877 		}
4878 	}
4879 
4880 	state_changed = B_FALSE;
4881 	(void) update_loc_state(locp, &state_changed);
4882 	if (state_changed) {
4883 		switch (locp->state) {
4884 		case LOC_STATE_CONNECTED:
4885 		case LOC_STATE_DISCONNECTED:
4886 		if (locp->prev_state == LOC_STATE_EMPTY ||
4887 			locp->prev_state == LOC_STATE_UNKNOWN) {
4888 			/* handle fru insertion */
4889 			dr_arg.action = HANDLE_INSERT;
4890 		} else {
4891 			/* handle loc state change */
4892 			dr_arg.action = HANDLE_LOCSTATE_CHANGE;
4893 		}
4894 		break;
4895 		case LOC_STATE_EMPTY:
4896 		/* handle fru removal */
4897 		if (locp->prev_state == LOC_STATE_UNKNOWN) {
4898 			/* post piclevent to update led */
4899 			dr_arg.action = HANDLE_LOCSTATE_CHANGE;
4900 		} else {
4901 			/* disconnected fru is removed */
4902 			dr_arg.action = HANDLE_REMOVE;
4903 		}
4904 		break;
4905 		default:
4906 		return (PICL_WALK_CONTINUE);
4907 		} /* end of switch */
4908 
4909 		dr_arg.data   = locp;
4910 		(void) pthread_mutex_lock(&ev_mutex);
4911 		if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
4912 			(void) pthread_mutex_unlock(&ev_mutex);
4913 			return (PICL_WALK_CONTINUE);
4914 		}
4915 		(void) pthread_cond_signal(&ev_cond);
4916 		(void) pthread_mutex_unlock(&ev_mutex);
4917 		return (PICL_WALK_CONTINUE);
4918 	} else {
4919 		/* connect the disconnect locations */
4920 		if (locp->state == LOC_STATE_DISCONNECTED &&
4921 			locp->autoconfig_enabled == B_TRUE) {
4922 			if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
4923 				FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
4924 					locp->name, rc);
4925 			}
4926 			return (PICL_WALK_CONTINUE);
4927 		}
4928 	}
4929 
4930 	/* post picl event for child fru */
4931 	if (child_frup == NULL) {
4932 		return (PICL_WALK_CONTINUE);
4933 	}
4934 
4935 	/* update the state */
4936 	(void) update_fru_state(child_frup, &state_changed);
4937 	if (state_changed) {
4938 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
4939 			fru_state[child_frup->state],
4940 			fru_state[child_frup->prev_state],
4941 			child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
4942 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4943 				child_frup->name, PICLEVENT_STATE_CHANGE, rc);
4944 		}
4945 	}
4946 
4947 	/* update the condition */
4948 	(void) update_fru_condition(child_frup, &cond_changed);
4949 	if (cond_changed) {
4950 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
4951 			fru_cond[child_frup->cond],
4952 			fru_cond[child_frup->prev_cond],
4953 			child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
4954 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4955 				child_frup->name, PICLEVENT_CONDITION_CHANGE,
4956 				rc);
4957 		}
4958 	}
4959 	return (PICL_WALK_CONTINUE);
4960 }
4961 
4962 static picl_errno_t
handle_chassis_configure(frutree_frunode_t * frup)4963 handle_chassis_configure(frutree_frunode_t *frup)
4964 {
4965 	picl_errno_t	rc;
4966 
4967 	if (frup ==  NULL) {
4968 		return (PICL_INVALIDARG);
4969 	}
4970 
4971 	(void) pthread_mutex_lock(&frup->mutex);
4972 	FRUTREE_DEBUG1(EVENTS, "DR_INCOMING_RES on %s", frup->name);
4973 	if (frup->state == FRU_STATE_UNCONFIGURED) {
4974 		frup->state = FRU_STATE_CONFIGURING;
4975 		(void) pthread_mutex_unlock(&frup->mutex);
4976 		/* initial probe/initialization */
4977 		/* create a thread to do the initialization */
4978 		if (pthread_create(&init_threadID, NULL, &init_thread,
4979 			NULL) != 0) {
4980 			return (PICL_FAILURE);
4981 		}
4982 		return (PICL_SUCCESS);
4983 	}
4984 	(void) pthread_mutex_unlock(&frup->mutex);
4985 
4986 	/*
4987 	 * 1. update the state of all the nodes in chassis
4988 	 * 2. handle all the state changes accordingly
4989 	 */
4990 	if ((rc = ptree_walk_tree_by_class(chassish, PICL_CLASS_LOCATION,
4991 		(void *)frup, reconfigure_chassis)) != PICL_SUCCESS) {
4992 		return (rc);
4993 	}
4994 	return (PICL_SUCCESS);
4995 }
4996 
4997 static picl_errno_t
handle_chassis_unconfigure(frutree_frunode_t * frup)4998 handle_chassis_unconfigure(frutree_frunode_t *frup)
4999 {
5000 	picl_errno_t rc;
5001 
5002 	if (frup->state == FRU_STATE_UNCONFIGURED) {
5003 		return (PICL_SUCCESS);
5004 	}
5005 
5006 	/* do any cleanups here */
5007 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5008 		PICLEVENTARGVAL_UNCONFIGURING, PICLEVENTARGVAL_CONFIGURED,
5009 		chassish, WAIT)) != PICL_SUCCESS) {
5010 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5011 			PICL_NODE_CHASSIS, PICLEVENT_STATE_CHANGE, rc);
5012 	}
5013 
5014 	if ((rc = ptree_update_propval_by_name(chassish,
5015 		PICL_PROP_STATE, PICLEVENTARGVAL_UNCONFIGURED,
5016 		PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
5017 		FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
5018 			PICL_PROP_STATE, PICL_NODE_CHASSIS, rc);
5019 	}
5020 	frup->prev_state = FRU_STATE_CONFIGURED;
5021 	frup->state = FRU_STATE_UNCONFIGURED;
5022 	(void) handle_fru_unconfigure(frup);
5023 
5024 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5025 		PICLEVENTARGVAL_UNCONFIGURED, PICLEVENTARGVAL_UNCONFIGURING,
5026 		chassish, WAIT)) != PICL_SUCCESS) {
5027 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5028 			PICL_NODE_CHASSIS, PICLEVENT_STATE_CHANGE, rc);
5029 	}
5030 	return (PICL_SUCCESS);
5031 }
5032 
5033 static picl_errno_t
configuration_fn(frutree_dr_arg_t * dr_arg)5034 configuration_fn(frutree_dr_arg_t *dr_arg)
5035 {
5036 	picl_errno_t rc;
5037 	picl_nodehdl_t parenth;
5038 	cfga_flags_t flags = 0;
5039 	frutree_frunode_t *frup = NULL;
5040 	frutree_locnode_t *locp = NULL;
5041 	hashdata_t *hashptr = NULL;
5042 	boolean_t state_changed = B_FALSE;
5043 
5044 	if (dr_arg == NULL)
5045 		return (PICL_FAILURE);
5046 
5047 	frup = (frutree_frunode_t *)dr_arg->data;
5048 	if (frup == NULL) {
5049 		free(dr_arg);
5050 		return (PICL_FAILURE);
5051 	}
5052 
5053 	if (frup->frunodeh == chassish) {
5054 		rc = handle_chassis_configure(frup);
5055 		free(dr_arg);
5056 		return (rc);
5057 	}
5058 
5059 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
5060 		&parenth, sizeof (parenth))) != PICL_SUCCESS) {
5061 		free(dr_arg);
5062 		return (rc);
5063 	}
5064 
5065 	if ((rc = hash_lookup_entry(parenth, (void **)&hashptr)) !=
5066 		PICL_SUCCESS) {
5067 		free(dr_arg);
5068 		return (rc);
5069 	}
5070 	locp = LOCDATA_PTR(hashptr);
5071 
5072 	/*
5073 	 * update the location state also, as this could be
5074 	 * user initiated connect operation
5075 	 */
5076 	(void) update_loc_state(locp, &state_changed);
5077 	if (state_changed)
5078 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5079 		loc_state[locp->state], loc_state[locp->prev_state],
5080 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5081 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5082 			locp->name, PICLEVENT_STATE_CHANGE, rc);
5083 	}
5084 
5085 	switch (dr_arg->action) {
5086 	case CPU_ONLINE:
5087 		flags |= CFGA_FLAG_FORCE;
5088 		FRUTREE_DEBUG1(EVENTS, "CPU online on %s", frup->name);
5089 		if (locp->state != LOC_STATE_CONNECTED) {
5090 			if (locp->autoconfig_enabled) {
5091 				if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
5092 					FRUTREE_DEBUG2(EVENTS,
5093 						CONNECT_FAILED_ERR,
5094 						locp->name, rc);
5095 				}
5096 			}
5097 			break;
5098 		} /*FALLTHRU*/
5099 
5100 		/* do configure now */
5101 	case CONFIGURE_FRU:	/* dr_incoming_res */
5102 		FRUTREE_DEBUG1(EVENTS, "DR_INCOMING_RES on %s", frup->name);
5103 		if ((rc = configure_fru(frup, flags)) != PICL_SUCCESS) {
5104 			FRUTREE_DEBUG2(EVENTS, CONFIGURE_FAILED_ERR,
5105 				frup->name, rc);
5106 			break;
5107 		}
5108 	}
5109 	free(dr_arg);
5110 	return (PICL_SUCCESS);
5111 }
5112 
5113 /* handles all dr related events */
5114 static picl_errno_t
handle_dr_event(frutree_dr_arg_t * dr_arg)5115 handle_dr_event(frutree_dr_arg_t *dr_arg)
5116 {
5117 	picl_errno_t rc;
5118 	picl_nodehdl_t loch, childh;
5119 	hashdata_t *hashptr = NULL;
5120 	cfga_flags_t flags = 0;
5121 	frutree_dr_arg_t *arg = NULL;
5122 	frutree_dr_arg_t fru_dr_arg;
5123 	frutree_locnode_t *locp = NULL;
5124 	frutree_frunode_t *frup = NULL, *child_frup = NULL;
5125 	boolean_t state_changed = B_FALSE, cond_changed = B_FALSE;
5126 
5127 	switch (dr_arg->action) {
5128 	case CPU_ONLINE:
5129 	case CONFIGURE_FRU:
5130 
5131 	frup = (frutree_frunode_t *)dr_arg->data;
5132 	arg = (frutree_dr_arg_t *)malloc(sizeof (frutree_dr_arg_t));
5133 	if (arg == NULL) {
5134 		FRUTREE_DEBUG2(EVENTS, CONFIGURE_FAILED_ERR,
5135 			frup->name, PICL_NOSPACE);
5136 		return (NULL);
5137 	}
5138 	arg->action = dr_arg->action;
5139 	arg->data = dr_arg->data;
5140 	(void) configuration_fn((void *)arg);
5141 	break;
5142 
5143 	case CPU_OFFLINE:
5144 	flags |= CFGA_FLAG_FORCE;
5145 	frup = (frutree_frunode_t *)dr_arg->data;
5146 	if (frup == NULL) {
5147 		break;
5148 	}
5149 	FRUTREE_DEBUG1(EVENTS, "CPU_OFFLINE on %s", frup->name);
5150 	if ((rc = unconfigure_fru(frup, flags)) != PICL_SUCCESS) {
5151 		FRUTREE_DEBUG2(EVENTS, UNCONFIG_FAILED_ERR, frup->name, rc);
5152 		break;
5153 	}
5154 
5155 	if ((rc = handle_fru_unconfigure(frup)) != PICL_SUCCESS) {
5156 		FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED, PICLEVENT_DR_REQ,
5157 			frup->name, rc);
5158 	}
5159 	break;
5160 
5161 	case UNCONFIGURE_FRU:	/* dr_outgoing_res */
5162 	frup = (frutree_frunode_t *)dr_arg->data;
5163 	if (frup == NULL) {
5164 		break;
5165 	}
5166 	FRUTREE_DEBUG1(EVENTS, "DR_OUTGOING_RES on %s", frup->name);
5167 	if (frup->frunodeh == chassish) {
5168 		(void) handle_chassis_unconfigure(frup);
5169 		break;
5170 	}
5171 
5172 	if ((rc = unconfigure_fru(frup, flags)) != PICL_SUCCESS) {
5173 		FRUTREE_DEBUG2(EVENTS, UNCONFIG_FAILED_ERR, frup->name, rc);
5174 		break;
5175 	}
5176 
5177 	if ((rc = handle_fru_unconfigure(frup)) != PICL_SUCCESS) {
5178 		FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
5179 			PICLEVENT_DR_REQ, frup->name, rc);
5180 	}
5181 
5182 	if (ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
5183 		&loch, sizeof (loch)) != PICL_SUCCESS) {
5184 		break;
5185 	}
5186 
5187 	if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
5188 		PICL_SUCCESS) {
5189 		break;
5190 	}
5191 	locp = LOCDATA_PTR(hashptr);
5192 
5193 	/* check the autoconfig flag */
5194 	if (locp->autoconfig_enabled == B_FALSE) {
5195 		break;
5196 	}
5197 
5198 	if ((rc = disconnect_fru(locp)) != PICL_SUCCESS) {
5199 		FRUTREE_DEBUG2(EVENTS, "SUNW_frutree:Disconnect on %s "
5200 			"failed(error=%d)", locp->name, rc);
5201 	}
5202 	break;
5203 
5204 	case HANDLE_CONFIGURE:	/* basic hotswap operation */
5205 
5206 	frup = (frutree_frunode_t *)dr_arg->data;
5207 	if (frup == NULL) {
5208 		break;
5209 	}
5210 	FRUTREE_DEBUG1(EVENTS, "HANDLE CONFIGURE on %s", frup->name);
5211 	handle_fru_configure(frup);
5212 	break;
5213 
5214 	case HANDLE_UNCONFIGURE: /* basic hotswap operation */
5215 
5216 	/* cleanup the internal data structures */
5217 
5218 	frup = (frutree_frunode_t *)dr_arg->data;
5219 	if (frup == NULL) {
5220 		break;
5221 	}
5222 	FRUTREE_DEBUG1(EVENTS, "HANDLE UNCONFIGURE on %s", frup->name);
5223 
5224 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5225 		fru_state[frup->state], fru_state[frup->prev_state],
5226 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5227 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5228 			frup->name, PICLEVENT_STATE_CHANGE, rc);
5229 	}
5230 
5231 	/* update the  fru condition */
5232 	(void) update_fru_condition(frup, &state_changed);
5233 	if (state_changed) {
5234 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5235 			fru_cond[frup->cond], fru_cond[frup->prev_cond],
5236 			frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5237 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5238 				frup->name, PICLEVENT_CONDITION_CHANGE, rc);
5239 		}
5240 	}
5241 	if ((rc = handle_fru_unconfigure(frup)) != PICL_SUCCESS) {
5242 		FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
5243 			PICLEVENT_DR_AP_STATE_CHANGE, frup->name, rc);
5244 	}
5245 	break;
5246 
5247 	case HANDLE_LOCSTATE_CHANGE: /* basic hotswap operation */
5248 	/* posts state change events of location */
5249 	locp = (frutree_locnode_t *)dr_arg->data;
5250 	if (locp == NULL) {
5251 		break;
5252 	}
5253 	FRUTREE_DEBUG1(EVENTS, "HANDLE LOC STATE CHANGE on %s", locp->name);
5254 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5255 		loc_state[locp->state], loc_state[locp->prev_state],
5256 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5257 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5258 			locp->name, PICLEVENT_STATE_CHANGE, rc);
5259 	}
5260 
5261 	/* wakeup threads sleeping on this condition */
5262 	(void) pthread_mutex_lock(&locp->mutex);
5263 	if (locp->state == LOC_STATE_CONNECTED) {
5264 		(void) pthread_cond_broadcast(&locp->cond_cv);
5265 	}
5266 	(void) pthread_mutex_unlock(&locp->mutex);
5267 
5268 	/* if the location has child fru, get its information */
5269 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
5270 		&childh, sizeof (childh)) == PICL_SUCCESS) {
5271 		/* get the child fru information */
5272 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
5273 			PICL_SUCCESS) {
5274 			child_frup = FRUDATA_PTR(hashptr);
5275 		}
5276 	}
5277 	/* update the child fru state and handle any state changes */
5278 	if (child_frup == NULL) {
5279 		break;
5280 	}
5281 
5282 	if ((rc = update_fru_state(child_frup, &state_changed)) !=
5283 		PICL_SUCCESS) {
5284 		FRUTREE_DEBUG2(EVENTS, GET_FRU_STATE_ERR, child_frup->name, rc);
5285 		break;
5286 	}
5287 
5288 	if (state_changed == B_FALSE) {
5289 		/*
5290 		 * if there is no change in state, check for condition
5291 		 * changes.
5292 		 * if there is a state change, handling state change
5293 		 * will take care of condition changes also.
5294 		 */
5295 		(void) update_fru_condition(child_frup, &cond_changed);
5296 		if (cond_changed == B_FALSE) {
5297 			break;
5298 		}
5299 
5300 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5301 			fru_cond[child_frup->cond],
5302 			fru_cond[child_frup->prev_cond],
5303 			child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5304 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5305 				child_frup->name,
5306 				PICLEVENT_CONDITION_CHANGE, rc);
5307 		}
5308 		break;
5309 	}
5310 
5311 	/* add to queue to handle the fru state change */
5312 	(void) pthread_mutex_lock(&child_frup->mutex);
5313 	/* figure out if this is config/unconfig operation */
5314 	if (child_frup->state == FRU_STATE_CONFIGURED) {
5315 		fru_dr_arg.action = HANDLE_CONFIGURE;
5316 		fru_dr_arg.data = child_frup;
5317 	} else if (child_frup->state == FRU_STATE_UNCONFIGURED) {
5318 		fru_dr_arg.action = HANDLE_UNCONFIGURE;
5319 		fru_dr_arg.data = child_frup;
5320 	}
5321 	(void) pthread_mutex_unlock(&child_frup->mutex);
5322 
5323 	(void) pthread_mutex_lock(&ev_mutex);
5324 	if ((rc = add_to_queue(fru_dr_arg)) != PICL_SUCCESS) {
5325 		(void) pthread_mutex_unlock(&ev_mutex);
5326 		break;
5327 	}
5328 	(void) pthread_cond_signal(&ev_cond);
5329 	(void) pthread_mutex_unlock(&ev_mutex);
5330 	break;
5331 
5332 	case HANDLE_INSERT: /* dr_apstate_change (HINT_INSERT) */
5333 	locp = (frutree_locnode_t *)dr_arg->data;
5334 	if (locp == NULL) {
5335 		break;
5336 	}
5337 	FRUTREE_DEBUG1(EVENTS, "HANDLE INSERT on %s", locp->name);
5338 	/* if the location has child fru, get its information */
5339 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
5340 		&childh, sizeof (childh)) == PICL_SUCCESS) {
5341 		/* get the child fru information */
5342 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
5343 			PICL_SUCCESS) {
5344 			child_frup = FRUDATA_PTR(hashptr);
5345 		}
5346 	}
5347 	if (child_frup) {
5348 		/*
5349 		 * if previous state is not empty, it could be a
5350 		 * hint insert to retry connects
5351 		 */
5352 		(void) update_loc_state(locp, &state_changed);
5353 		if (state_changed) {
5354 			if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5355 				loc_state[locp->state],
5356 				loc_state[locp->prev_state], locp->locnodeh,
5357 				WAIT)) != PICL_SUCCESS) {
5358 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5359 					locp->name, PICLEVENT_STATE_CHANGE, rc);
5360 			}
5361 		}
5362 
5363 		(void) update_fru_condition(child_frup, &cond_changed);
5364 		if (cond_changed == B_TRUE) {
5365 			if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5366 				fru_cond[child_frup->cond],
5367 				fru_cond[child_frup->prev_cond],
5368 				child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5369 					FRUTREE_DEBUG3(EVENTS,
5370 						PTREE_POST_PICLEVENT_ERR,
5371 						child_frup->name,
5372 						PICLEVENT_CONDITION_CHANGE, rc);
5373 				}
5374 			}
5375 		if (!locp->autoconfig_enabled) {
5376 			break;
5377 		}
5378 
5379 		if (locp->state != LOC_STATE_CONNECTED) {
5380 			if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
5381 				FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
5382 					locp->name, rc);
5383 			}
5384 		}
5385 		break;
5386 	}
5387 
5388 	(void) update_loc_state(locp, &state_changed);
5389 	if ((rc = create_fru_node(locp, &child_frup)) != PICL_SUCCESS) {
5390 		FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
5391 			PICLEVENT_DR_AP_STATE_CHANGE, locp->name, rc);
5392 		break;
5393 	}
5394 
5395 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5396 		loc_state[locp->state], loc_state[locp->prev_state],
5397 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5398 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5399 			locp->name, PICLEVENT_STATE_CHANGE, rc);
5400 	}
5401 
5402 	if (locp->autoconfig_enabled) {
5403 		if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
5404 			FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
5405 				locp->name, rc);
5406 		}
5407 	}
5408 	break;
5409 
5410 	case HANDLE_REMOVE: /* dr_apstate_change (HINT_REMOVE) */
5411 	locp = (frutree_locnode_t *)dr_arg->data;
5412 	if (locp == NULL) {
5413 		break;
5414 	}
5415 	FRUTREE_DEBUG1(EVENTS, "HANDLE REMOVE on %s", locp->name);
5416 
5417 	if (locp->state == LOC_STATE_EMPTY) {
5418 		break;	/* discard the spurious event */
5419 	}
5420 
5421 	(void) update_loc_state(locp, &state_changed);
5422 	/* if the location has child fru, get its information */
5423 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
5424 		&childh, sizeof (childh)) == PICL_SUCCESS) {
5425 		/* get the child fru information */
5426 		if (hash_lookup_entry(childh, (void **)&hashptr) ==
5427 			PICL_SUCCESS) {
5428 			frup = FRUDATA_PTR(hashptr);
5429 		}
5430 	}
5431 	if (frup == NULL) {
5432 		break;
5433 	}
5434 
5435 	/*
5436 	 * frutree need to post this event before handling the
5437 	 * fru remove, so that other plugins (like frudata) can
5438 	 * do the cleanup
5439 	 */
5440 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5441 		loc_state[locp->state], loc_state[locp->prev_state],
5442 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5443 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5444 			locp->name, PICLEVENT_STATE_CHANGE, rc);
5445 	}
5446 
5447 	if ((rc = handle_fru_remove(frup)) != PICL_SUCCESS) {
5448 		FRUTREE_DEBUG2(EVENTS, "SUNW_frutree:Error in handling"
5449 		"removal of fru under %s(error=%d)", locp->name, rc);
5450 	}
5451 	break;
5452 
5453 	case POST_COND_EVENT:
5454 	frup = (frutree_frunode_t *)dr_arg->data;
5455 	if (frup == NULL) {
5456 		break;
5457 	}
5458 	if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5459 		fru_cond[frup->cond], fru_cond[frup->prev_cond],
5460 		frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5461 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5462 			frup->name, PICLEVENT_CONDITION_CHANGE, rc);
5463 	}
5464 	default:
5465 		break;
5466 	}
5467 	return (PICL_SUCCESS);
5468 }
5469 
5470 /*ARGSUSED*/
5471 static void*
dr_thread(void * arg)5472 dr_thread(void * arg)
5473 {
5474 	ev_queue_t	*event = NULL;
5475 
5476 	(void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
5477 	(void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
5478 	for (;;) {
5479 		if (fini_called)
5480 			break;
5481 		(void) pthread_mutex_lock(&ev_mutex);
5482 		while (queue_head == NULL) {
5483 			(void) pthread_cond_wait(&ev_cond, &ev_mutex);
5484 		}
5485 
5486 		event = remove_from_queue();
5487 		(void) pthread_mutex_unlock(&ev_mutex);
5488 		while (event) {
5489 			(void) handle_dr_event(&event->arg);
5490 			free(event);
5491 			event = NULL;
5492 			(void) pthread_mutex_lock(&ev_mutex);
5493 			event = remove_from_queue();
5494 			(void) pthread_mutex_unlock(&ev_mutex);
5495 		}
5496 	}
5497 	return (NULL);
5498 }
5499 
5500 static picl_errno_t
update_port_state(frutree_portnode_t * portp,boolean_t post_ev)5501 update_port_state(frutree_portnode_t *portp, boolean_t post_ev)
5502 {
5503 	int state, cond;
5504 	picl_errno_t rc;
5505 	uint64_t ap_status_time;
5506 	boolean_t state_changed = B_FALSE;
5507 	boolean_t cond_changed = B_FALSE;
5508 	frutree_port_type_t port_type;
5509 
5510 	if (portp == NULL) {
5511 		return (PICL_INVALIDARG);
5512 	}
5513 	port_type = frutree_get_port_type(portp);
5514 
5515 	if (port_type == UNKNOWN_PORT) {
5516 		return (PICL_SUCCESS);
5517 	}
5518 	state = kstat_port_state(port_type, portp->driver,
5519 		portp->instance);
5520 	cond = kstat_port_cond(port_type, portp->driver,
5521 		portp->instance);
5522 	switch (state) {
5523 	case 0:
5524 		/* DOWN */
5525 		if (portp->state != PORT_STATE_DOWN) {
5526 			portp->state = PORT_STATE_DOWN;
5527 			state_changed = B_TRUE;
5528 		}
5529 		break;
5530 	case 1:
5531 		/* UP */
5532 		if (portp->state != PORT_STATE_UP) {
5533 			portp->state = PORT_STATE_UP;
5534 			state_changed = B_TRUE;
5535 		}
5536 		break;
5537 	default:
5538 		/* UNKNOWN */
5539 		if (portp->state != PORT_STATE_UNKNOWN) {
5540 			portp->state = PORT_STATE_UNKNOWN;
5541 			state_changed = B_TRUE;
5542 		}
5543 	}
5544 
5545 	if (post_ev && state_changed) {
5546 		ap_status_time = (uint64_t)(time(NULL));
5547 		if ((rc = ptree_update_propval_by_name(portp->portnodeh,
5548 			PICL_PROP_STATUS_TIME, &ap_status_time,
5549 			sizeof (uint64_t))) != PICL_SUCCESS) {
5550 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
5551 				PICL_PROP_STATUS_TIME, portp->name, rc);
5552 
5553 		}
5554 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5555 			port_state[portp->state], NULL,
5556 			portp->portnodeh, WAIT)) != PICL_SUCCESS) {
5557 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5558 				portp->name, PICLEVENT_STATE_CHANGE, rc);
5559 		}
5560 	}
5561 
5562 	switch (cond) {
5563 	case 0:
5564 		if (portp->cond != PORT_COND_OK) {
5565 			portp->cond = PORT_COND_OK;
5566 			cond_changed = B_TRUE;
5567 		}
5568 		break;
5569 	case 1:
5570 		if (portp->cond != PORT_COND_FAILING) {
5571 			portp->cond = PORT_COND_FAILING;
5572 			cond_changed = B_TRUE;
5573 		}
5574 		break;
5575 	case 2:
5576 		if (portp->cond != PORT_COND_FAILED) {
5577 			portp->cond = PORT_COND_FAILED;
5578 			cond_changed = B_TRUE;
5579 		}
5580 		break;
5581 	case 3:
5582 		if (portp->cond != PORT_COND_TESTING) {
5583 			portp->cond = PORT_COND_TESTING;
5584 			cond_changed = B_TRUE;
5585 		}
5586 		break;
5587 	default:
5588 		if (portp->cond != PORT_COND_UNKNOWN) {
5589 			portp->cond = PORT_COND_UNKNOWN;
5590 			cond_changed = B_TRUE;
5591 		}
5592 	}
5593 
5594 	if (post_ev && cond_changed) {
5595 		ap_status_time = (uint64_t)(time(NULL));
5596 		if ((rc = ptree_update_propval_by_name(portp->portnodeh,
5597 			PICL_PROP_CONDITION_TIME, &ap_status_time,
5598 			sizeof (uint64_t))) != PICL_SUCCESS) {
5599 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
5600 				PICL_PROP_CONDITION_TIME, portp->name, rc);
5601 		}
5602 		if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5603 			port_cond[portp->cond], NULL,
5604 			portp->portnodeh, WAIT)) != PICL_SUCCESS) {
5605 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5606 				portp->name, PICLEVENT_CONDITION_CHANGE, rc);
5607 		}
5608 	}
5609 	return (PICL_SUCCESS);
5610 }
5611 
5612 /*
5613  * monitor port nodes and scsi nodes under a fru
5614  */
5615 static int
monitor_nodes_under_fru(picl_nodehdl_t nodeh,void * c_args)5616 monitor_nodes_under_fru(picl_nodehdl_t nodeh, void *c_args)
5617 {
5618 	picl_errno_t rc;
5619 	picl_nodehdl_t parenth;
5620 	hashdata_t *hashptr = NULL;
5621 	boolean_t state_changed;
5622 	frutree_portnode_t *portp = NULL;
5623 	frutree_locnode_t *locp = NULL;
5624 	frutree_frunode_t *frup = NULL;
5625 	char class[PICL_PROPNAMELEN_MAX];
5626 	char slot_type[PICL_PROPNAMELEN_MAX];
5627 
5628 	if (c_args ==  NULL) {
5629 		return (PICL_INVALIDARG);
5630 	}
5631 	frup = (frutree_frunode_t *)c_args;
5632 
5633 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
5634 		&parenth, sizeof (parenth)) != PICL_SUCCESS) {
5635 		return (PICL_WALK_CONTINUE);
5636 	}
5637 
5638 	if (parenth != frup->frunodeh)
5639 		return (PICL_WALK_CONTINUE);
5640 
5641 	if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, class,
5642 		sizeof (class))) != PICL_SUCCESS) {
5643 		return (PICL_WALK_CONTINUE);
5644 	}
5645 
5646 	if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
5647 		PICL_SUCCESS) {
5648 		return (PICL_WALK_CONTINUE);
5649 	}
5650 
5651 	if (strcmp(class, PICL_CLASS_LOCATION) == 0) {
5652 		locp = LOCDATA_PTR(hashptr);
5653 		if (ptree_get_propval_by_name(locp->locnodeh,
5654 			PICL_PROP_SLOT_TYPE, slot_type,
5655 			sizeof (slot_type)) != PICL_SUCCESS) {
5656 			return (PICL_WALK_CONTINUE);
5657 		}
5658 		if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
5659 			strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
5660 			return (PICL_WALK_CONTINUE);
5661 		}
5662 		(void) update_loc_state(locp, &state_changed);
5663 		if (state_changed) {
5664 			if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5665 				loc_state[locp->state],
5666 				loc_state[locp->prev_state],
5667 				locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5668 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5669 					locp->name, PICLEVENT_STATE_CHANGE, rc);
5670 			}
5671 		}
5672 	} else if (strcmp(class, PICL_CLASS_PORT) == 0) {
5673 		portp = PORTDATA_PTR(hashptr);
5674 		(void) update_port_state(portp, B_TRUE);
5675 	}
5676 	return (PICL_WALK_CONTINUE);
5677 }
5678 
5679 /* This routine monitors only port node, scsi nodes */
5680 /* ARGSUSED */
5681 static int
monitor_fru(picl_nodehdl_t nodeh,void * c_args)5682 monitor_fru(picl_nodehdl_t nodeh, void *c_args)
5683 {
5684 	picl_errno_t rc;
5685 	picl_nodehdl_t loch;
5686 	hashdata_t *hashptr = NULL;
5687 	frutree_frunode_t *frup = NULL;
5688 	boolean_t state_changed, cond_changed;
5689 	char slot_type[PICL_PROPNAMELEN_MAX];
5690 
5691 	if (hash_lookup_entry(nodeh, (void **)&hashptr) !=
5692 		PICL_SUCCESS) {
5693 		return (PICL_WALK_CONTINUE);
5694 	}
5695 	frup = FRUDATA_PTR(hashptr);
5696 
5697 	(void) pthread_mutex_lock(&frup->mutex);
5698 	if (frup->dr_in_progress) {
5699 		(void) pthread_mutex_unlock(&frup->mutex);
5700 		return (PICL_WALK_CONTINUE);
5701 	}
5702 	frup->busy = B_TRUE;
5703 	(void) pthread_mutex_unlock(&frup->mutex);
5704 
5705 	/* get the parent information to determine if it is scsi slot or not */
5706 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
5707 		&loch, sizeof (loch)) != PICL_SUCCESS) {
5708 		return (PICL_WALK_CONTINUE);
5709 	}
5710 	if (ptree_get_propval_by_name(loch, PICL_PROP_SLOT_TYPE, slot_type,
5711 		sizeof (slot_type)) != PICL_SUCCESS) {
5712 		return (PICL_WALK_CONTINUE);
5713 	}
5714 
5715 	if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
5716 		strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
5717 		/* scsi fru */
5718 		(void) update_fru_state(frup, &state_changed);
5719 		(void) update_fru_condition(frup, &cond_changed);
5720 		if (state_changed) {
5721 			if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5722 				fru_state[frup->state],
5723 				fru_state[frup->prev_state],
5724 				frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5725 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5726 					frup->name, PICLEVENT_STATE_CHANGE, rc);
5727 			}
5728 		}
5729 		if (cond_changed) {
5730 			if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5731 				fru_cond[frup->cond], fru_cond[frup->prev_cond],
5732 				frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5733 				FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5734 					frup->name, PICLEVENT_CONDITION_CHANGE,
5735 					rc);
5736 			}
5737 		}
5738 		(void) pthread_mutex_lock(&frup->mutex);
5739 		frup->busy = B_FALSE;
5740 		(void) pthread_cond_signal(&frup->busy_cond_cv);
5741 		(void) pthread_mutex_unlock(&frup->mutex);
5742 		return (PICL_WALK_CONTINUE);
5743 	}
5744 
5745 	if (frup->state != FRU_STATE_CONFIGURED) {
5746 		(void) pthread_mutex_lock(&frup->mutex);
5747 		frup->busy = B_FALSE;
5748 		(void) pthread_cond_signal(&frup->busy_cond_cv);
5749 		(void) pthread_mutex_unlock(&frup->mutex);
5750 		return (PICL_WALK_CONTINUE);
5751 	}
5752 
5753 	(void) ptree_walk_tree_by_class(chassish,
5754 		NULL, (void *)frup, monitor_nodes_under_fru);
5755 
5756 	(void) pthread_mutex_lock(&frup->mutex);
5757 	frup->busy = B_FALSE;
5758 	(void) pthread_cond_signal(&frup->busy_cond_cv);
5759 	(void) pthread_mutex_unlock(&frup->mutex);
5760 	return (PICL_WALK_CONTINUE);
5761 }
5762 
5763 /* ARGSUSED */
5764 static void *
monitor_node_status(void * arg)5765 monitor_node_status(void *arg)
5766 {
5767 	int err;
5768 	timestruc_t	to;
5769 	struct timeval	tp;
5770 
5771 	(void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
5772 	(void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
5773 
5774 	FRUTREE_DEBUG0(EVENTS, "Monitoring for port status started");
5775 	do
5776 	{
5777 		(void) pthread_mutex_lock(&monitor_mutex);
5778 		(void) gettimeofday(&tp, NULL);
5779 		to.tv_sec = tp.tv_sec + frutree_poll_timeout;
5780 		to.tv_nsec = tp.tv_usec * 1000;
5781 		err = pthread_cond_timedwait(&monitor_cv, &monitor_mutex, &to);
5782 
5783 		(void) pthread_mutex_unlock(&monitor_mutex);
5784 		if (err == ETIMEDOUT) { /* woke up from sleep */
5785 			(void) ptree_walk_tree_by_class(chassish,
5786 				PICL_CLASS_FRU, (void *)NULL, monitor_fru);
5787 		}
5788 	} while (fini_called == 0);
5789 	return (NULL);
5790 }
5791 
5792 picl_errno_t
create_children(frutree_frunode_t * frup,char * scsi_loc,char * bus_addr,int slot_no,char * slot_type,boolean_t is_cfgadm_ap)5793 create_children(frutree_frunode_t *frup, char *scsi_loc, char *bus_addr,
5794 	int slot_no, char *slot_type, boolean_t is_cfgadm_ap)
5795 {
5796 	int i = 0;
5797 	picl_errno_t rc;
5798 	picl_nodehdl_t nodeh;
5799 	uint8_t geo_addr = 0;
5800 	hashdata_t *datap = NULL;
5801 	frutree_locnode_t *locp = NULL;
5802 	hashdata_t *hashptr = NULL;
5803 	char fru_type[PICL_PROPNAMELEN_MAX];
5804 	frutree_frunode_t *child_frup = NULL;
5805 	frutree_callback_data_t fru_arg;
5806 
5807 	if (frup == NULL || scsi_loc == NULL || slot_type == NULL) {
5808 		return (PICL_FAILURE);
5809 	}
5810 
5811 	/* check if the location is already created */
5812 	(void) strncpy(fru_arg.node_name, scsi_loc,
5813 		sizeof (fru_arg.node_name));
5814 	fru_arg.retnodeh = 0;
5815 	if ((rc = ptree_walk_tree_by_class(chassish, PICL_CLASS_LOCATION,
5816 		&fru_arg, frutree_get_nodehdl)) == PICL_SUCCESS) {
5817 		if (fru_arg.retnodeh != 0) { /* node is already present */
5818 			return (PICL_SUCCESS);
5819 		}
5820 	}
5821 
5822 	/* create the location node and all its properties */
5823 	if ((rc = ptree_create_node(scsi_loc, PICL_CLASS_LOCATION,
5824 		&nodeh)) != PICL_SUCCESS) {
5825 		return (rc);
5826 	}
5827 
5828 	if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5829 		PICL_PROPNAMELEN_MAX, PICL_PROP_SLOT_TYPE, NULLREAD,
5830 		NULLWRITE, nodeh, NULL, slot_type)) !=
5831 		PICL_SUCCESS) {
5832 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5833 			PICL_PROP_SLOT_TYPE, scsi_loc, rc);
5834 	}
5835 
5836 	if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5837 		PICL_PROPNAMELEN_MAX, PICL_PROP_LABEL, NULLREAD,
5838 		NULLWRITE, nodeh, NULL, bus_addr)) != PICL_SUCCESS) {
5839 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5840 			PICL_PROP_LABEL, scsi_loc, rc);
5841 	}
5842 
5843 	if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5844 		PICL_PROPNAMELEN_MAX, PICL_PROP_BUS_ADDR, NULLREAD,
5845 		NULLWRITE, nodeh, NULL, bus_addr)) != PICL_SUCCESS) {
5846 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5847 			PICL_PROP_BUS_ADDR, scsi_loc, rc);
5848 	}
5849 
5850 	geo_addr = slot_no;
5851 	if ((rc = create_property(PICL_PTYPE_UNSIGNED_INT, PICL_READ,
5852 		sizeof (uint8_t), PICL_PROP_GEO_ADDR, NULLREAD,
5853 		NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
5854 		&geo_addr)) != PICL_SUCCESS) {
5855 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5856 			PICL_PROP_GEO_ADDR, scsi_loc, rc);
5857 	}
5858 
5859 	if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5860 		PICL_PROPNAMELEN_MAX, PICL_PROP_DEVFS_PATH, NULLREAD,
5861 		NULLWRITE, nodeh, NULL, frup->fru_path)) !=
5862 		PICL_SUCCESS) {
5863 		FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5864 			PICL_PROP_DEVFS_PATH, scsi_loc, rc);
5865 	}
5866 
5867 	if ((rc = ptree_add_node(frup->frunodeh, nodeh)) != PICL_SUCCESS) {
5868 		(void) ptree_destroy_node(nodeh);
5869 		return (rc);
5870 	}
5871 
5872 	/* save the node in hashtable */
5873 	if ((rc = make_loc_data(scsi_loc, &datap)) != PICL_SUCCESS) {
5874 		return (rc);
5875 	}
5876 	locp = LOCDATA_PTR(datap);
5877 	locp->locnodeh = nodeh;
5878 	/* save data in hash table */
5879 	(void) hash_add_entry(nodeh, (void *)datap);
5880 
5881 	if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
5882 		PICL_SUCCESS) {
5883 		return (rc);
5884 	}
5885 	locp = LOCDATA_PTR(hashptr);
5886 
5887 	if (is_cfgadm_ap != B_TRUE) {	/* device found in libdevinfo */
5888 		locp->state_mgr = STATIC_LOC;
5889 		locp->state = LOC_STATE_CONNECTED;
5890 	}
5891 
5892 	if ((rc = location_init(locp)) != PICL_SUCCESS) {
5893 		return (rc);
5894 	}
5895 
5896 	/* if location is empty, done */
5897 	if (locp->state == LOC_STATE_EMPTY) {
5898 		if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5899 			PICLEVENTARGVAL_EMPTY, NULL,
5900 			locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5901 			FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5902 				locp->name, PICLEVENT_STATE_CHANGE, rc);
5903 		}
5904 		return (PICL_SUCCESS);
5905 	}
5906 
5907 	/* create the fru node and initilize it */
5908 	if ((rc = create_fru_node(locp, &child_frup)) != PICL_SUCCESS) {
5909 		return (rc);
5910 	}
5911 
5912 	/* post picl event on location (frudata is consumer for these events) */
5913 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5914 		loc_state[locp->state], PICLEVENTARGVAL_EMPTY,
5915 		locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5916 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5917 			locp->name, PICLEVENT_STATE_CHANGE, rc);
5918 	}
5919 
5920 	if (child_frup->state_mgr == STATIC_LOC) {
5921 		/* derive the fru_type from name */
5922 		while (i < strlen(scsi_loc)) {
5923 			if (isdigit(scsi_loc[i])) {
5924 				(void) strncpy(fru_type, scsi_loc, i);
5925 				fru_type[i] = '\0';
5926 				break;
5927 			}
5928 			++i;
5929 		}
5930 		if ((rc = ptree_update_propval_by_name(child_frup->frunodeh,
5931 			PICL_PROP_FRU_TYPE, fru_type, sizeof (fru_type))) !=
5932 			PICL_SUCCESS) {
5933 			FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
5934 				PICL_PROP_FRU_TYPE, child_frup->name, rc);
5935 		}
5936 	}
5937 
5938 	/* post picl state change event on fru state */
5939 	if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5940 		fru_state[child_frup->state], PICLEVENTARGVAL_UNKNOWN,
5941 		child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5942 		FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5943 			frup->name, PICLEVENT_STATE_CHANGE, rc);
5944 	}
5945 	/*  for scsi FRUs we need not probe further */
5946 	return (PICL_SUCCESS);
5947 }
5948 
5949 /*
5950  * recursive search in the subtree
5951  */
5952 /*ARGSUSED*/
5953 boolean_t
is_location_present_in_subtree(frutree_frunode_t * frup,const char * name,const char * path)5954 is_location_present_in_subtree(frutree_frunode_t *frup, const char *name,
5955 	const char *path)
5956 {
5957 	frutree_callback_data_t fru_arg;
5958 
5959 	(void) strncpy(fru_arg.node_name, name,
5960 		sizeof (fru_arg.node_name));
5961 	fru_arg.retnodeh = 0;
5962 	if (ptree_walk_tree_by_class(frup->frunodeh, PICL_CLASS_LOCATION,
5963 		&fru_arg, frutree_get_nodehdl) == PICL_SUCCESS) {
5964 		if (fru_arg.retnodeh != 0) { /* node is already present */
5965 			return (B_TRUE);
5966 		}
5967 	}
5968 	return (B_FALSE);
5969 }
5970