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